修改ambari样式-前端View扩展[二]
# 3. 基于 displayType
的渲染
# 3.1 作用
- 定义:基于
displayType
控制页面控件类型和展示样式。适合高级配置场景,可以灵活指定不同类型的表单控件(如单选按钮、复选框、文本框等)。 - 使用场景:适合属性繁多、控件种类丰富的高级配置页面,便于多样化输入交互。
# 3.2 渲染效果说明
在 Ambari 的页面渲染体系中,displayType
是决定控件展现的关键配置。不同 displayType
会直接关联不同的控件组件,比如单选、复选、密码框、目录、多行文本区等。
# 3.2.1 displayType
映射表
displayType | 对应控件视图 | 渲染效果 | 使用场景 |
---|---|---|---|
user / group | App.ServiceConfigTextFieldUserGroupWithID | 用户/组输入文本框 | 设置用户或组属性 |
checkbox / boolean | App.ServiceConfigCheckbox | 渲染复选框 | 启用/禁用功能的布尔配置 |
boolean-inverted | App.ServiceConfigCheckbox | 渲染反向布尔复选框 | 反向布尔配置 |
password | App.ServiceConfigPasswordField | 密码输入框,字符隐藏 | 输入敏感信息 |
combobox | App.ServiceConfigComboBox | 下拉菜单 | 选定项选择 |
radio button | App.ServiceConfigRadioButtons | 单选按钮组 | 互斥选项选择 |
directories | App.ServiceConfigTextArea | 多行文本框,多目录路径输入 | 多路径配置 |
directory | App.ServiceConfigTextField | 单行文本框,目录路径输入 | 单目录配置 |
content | App.ServiceConfigTextAreaContent | 大文本区,长文本/脚本 | 配置脚本/大段文本 |
multiLine | App.ServiceConfigTextArea | 多行文本框,多行输入 | 长文本输入 |
custom | App.ServiceConfigBigTextArea | 超大文本框,支持复杂内容 | 复杂文本/配置文件输入 |
componentHost | App.ServiceConfigMasterHostView | 主机选择器 | 组件主机分配 |
label | App.ServiceConfigLabelView | 只读标签,仅展示 | 显示只读信息 |
componentHosts | App.ServiceConfigComponentHostsView | 主机多选列表,多个主机分配 | 多主机组件 |
supportTextConnection | App.checkConnectionView | 测试连接按钮 | 连通性检测 |
capacityScheduler | App.CapacitySceduler | YARN容量调度控件 | 调度策略设置 |
default | App.ServiceConfigTextFieldWithUnit / App.ServiceConfigTextField | 单行文本框,可附加单位 | 默认文本输入 |
# 3.2.2 渲染逻辑代码示例
【代码位置:app/models/configs/objects/service_config_property.js
】
getViewClass: function (displayType, dependentConfigPattern, unit) {
switch (displayType) {
case 'user':
case 'group':
return App.ServiceConfigTextFieldUserGroupWithID;
case 'checkbox':
case 'boolean':
return dependentConfigPattern ? App.ServiceConfigCheckboxWithDependencies : App.ServiceConfigCheckbox;
case 'boolean-inverted':
return App.ServiceConfigCheckbox;
case 'password':
return App.ServiceConfigPasswordField;
case 'combobox':
return App.ServiceConfigComboBox;
case 'radio button':
return App.ServiceConfigRadioButtons;
case 'directories':
return App.ServiceConfigTextArea;
case 'directory':
return App.ServiceConfigTextField;
case 'content':
return App.ServiceConfigTextAreaContent;
case 'multiLine':
return App.ServiceConfigTextArea;
case 'custom':
return App.ServiceConfigBigTextArea;
case 'componentHost':
return App.ServiceConfigMasterHostView;
case 'label':
return App.ServiceConfigLabelView;
case 'componentHosts':
return App.ServiceConfigComponentHostsView;
case 'supportTextConnection':
return App.checkConnectionView;
case 'capacityScheduler':
return App.CapacitySceduler;
default:
return unit ? App.ServiceConfigTextFieldWithUnit : App.ServiceConfigTextField;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 3.2.3 displayType
为 radio button
的典型配置
示例(app/data/configs/services/ranger_properties.js
):
{
"category": "RangerSettings",
"displayType": "radio button",
"filename": "ranger-admin-site.xml",
"name": "ranger.authentication.method",
"options": [
{
"displayName": "LDAP",
"foreignKeys": [
"ranger.ldap.group.roleattribute",
"ranger.ldap.url",
"ranger.ldap.user.dnpattern",
"ranger.ldap.base.dn",
"ranger.ldap.bind.dn",
"ranger.ldap.bind.password",
"ranger.ldap.referral",
"ranger.ldap.user.searchfilter",
"ranger.ldap.group.searchbase",
"ranger.ldap.group.searchfilter"
]
},
{
"displayName": "ACTIVE_DIRECTORY",
"foreignKeys": [
"ranger.ldap.ad.domain",
"ranger.ldap.ad.url",
"ranger.ldap.ad.base.dn",
"ranger.ldap.ad.bind.dn",
"ranger.ldap.ad.bind.password",
"ranger.ldap.ad.referral",
"ranger.ldap.ad.user.searchfilter"
]
},
{
"displayName": "UNIX",
"foreignKeys": [
"ranger.unixauth.service.port",
"ranger.unixauth.service.hostname",
"ranger.unixauth.remote.login.enabled"
]
},
{
"displayName": "PAM"
},
{
"displayName": "NONE"
}
],
"radioName": "authentication-method",
"serviceName": "RANGER"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 3.3 前端数据流与配置处理链
# 3.3.1 不依赖后端的 JS 配置
位置:app/data/BIGTOP/site_properties.js
module.exports = {
configProperties: [
{
name: 'some_property',
displayName: 'Some Property',
description: 'Description of the property.',
serviceName: 'BIGTOP',
filename: 'bigtop-site.xml',
category: 'General',
displayType: 'text',
isRequired: true
},
...
]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
代码注释和结构未删减
# 3.3.2 依赖切片的配置
位置:app/data/configs/site_properties.js
var includeSiteProperties = function () {
var serviceNames = Array.prototype.slice.call(arguments);
return serviceNames.reduce(function (acc, serviceName) {
return acc.concat(require('data/configs/services/' + serviceName + '_properties'));
}, []);
};
module.exports = {
configProperties: includeSiteProperties(
'accumulo',
'ambari_infra_solr',
'ambari_metrics',
'falcon',
'flume',
'glusterfs',
'hawq',
'hbase',
'hdfs',
'hive',
'kafka',
'kerberos',
'knox',
'logsearch',
'mapreduce2',
'oozie',
'ranger',
'storm',
'tez',
'yarn',
'zookeeper'
)
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
所有 require 片段原样保留
# 3.3.3 前端渲染处理
位置: app/utils/config.js
allPreDefinedSiteProperties: require('data/configs/site_properties').configProperties,
preDefinedSiteProperties
:
function () {
var serviceNames = App.StackService.find().mapProperty('serviceName').concat('MISC');
return this.get('allPreDefinedSiteProperties').filter(function (p) {
return serviceNames.contains(p.serviceName);
});
}
.
property().volatile(),
preDefinedSitePropertiesMap
:
function () {
var map = {};
this.get('preDefinedSiteProperties').forEach(function (c) {
map[this.configId(c.name, c.filename)] = c;
}, this);
return map;
}
.
property('preDefinedSiteProperties'),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 3.3.4 渲染过程
位置:app/mappers/configs/stack_config_properties_mapper.js
getUIConfig: function (propertyName, siteName) {
return App.config.get('preDefinedSitePropertiesMap')[App.config.configId(propertyName, siteName)];
}
,
mergeWithUI: function (config) {
var c = config.StackConfigurations;
var uiConfigProperty = this.getUIConfig(c.property_name, c.type);
config.category = uiConfigProperty && uiConfigProperty.category ? uiConfigProperty.category : App.config.getDefaultCategory(true, c.type);
if (uiConfigProperty) {
config.index = (uiConfigProperty.index !== undefined) ? uiConfigProperty.index : Infinity;
if (uiConfigProperty.displayType) {
c.property_value_attributes.type = uiConfigProperty.displayType;
config.radioName = uiConfigProperty.radioName;
config.options = uiConfigProperty.options;
}
config.dependentConfigPattern = uiConfigProperty.dependentConfigPattern;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 3.5 使用的模板路径
模板路径:
app/templates/wizard/controls_service_config_radio_buttons.hbs
模板代码:
{{!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
}}
{{#each option in view.options}}
{{#unless option.hidden}}
<div class="radio">
{{view App.ServiceConfigRadioButton nameBinding="view.name" valueBinding="option.displayName"
radioIdBinding="option.radioId"}}
<label {{bindAttr for="option.radioId" class="option.className" }}>
{{option.displayName}}
</label>
</div>
{{/unless}}
{{/each}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 总结
- HBS 模板技术使前端控件高度灵活 🎨 Handlebars 模板结合数据源,动态生成各种配置控件 UI。
- displayType 直观驱动控件类型和展现 🛠️ 无论是主题配置还是高级页面,都可通过 displayType 精确控制展示。
- 自定义组件需前端深度集成 🚧 按钮/交互型控件需补充 JS 逻辑与模板扩展,不可单靠 JSON 配置实现。