> For the complete documentation index, see [llms.txt](https://hezhiqiang.gitbook.io/elkstack/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hezhiqiang.gitbook.io/elkstack/kibana/source-code-analysis/dashboard.md).

# 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` 数组字段。实现如下：

```
  module.factory('SavedDashboard', function (courier) {
    _.class(SavedDashboard).inherits(courier.SavedObject);
    function SavedDashboard(id) {
      SavedDashboard.Super.call(this, {
        type: SavedDashboard.type,
        mapping: SavedDashboard.mapping,
        searchSource: SavedDashboard.searchsource,
        id: id,
        defaults: {
          title: 'New Dashboard',
          hits: 0,
          description: '',
          panelsJSON: '[]',
          optionsJSON: angular.toJson({
            darkTheme: config.get('dashboard:defaultDarkTheme')
          }),
          uiStateJSON: '{}',
          version: 1,
          timeRestore: false,
          timeTo: undefined,
          timeFrom: undefined,
          refreshInterval: undefined
        },
        clearSavedIndexPattern: true
      });
    }
```

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

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

```
        function updateQueryOnRootSource() {
          var filters = queryFilter.getFilters();
          if ($state.query) {
            dash.searchSource.set('filter', _.union(filters, [{
              query: $state.query
            }]));
          } else {
            dash.searchSource.set('filter', filters);
          }
        }

        $scope.$listen(queryFilter, 'update', function () {
          updateQueryOnRootSource();
          $state.save();
        });
```

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

```
  <dashboard-grid></dashboard-grid>
```

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

```
          $scope.$watchCollection('state.panels', function (panels) {
            const currentPanels = gridster.$widgets.toArray().map(function (el) {
              return getPanelFor(el);
            });
            const removed = _.difference(currentPanels, panels);
            const added = _.difference(panels, currentPanels);
            if (added.length) added.forEach(addPanel);
            ...
```

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

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

```
        var addPanel = function (panel) {
          _.defaults(panel, {
            size_x: 3,
            size_y: 2
          });
          ...
          panel.$scope = $scope.$new();
          panel.$scope.panel = panel;
          panel.$el = $compile('<li><dashboard-panel></li>')(panel.$scope);
          gridster.add_widget(panel.$el, panel.size_x, panel.size_y, panel.col, panel.row);
          ...
        };
```

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

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

```
 <visualize ng-switch-when="visualization"
    vis="savedObj.vis"
    search-source="savedObj.searchSource"
    class="panel-content">
  </visualize>

  <doc-table ng-switch-when="search"
    search-source="savedObj.searchSource"
    sorting="panel.sort"
    columns="panel.columns"
    class="panel-content"
    filter="filter">
  </doc-table>
```

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

```
define(function (require) {
  return function visualizationLoader(savedVisualizations, Private) { // Inject services here
    return function (panel, $scope) {
      return savedVisualizations.get(panel.id)
        .then(function (savedVis) {
          savedVis.vis.listeners.click = filterBarClickHandler($scope.state);
          savedVis.vis.listeners.brush = brushEvent;

          return {
            savedObj: savedVis,
            panel: panel,
            editUrl: savedVisualizations.urlFor(panel.id)
          };
        });
    };
  };
});
```

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