08-成神之路_ambari_Ambari实战-016-代码生命周期-metainfo-themes详解🎯
1. 引言与问题概述
1.1 背景介绍
在 Ambari 的早期版本中,页面的样式相对单一,用户在操作和配置时,界面元素的交互和展示方式比较局限。随着用户对可视化界面和交互体验的要求逐渐提高,简单的输入框和下拉菜单已经不能满足复杂的集群管理需求 🛠️。
为了解决这一问题,Ambari 引入了 theme.json
文件,用于优化和美化前端页面。通过结合 metainfo.xml
,开发者可以根据不同场景自定义各种 UI 控件,并调整页面的布局和样式,提升用户的操作体验 ✨。
这么做的好处包括:
- 丰富交互体验 🎨:通过自定义
widget
,你可以为配置项增加滑块、单选按钮、时间选择器等控件,大大增强页面的互动性和用户体验 👩💻。 - 直观的配置展示 🧩:分区域、分层次的配置展示让用户可以快速定位配置项,清晰理解配置的逻辑层次,从而更有效地进行操作 📊。
通过这些优化,Ambari 的界面变得更加灵活、易于维护,适合各种不同需求的集群管理场景,为用户带来了极大的便利和提升 💼。
1.2 目标 🎯
本篇文章的目标是通过精讲 theme.json
的使用方法,帮助读者掌握页面定制与优化的技巧,并实现以下三个目标:
-
熟练自定义页面样式和风格 🎨:你将学会如何通过配置
theme.json
和metainfo.xml
来定义和调整 Ambari 的 UI 样式,打造独特的界面体验,按照自己的理解重新定义组件 🚀。 -
轻松剖析 Ambari 源码 💻:你将了解
theme.json
是如何与 Ambari 源码交互,并学会如何从源码角度剖析前端渲染的逻辑,提升对 Ambari 内部结构的理解 🛠️。 -
方便二次开发 🛠️:为需要进行二次开发的用户提供便利,能够轻松扩展 Ambari 的前端功能,使其更好地适应具体业务场景,提升开发效率 🔄。
通过本文,你将具备自定义页面和组件的能力,并深入理解 Ambari 的源码架构,为后续的开发和维护打下坚实的基础 💪。
修改前的风格:
修改后的风格:
2. 核心概念解析 🧠
2.1 Ambari 中如何使用主题
Ambari 的主题配置是通过 metainfo.xml
文件来引入和管理的。不同组件可以各自定义自己的主题文件,RANGER
作为一个动态的示例组件在此说明。在不同的实际环境中,用户可以根据需求将 RANGER
替换为其他服务组件的名称,如 HDFS
、HIVE
等。
2.1.1 如何使用 theme.json
为了更好地定制组件的 UI,Ambari 使用了 theme.json
文件。这些文件通过在 metainfo.xml
中配置,并放置在 themes
文件夹下。我们以 RANGER
组件为例:
<themes>
<theme>
<fileName>credentials.json</fileName>
<default>true</default>
</theme>
<theme>
<fileName>database.json</fileName>
<default>true</default>
</theme>
<theme>
<fileName>directories.json</fileName>
<default>true</default>
</theme>
<theme>
<fileName>theme_version_2.json</fileName>
<default>true</default>
</theme>
</themes>
该配置段落说明了 RANGER
的主题文件(存放在 resources/stacks/BIGTOP/3.2.0/services/RANGER/themes/
目录下)。这些 JSON 文件中定义了 UI 布局和控件类型。
2.1.2 存放路径
不同组件都需要将主题文件存放在相应路径下,以下是 RANGER
示例中的存放结构:
resources/stacks/BIGTOP/3.2.0/services/RANGER/
│
├── themes/
│ ├── credentials.json
│ ├── database.json
│ ├── directories.json
│ └── theme_version_2.json
在实际使用时,RANGER
可以替换为其他组件名,如 HDFS
、HIVE
等,保持相同的文件夹结构以引入主题文件。
2.2 theme.json
中的字段规则
theme.json
文件主要用于定义页面布局和配置项的展示效果。这里我们以 RANGER
的 theme_version_2.json
为例,展示该文件中的布局定义和控件类型。
2.2.1 layouts
字段解析
layouts
字段定义了界面的整体布局,包括页面的列数、行数、以及页面中的分区和子分区。以下表格展示了 layouts
的层次结构:
层级 | 字段名称 | 类型 | 解释 | 示例 |
---|---|---|---|---|
顶层 | name | string | 布局名称,通常为默认值 "default" | "default" |
顶层 | tabs | array | 布局的标签页集合,包含多个标签页的定义 | - |
第二层 | name | string | 标签页名称,用于区分不同的标签页 | "ranger_admin_settings" |
第二层 | display-name | string | 标签页显示名称 | "Ranger Admin" |
第二层 | layout | object | 标签页的布局信息,包含列数、行数、分区等布局结构 | - |
第三层 | tab-columns | string | 标签页中的列数 | "2" |
第三层 | tab-rows | string | 标签页中的行数 | "2" |
第三层 | sections | array | 分区集合,每个分区包含多个子分区 | - |
第四层 | name | string | 分区名称 | "section-ranger-admin" |
第四层 | display-name | string | 分区显示名称 | "Ranger Admin" |
第四层 | section-columns | string | 分区中的列数 | "2" |
第四层 | section-rows | string | 分区中的行数 | "3" |
第五层 | subsections | array | 子分区集合,定义分区中的具体位置 | - |
第六层 | row-index | string | 子分区的行索引,用于确定该子分区在分区中的具体位置 | "0" |
第六层 | column-index | string | 子分区的列索引,用于确定该子分区在分区中的具体位置 | "0" |
第六层 | depends-on | array | 配置项的依赖关系,依据配置项的状态来控制该子分区的显示 | - |
示例代码:
{
"name": "default",
"layouts": [
{
"name": "default",
"tabs": [
{
"name": "ranger_admin_settings",
"display-name": "Ranger Admin",
"layout": {
"tab-columns": "2",
"tab-rows": "2",
"sections": [
{
"name": "section-ranger-admin",
"display-name": "Ranger Admin",
"section-columns": "2",
"section-rows": "3",
"subsections": [
{
"name": "subsection-ranger-db-row1-col1",
"row-index": "0",
"column-index": "0"
}
]
}
]
}
}
]
}
]
}
⬇️⬇️⬇️查看全部内容⬇️⬇️⬇️
更多详细内容请关注我们的微信公众号:发送"文章"关键字获取
或加入QQ1群,了解版本动向,解答大数据问题。
⬆️⬆️⬆️查看全部内容⬆️⬆️⬆️
首先,我们通过 loadConfigTheme
方法加载服务的主题配置数据:
App.ThemesMappingMixin = Em.Mixin.create({
/**
* 从服务器加载指定服务的配置主题
* @param {string} serviceName 服务名称
* @returns {$.ajax} 返回一个异步请求的 promise
* @method loadConfigTheme
*/
loadConfigTheme: function(serviceName) {
const dfd = $.Deferred(); // 创建一个延迟对象,方便处理异步流程
if (App.Tab.find().mapProperty('serviceName').contains(serviceName)) {
// 如果服务已经加载过,直接resolve,避免重复请求
dfd.resolve();
} else {
App.ajax.send({
name: 'configs.theme', // 配置请求的名称
sender: this,
data: {
serviceName: serviceName, // 请求中传递的服务名称
stackVersionUrl: App.get('stackVersionURL') // 获取当前栈的版本URL
},
success: '_saveThemeToModel' // 成功回调,处理返回的数据
}).complete(dfd.resolve); // 在请求完成后,无论成功或失败都resolve
}
return dfd.promise(); // 返回 promise,用于调用链的处理
},
loadConfigTheme
方法解析
- 这个方法的核心功能是向服务器发送请求,获取指定服务的主题配置。
- 它首先检查主题是否已经加载过,如果加载过则跳过请求,直接
resolve
,从而提升性能。 - 如果服务的主题尚未加载,则通过
App.ajax.send
发送 AJAX 请求,向服务端获取主题配置。 - 成功获取主题配置后,调用
this._saveThemeToModel
方法,将主题数据保存到前端模型中。
成功回调 _saveThemeToModel
方法如下:
/**
* 成功回调,将获取的主题数据映射保存到模型
* @param {object} data 从服务器返回的数据
* @param {object} opt AJAX 请求选项
* @param {object} params 请求的参数
* @private
* @method saveThemeToModel
*/
_saveThemeToModel: function(data, opt, params) {
App.themesMapper.map(data, [params.serviceName]); // 使用 themesMapper 将数据映射到指定服务
},
_saveThemeToModel
方法解析
- 该方法的作用是将从服务器返回的主题数据映射到前端模型中。
- 它使用了
App.themesMapper.map
方法,将获取到的数据与指定的serviceName
进行绑定,从而将配置的主题内容与服务的 UI 对应起来。 - 这一步完成后,页面可以根据这些主题配置来渲染服务的相关 UI。
接下来,App.themesMapper.map
方法负责将数据映射到模型中,该方法位于 app/mappers/themes_mapper.js
文件中。通过这个方法,JSON 文件中的主题数据将被解析并保存到前端应用的模型中,供 UI 渲染时使用。
App.themesMapper = App.QuickDataMapper.create({
map: function(data, serviceNames) {
serviceNames.forEach(function(serviceName) {
var serviceTheme = data.items.find(item => item.ThemeInfo.service_name === serviceName);
if (serviceTheme) {
// 将解析后的 theme_data 存入相应的服务模型中
App.Tab.find().findProperty('serviceName', serviceName).set('theme', serviceTheme.ThemeInfo.theme_data.Theme);
}
});
}
});
themesMapper.map
方法解析
themesMapper.map
是一个快速映射工具,它遍历从服务器返回的主题配置文件,并将其中的主题数据映射到对应的服务模型上。- 通过
findProperty
方法,它找到与服务名称相匹配的服务,并将主题数据保存在该服务的theme
属性中。 - 此时,前端模型中的主题数据就准备好供页面使用了。
通过这段源码,我们清楚地了解到 Ambari 是如何通过 AJAX 请求从服务器获取主题配置,并将这些配置数据映射到前端模型中。在主题配置加载到模型之后,页面就可以根据这些配置来调整 UI 的布局和风格。
如果你想进一步了解 Ambari 的前端渲染机制,接下来可以阅读更多关于 Ambari UI 配置的文档或探索其组件的工作原理。
5.4 推荐阅读 📖
如果你对如何自定义 Ambari 的 UI 配置和主题有更多兴趣,可以参考以下推荐文章:
这些文章将进一步深入探讨如何通过配置文件和主题文件扩展和定制 Ambari 的前端 UI 逻辑,帮助你掌握更多技巧和最佳实践。