dashboard

plugins/kibana/public/dashboard/index.js 结构跟 visualize 类似,设置两个调用 savedDashboards.get() 方法的 routes,提供一个叫 dashboard-app 的 directive。

savedDashboards 由 plugins/kibana/public/dashboard/services/saved_dashboard.js 提供,调用 es.search 获取数据,生成 savedDashboard 对象,这个对象同样也是继承 savedObject,主要内容是 panelsJSON 数组字段。实现如下:

  1. module.factory('SavedDashboard', function (courier) {
  2. _.class(SavedDashboard).inherits(courier.SavedObject);
  3. function SavedDashboard(id) {
  4. SavedDashboard.Super.call(this, {
  5. type: SavedDashboard.type,
  6. mapping: SavedDashboard.mapping,
  7. searchSource: SavedDashboard.searchsource,
  8. id: id,
  9. defaults: {
  10. title: 'New Dashboard',
  11. hits: 0,
  12. description: '',
  13. panelsJSON: '[]',
  14. optionsJSON: angular.toJson({
  15. darkTheme: config.get('dashboard:defaultDarkTheme')
  16. }),
  17. uiStateJSON: '{}',
  18. version: 1,
  19. timeRestore: false,
  20. timeTo: undefined,
  21. timeFrom: undefined,
  22. refreshInterval: undefined
  23. },
  24. clearSavedIndexPattern: true
  25. });
  26. }

可以注意到,这个 panelsJSON 是一个字符串,这跟之前 kbnIndex 提到的是一致的。

dashboard-app 中,最重要的功能,是监听搜索框和过滤条件的变更,我们可以看到 init 函数中有下面这段:

  1. function updateQueryOnRootSource() {
  2. var filters = queryFilter.getFilters();
  3. if ($state.query) {
  4. dash.searchSource.set('filter', _.union(filters, [{
  5. query: $state.query
  6. }]));
  7. } else {
  8. dash.searchSource.set('filter', filters);
  9. }
  10. }
  11. $scope.$listen(queryFilter, 'update', function () {
  12. updateQueryOnRootSource();
  13. $state.save();
  14. });

在 index.html 里,实际承载面板的,是下面这行:

  1. <dashboard-grid></dashboard-grid>

这也是一个 angular directive,通过加载 plugins/kibana/public/dashboard/directives/grid.js 引入的。其中添加面板相关的代码有两部分:

  1. $scope.$watchCollection('state.panels', function (panels) {
  2. const currentPanels = gridster.$widgets.toArray().map(function (el) {
  3. return getPanelFor(el);
  4. });
  5. const removed = _.difference(currentPanels, panels);
  6. const added = _.difference(panels, currentPanels);
  7. if (added.length) added.forEach(addPanel);
  8. ...

这段用来监听 $state.panels 数组,一旦有新增面板,调用 addPanel 函数。同理也有删除面板的,这里就不重复贴了。

而 addPanel 函数的实现大致如下:

  1. var addPanel = function (panel) {
  2. _.defaults(panel, {
  3. size_x: 3,
  4. size_y: 2
  5. });
  6. ...
  7. panel.$scope = $scope.$new();
  8. panel.$scope.panel = panel;
  9. panel.$el = $compile('<li><dashboard-panel></li>')(panel.$scope);
  10. gridster.add_widget(panel.$el, panel.size_x, panel.size_y, panel.col, panel.row);
  11. ...
  12. };

这里即验证了之前 kbnIndex 小节中讲的 gridster 默认大小,又引入了一个新的 directive,叫 dashboard-panel。

dashboard-panel 在 plugins/kibana/public/dashboard/components/panel/panel.js 中实现,其中使用了 plugins/kibana/public/dashboard/components/panel/panel.html 页面。页面最后是这么一段:

  1. <visualize ng-switch-when="visualization"
  2. vis="savedObj.vis"
  3. search-source="savedObj.searchSource"
  4. class="panel-content">
  5. </visualize>
  6. <doc-table ng-switch-when="search"
  7. search-source="savedObj.searchSource"
  8. sorting="panel.sort"
  9. columns="panel.columns"
  10. class="panel-content"
  11. filter="filter">
  12. </doc-table>

这里使用的 savedObj 对象,来自 plugins/kibana/public/dashboard/components/panel/lib/load_panel.js 获取的 savedSearch 或者 savedVisualization。获得的对象,以 savedVisualization 为例:

  1. define(function (require) {
  2. return function visualizationLoader(savedVisualizations, Private) { // Inject services here
  3. return function (panel, $scope) {
  4. return savedVisualizations.get(panel.id)
  5. .then(function (savedVis) {
  6. savedVis.vis.listeners.click = filterBarClickHandler($scope.state);
  7. savedVis.vis.listeners.brush = brushEvent;
  8. return {
  9. savedObj: savedVis,
  10. panel: panel,
  11. editUrl: savedVisualizations.urlFor(panel.id)
  12. };
  13. });
  14. };
  15. };
  16. });

而 visualize 和 doc-table 两个 directive。这两个正是之前在 visualize 和 discover 插件解析里提到过的,在 components/ 底下实现。