Просмотр исходного кода

tech: minor progress on mobx state tree & react containers, working on unit testing

Torkel Ödegaard 8 лет назад
Родитель
Сommit
5b91bb9163

+ 24 - 0
public/app/containers/ServerStats/ServerStats.jest.tsx

@@ -0,0 +1,24 @@
+import React from 'react';
+import renderer from 'react-test-renderer';
+import { ServerStats } from './ServerStats';
+import { RootStore } from 'app/stores/RootStore';
+
+describe('ServerStats', () => {
+  it('Should render table with stats', done => {
+    let backendSrvMock = {
+      get: jest.fn().mockReturnValue(
+        Promise.resolve({
+          dashboards: 10,
+        })
+      ),
+    };
+
+    const store = RootStore.create({}, { backendSrv: backendSrvMock });
+    const page = renderer.create(<ServerStats store={store} />);
+
+    setTimeout(() => {
+      expect(page.toJSON()).toMatchSnapshot();
+      done();
+    });
+  });
+});

+ 4 - 5
public/app/containers/ServerStats.tsx → public/app/containers/ServerStats/ServerStats.tsx

@@ -9,20 +9,19 @@ export interface IProps {
 
 @inject('store')
 @observer
-export default class ServerStats extends React.Component<IProps, any> {
-  navModel: NavModel;
-
+export class ServerStats extends React.Component<IProps, any> {
   constructor(props) {
     super(props);
 
-    this.navModel = new NavModelSrv().getNav('cfg', 'admin', 'server-stats', 1);
+    // this.navModel = new NavModelSrv().getNav('cfg', 'admin', 'server-stats', 1);
+    this.props.store.nav.load('cfg', 'admin', 'server-stats');
     this.props.store.serverStats.load();
   }
 
   render() {
     return (
       <div>
-        <PageHeader model={this.navModel} />
+        <PageHeader model={this.props.store.nav} />
         <div className="page-container page-body">
           <table className="filter-table form-inline">
             <thead>

+ 99 - 0
public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap

@@ -0,0 +1,99 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ServerStats Should render table with stats 1`] = `
+<div>
+  // 
+  <div
+    className="page-container page-body"
+  >
+    <table
+      className="filter-table form-inline"
+    >
+      <thead>
+        <tr>
+          <th>
+            Name
+          </th>
+          <th>
+            Value
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td>
+            Total dashboards
+          </td>
+          <td>
+            10
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total users
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Active users (seen last 30 days)
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total orgs
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total playlists
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total snapshots
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total dashboard tags
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total starred dashboards
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+        <tr>
+          <td>
+            Total alerts
+          </td>
+          <td>
+            0
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</div>
+`;

+ 1 - 1
public/app/routes/ReactContainer.tsx

@@ -16,7 +16,7 @@ function WrapInProvider(store, Component, props) {
 export function reactContainer($route) {
   return {
     restrict: 'E',
-    template: '<h2>hasad</h2>',
+    template: '',
     link(scope, elem) {
       let component = $route.current.locals.component;
       let props = {};

+ 0 - 26
public/app/routes/bundle_loader.ts

@@ -1,26 +0,0 @@
-export class BundleLoader {
-  lazy: any;
-
-  constructor(bundleName) {
-    var defer = null;
-
-    this.lazy = [
-      '$q',
-      '$route',
-      '$rootScope',
-      ($q, $route, $rootScope) => {
-        if (defer) {
-          return defer.promise;
-        }
-
-        defer = $q.defer();
-
-        System.import(bundleName).then(() => {
-          defer.resolve();
-        });
-
-        return defer.promise;
-      },
-    ];
-  }
-}

+ 1 - 1
public/app/routes/routes.ts

@@ -1,6 +1,6 @@
 import './dashboard_loaders';
 import './ReactContainer';
-import ServerStats from 'app/containers/ServerStats';
+import { ServerStats } from 'app/containers/ServerStats/ServerStats';
 
 /** @ngInject **/
 export function setupAngularRoutes($routeProvider, $locationProvider) {

+ 74 - 0
public/app/stores/NavStore/NavStore.ts

@@ -0,0 +1,74 @@
+import { types } from 'mobx-state-tree';
+import config from 'app/core/config';
+import _ from 'lodash';
+
+export const NavItem = types.model('NavItem', {
+  id: types.identifier(types.string),
+  text: types.string,
+  url: types.optional(types.string, ''),
+  description: types.optional(types.string, ''),
+  icon: types.optional(types.string, ''),
+  img: types.optional(types.string, ''),
+  active: types.optional(types.boolean, false),
+  children: types.optional(types.array(types.late(() => NavItem)), []),
+});
+
+export const NavStore = types
+  .model('NavStore', {
+    main: types.maybe(NavItem),
+    node: types.maybe(NavItem),
+    breadcrumbs: types.optional(types.array(NavItem), []),
+  })
+  .actions(self => ({
+    load(...args) {
+      var children = config.bootData.navTree;
+      let main, node;
+      let breadcrumbs = [];
+
+      for (let id of args) {
+        // if its a number then it's the index to use for main
+        if (_.isNumber(id)) {
+          main = breadcrumbs[id];
+          break;
+        }
+
+        let current = _.find(children, { id: id });
+        breadcrumbs.push(current);
+        main = node;
+        node = current;
+        children = node.children;
+      }
+
+      if (main.children) {
+        for (let item of main.children) {
+          item.active = false;
+
+          if (item.url === node.url) {
+            item.active = true;
+          }
+        }
+      }
+
+      self.main = NavItem.create(main);
+      self.node = NavItem.create(node);
+
+      for (let item of breadcrumbs) {
+        self.breadcrumbs.push(NavItem.create(item));
+      }
+
+      // self.main = NavItem.create({
+      //   id: 'test',
+      //   text: 'test',
+      //   url: '/test';
+      //   children: [
+      //     {
+      //       id: 'test',
+      //       text: 'text',
+      //       url: '/test',
+      //       active: true,
+      //       children: []
+      //     }
+      //   ]
+      // });
+    },
+  }));

+ 2 - 0
public/app/stores/RootStore.ts

@@ -1,6 +1,7 @@
 import { types } from 'mobx-state-tree';
 import { SearchStore } from './SearchStore';
 import { ServerStatsStore } from './ServerStatsStore';
+import { NavStore } from './NavStore/NavStore';
 
 export const RootStore = types.model({
   search: types.optional(SearchStore, {
@@ -9,6 +10,7 @@ export const RootStore = types.model({
   serverStats: types.optional(ServerStatsStore, {
     stats: [],
   }),
+  nav: types.optional(NavStore, {}),
 });
 
 type IRootStoreType = typeof RootStore.Type;

+ 18 - 13
public/app/stores/ServerStatsStore.tsx

@@ -2,28 +2,33 @@ import { types, getEnv, flow } from 'mobx-state-tree';
 
 export const ServerStat = types.model('ServerStat', {
   name: types.string,
-  value: types.number,
+  value: types.optional(types.number, 0),
 });
 
 export const ServerStatsStore = types
   .model('ServerStatsStore', {
     stats: types.array(ServerStat),
+    error: types.optional(types.string, ''),
   })
   .actions(self => ({
     load: flow(function* load() {
       let backendSrv = getEnv(self).backendSrv;
 
-      let res = yield backendSrv.get('/api/admin/stats');
-
-      self.stats.clear();
-      self.stats.push(ServerStat.create({ name: 'Total dashboards', value: res.dashboards }));
-      self.stats.push(ServerStat.create({ name: 'Total users', value: res.users }));
-      self.stats.push(ServerStat.create({ name: 'Active users (seen last 30 days)', value: res.activeUsers }));
-      self.stats.push(ServerStat.create({ name: 'Total orgs', value: res.orgs }));
-      self.stats.push(ServerStat.create({ name: 'Total playlists', value: res.playlists }));
-      self.stats.push(ServerStat.create({ name: 'Total snapshots', value: res.snapshots }));
-      self.stats.push(ServerStat.create({ name: 'Total dashboard tags', value: res.tags }));
-      self.stats.push(ServerStat.create({ name: 'Total starred dashboards', value: res.stars }));
-      self.stats.push(ServerStat.create({ name: 'Total alerts', value: res.alerts }));
+      try {
+        let res = yield backendSrv.get('/api/admin/stats');
+        self.stats.clear();
+        self.stats.push(ServerStat.create({ name: 'Total dashboards', value: res.dashboards }));
+        self.stats.push(ServerStat.create({ name: 'Total users', value: res.users }));
+        self.stats.push(ServerStat.create({ name: 'Active users (seen last 30 days)', value: res.activeUsers }));
+        self.stats.push(ServerStat.create({ name: 'Total orgs', value: res.orgs }));
+        self.stats.push(ServerStat.create({ name: 'Total playlists', value: res.playlists }));
+        self.stats.push(ServerStat.create({ name: 'Total snapshots', value: res.snapshots }));
+        self.stats.push(ServerStat.create({ name: 'Total dashboard tags', value: res.tags }));
+        self.stats.push(ServerStat.create({ name: 'Total starred dashboards', value: res.stars }));
+        self.stats.push(ServerStat.create({ name: 'Total alerts', value: res.alerts }));
+      } catch (err) {
+        console.log('ServerStats.load error', err);
+        self.error = err.toString();
+      }
     }),
   }));