From af1f3dd77b4becc34354c4395ebcf0023c2889a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 19 Dec 2017 17:26:51 +0100 Subject: [PATCH 01/17] poc: mobx poc --- package.json | 3 + public/app/containers/ServerStats.tsx | 27 +++++ public/app/core/angular_wrappers.ts | 20 ++-- public/app/features/admin/partials/stats.html | 109 +++++++++--------- public/app/store/store.ts | 16 +++ 5 files changed, 112 insertions(+), 63 deletions(-) create mode 100644 public/app/containers/ServerStats.tsx create mode 100644 public/app/store/store.ts diff --git a/package.json b/package.json index 17817d60ef8..32846b2d493 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,9 @@ "file-saver": "^1.3.3", "jquery": "^3.2.1", "lodash": "^4.17.4", + "mobx": "^3.4.1", + "mobx-react": "^4.3.5", + "mobx-state-tree": "^1.3.1", "moment": "^2.18.1", "mousetrap": "^1.6.0", "perfect-scrollbar": "^1.2.0", diff --git a/public/app/containers/ServerStats.tsx b/public/app/containers/ServerStats.tsx new file mode 100644 index 00000000000..8f6a6ac3ca2 --- /dev/null +++ b/public/app/containers/ServerStats.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import PageHeader from "app/core/components/PageHeader/PageHeader"; +import { NavModel, NavModelSrv } from "app/core/nav_model_srv"; + +export interface IState { + navModel: NavModel; +} + +export default class ServerStats extends React.Component { + constructor(props) { + super(props); + + const navModelSrv = new NavModelSrv(); + + this.state = { + navModel: navModelSrv.getNav("cfg", "admin", "server-stats", 1) + }; + } + + render() { + return ( + +

ServerStats

+
+ ); + } +} diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index 83a70fa4c8a..2774b46d3f4 100644 --- a/public/app/core/angular_wrappers.ts +++ b/public/app/core/angular_wrappers.ts @@ -1,12 +1,14 @@ -import { react2AngularDirective } from 'app/core/utils/react2angular'; -import { PasswordStrength } from './components/PasswordStrength'; -import PageHeader from './components/PageHeader/PageHeader'; -import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA'; -import LoginBackground from './components/Login/LoginBackground'; +import { react2AngularDirective } from "app/core/utils/react2angular"; +import { PasswordStrength } from "./components/PasswordStrength"; +import PageHeader from "./components/PageHeader/PageHeader"; +import EmptyListCTA from "./components/EmptyListCTA/EmptyListCTA"; +import LoginBackground from "./components/Login/LoginBackground"; +import ServerStats from "app/containers/ServerStats"; export function registerAngularDirectives() { - react2AngularDirective('passwordStrength', PasswordStrength, ['password']); - react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']); - react2AngularDirective('emptyListCta', EmptyListCTA, ['model']); - react2AngularDirective('loginBackground', LoginBackground, []); + react2AngularDirective("passwordStrength", PasswordStrength, ["password"]); + react2AngularDirective("pageHeader", PageHeader, ["model", "noTabs"]); + react2AngularDirective("emptyListCta", EmptyListCTA, ["model"]); + react2AngularDirective("loginBackground", LoginBackground, []); + react2AngularDirective("containerServerStats", ServerStats, []); } diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html index e2a4bb62301..4298046f390 100644 --- a/public/app/features/admin/partials/stats.html +++ b/public/app/features/admin/partials/stats.html @@ -1,54 +1,55 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameValue
Total dashboards{{ctrl.stats.dashboards}}
Total users{{ctrl.stats.users}}
Active users (seen last 14 days){{ctrl.stats.activeUsers}}
Total organizations{{ctrl.stats.orgs}}
Total datasources{{ctrl.stats.datasources}}
Total playlists{{ctrl.stats.playlists}}
Total snapshots{{ctrl.stats.snapshots}}
Total dashboard tags{{ctrl.stats.tags}}
Total starred dashboards{{ctrl.stats.stars}}
Total alerts{{ctrl.stats.alerts}}
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/app/store/store.ts b/public/app/store/store.ts new file mode 100644 index 00000000000..e18e73690b8 --- /dev/null +++ b/public/app/store/store.ts @@ -0,0 +1,16 @@ +import { types } from "mobx-state-tree"; + +const Search = types.model({ + name: "", + done: false +}); + +const RootStore = types.model({ + search: types.map(Search) +}); + +const store = RootStore.create({ + search: {} +}); + +export { store }; From ee216ba6fb45dbf2a5ef402e691659b11e0e7e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 20 Dec 2017 10:53:16 +0100 Subject: [PATCH 02/17] poc: mobx test --- public/app/containers/ServerStats.tsx | 25 ++++++++++++++++++++----- public/app/store/store.ts | 20 ++++++++++++-------- tsconfig.json | 2 +- yarn.lock | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/public/app/containers/ServerStats.tsx b/public/app/containers/ServerStats.tsx index 8f6a6ac3ca2..b6488725f6a 100644 --- a/public/app/containers/ServerStats.tsx +++ b/public/app/containers/ServerStats.tsx @@ -1,27 +1,42 @@ import React from "react"; +import { observer } from "mobx-react"; import PageHeader from "app/core/components/PageHeader/PageHeader"; import { NavModel, NavModelSrv } from "app/core/nav_model_srv"; +import { store } from "app/store/store"; export interface IState { navModel: NavModel; + search: any; } -export default class ServerStats extends React.Component { +@observer +export default class ServerStats extends React.Component { constructor(props) { super(props); const navModelSrv = new NavModelSrv(); this.state = { - navModel: navModelSrv.getNav("cfg", "admin", "server-stats", 1) + navModel: navModelSrv.getNav("cfg", "admin", "server-stats", 1), + search: store.search }; } + onClick = () => { + this.state.search.search(); + }; + render() { + console.log("render"); return ( - -

ServerStats

-
+
+ + +
+ name: +

{this.state.search.name}

+
+
); } } diff --git a/public/app/store/store.ts b/public/app/store/store.ts index e18e73690b8..e996d804710 100644 --- a/public/app/store/store.ts +++ b/public/app/store/store.ts @@ -1,16 +1,20 @@ import { types } from "mobx-state-tree"; -const Search = types.model({ - name: "", - done: false -}); +const Search = types + .model({ + name: "asdas", + done: false + }) + .actions(self => ({ + search() { + self.name = "changed"; + } + })); const RootStore = types.model({ - search: types.map(Search) + search: types.optional(Search, {}) }); -const store = RootStore.create({ - search: {} -}); +const store = RootStore.create({}); export { store }; diff --git a/tsconfig.json b/tsconfig.json index bc9222ac87d..3596930a62f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ "sourceMap": true, "noEmitOnError": false, "emitDecoratorMetadata": false, - "experimentalDecorators": false, + "experimentalDecorators": true, "noImplicitReturns": true, "noImplicitThis": false, "noImplicitUseStrict":false, diff --git a/yarn.lock b/yarn.lock index a419e1020c9..161927c0db8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4399,6 +4399,10 @@ hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" +hoist-non-react-statics@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -6303,6 +6307,20 @@ mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi dependencies: minimist "0.0.8" +mobx-react@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-4.3.5.tgz#76853f2f2ef4a6f960c374bcd9f01e875929c04c" + dependencies: + hoist-non-react-statics "^2.3.1" + +mobx-state-tree@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mobx-state-tree/-/mobx-state-tree-1.3.1.tgz#9e1ba9b8b6ea183f1a4a2ae1f67bfa8f2bcae4fe" + +mobx@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-3.4.1.tgz#37abe5ee882d401828d9f26c6c1a2f47614bbbef" + mocha@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.0.1.tgz#0aee5a95cf69a4618820f5e51fa31717117daf1b" From 354913a704dc8723d456df2c2476bbb3397fe167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 20 Dec 2017 17:24:04 +0100 Subject: [PATCH 03/17] mobx: progress on poc --- public/app/app.ts | 3 + public/app/containers/ServerStats.tsx | 42 ------- public/app/core/angular_wrappers.ts | 4 +- .../core/components/search/SearchResult.tsx | 84 ++++++++++++++ public/app/core/components/search/search.html | 11 +- public/app/features/admin/partials/stats.html | 109 +++++++++--------- public/app/store/store.ts | 20 ---- public/app/stores/RootStore.ts | 11 ++ public/app/stores/SearchStore.ts | 44 +++++++ public/app/stores/store.ts | 7 ++ 10 files changed, 211 insertions(+), 124 deletions(-) delete mode 100644 public/app/containers/ServerStats.tsx create mode 100644 public/app/core/components/search/SearchResult.tsx delete mode 100644 public/app/store/store.ts create mode 100644 public/app/stores/RootStore.ts create mode 100644 public/app/stores/SearchStore.ts create mode 100644 public/app/stores/store.ts diff --git a/public/app/app.ts b/public/app/app.ts index 8ddacc4ed04..0fd00c8e1bb 100644 --- a/public/app/app.ts +++ b/public/app/app.ts @@ -19,6 +19,7 @@ import angular from "angular"; import config from "app/core/config"; import _ from "lodash"; import moment from "moment"; +import { createStore } from "app/stores/store"; // add move to lodash for backward compatabiltiy _.move = function(array, fromIndex, toIndex) { @@ -135,6 +136,8 @@ export class GrafanaApp { Promise.all(preBootRequires) .then(() => { + createStore(); + // disable tool tip animation $.fn.tooltip.defaults.animation = false; // bootstrap the app diff --git a/public/app/containers/ServerStats.tsx b/public/app/containers/ServerStats.tsx deleted file mode 100644 index b6488725f6a..00000000000 --- a/public/app/containers/ServerStats.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from "react"; -import { observer } from "mobx-react"; -import PageHeader from "app/core/components/PageHeader/PageHeader"; -import { NavModel, NavModelSrv } from "app/core/nav_model_srv"; -import { store } from "app/store/store"; - -export interface IState { - navModel: NavModel; - search: any; -} - -@observer -export default class ServerStats extends React.Component { - constructor(props) { - super(props); - - const navModelSrv = new NavModelSrv(); - - this.state = { - navModel: navModelSrv.getNav("cfg", "admin", "server-stats", 1), - search: store.search - }; - } - - onClick = () => { - this.state.search.search(); - }; - - render() { - console.log("render"); - return ( -
- - -
- name: -

{this.state.search.name}

-
-
- ); - } -} diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index 2774b46d3f4..839ff011d5a 100644 --- a/public/app/core/angular_wrappers.ts +++ b/public/app/core/angular_wrappers.ts @@ -3,12 +3,12 @@ import { PasswordStrength } from "./components/PasswordStrength"; import PageHeader from "./components/PageHeader/PageHeader"; import EmptyListCTA from "./components/EmptyListCTA/EmptyListCTA"; import LoginBackground from "./components/Login/LoginBackground"; -import ServerStats from "app/containers/ServerStats"; +import { SearchResult } from "./components/search/SearchResult"; export function registerAngularDirectives() { react2AngularDirective("passwordStrength", PasswordStrength, ["password"]); react2AngularDirective("pageHeader", PageHeader, ["model", "noTabs"]); react2AngularDirective("emptyListCta", EmptyListCTA, ["model"]); react2AngularDirective("loginBackground", LoginBackground, []); - react2AngularDirective("containerServerStats", ServerStats, []); + react2AngularDirective("searchResult", SearchResult, []); } diff --git a/public/app/core/components/search/SearchResult.tsx b/public/app/core/components/search/SearchResult.tsx new file mode 100644 index 00000000000..fd96e55f912 --- /dev/null +++ b/public/app/core/components/search/SearchResult.tsx @@ -0,0 +1,84 @@ +import React from "react"; +import classNames from "classnames"; +import { observer } from "mobx-react"; +import { store } from "app/stores/store"; + +export interface SearchResultProps { + search: any; +} + +@observer +export class SearchResult extends React.Component { + constructor(props) { + super(props); + + this.state = { + search: store.search + }; + } + + render() { + return this.state.search.sections.map(section => { + return ; + }); + } +} + +export interface SectionProps { + section: any; +} + +@observer +export class SearchResultSection extends React.Component { + constructor(props) { + super(props); + } + + renderItem(item) { + return ( + + + + + +
{item.title}
+
+
+ ); + } + + toggleSection = () => { + this.props.section.toggle(); + }; + + render() { + let collapseClassNames = classNames({ + fa: true, + "fa-plus": !this.props.section.expanded, + "fa-minus": this.props.section.expanded, + "search-section__header__toggle": true + }); + + return ( +
+
+ + + {this.props.section.title} + + +
+ {this.props.section.expanded && ( +
+ {this.props.section.items.map(this.renderItem)} +
+ )} +
+ ); + } +} diff --git a/public/app/core/components/search/search.html b/public/app/core/components/search/search.html index 3b83284757e..50568d4ed85 100644 --- a/public/app/core/components/search/search.html +++ b/public/app/core/components/search/search.html @@ -22,11 +22,12 @@
No dashboards matching your query were found.
- + + + + + +
diff --git a/public/app/features/admin/partials/stats.html b/public/app/features/admin/partials/stats.html index 4298046f390..e2a4bb62301 100644 --- a/public/app/features/admin/partials/stats.html +++ b/public/app/features/admin/partials/stats.html @@ -1,55 +1,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameValue
Total dashboards{{ctrl.stats.dashboards}}
Total users{{ctrl.stats.users}}
Active users (seen last 14 days){{ctrl.stats.activeUsers}}
Total organizations{{ctrl.stats.orgs}}
Total datasources{{ctrl.stats.datasources}}
Total playlists{{ctrl.stats.playlists}}
Total snapshots{{ctrl.stats.snapshots}}
Total dashboard tags{{ctrl.stats.tags}}
Total starred dashboards{{ctrl.stats.stars}}
Total alerts{{ctrl.stats.alerts}}
+
diff --git a/public/app/store/store.ts b/public/app/store/store.ts deleted file mode 100644 index e996d804710..00000000000 --- a/public/app/store/store.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { types } from "mobx-state-tree"; - -const Search = types - .model({ - name: "asdas", - done: false - }) - .actions(self => ({ - search() { - self.name = "changed"; - } - })); - -const RootStore = types.model({ - search: types.optional(Search, {}) -}); - -const store = RootStore.create({}); - -export { store }; diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore.ts new file mode 100644 index 00000000000..512ec8da622 --- /dev/null +++ b/public/app/stores/RootStore.ts @@ -0,0 +1,11 @@ +import { types } from "mobx-state-tree"; +import { SearchStore } from "./SearchStore"; + +export const RootStore = types.model({ + search: types.optional(SearchStore, { + sections: [] + }) +}); + +type IRootStoreType = typeof RootStore.Type; +export interface IRootStore extends IRootStoreType {} diff --git a/public/app/stores/SearchStore.ts b/public/app/stores/SearchStore.ts new file mode 100644 index 00000000000..f4f9a4ece9e --- /dev/null +++ b/public/app/stores/SearchStore.ts @@ -0,0 +1,44 @@ +import { types } from "mobx-state-tree"; + +export const ResultItem = types.model("ResultItem", { + id: types.identifier(types.number), + folderId: types.optional(types.number, 0), + title: types.string, + url: types.string, + icon: types.string, + folderTitle: types.optional(types.string, "") +}); + +export const SearchResultSection = types + .model("SearchResultSection", { + id: types.identifier(), + title: types.string, + icon: types.string, + expanded: types.boolean, + items: types.array(ResultItem) + }) + .actions(self => ({ + toggle() { + self.expanded = !self.expanded; + } + })); + +export const SearchStore = types + .model("SearchStore", { + sections: types.array(SearchResultSection) + }) + .actions(self => ({ + query() { + for (let i = 0; i < 100; i++) { + self.sections.push( + SearchResultSection.create({ + id: "starred" + i, + title: "starred", + icon: "fa fa-fw fa-star-o", + expanded: false, + items: [] + }) + ); + } + } + })); diff --git a/public/app/stores/store.ts b/public/app/stores/store.ts new file mode 100644 index 00000000000..80cb51c3006 --- /dev/null +++ b/public/app/stores/store.ts @@ -0,0 +1,7 @@ +import { RootStore, IRootStore } from "./RootStore"; + +export let store: IRootStore; + +export function createStore() { + store = RootStore.create({}); +} From 444240dffcbd01aae97331a005458a5404b1ccbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 21 Dec 2017 08:27:47 +0100 Subject: [PATCH 04/17] tech: mobx tests --- public/app/core/components/search/SearchResult.tsx | 2 ++ public/app/core/components/search/search.html | 11 +++++------ public/app/stores/SearchStore.ts | 11 +++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/public/app/core/components/search/SearchResult.tsx b/public/app/core/components/search/SearchResult.tsx index fd96e55f912..6d6b001cc1d 100644 --- a/public/app/core/components/search/SearchResult.tsx +++ b/public/app/core/components/search/SearchResult.tsx @@ -15,6 +15,8 @@ export class SearchResult extends React.Component { this.state = { search: store.search }; + + store.search.query(); } render() { diff --git a/public/app/core/components/search/search.html b/public/app/core/components/search/search.html index 50568d4ed85..3b83284757e 100644 --- a/public/app/core/components/search/search.html +++ b/public/app/core/components/search/search.html @@ -22,12 +22,11 @@
No dashboards matching your query were found.
- - - - - - +
diff --git a/public/app/stores/SearchStore.ts b/public/app/stores/SearchStore.ts index f4f9a4ece9e..1779462a36d 100644 --- a/public/app/stores/SearchStore.ts +++ b/public/app/stores/SearchStore.ts @@ -20,6 +20,17 @@ export const SearchResultSection = types .actions(self => ({ toggle() { self.expanded = !self.expanded; + + for (let i = 0; i < 100; i++) { + self.items.push( + ResultItem.create({ + id: i, + title: "Dashboard " + self.items.length, + icon: "gicon gicon-dashboard", + url: "asd" + }) + ); + } } })); From 9f7560b6f9e199ab5790adce7074af993c131679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 21 Dec 2017 12:20:55 +0100 Subject: [PATCH 05/17] ux: removed unused stuff form style guide --- .../app/features/styleguide/styleguide.html | 8 ----- public/app/features/styleguide/styleguide.ts | 34 ------------------- public/app/stores/ServerStatsStore.tsx | 1 + 3 files changed, 1 insertion(+), 42 deletions(-) diff --git a/public/app/features/styleguide/styleguide.html b/public/app/features/styleguide/styleguide.html index 7a003168ec8..0ff6de9f017 100644 --- a/public/app/features/styleguide/styleguide.html +++ b/public/app/features/styleguide/styleguide.html @@ -14,14 +14,6 @@ -
-
-
- -
-
-
-

Forms

diff --git a/public/app/features/styleguide/styleguide.ts b/public/app/features/styleguide/styleguide.ts index 1337e28d8e5..6bdf7980dbf 100644 --- a/public/app/features/styleguide/styleguide.ts +++ b/public/app/features/styleguide/styleguide.ts @@ -1,51 +1,17 @@ import coreModule from 'app/core/core_module'; import config from 'app/core/config'; -import _ from 'lodash'; class StyleGuideCtrl { - colors: any = []; theme: string; buttonNames = ['primary', 'secondary', 'inverse', 'success', 'warning', 'danger']; buttonSizes = ['btn-small', '', 'btn-large']; buttonVariants = ['-']; - icons: any = []; - page: any; - pages = ['colors', 'buttons', 'icons', 'plugins']; navModel: any; /** @ngInject **/ constructor(private $http, private $routeParams, private backendSrv, navModelSrv) { this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide', 1); this.theme = config.bootData.user.lightTheme ? 'light' : 'dark'; - this.page = {}; - - if ($routeParams.page) { - this.page[$routeParams.page] = 1; - } else { - this.page.colors = true; - } - - if (this.page.colors) { - this.loadColors(); - } - - if (this.page.icons) { - this.loadIcons(); - } - } - - loadColors() { - this.$http.get('public/build/styleguide.json').then(res => { - this.colors = _.map(res.data[this.theme], (value, key) => { - return { name: key, value: value }; - }); - }); - } - - loadIcons() { - this.$http.get('public/sass/icons.json').then(res => { - this.icons = res.data; - }); } switchTheme() { diff --git a/public/app/stores/ServerStatsStore.tsx b/public/app/stores/ServerStatsStore.tsx index db7a750eeb4..a388fb77269 100644 --- a/public/app/stores/ServerStatsStore.tsx +++ b/public/app/stores/ServerStatsStore.tsx @@ -15,6 +15,7 @@ export const ServerStatsStore = types 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 })); From 02ad2e5f0f20aa64af94add724963e084479d154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 21 Dec 2017 12:31:04 +0100 Subject: [PATCH 06/17] tech: cleaned up unused stuff --- public/app/core/components/grafana_app.ts | 59 -------------------- public/app/features/styleguide/styleguide.ts | 2 +- 2 files changed, 1 insertion(+), 60 deletions(-) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index 01bd80c2bee..defd04cefd9 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -49,65 +49,6 @@ export class GrafanaCtrl { appEvents.emit(name, payload); }; - $rootScope.colors = [ - '#7EB26D', - '#EAB839', - '#6ED0E0', - '#EF843C', - '#E24D42', - '#1F78C1', - '#BA43A9', - '#705DA0', - '#508642', - '#CCA300', - '#447EBC', - '#C15C17', - '#890F02', - '#0A437C', - '#6D1F62', - '#584477', - '#B7DBAB', - '#F4D598', - '#70DBED', - '#F9BA8F', - '#F29191', - '#82B5D8', - '#E5A8E2', - '#AEA2E0', - '#629E51', - '#E5AC0E', - '#64B0C8', - '#E0752D', - '#BF1B00', - '#0A50A1', - '#962D82', - '#614D93', - '#9AC48A', - '#F2C96D', - '#65C5DB', - '#F9934E', - '#EA6460', - '#5195CE', - '#D683CE', - '#806EB7', - '#3F6833', - '#967302', - '#2F575E', - '#99440A', - '#58140C', - '#052B51', - '#511749', - '#3F2B5B', - '#E0F9D7', - '#FCEACA', - '#CFFAFF', - '#F9E2D2', - '#FCE2DE', - '#BADFF4', - '#F9D9F9', - '#DEDAF7', - ]; - $scope.init(); } } diff --git a/public/app/features/styleguide/styleguide.ts b/public/app/features/styleguide/styleguide.ts index 6bdf7980dbf..e348f963cd9 100644 --- a/public/app/features/styleguide/styleguide.ts +++ b/public/app/features/styleguide/styleguide.ts @@ -9,7 +9,7 @@ class StyleGuideCtrl { navModel: any; /** @ngInject **/ - constructor(private $http, private $routeParams, private backendSrv, navModelSrv) { + constructor(private $routeParams, private backendSrv, navModelSrv) { this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide', 1); this.theme = config.bootData.user.lightTheme ? 'light' : 'dark'; } From 5b91bb9163abce2966ebf8744429bc8d67d72d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 27 Dec 2017 13:15:27 +0100 Subject: [PATCH 07/17] tech: minor progress on mobx state tree & react containers, working on unit testing --- .../ServerStats/ServerStats.jest.tsx | 24 +++++ .../{ => ServerStats}/ServerStats.tsx | 9 +- .../__snapshots__/ServerStats.jest.tsx.snap | 99 +++++++++++++++++++ public/app/routes/ReactContainer.tsx | 2 +- public/app/routes/bundle_loader.ts | 26 ----- public/app/routes/routes.ts | 2 +- public/app/stores/NavStore/NavStore.ts | 74 ++++++++++++++ public/app/stores/RootStore.ts | 2 + public/app/stores/ServerStatsStore.tsx | 31 +++--- 9 files changed, 223 insertions(+), 46 deletions(-) create mode 100644 public/app/containers/ServerStats/ServerStats.jest.tsx rename public/app/containers/{ => ServerStats}/ServerStats.tsx (77%) create mode 100644 public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap delete mode 100644 public/app/routes/bundle_loader.ts create mode 100644 public/app/stores/NavStore/NavStore.ts diff --git a/public/app/containers/ServerStats/ServerStats.jest.tsx b/public/app/containers/ServerStats/ServerStats.jest.tsx new file mode 100644 index 00000000000..da30f24568a --- /dev/null +++ b/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(); + + setTimeout(() => { + expect(page.toJSON()).toMatchSnapshot(); + done(); + }); + }); +}); diff --git a/public/app/containers/ServerStats.tsx b/public/app/containers/ServerStats/ServerStats.tsx similarity index 77% rename from public/app/containers/ServerStats.tsx rename to public/app/containers/ServerStats/ServerStats.tsx index b4ec56c4311..c5fdbe8a2fd 100644 --- a/public/app/containers/ServerStats.tsx +++ b/public/app/containers/ServerStats/ServerStats.tsx @@ -9,20 +9,19 @@ export interface IProps { @inject('store') @observer -export default class ServerStats extends React.Component { - navModel: NavModel; - +export class ServerStats extends React.Component { 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 (
- +
diff --git a/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap b/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap new file mode 100644 index 00000000000..c36cc64e3a1 --- /dev/null +++ b/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`] = ` +
+ // +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Value +
+ Total dashboards + + 10 +
+ Total users + + 0 +
+ Active users (seen last 30 days) + + 0 +
+ Total orgs + + 0 +
+ Total playlists + + 0 +
+ Total snapshots + + 0 +
+ Total dashboard tags + + 0 +
+ Total starred dashboards + + 0 +
+ Total alerts + + 0 +
+
+
+`; diff --git a/public/app/routes/ReactContainer.tsx b/public/app/routes/ReactContainer.tsx index 92a1baa9a8c..7db429f7dc2 100644 --- a/public/app/routes/ReactContainer.tsx +++ b/public/app/routes/ReactContainer.tsx @@ -16,7 +16,7 @@ function WrapInProvider(store, Component, props) { export function reactContainer($route) { return { restrict: 'E', - template: '

hasad

', + template: '', link(scope, elem) { let component = $route.current.locals.component; let props = {}; diff --git a/public/app/routes/bundle_loader.ts b/public/app/routes/bundle_loader.ts deleted file mode 100644 index e4e345b49fc..00000000000 --- a/public/app/routes/bundle_loader.ts +++ /dev/null @@ -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; - }, - ]; - } -} diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index 592e56dfda7..ab6b74b1492 100644 --- a/public/app/routes/routes.ts +++ b/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) { diff --git a/public/app/stores/NavStore/NavStore.ts b/public/app/stores/NavStore/NavStore.ts new file mode 100644 index 00000000000..375a8a27fc6 --- /dev/null +++ b/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: [] + // } + // ] + // }); + }, + })); diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore.ts index 55727b6ff68..c77f4378bfd 100644 --- a/public/app/stores/RootStore.ts +++ b/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; diff --git a/public/app/stores/ServerStatsStore.tsx b/public/app/stores/ServerStatsStore.tsx index a388fb77269..b8a3968d427 100644 --- a/public/app/stores/ServerStatsStore.tsx +++ b/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(); + } }), })); From 8fd8853770d41667a6cc5eff21f3388dce2029c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 28 Dec 2017 17:01:28 +0100 Subject: [PATCH 08/17] tech: progress on react pages --- .../ServerStats/ServerStats.jest.tsx | 22 ++++-- .../containers/ServerStats/ServerStats.tsx | 4 +- .../__snapshots__/ServerStats.jest.tsx.snap | 73 ++++++++++++++++++- .../app/core/components/sidemenu/sidemenu.ts | 6 +- public/app/stores/{NavStore => }/NavStore.ts | 36 ++------- public/app/stores/RootStore.ts | 2 +- public/app/stores/store.ts | 2 + public/test/mocks/common.ts | 14 ++++ 8 files changed, 115 insertions(+), 44 deletions(-) rename public/app/stores/{NavStore => }/NavStore.ts (56%) create mode 100644 public/test/mocks/common.ts diff --git a/public/app/containers/ServerStats/ServerStats.jest.tsx b/public/app/containers/ServerStats/ServerStats.jest.tsx index da30f24568a..07b938c4d0f 100644 --- a/public/app/containers/ServerStats/ServerStats.jest.tsx +++ b/public/app/containers/ServerStats/ServerStats.jest.tsx @@ -2,18 +2,24 @@ import React from 'react'; import renderer from 'react-test-renderer'; import { ServerStats } from './ServerStats'; import { RootStore } from 'app/stores/RootStore'; +import { backendSrv, createNavTree } from 'test/mocks/common'; describe('ServerStats', () => { it('Should render table with stats', done => { - let backendSrvMock = { - get: jest.fn().mockReturnValue( - Promise.resolve({ - dashboards: 10, - }) - ), - }; + backendSrv.get.mockReturnValue( + Promise.resolve({ + dashboards: 10, + }) + ); + + const store = RootStore.create( + {}, + { + backendSrv: backendSrv, + navTree: createNavTree('cfg', 'admin', 'server-stats'), + } + ); - const store = RootStore.create({}, { backendSrv: backendSrvMock }); const page = renderer.create(); setTimeout(() => { diff --git a/public/app/containers/ServerStats/ServerStats.tsx b/public/app/containers/ServerStats/ServerStats.tsx index c5fdbe8a2fd..9c846b0f813 100644 --- a/public/app/containers/ServerStats/ServerStats.tsx +++ b/public/app/containers/ServerStats/ServerStats.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { inject, observer } from 'mobx-react'; import PageHeader from 'app/core/components/PageHeader/PageHeader'; -import { NavModel, NavModelSrv } from 'app/core/nav_model_srv'; export interface IProps { store: any; @@ -13,8 +12,7 @@ export class ServerStats extends React.Component { constructor(props) { super(props); - // this.navModel = new NavModelSrv().getNav('cfg', 'admin', 'server-stats', 1); - this.props.store.nav.load('cfg', 'admin', 'server-stats'); + this.props.store.nav.load('cfg', 'admin', 'server-stats', 1); this.props.store.serverStats.load(); } diff --git a/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap b/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap index c36cc64e3a1..7e6f1d11c27 100644 --- a/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap +++ b/public/app/containers/ServerStats/__snapshots__/ServerStats.jest.tsx.snap @@ -2,7 +2,78 @@ exports[`ServerStats Should render table with stats 1`] = `
- // +
+
+
+
+ + + + +
+

+ admin-Text +

+ +
+
+ +
+
+
diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index 0276a7331b3..fb9d9be7f70 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -16,8 +16,10 @@ export class SideMenuCtrl { constructor(private $scope, private $rootScope, private $location, private contextSrv, private $timeout) { this.isSignedIn = contextSrv.isSignedIn; this.user = contextSrv.user; - this.mainLinks = _.filter(config.bootData.navTree, item => !item.hideFromMenu); - this.bottomNav = _.filter(config.bootData.navTree, item => item.hideFromMenu); + + let navTree = _.cloneDeep(config.bootData.navTree); + this.mainLinks = _.filter(navTree, item => !item.hideFromMenu); + this.bottomNav = _.filter(navTree, item => item.hideFromMenu); this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path()); if (contextSrv.user.orgCount > 1) { diff --git a/public/app/stores/NavStore/NavStore.ts b/public/app/stores/NavStore.ts similarity index 56% rename from public/app/stores/NavStore/NavStore.ts rename to public/app/stores/NavStore.ts index 375a8a27fc6..aab33cc40fc 100644 --- a/public/app/stores/NavStore/NavStore.ts +++ b/public/app/stores/NavStore.ts @@ -1,12 +1,11 @@ -import { types } from 'mobx-state-tree'; -import config from 'app/core/config'; +import { types, getEnv } from 'mobx-state-tree'; 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, ''), + subTitle: types.optional(types.string, ''), icon: types.optional(types.string, ''), img: types.optional(types.string, ''), active: types.optional(types.boolean, false), @@ -17,26 +16,24 @@ 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; + var children = getEnv(self).navTree; let main, node; - let breadcrumbs = []; + let parents = []; for (let id of args) { // if its a number then it's the index to use for main if (_.isNumber(id)) { - main = breadcrumbs[id]; + main = parents[id]; break; } - let current = _.find(children, { id: id }); - breadcrumbs.push(current); + node = _.find(children, { id: id }); main = node; - node = current; children = node.children; + parents.push(node); } if (main.children) { @@ -51,24 +48,5 @@ export const NavStore = types 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: [] - // } - // ] - // }); }, })); diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore.ts index c77f4378bfd..e6a445f8243 100644 --- a/public/app/stores/RootStore.ts +++ b/public/app/stores/RootStore.ts @@ -1,7 +1,7 @@ import { types } from 'mobx-state-tree'; import { SearchStore } from './SearchStore'; import { ServerStatsStore } from './ServerStatsStore'; -import { NavStore } from './NavStore/NavStore'; +import { NavStore } from './NavStore'; export const RootStore = types.model({ search: types.optional(SearchStore, { diff --git a/public/app/stores/store.ts b/public/app/stores/store.ts index 873eb9d5efe..3e40206a122 100644 --- a/public/app/stores/store.ts +++ b/public/app/stores/store.ts @@ -1,4 +1,5 @@ import { RootStore, IRootStore } from './RootStore'; +import config from 'app/core/config'; export let store: IRootStore; @@ -7,6 +8,7 @@ export function createStore(backendSrv) { {}, { backendSrv: backendSrv, + navTree: config.bootData.navTree, } ); } diff --git a/public/test/mocks/common.ts b/public/test/mocks/common.ts new file mode 100644 index 00000000000..3bbb7db4792 --- /dev/null +++ b/public/test/mocks/common.ts @@ -0,0 +1,14 @@ +export const backendSrv = { + get: jest.fn(), +}; + +export function createNavTree(...args) { + let root = []; + let node = root; + for (let arg of args) { + let child = { id: arg, url: `/url/${arg}`, text: `${arg}-Text`, children: [] }; + node.push(child); + node = child.children; + } + return root; +} From 4c1a67c34ee4bbcff7d59fbb91be99d965d7824d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 28 Dec 2017 18:49:33 +0100 Subject: [PATCH 09/17] tech: began reworking alerting list to mobx --- .../AlertRuleList/AlertRuleList.tsx | 94 +++++++++++++++++++ .../containers/ServerStats/ServerStats.tsx | 2 +- public/app/features/alerting/alert_def.ts | 2 - public/app/routes/routes.ts | 7 ++ public/app/stores/AlertingStore.ts | 51 ++++++++++ public/app/stores/NavStore.ts | 9 +- public/app/stores/RootStore.ts | 4 + public/app/stores/ServerStatsStore.tsx | 27 +++--- 8 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 public/app/containers/AlertRuleList/AlertRuleList.tsx create mode 100644 public/app/stores/AlertingStore.ts diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx new file mode 100644 index 00000000000..ee5a38cb24c --- /dev/null +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -0,0 +1,94 @@ +import React from 'react'; +import classNames from 'classnames'; +import { inject, observer } from 'mobx-react'; +import PageHeader from 'app/core/components/PageHeader/PageHeader'; + +export interface IProps { + store: any; +} + +@inject('store') +@observer +export class AlertRuleList extends React.Component { + constructor(props) { + super(props); + + this.props.store.nav.load('alerting', 'alert-list'); + this.props.store.alerting.loadRules(); + } + + render() { + return ( +
+ +
+
+
+ + +
+ +
-
    {this.props.store.alerting.rules.map(AlertRuleItem)}
+
    {alertList.rules.map(rule => )}
@@ -52,43 +76,68 @@ export class AlertRuleList extends React.Component { } } -function AlertRuleItem(rule) { - let stateClass = classNames({ - fa: true, - 'fa-play': rule.state === 'paused', - 'fa-pause': rule.state !== 'paused', - }); - - let ruleUrl = `dashboard/${rule.dashboardUri}?panelId=${rule.panelId}&fullscreen&edit&tab=alert`; - +function AlertStateFilterOption({ text, value }) { return ( -
  • -
    -
    - -
    -
    -
    - -
    - - {rule.stateText} - - for {rule.stateAge} -
    - {rule.info &&
    {rule.info}
    } -
    -
    -
    -
  • + ); } + +export interface AlertRuleItemProps { + rule: IAlertRule; +} + +@observer +export class AlertRuleItem extends React.Component { + toggleState = () => { + this.props.rule.togglePaused(); + }; + + render() { + const { rule } = this.props; + + let stateClass = classNames({ + fa: true, + 'fa-play': rule.isPaused, + 'fa-pause': !rule.isPaused, + }); + + let ruleUrl = `dashboard/${rule.dashboardUri}?panelId=${rule.panelId}&fullscreen&edit&tab=alert`; + + return ( +
  • +
    +
    + +
    +
    +
    + +
    + + {rule.stateText} + + for {rule.stateAge} +
    + {rule.info &&
    {rule.info}
    } +
    +
    +
    +
  • + ); + } +} diff --git a/public/app/stores/AlertListStore.ts b/public/app/stores/AlertListStore.ts new file mode 100644 index 00000000000..a72341b47be --- /dev/null +++ b/public/app/stores/AlertListStore.ts @@ -0,0 +1,85 @@ +import { types, getEnv, flow } from 'mobx-state-tree'; +import moment from 'moment'; +import alertDef from 'app/features/alerting/alert_def'; + +function setStateFields(rule, state) { + let stateModel = alertDef.getStateDisplayModel(state); + rule.state = state; + rule.stateText = stateModel.text; + rule.stateIcon = stateModel.iconClass; + rule.stateClass = stateModel.stateClass; + rule.stateAge = moment(rule.newStateDate) + .fromNow() + .replace(' ago', ''); +} + +export const AlertRule = types + .model('AlertRule', { + id: types.identifier(types.number), + dashboardId: types.number, + panelId: types.number, + name: types.string, + state: types.string, + stateText: types.string, + stateIcon: types.string, + stateClass: types.string, + stateAge: types.string, + info: types.optional(types.string, ''), + dashboardUri: types.string, + }) + .views(self => ({ + get isPaused() { + return self.state === 'paused'; + }, + })) + .actions(self => ({ + /** + * will toggle alert rule paused state + */ + togglePaused: flow(function* togglePaused() { + let backendSrv = getEnv(self).backendSrv; + + var payload = { paused: self.isPaused }; + let res = yield backendSrv.post(`/api/alerts/${self.id}/pause`, payload); + setStateFields(self, res.state); + self.info = ''; + }), + })); + +type IAlertRuleType = typeof AlertRule.Type; +export interface IAlertRule extends IAlertRuleType {} + +export const AlertListStore = types + .model('AlertListStore', { + rules: types.array(AlertRule), + stateFilter: types.optional(types.string, 'all'), + }) + .actions(self => ({ + setStateFilter: function(state) { + self.stateFilter = state; + }, + + loadRules: flow(function* load() { + let backendSrv = getEnv(self).backendSrv; + + let filters = { state: self.stateFilter }; + + let rules = yield backendSrv.get('/api/alerts', filters); + + self.rules.clear(); + + for (let rule of rules) { + setStateFields(rule, rule.state); + + if (rule.executionError) { + rule.info = 'Execution Error: ' + rule.executionError; + } + + if (rule.evalData && rule.evalData.noData) { + rule.info = 'Query returned no data'; + } + + self.rules.push(AlertRule.create(rule)); + } + }), + })); diff --git a/public/app/stores/AlertingStore.ts b/public/app/stores/AlertingStore.ts deleted file mode 100644 index f364da58cd0..00000000000 --- a/public/app/stores/AlertingStore.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { types, getEnv, flow } from 'mobx-state-tree'; -import moment from 'moment'; -import alertDef from 'app/features/alerting/alert_def'; - -export const AlertRule = types.model('AlertRule', { - id: types.identifier(types.number), - dashboardId: types.number, - panelId: types.number, - name: types.string, - state: types.string, - stateText: types.string, - stateIcon: types.string, - stateClass: types.string, - stateAge: types.string, - info: types.optional(types.string, ''), - dashboardUri: types.string, -}); - -export const AlertingStore = types - .model('AlertingStore', { - rules: types.array(AlertRule), - }) - .actions(self => ({ - loadRules: flow(function* load() { - let backendSrv = getEnv(self).backendSrv; - - let rules = yield backendSrv.get('/api/alerts'); - - self.rules.clear(); - - for (let rule of rules) { - let stateModel = alertDef.getStateDisplayModel(rule.state); - rule.stateText = stateModel.text; - rule.stateIcon = stateModel.iconClass; - rule.stateClass = stateModel.stateClass; - rule.stateAge = moment(rule.newStateDate) - .fromNow() - .replace(' ago', ''); - - if (rule.executionError) { - rule.info = 'Execution Error: ' + rule.executionError; - } - - if (rule.evalData && rule.evalData.noData) { - rule.info = 'Query returned no data'; - } - - self.rules.push(AlertRule.create(rule)); - } - }), - })); diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore.ts index a275a12c2ff..729faf7b533 100644 --- a/public/app/stores/RootStore.ts +++ b/public/app/stores/RootStore.ts @@ -2,7 +2,7 @@ import { types } from 'mobx-state-tree'; import { SearchStore } from './SearchStore'; import { ServerStatsStore } from './ServerStatsStore'; import { NavStore } from './NavStore'; -import { AlertingStore } from './AlertingStore'; +import { AlertListStore } from './AlertListStore'; export const RootStore = types.model({ search: types.optional(SearchStore, { @@ -12,7 +12,7 @@ export const RootStore = types.model({ stats: [], }), nav: types.optional(NavStore, {}), - alerting: types.optional(AlertingStore, { + alertList: types.optional(AlertListStore, { rules: [], }), }); From 8f50795a940dfb11e429be2e08366b97b928c10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sun, 31 Dec 2017 22:31:11 +0100 Subject: [PATCH 12/17] tech: url and query mobx store so now react components and containers can read and modify url path and query via mobx store --- .../AlertRuleList/AlertRuleList.tsx | 10 ++- public/app/core/components/grafana_app.ts | 9 +-- public/app/core/services/all.js | 2 +- .../{global_event_srv.ts => bridge_srv.ts} | 38 ++++++++-- ...l_event_srv.jest.ts => bridge_srv.jest.ts} | 5 +- .../app/features/alerting/alert_list_ctrl.ts | 74 ------------------- public/app/features/alerting/all.ts | 1 - .../alerting/partials/alert_list.html | 61 --------------- public/app/routes/ReactContainer.tsx | 2 +- public/app/routes/routes.ts | 3 +- public/app/stores/AlertListStore.ts | 6 +- public/app/stores/RootStore.ts | 5 ++ public/app/stores/ViewStore.ts | 35 +++++++++ public/app/stores/store.ts | 2 + 14 files changed, 93 insertions(+), 160 deletions(-) rename public/app/core/services/{global_event_srv.ts => bridge_srv.ts} (50%) rename public/app/core/specs/{global_event_srv.jest.ts => bridge_srv.jest.ts} (73%) delete mode 100644 public/app/features/alerting/alert_list_ctrl.ts delete mode 100644 public/app/features/alerting/partials/alert_list.html create mode 100644 public/app/stores/ViewStore.ts diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx index ee72dd53b9d..1ec461925c2 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -25,12 +25,16 @@ export class AlertRuleList extends React.Component { constructor(props) { super(props); - this.props.store.nav.load('alerting', 'alert-list'); - this.props.store.alertList.loadRules(); + const store = this.props.store; + + store.nav.load('alerting', 'alert-list'); + store.alertList.setStateFilter(store.view.query.get('state') || 'all'); + store.alertList.loadRules(); } onStateFilterChanged = evt => { this.props.store.alertList.setStateFilter(evt.target.value); + this.props.store.view.updateQuery({ state: evt.target.value }); this.props.store.alertList.loadRules(); }; @@ -54,7 +58,7 @@ export class AlertRuleList extends React.Component {
    - {this.stateFilters.map(AlertStateFilterOption)}
    diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index defd04cefd9..eb51334f358 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -10,19 +10,18 @@ import { createStore } from 'app/stores/store'; export class GrafanaCtrl { /** @ngInject */ - constructor($scope, alertSrv, utilSrv, $rootScope, $controller, contextSrv, globalEventSrv, backendSrv) { + constructor($scope, alertSrv, utilSrv, $rootScope, $controller, contextSrv, bridgeSrv, backendSrv) { createStore(backendSrv); $scope.init = function() { $scope.contextSrv = contextSrv; - - $rootScope.appSubUrl = config.appSubUrl; + $scope.appSubUrl = config.appSubUrl; $scope._ = _; profiler.init(config, $rootScope); alertSrv.init(); utilSrv.init(); - globalEventSrv.init(); + bridgeSrv.init(); $scope.dashAlerts = alertSrv; }; @@ -54,7 +53,7 @@ export class GrafanaCtrl { } /** @ngInject */ -export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScope) { +export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScope, $location) { return { restrict: 'E', controller: GrafanaCtrl, diff --git a/public/app/core/services/all.js b/public/app/core/services/all.js index 0053d789cbe..0a973440c5e 100644 --- a/public/app/core/services/all.js +++ b/public/app/core/services/all.js @@ -8,6 +8,6 @@ define([ './segment_srv', './backend_srv', './dynamic_directive_srv', - './global_event_srv' + './bridge_srv' ], function () {}); diff --git a/public/app/core/services/global_event_srv.ts b/public/app/core/services/bridge_srv.ts similarity index 50% rename from public/app/core/services/global_event_srv.ts rename to public/app/core/services/bridge_srv.ts index 0569b9933d8..561f651b089 100644 --- a/public/app/core/services/global_event_srv.ts +++ b/public/app/core/services/bridge_srv.ts @@ -1,15 +1,16 @@ -import coreModule from 'app/core/core_module'; +import coreModule from 'app/core/core_module'; import config from 'app/core/config'; import appEvents from 'app/core/app_events'; +import { store } from 'app/stores/store'; +import { reaction } from 'mobx'; -// This service is for registering global events. -// Good for communication react > angular and vice verse -export class GlobalEventSrv { +// Services that handles angular -> mobx store sync & other react <-> angular sync +export class BridgeSrv { private appSubUrl; private fullPageReloadRoutes; /** @ngInject */ - constructor(private $location, private $timeout, private $window) { + constructor(private $location, private $timeout, private $window, private $rootScope) { this.appSubUrl = config.appSubUrl; this.fullPageReloadRoutes = ['/logout']; } @@ -25,6 +26,31 @@ export class GlobalEventSrv { } init() { + this.$rootScope.$on('$routeUpdate', (evt, data) => { + let angularUrl = this.$location.url(); + if (store.view.currentUrl !== angularUrl) { + store.view.updatePathAndQuery(this.$location.path(), this.$location.search()); + } + }); + + this.$rootScope.$on('$routeChangeSuccess', (evt, data) => { + let angularUrl = this.$location.url(); + if (store.view.currentUrl !== angularUrl) { + store.view.updatePathAndQuery(this.$location.path(), this.$location.search()); + } + }); + + reaction( + () => store.view.currentUrl, + currentUrl => { + let angularUrl = this.$location.url(); + if (angularUrl !== currentUrl) { + this.$location.url(currentUrl); + console.log('store updating angular $location.url', currentUrl); + } + } + ); + appEvents.on('location-change', payload => { const urlWithoutBase = this.stripBaseFromUrl(payload.href); if (this.fullPageReloadRoutes.indexOf(urlWithoutBase) > -1) { @@ -40,4 +66,4 @@ export class GlobalEventSrv { } } -coreModule.service('globalEventSrv', GlobalEventSrv); +coreModule.service('bridgeSrv', BridgeSrv); diff --git a/public/app/core/specs/global_event_srv.jest.ts b/public/app/core/specs/bridge_srv.jest.ts similarity index 73% rename from public/app/core/specs/global_event_srv.jest.ts rename to public/app/core/specs/bridge_srv.jest.ts index ba318b81cc7..08fc296986d 100644 --- a/public/app/core/specs/global_event_srv.jest.ts +++ b/public/app/core/specs/bridge_srv.jest.ts @@ -1,5 +1,4 @@ -import { GlobalEventSrv } from 'app/core/services/global_event_srv'; -import { beforeEach } from 'test/lib/common'; +import { GlobalEventSrv } from 'app/core/services/bridge_srv'; jest.mock('app/core/config', () => { return { @@ -7,7 +6,7 @@ jest.mock('app/core/config', () => { }; }); -describe('GlobalEventSrv', () => { +describe('BridgeSrv', () => { let searchSrv; beforeEach(() => { diff --git a/public/app/features/alerting/alert_list_ctrl.ts b/public/app/features/alerting/alert_list_ctrl.ts deleted file mode 100644 index 47cd8b2cad7..00000000000 --- a/public/app/features/alerting/alert_list_ctrl.ts +++ /dev/null @@ -1,74 +0,0 @@ -/// - -import _ from 'lodash'; -import moment from 'moment'; - -import { coreModule, appEvents } from 'app/core/core'; -import alertDef from './alert_def'; - -export class AlertListCtrl { - alerts: any; - stateFilters = [ - { text: 'All', value: null }, - { text: 'OK', value: 'ok' }, - { text: 'Not OK', value: 'not_ok' }, - { text: 'Alerting', value: 'alerting' }, - { text: 'No Data', value: 'no_data' }, - { text: 'Paused', value: 'paused' }, - ]; - filters = { - state: 'ALL', - }; - navModel: any; - - /** @ngInject */ - constructor(private backendSrv, private $location, navModelSrv) { - this.navModel = navModelSrv.getNav('alerting', 'alert-list', 0); - - var params = $location.search(); - this.filters.state = params.state || null; - this.loadAlerts(); - } - - filtersChanged() { - this.$location.search(this.filters); - } - - loadAlerts() { - this.backendSrv.get('/api/alerts', this.filters).then(result => { - this.alerts = _.map(result, alert => { - alert.stateModel = alertDef.getStateDisplayModel(alert.state); - alert.newStateDateAgo = moment(alert.newStateDate) - .fromNow() - .replace(' ago', ''); - if (alert.evalData && alert.evalData.no_data) { - alert.no_data = true; - } - return alert; - }); - }); - } - - pauseAlertRule(alertId: any) { - var alert = _.find(this.alerts, { id: alertId }); - - var payload = { - paused: alert.state !== 'paused', - }; - - this.backendSrv.post(`/api/alerts/${alert.id}/pause`, payload).then(result => { - alert.state = result.state; - alert.stateModel = alertDef.getStateDisplayModel(result.state); - }); - } - - openHowTo() { - appEvents.emit('show-modal', { - src: 'public/app/features/alerting/partials/alert_howto.html', - modalClass: 'confirm-modal', - model: {}, - }); - } -} - -coreModule.controller('AlertListCtrl', AlertListCtrl); diff --git a/public/app/features/alerting/all.ts b/public/app/features/alerting/all.ts index f44bc975057..91d3a4109e7 100644 --- a/public/app/features/alerting/all.ts +++ b/public/app/features/alerting/all.ts @@ -1,3 +1,2 @@ -import './alert_list_ctrl'; import './notifications_list_ctrl'; import './notification_edit_ctrl'; diff --git a/public/app/features/alerting/partials/alert_list.html b/public/app/features/alerting/partials/alert_list.html deleted file mode 100644 index e7eb2533463..00000000000 --- a/public/app/features/alerting/partials/alert_list.html +++ /dev/null @@ -1,61 +0,0 @@ - - -
    - -
    -
    - -
    - -
    -
    - -
    -
    - - - - How to add an alert - -
    - -
    - -
      -
    1. -
      -
      - -
      -
      -
      - -
      - - - {{alert.stateModel.text}} (due to no data) - for {{alert.newStateDateAgo}} -
      -
      - Error: "{{alert.executionError}}" -
      -
      -
      -
      -
    2. -
    -
    -
    diff --git a/public/app/routes/ReactContainer.tsx b/public/app/routes/ReactContainer.tsx index 7db429f7dc2..b0f4e6b6ee5 100644 --- a/public/app/routes/ReactContainer.tsx +++ b/public/app/routes/ReactContainer.tsx @@ -13,7 +13,7 @@ function WrapInProvider(store, Component, props) { } /** @ngInject */ -export function reactContainer($route) { +export function reactContainer($route, $location) { return { restrict: 'E', template: '', diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index a6d1736c67c..ec65e4ec25a 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -226,8 +226,9 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { controller: 'AlertListCtrl', controllerAs: 'ctrl', }) - .when('/alerting/list2', { + .when('/alerting/list', { template: '', + reloadOnSearch: false, resolve: { component: () => AlertRuleList, }, diff --git a/public/app/stores/AlertListStore.ts b/public/app/stores/AlertListStore.ts index a72341b47be..6abb4484bc6 100644 --- a/public/app/stores/AlertListStore.ts +++ b/public/app/stores/AlertListStore.ts @@ -61,14 +61,12 @@ export const AlertListStore = types loadRules: flow(function* load() { let backendSrv = getEnv(self).backendSrv; - let filters = { state: self.stateFilter }; - - let rules = yield backendSrv.get('/api/alerts', filters); + let apiRules = yield backendSrv.get('/api/alerts', filters); self.rules.clear(); - for (let rule of rules) { + for (let rule of apiRules) { setStateFields(rule, rule.state); if (rule.executionError) { diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore.ts index 729faf7b533..1b0640d4c71 100644 --- a/public/app/stores/RootStore.ts +++ b/public/app/stores/RootStore.ts @@ -3,6 +3,7 @@ import { SearchStore } from './SearchStore'; import { ServerStatsStore } from './ServerStatsStore'; import { NavStore } from './NavStore'; import { AlertListStore } from './AlertListStore'; +import { ViewStore } from './ViewStore'; export const RootStore = types.model({ search: types.optional(SearchStore, { @@ -15,6 +16,10 @@ export const RootStore = types.model({ alertList: types.optional(AlertListStore, { rules: [], }), + view: types.optional(ViewStore, { + path: '', + query: {}, + }), }); type IRootStoreType = typeof RootStore.Type; diff --git a/public/app/stores/ViewStore.ts b/public/app/stores/ViewStore.ts new file mode 100644 index 00000000000..8d4df403e72 --- /dev/null +++ b/public/app/stores/ViewStore.ts @@ -0,0 +1,35 @@ +import { types } from 'mobx-state-tree'; +import _ from 'lodash'; +import $ from 'jquery'; + +export const ViewStore = types + .model({ + path: types.string, + query: types.map(types.string), + }) + .views(self => ({ + get currentUrl() { + let path = self.path; + if (self.query.size) { + path += '?' + $.param(self.query.toJS()); + } + return path; + }, + })) + .actions(self => ({ + updatePathAndQuery(path: string, query: any) { + self.path = path; + self.query.clear(); + + for (let key of _.keys(query)) { + self.query.set(key, query[key]); + } + }, + + updateQuery(query: any) { + self.query.clear(); + for (let key of _.keys(query)) { + self.query.set(key, query[key]); + } + }, + })); diff --git a/public/app/stores/store.ts b/public/app/stores/store.ts index 3e40206a122..3405dc38157 100644 --- a/public/app/stores/store.ts +++ b/public/app/stores/store.ts @@ -11,4 +11,6 @@ export function createStore(backendSrv) { navTree: config.bootData.navTree, } ); + + return store; } From 3301f8f19446fb7a1daef584fe09d9af57be8ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 1 Jan 2018 15:39:26 +0100 Subject: [PATCH 13/17] react: trying to get enzyme and mobx tests working --- .../AlertRuleList/AlertRuleList.jest.tsx | 54 +++++ .../AlertRuleList/AlertRuleList.tsx | 17 +- .../__snapshots__/AlertRuleList.jest.tsx.snap | 224 ++++++++++++++++++ public/app/core/specs/bridge_srv.jest.ts | 4 +- public/app/stores/AlertListStore.ts | 11 +- public/app/stores/NavStore.ts | 4 + yarn.lock | 2 +- 7 files changed, 300 insertions(+), 16 deletions(-) create mode 100644 public/app/containers/AlertRuleList/AlertRuleList.jest.tsx create mode 100644 public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx new file mode 100644 index 00000000000..b32b8194e47 --- /dev/null +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +// import renderer from 'react-test-renderer'; +import moment from 'moment'; +import { AlertRuleList, AlertRuleItem } from './AlertRuleList'; +import { RootStore } from 'app/stores/RootStore'; +import { backendSrv, createNavTree } from 'test/mocks/common'; +import { shallow } from 'enzyme'; + +describe('AlertRuleList', () => { + let page, store; + + beforeAll(done => { + backendSrv.get.mockReturnValue( + Promise.resolve([ + { + id: 11, + dashboardId: 58, + panelId: 3, + name: 'Panel Title alert', + state: 'ok', + newStateDate: moment() + .subtract(5, 'minutes') + .format(), + evalData: {}, + executionError: '', + dashboardUri: 'db/mygool', + }, + ]) + ); + + store = RootStore.create( + {}, + { + backendSrv: backendSrv, + navTree: createNavTree('alerting', 'alert-list'), + } + ); + + page = shallow() + .first() + .shallow(); + setTimeout(done, 100); + //page = renderer.create(); + }); + + it('should call api to get rules', () => { + expect(backendSrv.get.mock.calls[0][0]).toEqual('/api/alerts'); + }); + + it('should render 1 rule', () => { + console.log(page.find('.card-section').debug()); + expect(page.find(AlertRuleItem)).toHaveLength(1); + }); +}); diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx index 1ec461925c2..03fbf75fcec 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -25,19 +25,21 @@ export class AlertRuleList extends React.Component { constructor(props) { super(props); - const store = this.props.store; - - store.nav.load('alerting', 'alert-list'); - store.alertList.setStateFilter(store.view.query.get('state') || 'all'); - store.alertList.loadRules(); + this.props.store.nav.load('alerting', 'alert-list'); + this.fetchRules(); } onStateFilterChanged = evt => { - this.props.store.alertList.setStateFilter(evt.target.value); this.props.store.view.updateQuery({ state: evt.target.value }); - this.props.store.alertList.loadRules(); + this.fetchRules(); }; + fetchRules() { + this.props.store.alertList.loadRules({ + state: this.props.store.view.query.get('state') || 'all', + }); + } + onOpenHowTo = () => { appEvents.emit('show-modal', { src: 'public/app/features/alerting/partials/alert_howto.html', @@ -48,6 +50,7 @@ export class AlertRuleList extends React.Component { render() { const { nav, alertList } = this.props.store; + console.log('render', alertList.rules.length); return (
    diff --git a/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap new file mode 100644 index 00000000000..73072f487ea --- /dev/null +++ b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap @@ -0,0 +1,224 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AlertRuleList should render page 1`] = ` +
    +
    +
    +
    +
    + + + + +
    +

    + alerting-Text +

    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    + +
    +
    + +
    +
      +
    1. +
      +
      + +
      +
      +
      + +
      + + + + OK + + + for + 5 minutes + +
      + +
      +
      +
      +
    2. +
    +
    +
    +
    +`; diff --git a/public/app/core/specs/bridge_srv.jest.ts b/public/app/core/specs/bridge_srv.jest.ts index 08fc296986d..f29c88d7a05 100644 --- a/public/app/core/specs/bridge_srv.jest.ts +++ b/public/app/core/specs/bridge_srv.jest.ts @@ -1,4 +1,4 @@ -import { GlobalEventSrv } from 'app/core/services/bridge_srv'; +import { BridgeSrv } from 'app/core/services/bridge_srv'; jest.mock('app/core/config', () => { return { @@ -10,7 +10,7 @@ describe('BridgeSrv', () => { let searchSrv; beforeEach(() => { - searchSrv = new GlobalEventSrv(null, null, null); + searchSrv = new BridgeSrv(null, null, null, null); }); describe('With /subUrl as appSubUrl', () => { diff --git a/public/app/stores/AlertListStore.ts b/public/app/stores/AlertListStore.ts index 6abb4484bc6..a581ec0fedc 100644 --- a/public/app/stores/AlertListStore.ts +++ b/public/app/stores/AlertListStore.ts @@ -55,13 +55,12 @@ export const AlertListStore = types stateFilter: types.optional(types.string, 'all'), }) .actions(self => ({ - setStateFilter: function(state) { - self.stateFilter = state; - }, - - loadRules: flow(function* load() { + loadRules: flow(function* load(filters) { let backendSrv = getEnv(self).backendSrv; - let filters = { state: self.stateFilter }; + + // store state filter used in api query + self.stateFilter = filters.state; + let apiRules = yield backendSrv.get('/api/alerts', filters); self.rules.clear(); diff --git a/public/app/stores/NavStore.ts b/public/app/stores/NavStore.ts index 51bf39b803e..edd25d965ee 100644 --- a/public/app/stores/NavStore.ts +++ b/public/app/stores/NavStore.ts @@ -25,6 +25,10 @@ export const NavStore = types for (let id of args) { node = _.find(children, { id: id }); + if (!node) { + throw new Error(`NavItem with id ${id} not found`); + } + children = node.children; parents.push(node); } diff --git a/yarn.lock b/yarn.lock index 870cfd637bf..161927c0db8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10087,7 +10087,7 @@ whatwg-encoding@^1.0.1: dependencies: iconv-lite "0.4.19" -whatwg-fetch@>=0.10.0, whatwg-fetch@^2.0.3: +whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" From 644adef4651c4c1331e947078be934fa2f3ca98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 1 Jan 2018 16:04:32 +0100 Subject: [PATCH 14/17] tech: enzyme container test working --- package.json | 16 +- .../AlertRuleList/AlertRuleList.jest.tsx | 8 +- .../AlertRuleList/AlertRuleList.tsx | 1 - .../__snapshots__/AlertRuleList.jest.tsx.snap | 224 ---------- yarn.lock | 394 +++++++++++++++--- 5 files changed, 354 insertions(+), 289 deletions(-) delete mode 100644 public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap diff --git a/package.json b/package.json index 613e5cfb06c..69e54ddf0e7 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "html-loader": "^0.5.1", "html-webpack-plugin": "^2.30.1", "husky": "^0.14.3", - "jest": "^21.2.1", + "jest": "^22.0.4", "jshint-stylish": "~2.2.1", "json-loader": "^0.5.7", "karma": "1.7.0", @@ -83,12 +83,12 @@ "sinon": "1.17.6", "systemjs": "0.20.19", "systemjs-plugin-css": "^0.1.36", - "ts-jest": "^21.1.3", - "ts-loader": "^2.3.7", - "tslint": "^5.7.0", + "ts-jest": "^22.0.0", + "ts-loader": "^3.2.0", + "tslint": "^5.8.0", "tslint-loader": "^3.5.3", - "typescript": "^2.5.2", - "webpack": "^3.6.0", + "typescript": "^2.6.2", + "webpack": "^3.10.0", "webpack-bundle-analyzer": "^2.9.0", "webpack-cleanup-plugin": "^0.5.1", "webpack-merge": "^4.1.0", @@ -145,8 +145,8 @@ "mousetrap": "^1.6.0", "perfect-scrollbar": "^1.2.0", "prop-types": "^15.6.0", - "react": "^16.1.1", - "react-dom": "^16.1.1", + "react": "^16.2.0", + "react-dom": "^16.2.0", "react-grid-layout": "^0.16.1", "react-sizeme": "^2.3.6", "remarkable": "^1.7.1", diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx index b32b8194e47..5485da1dfdd 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -39,8 +39,11 @@ describe('AlertRuleList', () => { page = shallow() .first() .shallow(); - setTimeout(done, 100); - //page = renderer.create(); + + setTimeout(() => { + page.update(); + done(); + }); }); it('should call api to get rules', () => { @@ -48,7 +51,6 @@ describe('AlertRuleList', () => { }); it('should render 1 rule', () => { - console.log(page.find('.card-section').debug()); expect(page.find(AlertRuleItem)).toHaveLength(1); }); }); diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx index 03fbf75fcec..19a23e43c33 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -50,7 +50,6 @@ export class AlertRuleList extends React.Component { render() { const { nav, alertList } = this.props.store; - console.log('render', alertList.rules.length); return (
    diff --git a/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap deleted file mode 100644 index 73072f487ea..00000000000 --- a/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap +++ /dev/null @@ -1,224 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`AlertRuleList should render page 1`] = ` -
    -
    -
    -
    -
    - - - - -
    -

    - alerting-Text -

    - -
    -
    - -
    -
    -
    -
    -
    -
    - -
    - -
    -
    - -
    -
      -
    1. -
      -
      - -
      -
      -
      - -
      - - - - OK - - - for - 5 minutes - -
      - -
      -
      -
      -
    2. -
    -
    -
    -
    -`; diff --git a/yarn.lock b/yarn.lock index 161927c0db8..5fbedb3fa43 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@babel/code-frame@^7.0.0-beta.35": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.36.tgz#2349d7ec04b3a06945ae173280ef8579b63728e4" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + "@types/cheerio@*": version "0.22.5" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.5.tgz#db749e8470d98f103d51407db9bee5a8b9d20d45" @@ -197,7 +205,11 @@ version "21.1.8" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-21.1.8.tgz#d497213725684f1e5a37900b17a47c9c018f1a97" -"@types/node@*", "@types/node@^8.0.31": +"@types/node@*": + version "8.5.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.2.tgz#83b8103fa9a2c2e83d78f701a9aa7c9539739aa5" + +"@types/node@^8.0.31": version "8.0.53" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8" @@ -257,6 +269,12 @@ acorn-globals@^3.1.0: dependencies: acorn "^4.0.4" +acorn-globals@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" + dependencies: + acorn "^5.0.0" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -275,6 +293,10 @@ acorn@^5.0.0, acorn@^5.1.1, acorn@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" +acorn@^5.1.2: + version "5.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" + acorn@~2.6.4: version "2.6.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.6.4.tgz#eb1f45b4a43fa31d03701a5ec46f3b52673e90ee" @@ -834,6 +856,10 @@ babel-plugin-jest-hoist@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" +babel-plugin-jest-hoist@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.0.3.tgz#62cde5fe962fd41ae89c119f481ca5cd7dd48bb4" + babel-plugin-syntax-object-rest-spread@^6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -1063,6 +1089,13 @@ babel-preset-jest@^21.2.0: babel-plugin-jest-hoist "^21.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-jest@^22.0.1: + version "22.0.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.0.3.tgz#e2bb6f6b4a509d3ea0931f013db78c5a84856693" + dependencies: + babel-plugin-jest-hoist "^22.0.3" + babel-plugin-syntax-object-rest-spread "^6.13.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -1303,6 +1336,10 @@ brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" +browser-process-hrtime@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" + browser-resolve@^1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" @@ -1578,7 +1615,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.0, chalk@~1.1.1: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" dependencies: @@ -2781,6 +2818,10 @@ domelementtype@~1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" +domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.0.tgz#81fe5df81b3f057052cde3a9fa9bf536a85b9ab0" + domhandler@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" @@ -3012,16 +3053,21 @@ enzyme-adapter-utils@^1.1.0: prop-types "^15.5.10" enzyme@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.2.0.tgz#998bdcda0fc71b8764a0017f7cc692c943f54a7a" + version "3.3.0" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479" dependencies: cheerio "^1.0.0-rc.2" function.prototype.name "^1.0.3" has "^1.0.1" + is-boolean-object "^1.0.0" + is-callable "^1.1.3" + is-number-object "^1.0.3" + is-string "^1.0.4" is-subset "^0.1.1" lodash "^4.17.4" + object-inspect "^1.5.0" object-is "^1.0.1" - object.assign "^4.0.4" + object.assign "^4.1.0" object.entries "^1.0.4" object.values "^1.0.4" raf "^3.4.0" @@ -3146,7 +3192,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@^1.6.1: +escodegen@^1.6.1, escodegen@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" dependencies: @@ -3372,6 +3418,17 @@ expect@^21.2.1: jest-message-util "^21.2.1" jest-regex-util "^21.2.0" +expect@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-22.0.3.tgz#bb486de7d41bf3eb60d3b16dfd1c158a4d91ddfa" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^22.0.3" + jest-get-type "^22.0.3" + jest-matcher-utils "^22.0.3" + jest-message-util "^22.0.3" + jest-regex-util "^22.0.3" + expose-loader@^0.7.3: version "0.7.4" resolved "https://registry.yarnpkg.com/expose-loader/-/expose-loader-0.7.4.tgz#9bcdd3878b5da9107930b55a03f65afe90b3314a" @@ -3743,6 +3800,14 @@ fs-access@^1.0.0: dependencies: null-check "^1.0.0" +fs-extra@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" @@ -3759,14 +3824,6 @@ fs-extra@^3.0.1: jsonfile "^3.0.0" universalify "^0.1.0" -fs-extra@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-vacuum@~1.2.10: version "1.2.10" resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" @@ -3817,11 +3874,11 @@ function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" function.prototype.name@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.3.tgz#0099ae5572e9dd6f03c97d023fd92bcc5e639eac" + version "1.1.0" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.0.tgz#8bd763cc0af860a859cc5d49384d74b932cd2327" dependencies: define-properties "^1.1.2" - function-bind "^1.1.0" + function-bind "^1.1.1" is-callable "^1.1.3" gauge@~2.7.3: @@ -4290,6 +4347,10 @@ has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + has-unicode@^2.0.0, has-unicode@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -4747,6 +4808,10 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" +is-boolean-object@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93" + is-buffer@^1.0.2, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -4885,6 +4950,10 @@ is-npm@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" +is-number-object@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799" + is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" @@ -4987,6 +5056,10 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-string@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.4.tgz#cc3a9b69857d621e963725a24caeec873b826e64" + is-subset@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" @@ -5171,6 +5244,22 @@ jest-config@^21.2.1: jest-validate "^21.2.1" pretty-format "^21.2.1" +jest-config@^22.0.1: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.0.4.tgz#9c2a46c0907b1a1af54d9cdbf18e99b447034e11" + dependencies: + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^22.0.4" + jest-environment-node "^22.0.4" + jest-get-type "^22.0.3" + jest-jasmine2 "^22.0.4" + jest-regex-util "^22.0.3" + jest-resolve "^22.0.4" + jest-util "^22.0.4" + jest-validate "^22.0.3" + pretty-format "^22.0.3" + jest-diff@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-21.2.1.tgz#46cccb6cab2d02ce98bc314011764bb95b065b4f" @@ -5180,6 +5269,15 @@ jest-diff@^21.2.1: jest-get-type "^21.2.0" pretty-format "^21.2.1" +jest-diff@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.0.3.tgz#ffed5aba6beaf63bb77819ba44dd520168986321" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.0.3" + pretty-format "^22.0.3" + jest-docblock@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" @@ -5192,6 +5290,14 @@ jest-environment-jsdom@^21.2.1: jest-util "^21.2.1" jsdom "^9.12.0" +jest-environment-jsdom@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.0.4.tgz#5723d4e724775ed38948de792e62f2d6a7f452df" + dependencies: + jest-mock "^22.0.3" + jest-util "^22.0.4" + jsdom "^11.5.1" + jest-environment-node@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-21.2.1.tgz#98c67df5663c7fbe20f6e792ac2272c740d3b8c8" @@ -5199,10 +5305,21 @@ jest-environment-node@^21.2.1: jest-mock "^21.2.0" jest-util "^21.2.1" +jest-environment-node@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.0.4.tgz#068671f85a545f96a5469be3a3dd228fca79c709" + dependencies: + jest-mock "^22.0.3" + jest-util "^22.0.4" + jest-get-type@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23" +jest-get-type@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.0.3.tgz#fa894b677c0fcd55eff3fd8ee28c7be942e32d36" + jest-haste-map@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-21.2.0.tgz#1363f0a8bb4338f24f001806571eff7a4b2ff3d8" @@ -5227,6 +5344,20 @@ jest-jasmine2@^21.2.1: jest-snapshot "^21.2.1" p-cancelable "^0.3.0" +jest-jasmine2@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.0.4.tgz#f7c0965116efe831ec674dc954b0134639b3dcee" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + expect "^22.0.3" + graceful-fs "^4.1.11" + jest-diff "^22.0.3" + jest-matcher-utils "^22.0.3" + jest-message-util "^22.0.3" + jest-snapshot "^22.0.3" + source-map-support "^0.5.0" + jest-matcher-utils@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-21.2.1.tgz#72c826eaba41a093ac2b4565f865eb8475de0f64" @@ -5235,6 +5366,14 @@ jest-matcher-utils@^21.2.1: jest-get-type "^21.2.0" pretty-format "^21.2.1" +jest-matcher-utils@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.0.3.tgz#2ec15ca1af7dcabf4daddc894ccce224b948674e" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.0.3" + pretty-format "^22.0.3" + jest-message-util@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-21.2.1.tgz#bfe5d4692c84c827d1dcf41823795558f0a1acbe" @@ -5243,14 +5382,32 @@ jest-message-util@^21.2.1: micromatch "^2.3.11" slash "^1.0.0" +jest-message-util@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.0.3.tgz#bf674b2762ef2dd53facf2136423fcca264976df" + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + jest-mock@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-21.2.0.tgz#7eb0770e7317968165f61ea2a7281131534b3c0f" +jest-mock@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.0.3.tgz#c875e47b5b729c6c020a2fab317b275c0cf88961" + jest-regex-util@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-21.2.0.tgz#1b1e33e63143babc3e0f2e6c9b5ba1eb34b2d530" +jest-regex-util@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.0.3.tgz#c5c10229de5ce2b27bf4347916d95b802ae9aa4d" + jest-resolve-dependencies@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-21.2.0.tgz#9e231e371e1a736a1ad4e4b9a843bc72bfe03d09" @@ -5265,6 +5422,13 @@ jest-resolve@^21.2.0: chalk "^2.0.1" is-builtin-module "^1.0.0" +jest-resolve@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.0.4.tgz#a6e47f55e9388c7341b5e9732aedc6fe30906121" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + jest-runner@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-21.2.1.tgz#194732e3e518bfb3d7cbfc0fd5871246c7e1a467" @@ -5313,6 +5477,17 @@ jest-snapshot@^21.2.1: natural-compare "^1.4.0" pretty-format "^21.2.1" +jest-snapshot@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.0.3.tgz#a949b393781d2fdb4773f6ea765dd67ad1da291e" + dependencies: + chalk "^2.0.1" + jest-diff "^22.0.3" + jest-matcher-utils "^22.0.3" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^22.0.3" + jest-util@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-21.2.1.tgz#a274b2f726b0897494d694a6c3d6a61ab819bb78" @@ -5325,6 +5500,18 @@ jest-util@^21.2.1: jest-validate "^21.2.1" mkdirp "^0.5.1" +jest-util@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.0.4.tgz#d920a513e0645aaab030cee38e4fe7d5bed8bb6d" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^22.0.3" + jest-validate "^22.0.3" + mkdirp "^0.5.1" + jest-validate@^21.1.0, jest-validate@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7" @@ -5334,6 +5521,15 @@ jest-validate@^21.1.0, jest-validate@^21.2.1: leven "^2.1.0" pretty-format "^21.2.1" +jest-validate@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.0.3.tgz#2850d949a36c48b1a40f7eebae1d8539126f7829" + dependencies: + chalk "^2.0.1" + jest-get-type "^22.0.3" + leven "^2.1.0" + pretty-format "^22.0.3" + jest@^21.2.1: version "21.2.1" resolved "https://registry.yarnpkg.com/jest/-/jest-21.2.1.tgz#c964e0b47383768a1438e3ccf3c3d470327604e1" @@ -5433,6 +5629,35 @@ jsdoctypeparser@~1.2.0: dependencies: lodash "^3.7.0" +jsdom@^11.5.1: + version "11.5.1" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.5.1.tgz#5df753b8d0bca20142ce21f4f6c039f99a992929" + dependencies: + abab "^1.0.3" + acorn "^5.1.2" + acorn-globals "^4.0.0" + array-equal "^1.0.0" + browser-process-hrtime "^0.1.2" + content-type-parser "^1.0.1" + cssom ">= 0.3.2 < 0.4.0" + cssstyle ">= 0.2.37 < 0.3.0" + domexception "^1.0.0" + escodegen "^1.9.0" + html-encoding-sniffer "^1.0.1" + left-pad "^1.2.0" + nwmatcher "^1.4.3" + parse5 "^3.0.2" + pn "^1.0.0" + request "^2.83.0" + request-promise-native "^1.0.3" + sax "^1.2.1" + symbol-tree "^3.2.1" + tough-cookie "^2.3.3" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.1" + whatwg-url "^6.3.0" + xml-name-validator "^2.0.1" + jsdom@^9.12.0: version "9.12.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4" @@ -5723,6 +5948,10 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +left-pad@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee" + leven@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" @@ -5931,6 +6160,10 @@ lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" @@ -5955,7 +6188,7 @@ lodash@^3.10.1, lodash@^3.5.0, lodash@^3.6.0, lodash@^3.7.0, lodash@^3.8.0, loda version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.4: +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -6906,7 +7139,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -"nwmatcher@>= 1.3.9 < 2.0.0": +"nwmatcher@>= 1.3.9 < 2.0.0", nwmatcher@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" @@ -6934,11 +7167,15 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-inspect@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.5.0.tgz#9d876c11e40f485c79215670281b767488f9bfe3" + object-is@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" -object-keys@^1.0.10, object-keys@^1.0.8: +object-keys@^1.0.11, object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -6948,13 +7185,14 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" +object.assign@^4.0.4, object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" dependencies: define-properties "^1.1.2" - function-bind "^1.1.0" - object-keys "^1.0.10" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" object.entries@^1.0.4: version "1.0.4" @@ -7195,7 +7433,7 @@ parse5@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" -parse5@^3.0.1: +parse5@^3.0.1, parse5@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" dependencies: @@ -7384,6 +7622,10 @@ pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7741,6 +7983,13 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-format@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.0.3.tgz#a2bfa59fc33ad24aa4429981bb52524b41ba5dd7" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -7856,6 +8105,10 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +punycode@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7966,9 +8219,9 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-dom@^16.1.1: - version "16.1.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.1.1.tgz#b2e331b6d752faf1a2d31399969399a41d8d45f8" +react-dom@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -8015,9 +8268,9 @@ react-test-renderer@^16.0.0, react-test-renderer@^16.0.0-0: object-assign "^4.1.1" prop-types "^15.6.0" -react@^16.1.1: - version "16.1.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.1.1.tgz#d5c4ef795507e3012282dd51261ff9c0e824fe1f" +react@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -8319,7 +8572,21 @@ request-progress@^2.0.1: dependencies: throttleit "^1.0.0" -request@2, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@~2.83.0: +request-promise-core@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" + dependencies: + lodash "^4.13.1" + +request-promise-native@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" + dependencies: + request-promise-core "1.1.1" + stealthy-require "^1.1.0" + tough-cookie ">=2.3.3" + +request@2, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@^2.83.0, request@~2.83.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: @@ -9052,6 +9319,10 @@ stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" +stack-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.1.tgz#d4f33ab54e8e38778b0ca5cfd3b3afb12db68620" + staged-git-files@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/staged-git-files/-/staged-git-files-0.0.4.tgz#d797e1b551ca7a639dec0237dc6eb4bb9be17d35" @@ -9077,6 +9348,10 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" +stealthy-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -9506,12 +9781,18 @@ toposort@^1.0.0: version "1.0.6" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" -tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3: +tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" +tr46@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + dependencies: + punycode "^2.1.0" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -9538,27 +9819,26 @@ tryor@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" -ts-jest@^21.1.3: - version "21.2.3" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-21.2.3.tgz#d90cd143c433e8dfd9b8df54921c7f3f1d8b9819" +ts-jest@^22.0.0: + version "22.0.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.0.0.tgz#cce1a5f1106150ca002d09f7e85913355ceb5e8d" dependencies: babel-core "^6.24.1" babel-plugin-istanbul "^4.1.4" babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-preset-jest "^21.2.0" + babel-preset-jest "^22.0.1" cpx "^1.5.0" - fs-extra "^4.0.2" - jest-config "^21.2.1" - jest-util "^21.2.1" + fs-extra "4.0.3" + jest-config "^22.0.1" pkg-dir "^2.0.0" source-map-support "^0.5.0" yargs "^10.0.3" -ts-loader@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-2.3.7.tgz#a9028ced473bee12f28a75f9c5b139979d33f2fc" +ts-loader@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-3.2.0.tgz#23211922179b81f7448754b7fdfca45b8374a15a" dependencies: - chalk "^2.0.1" + chalk "^2.3.0" enhanced-resolve "^3.0.0" loader-utils "^1.0.2" semver "^5.0.1" @@ -9577,7 +9857,7 @@ tslint-loader@^3.5.3: rimraf "^2.4.4" semver "^5.3.0" -tslint@^5.7.0: +tslint@^5.8.0: version "5.8.0" resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13" dependencies: @@ -9634,9 +9914,9 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^2.5.2: - version "2.6.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631" +typescript@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" ua-parser-js@^0.7.9: version "0.7.17" @@ -9996,7 +10276,7 @@ webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" -webidl-conversions@^4.0.0: +webidl-conversions@^4.0.0, webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -10054,9 +10334,9 @@ webpack-sources@^1.0.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^3.6.0: - version "3.8.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.8.1.tgz#b16968a81100abe61608b0153c9159ef8bb2bd83" +webpack@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725" dependencies: acorn "^5.0.0" acorn-dynamic-import "^2.0.0" @@ -10098,6 +10378,14 @@ whatwg-url@^4.3.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +whatwg-url@^6.3.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.0" + webidl-conversions "^4.0.1" + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" From 5981f67226c2ab2cefde55cf8c32cde1994eec4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 1 Jan 2018 18:54:23 +0100 Subject: [PATCH 15/17] tech: enzyme container test working --- jest.config.js | 3 +- package.json | 1 + .../AlertRuleList/AlertRuleList.jest.tsx | 38 +- public/test/mocks/common.ts | 1 + yarn.lock | 433 ++++++------------ 5 files changed, 178 insertions(+), 298 deletions(-) diff --git a/jest.config.js b/jest.config.js index ead97e39dad..606465c9840 100644 --- a/jest.config.js +++ b/jest.config.js @@ -24,5 +24,6 @@ module.exports = { "setupFiles": [ "./public/test/jest-shim.ts", "./public/test/jest-setup.ts" - ] + ], + "snapshotSerializers": ["enzyme-to-json/serializer"], }; diff --git a/package.json b/package.json index 69e54ddf0e7..bf3bdf616a7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "css-loader": "^0.28.7", "enzyme": "^3.1.0", "enzyme-adapter-react-16": "^1.0.1", + "enzyme-to-json": "^3.3.0", "es6-promise": "^3.0.2", "es6-shim": "^0.35.3", "expect.js": "~0.2.0", diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx index 5485da1dfdd..c49343697f7 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -1,15 +1,15 @@ import React from 'react'; -// import renderer from 'react-test-renderer'; import moment from 'moment'; -import { AlertRuleList, AlertRuleItem } from './AlertRuleList'; +import { AlertRuleList } from './AlertRuleList'; import { RootStore } from 'app/stores/RootStore'; import { backendSrv, createNavTree } from 'test/mocks/common'; -import { shallow } from 'enzyme'; +import { mount } from 'enzyme'; +import toJson from 'enzyme-to-json'; describe('AlertRuleList', () => { let page, store; - beforeAll(done => { + beforeAll(() => { backendSrv.get.mockReturnValue( Promise.resolve([ { @@ -36,14 +36,7 @@ describe('AlertRuleList', () => { } ); - page = shallow() - .first() - .shallow(); - - setTimeout(() => { - page.update(); - done(); - }); + page = mount(); }); it('should call api to get rules', () => { @@ -51,6 +44,25 @@ describe('AlertRuleList', () => { }); it('should render 1 rule', () => { - expect(page.find(AlertRuleItem)).toHaveLength(1); + page.update(); + let ruleNode = page.find('.card-item-wrapper'); + expect(toJson(ruleNode)).toMatchSnapshot(); + }); + + it('toggle state should change pause rule if not paused', async () => { + backendSrv.post.mockReturnValue( + Promise.resolve({ + state: 'paused', + }) + ); + + page.find('.fa-pause').simulate('click'); + + // wait for api call to resolve + await Promise.resolve(); + page.update(); + + expect(store.alertList.rules[0].state).toBe('paused'); + expect(page.find('.fa-play')).toHaveLength(1); }); }); diff --git a/public/test/mocks/common.ts b/public/test/mocks/common.ts index 3bbb7db4792..0c0ae0aea6b 100644 --- a/public/test/mocks/common.ts +++ b/public/test/mocks/common.ts @@ -1,5 +1,6 @@ export const backendSrv = { get: jest.fn(), + post: jest.fn(), }; export function createNavTree(...args) { diff --git a/yarn.lock b/yarn.lock index 5fbedb3fa43..2c54a93aed8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -263,12 +263,6 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" -acorn-globals@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" - dependencies: - acorn "^4.0.4" - acorn-globals@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" @@ -285,7 +279,7 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.3, acorn@^4.0.4: +acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" @@ -817,12 +811,12 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-jest@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-21.2.0.tgz#2ce059519a9374a2c46f2455b6fbef5ad75d863e" +babel-jest@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.0.4.tgz#533c46de37d7c9d7612f408c76314be9277e0c26" dependencies: - babel-plugin-istanbul "^4.0.0" - babel-preset-jest "^21.2.0" + babel-plugin-istanbul "^4.1.5" + babel-preset-jest "^22.0.3" babel-loader@^7.1.2: version "7.1.2" @@ -844,7 +838,7 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-istanbul@^4.0.0, babel-plugin-istanbul@^4.1.4: +babel-plugin-istanbul@^4.1.4, babel-plugin-istanbul@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" dependencies: @@ -852,10 +846,6 @@ babel-plugin-istanbul@^4.0.0, babel-plugin-istanbul@^4.1.4: istanbul-lib-instrument "^1.7.5" test-exclude "^4.1.1" -babel-plugin-jest-hoist@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" - babel-plugin-jest-hoist@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.0.3.tgz#62cde5fe962fd41ae89c119f481ca5cd7dd48bb4" @@ -1082,14 +1072,7 @@ babel-preset-es2015@^6.24.1: babel-plugin-transform-es2015-unicode-regex "^6.24.1" babel-plugin-transform-regenerator "^6.24.1" -babel-preset-jest@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz#ff9d2bce08abd98e8a36d9a8a5189b9173b85638" - dependencies: - babel-plugin-jest-hoist "^21.2.0" - babel-plugin-syntax-object-rest-spread "^6.13.0" - -babel-preset-jest@^22.0.1: +babel-preset-jest@^22.0.1, babel-preset-jest@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.0.3.tgz#e2bb6f6b4a509d3ea0931f013db78c5a84856693" dependencies: @@ -1216,6 +1199,10 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +bindings@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" + bl@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" @@ -2742,6 +2729,10 @@ detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + dezalgo@^1.0.0, dezalgo@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" @@ -3052,6 +3043,12 @@ enzyme-adapter-utils@^1.1.0: object.assign "^4.0.4" prop-types "^15.5.10" +enzyme-to-json@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/enzyme-to-json/-/enzyme-to-json-3.3.0.tgz#553e23a09ffb4b0cf09287e2edf9c6539fddaa84" + dependencies: + lodash "^4.17.4" + enzyme@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.3.0.tgz#0971abd167f2d4bf3f5bd508229e1c4b6dc50479" @@ -3089,7 +3086,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.6.1: +es-abstract@^1.5.1, es-abstract@^1.6.1: version "1.10.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: @@ -3192,7 +3189,7 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@^1.6.1, escodegen@^1.9.0: +escodegen@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" dependencies: @@ -3407,17 +3404,6 @@ expect.js@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/expect.js/-/expect.js-0.2.0.tgz#1028533d2c1c363f74a6796ff57ec0520ded2be1" -expect@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-21.2.1.tgz#003ac2ac7005c3c29e73b38a272d4afadd6d1d7b" - dependencies: - ansi-styles "^3.2.0" - jest-diff "^21.2.1" - jest-get-type "^21.2.0" - jest-matcher-utils "^21.2.1" - jest-message-util "^21.2.1" - jest-regex-util "^21.2.0" - expect@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/expect/-/expect-22.0.3.tgz#bb486de7d41bf3eb60d3b16dfd1c158a4d91ddfa" @@ -5125,7 +5111,7 @@ isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -istanbul-api@^1.1.1: +istanbul-api@^1.1.14: version "1.2.1" resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.1.tgz#0c60a0515eb11c7d65c6b50bba2c6e999acd8620" dependencies: @@ -5141,7 +5127,7 @@ istanbul-api@^1.1.1: mkdirp "^0.5.1" once "^1.4.0" -istanbul-lib-coverage@^1.0.1, istanbul-lib-coverage@^1.1.1: +istanbul-lib-coverage@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" @@ -5151,7 +5137,7 @@ istanbul-lib-hook@^1.1.0: dependencies: append-transform "^0.4.0" -istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.9.1: +istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0, istanbul-lib-instrument@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz#250b30b3531e5d3251299fdd64b0b2c9db6b558e" dependencies: @@ -5172,7 +5158,7 @@ istanbul-lib-report@^1.1.2: path-parse "^1.0.5" supports-color "^3.1.2" -istanbul-lib-source-maps@^1.1.0, istanbul-lib-source-maps@^1.2.2: +istanbul-lib-source-maps@^1.2.1, istanbul-lib-source-maps@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz#750578602435f28a0c04ee6d7d9e0f2960e62c1c" dependencies: @@ -5188,63 +5174,49 @@ istanbul-reports@^1.1.3: dependencies: handlebars "^4.0.3" -jest-changed-files@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-21.2.0.tgz#5dbeecad42f5d88b482334902ce1cba6d9798d29" +jest-changed-files@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.0.3.tgz#3771315acfa24a0ed7e6c545de620db6f1b2d164" dependencies: throat "^4.0.0" -jest-cli@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-21.2.1.tgz#9c528b6629d651911138d228bdb033c157ec8c00" +jest-cli@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.0.4.tgz#0052abaad45c57861c05da8ab5d27bad13ad224d" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.1" glob "^7.1.2" graceful-fs "^4.1.11" is-ci "^1.0.10" - istanbul-api "^1.1.1" - istanbul-lib-coverage "^1.0.1" - istanbul-lib-instrument "^1.4.2" - istanbul-lib-source-maps "^1.1.0" - jest-changed-files "^21.2.0" - jest-config "^21.2.1" - jest-environment-jsdom "^21.2.1" - jest-haste-map "^21.2.0" - jest-message-util "^21.2.1" - jest-regex-util "^21.2.0" - jest-resolve-dependencies "^21.2.0" - jest-runner "^21.2.1" - jest-runtime "^21.2.1" - jest-snapshot "^21.2.1" - jest-util "^21.2.1" + istanbul-api "^1.1.14" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-instrument "^1.8.0" + istanbul-lib-source-maps "^1.2.1" + jest-changed-files "^22.0.3" + jest-config "^22.0.4" + jest-environment-jsdom "^22.0.4" + jest-get-type "^22.0.3" + jest-haste-map "^22.0.3" + jest-message-util "^22.0.3" + jest-regex-util "^22.0.3" + jest-resolve-dependencies "^22.0.3" + jest-runner "^22.0.4" + jest-runtime "^22.0.4" + jest-snapshot "^22.0.3" + jest-util "^22.0.4" + jest-worker "^22.0.3" micromatch "^2.3.11" - node-notifier "^5.0.2" - pify "^3.0.0" + node-notifier "^5.1.2" + realpath-native "^1.0.0" + rimraf "^2.5.4" slash "^1.0.0" string-length "^2.0.0" strip-ansi "^4.0.0" which "^1.2.12" - worker-farm "^1.3.1" - yargs "^9.0.0" + yargs "^10.0.3" -jest-config@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-21.2.1.tgz#c7586c79ead0bcc1f38c401e55f964f13bf2a480" - dependencies: - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^21.2.1" - jest-environment-node "^21.2.1" - jest-get-type "^21.2.0" - jest-jasmine2 "^21.2.1" - jest-regex-util "^21.2.0" - jest-resolve "^21.2.0" - jest-util "^21.2.1" - jest-validate "^21.2.1" - pretty-format "^21.2.1" - -jest-config@^22.0.1: +jest-config@^22.0.1, jest-config@^22.0.4: version "22.0.4" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.0.4.tgz#9c2a46c0907b1a1af54d9cdbf18e99b447034e11" dependencies: @@ -5260,15 +5232,6 @@ jest-config@^22.0.1: jest-validate "^22.0.3" pretty-format "^22.0.3" -jest-diff@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-21.2.1.tgz#46cccb6cab2d02ce98bc314011764bb95b065b4f" - dependencies: - chalk "^2.0.1" - diff "^3.2.0" - jest-get-type "^21.2.0" - pretty-format "^21.2.1" - jest-diff@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.0.3.tgz#ffed5aba6beaf63bb77819ba44dd520168986321" @@ -5278,17 +5241,11 @@ jest-diff@^22.0.3: jest-get-type "^22.0.3" pretty-format "^22.0.3" -jest-docblock@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" - -jest-environment-jsdom@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-21.2.1.tgz#38d9980c8259b2a608ec232deee6289a60d9d5b4" +jest-docblock@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.0.3.tgz#c33aa22682b9fc68a5373f5f82994428a2ded601" dependencies: - jest-mock "^21.2.0" - jest-util "^21.2.1" - jsdom "^9.12.0" + detect-newline "^2.1.0" jest-environment-jsdom@^22.0.4: version "22.0.4" @@ -5298,13 +5255,6 @@ jest-environment-jsdom@^22.0.4: jest-util "^22.0.4" jsdom "^11.5.1" -jest-environment-node@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-21.2.1.tgz#98c67df5663c7fbe20f6e792ac2272c740d3b8c8" - dependencies: - jest-mock "^21.2.0" - jest-util "^21.2.1" - jest-environment-node@^22.0.4: version "22.0.4" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.0.4.tgz#068671f85a545f96a5469be3a3dd228fca79c709" @@ -5320,29 +5270,16 @@ jest-get-type@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.0.3.tgz#fa894b677c0fcd55eff3fd8ee28c7be942e32d36" -jest-haste-map@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-21.2.0.tgz#1363f0a8bb4338f24f001806571eff7a4b2ff3d8" +jest-haste-map@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.0.3.tgz#c9ecb5c871c5465d4bde4139e527fa0dc784aa2d" dependencies: fb-watchman "^2.0.0" graceful-fs "^4.1.11" - jest-docblock "^21.2.0" + jest-docblock "^22.0.3" + jest-worker "^22.0.3" micromatch "^2.3.11" sane "^2.0.0" - worker-farm "^1.3.1" - -jest-jasmine2@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-21.2.1.tgz#9cc6fc108accfa97efebce10c4308548a4ea7592" - dependencies: - chalk "^2.0.1" - expect "^21.2.1" - graceful-fs "^4.1.11" - jest-diff "^21.2.1" - jest-matcher-utils "^21.2.1" - jest-message-util "^21.2.1" - jest-snapshot "^21.2.1" - p-cancelable "^0.3.0" jest-jasmine2@^22.0.4: version "22.0.4" @@ -5358,13 +5295,13 @@ jest-jasmine2@^22.0.4: jest-snapshot "^22.0.3" source-map-support "^0.5.0" -jest-matcher-utils@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-21.2.1.tgz#72c826eaba41a093ac2b4565f865eb8475de0f64" +jest-leak-detector@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.0.3.tgz#b64904f0e8954a11edb79b0809ff4717fa762d99" dependencies: - chalk "^2.0.1" - jest-get-type "^21.2.0" - pretty-format "^21.2.1" + pretty-format "^22.0.3" + optionalDependencies: + weak "^1.0.1" jest-matcher-utils@^22.0.3: version "22.0.3" @@ -5374,14 +5311,6 @@ jest-matcher-utils@^22.0.3: jest-get-type "^22.0.3" pretty-format "^22.0.3" -jest-message-util@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-21.2.1.tgz#bfe5d4692c84c827d1dcf41823795558f0a1acbe" - dependencies: - chalk "^2.0.1" - micromatch "^2.3.11" - slash "^1.0.0" - jest-message-util@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.0.3.tgz#bf674b2762ef2dd53facf2136423fcca264976df" @@ -5392,35 +5321,19 @@ jest-message-util@^22.0.3: slash "^1.0.0" stack-utils "^1.0.1" -jest-mock@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-21.2.0.tgz#7eb0770e7317968165f61ea2a7281131534b3c0f" - jest-mock@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.0.3.tgz#c875e47b5b729c6c020a2fab317b275c0cf88961" -jest-regex-util@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-21.2.0.tgz#1b1e33e63143babc3e0f2e6c9b5ba1eb34b2d530" - jest-regex-util@^22.0.3: version "22.0.3" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.0.3.tgz#c5c10229de5ce2b27bf4347916d95b802ae9aa4d" -jest-resolve-dependencies@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-21.2.0.tgz#9e231e371e1a736a1ad4e4b9a843bc72bfe03d09" +jest-resolve-dependencies@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.0.3.tgz#202ddf370069702cd1865a1952fcc7e52c92720e" dependencies: - jest-regex-util "^21.2.0" - -jest-resolve@^21.2.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-21.2.0.tgz#068913ad2ba6a20218e5fd32471f3874005de3a6" - dependencies: - browser-resolve "^1.11.2" - chalk "^2.0.1" - is-builtin-module "^1.0.0" + jest-regex-util "^22.0.3" jest-resolve@^22.0.4: version "22.0.4" @@ -5429,53 +5342,43 @@ jest-resolve@^22.0.4: browser-resolve "^1.11.2" chalk "^2.0.1" -jest-runner@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-21.2.1.tgz#194732e3e518bfb3d7cbfc0fd5871246c7e1a467" +jest-runner@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.0.4.tgz#3aa43a31b05ce8271539df580c2eb916023d3367" dependencies: - jest-config "^21.2.1" - jest-docblock "^21.2.0" - jest-haste-map "^21.2.0" - jest-jasmine2 "^21.2.1" - jest-message-util "^21.2.1" - jest-runtime "^21.2.1" - jest-util "^21.2.1" - pify "^3.0.0" + jest-config "^22.0.4" + jest-docblock "^22.0.3" + jest-haste-map "^22.0.3" + jest-jasmine2 "^22.0.4" + jest-leak-detector "^22.0.3" + jest-message-util "^22.0.3" + jest-runtime "^22.0.4" + jest-util "^22.0.4" + jest-worker "^22.0.3" throat "^4.0.0" - worker-farm "^1.3.1" -jest-runtime@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-21.2.1.tgz#99dce15309c670442eee2ebe1ff53a3cbdbbb73e" +jest-runtime@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.0.4.tgz#8f69aa7b5fbb3acd35dc262cbf654e563f69b7b4" dependencies: babel-core "^6.0.0" - babel-jest "^21.2.0" - babel-plugin-istanbul "^4.0.0" + babel-jest "^22.0.4" + babel-plugin-istanbul "^4.1.5" chalk "^2.0.1" convert-source-map "^1.4.0" graceful-fs "^4.1.11" - jest-config "^21.2.1" - jest-haste-map "^21.2.0" - jest-regex-util "^21.2.0" - jest-resolve "^21.2.0" - jest-util "^21.2.1" + jest-config "^22.0.4" + jest-haste-map "^22.0.3" + jest-regex-util "^22.0.3" + jest-resolve "^22.0.4" + jest-util "^22.0.4" json-stable-stringify "^1.0.1" micromatch "^2.3.11" + realpath-native "^1.0.0" slash "^1.0.0" strip-bom "3.0.0" write-file-atomic "^2.1.0" - yargs "^9.0.0" - -jest-snapshot@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-21.2.1.tgz#29e49f16202416e47343e757e5eff948c07fd7b0" - dependencies: - chalk "^2.0.1" - jest-diff "^21.2.1" - jest-matcher-utils "^21.2.1" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^21.2.1" + yargs "^10.0.3" jest-snapshot@^22.0.3: version "22.0.3" @@ -5488,18 +5391,6 @@ jest-snapshot@^22.0.3: natural-compare "^1.4.0" pretty-format "^22.0.3" -jest-util@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-21.2.1.tgz#a274b2f726b0897494d694a6c3d6a61ab819bb78" - dependencies: - callsites "^2.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.11" - jest-message-util "^21.2.1" - jest-mock "^21.2.0" - jest-validate "^21.2.1" - mkdirp "^0.5.1" - jest-util@^22.0.4: version "22.0.4" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.0.4.tgz#d920a513e0645aaab030cee38e4fe7d5bed8bb6d" @@ -5512,7 +5403,7 @@ jest-util@^22.0.4: jest-validate "^22.0.3" mkdirp "^0.5.1" -jest-validate@^21.1.0, jest-validate@^21.2.1: +jest-validate@^21.1.0: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7" dependencies: @@ -5530,11 +5421,17 @@ jest-validate@^22.0.3: leven "^2.1.0" pretty-format "^22.0.3" -jest@^21.2.1: - version "21.2.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-21.2.1.tgz#c964e0b47383768a1438e3ccf3c3d470327604e1" +jest-worker@^22.0.3: + version "22.0.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.0.3.tgz#30433faca67814a8f80559f75ab2ceaa61332fd2" dependencies: - jest-cli "^21.2.1" + merge-stream "^1.0.1" + +jest@^22.0.4: + version "22.0.4" + resolved "https://registry.yarnpkg.com/jest/-/jest-22.0.4.tgz#d3cf560ece6b825b115dce80b9826ceb40f87961" + dependencies: + jest-cli "^22.0.4" jquery@^3.2.1: version "3.2.1" @@ -5658,30 +5555,6 @@ jsdom@^11.5.1: whatwg-url "^6.3.0" xml-name-validator "^2.0.1" -jsdom@^9.12.0: - version "9.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4" - dependencies: - abab "^1.0.3" - acorn "^4.0.4" - acorn-globals "^3.1.0" - array-equal "^1.0.0" - content-type-parser "^1.0.1" - cssom ">= 0.3.2 < 0.4.0" - cssstyle ">= 0.2.37 < 0.3.0" - escodegen "^1.6.1" - html-encoding-sniffer "^1.0.1" - nwmatcher ">= 1.3.9 < 2.0.0" - parse5 "^1.5.1" - request "^2.79.0" - sax "^1.2.1" - symbol-tree "^3.2.1" - tough-cookie "^2.3.2" - webidl-conversions "^4.0.0" - whatwg-encoding "^1.0.1" - whatwg-url "^4.3.0" - xml-name-validator "^2.0.1" - jsesc@^0.5.0, jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -6378,6 +6251,12 @@ merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + merge@^1.1.3, merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -6617,7 +6496,7 @@ mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.3.0, nan@^2.3.2, nan@^2.6.2: +nan@^2.0.5, nan@^2.3.0, nan@^2.3.2, nan@^2.6.2: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" @@ -6802,7 +6681,7 @@ node-libs-browser@^2.0.0: util "^0.10.3" vm-browserify "0.0.4" -node-notifier@^5.0.2: +node-notifier@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" dependencies: @@ -7139,7 +7018,7 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -"nwmatcher@>= 1.3.9 < 2.0.0", nwmatcher@^1.4.3: +nwmatcher@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" @@ -7203,6 +7082,13 @@ object.entries@^1.0.4: function-bind "^1.1.0" has "^1.0.1" +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -7319,10 +7205,6 @@ osenv@0, osenv@^0.1.4, osenv@~0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -7429,10 +7311,6 @@ parse-json@^3.0.0: dependencies: error-ex "^1.3.1" -parse5@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" - parse5@^3.0.1, parse5@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" @@ -8418,6 +8296,12 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" +realpath-native@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.0.0.tgz#7885721a83b43bd5327609f0ddecb2482305fdf0" + dependencies: + util.promisify "^1.0.0" + recast@~0.11.12: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" @@ -8586,7 +8470,7 @@ request-promise-native@^1.0.3: stealthy-require "^1.1.0" tough-cookie ">=2.3.3" -request@2, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@^2.83.0, request@~2.83.0: +request@2, request@^2.74.0, request@^2.81.0, request@^2.83.0, request@~2.83.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: @@ -9781,7 +9665,7 @@ toposort@^1.0.0: version "1.0.6" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec" -tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: +tough-cookie@>=2.3.3, tough-cookie@^2.3.3, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: @@ -9793,10 +9677,6 @@ tr46@^1.0.0: dependencies: punycode "^2.1.0" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -10142,6 +10022,13 @@ util-extend@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" +util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -10272,11 +10159,14 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" +weak@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/weak/-/weak-1.0.1.tgz#ab99aab30706959aa0200cb8cf545bb9cb33b99e" + dependencies: + bindings "^1.2.1" + nan "^2.0.5" -webidl-conversions@^4.0.0, webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: +webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -10371,13 +10261,6 @@ whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" -whatwg-url@^4.3.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0" - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - whatwg-url@^6.3.0: version "6.4.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" @@ -10450,7 +10333,7 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -worker-farm@^1.3.1, worker-farm@~1.5.0: +worker-farm@~1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" dependencies: @@ -10622,24 +10505,6 @@ yargs@^8.0.2: y18n "^3.2.1" yargs-parser "^7.0.0" -yargs@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" From f049fc4816fb808c771a395f9d9628bf93ef401b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 2 Jan 2018 11:02:43 +0100 Subject: [PATCH 16/17] mobx: fixed issue with view store, and added missing snapshot --- .../__snapshots__/AlertRuleList.jest.tsx.snap | 72 +++++++++++++++++++ public/app/stores/ViewStore.ts | 4 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap diff --git a/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap new file mode 100644 index 00000000000..b15a8605b7a --- /dev/null +++ b/public/app/containers/AlertRuleList/__snapshots__/AlertRuleList.jest.tsx.snap @@ -0,0 +1,72 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AlertRuleList should render 1 rule 1`] = ` +
  • +
    +
    + +
    +
    +
    + +
    + + + + OK + + + for + 5 minutes + +
    +
    +
    +
    +
  • +`; diff --git a/public/app/stores/ViewStore.ts b/public/app/stores/ViewStore.ts index 8d4df403e72..6095e45fc9d 100644 --- a/public/app/stores/ViewStore.ts +++ b/public/app/stores/ViewStore.ts @@ -2,10 +2,12 @@ import { types } from 'mobx-state-tree'; import _ from 'lodash'; import $ from 'jquery'; +let QueryValueType = types.union(types.string, types.boolean, types.number); + export const ViewStore = types .model({ path: types.string, - query: types.map(types.string), + query: types.map(QueryValueType), }) .views(self => ({ get currentUrl() { From 8abef88b943b71bc0fba78a4f774ccc7f3ac424d Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Wed, 3 Jan 2018 20:11:07 +0100 Subject: [PATCH 17/17] mobx: poc in using each store as individual prop on the react containers (#10414) * mobx: poc in using each store as individual prop on the react containers * prettier test * fix: end the war between prettier vs tslint. * mobx: Move stores into their own folders * mobx: Refactor the AlertRule into its own file and add a helper-file * mobx: Move NavItem out of NavStore and remove lodash dependancy * mobx: Move ResultItem and SearchResultSection models out of the SearchStore * mobx: ServerStatsStore rename .tsx => .ts. And move ServerStat-model to its own file. * mobx: Remove lodash and jquery dependancy from ViewStore * mobx: Remove issue with double question mark --- .../AlertRuleList/AlertRuleList.jest.tsx | 4 +- .../AlertRuleList/AlertRuleList.tsx | 22 ++--- public/app/containers/IContainerProps.ts | 15 ++++ .../ServerStats/ServerStats.jest.tsx | 4 +- .../containers/ServerStats/ServerStats.tsx | 19 ++--- public/app/routes/ReactContainer.tsx | 2 +- public/app/stores/AlertListStore.ts | 82 ------------------- .../stores/AlertListStore/AlertListStore.ts | 34 ++++++++ public/app/stores/AlertListStore/AlertRule.ts | 34 ++++++++ public/app/stores/AlertListStore/helpers.ts | 13 +++ public/app/stores/NavStore/NavItem.ts | 12 +++ public/app/stores/{ => NavStore}/NavStore.ts | 18 +--- .../app/stores/{ => RootStore}/RootStore.ts | 10 +-- public/app/stores/SearchStore.ts | 55 ------------- public/app/stores/SearchStore/ResultItem.ts | 10 +++ .../stores/SearchStore/SearchResultSection.ts | 27 ++++++ public/app/stores/SearchStore/SearchStore.ts | 22 +++++ .../app/stores/ServerStatsStore/ServerStat.ts | 6 ++ .../ServerStatsStore.ts} | 13 +-- public/app/stores/ViewStore.ts | 37 --------- public/app/stores/ViewStore/ViewStore.ts | 46 +++++++++++ public/app/stores/store.ts | 2 +- 22 files changed, 256 insertions(+), 231 deletions(-) create mode 100644 public/app/containers/IContainerProps.ts delete mode 100644 public/app/stores/AlertListStore.ts create mode 100644 public/app/stores/AlertListStore/AlertListStore.ts create mode 100644 public/app/stores/AlertListStore/AlertRule.ts create mode 100644 public/app/stores/AlertListStore/helpers.ts create mode 100644 public/app/stores/NavStore/NavItem.ts rename public/app/stores/{ => NavStore}/NavStore.ts (60%) rename public/app/stores/{ => RootStore}/RootStore.ts (61%) delete mode 100644 public/app/stores/SearchStore.ts create mode 100644 public/app/stores/SearchStore/ResultItem.ts create mode 100644 public/app/stores/SearchStore/SearchResultSection.ts create mode 100644 public/app/stores/SearchStore/SearchStore.ts create mode 100644 public/app/stores/ServerStatsStore/ServerStat.ts rename public/app/stores/{ServerStatsStore.tsx => ServerStatsStore/ServerStatsStore.ts} (79%) delete mode 100644 public/app/stores/ViewStore.ts create mode 100644 public/app/stores/ViewStore/ViewStore.ts diff --git a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx index c49343697f7..1025a7991f6 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.jest.tsx @@ -1,7 +1,7 @@ import React from 'react'; import moment from 'moment'; import { AlertRuleList } from './AlertRuleList'; -import { RootStore } from 'app/stores/RootStore'; +import { RootStore } from 'app/stores/RootStore/RootStore'; import { backendSrv, createNavTree } from 'test/mocks/common'; import { mount } from 'enzyme'; import toJson from 'enzyme-to-json'; @@ -36,7 +36,7 @@ describe('AlertRuleList', () => { } ); - page = mount(); + page = mount(); }); it('should call api to get rules', () => { diff --git a/public/app/containers/AlertRuleList/AlertRuleList.tsx b/public/app/containers/AlertRuleList/AlertRuleList.tsx index 19a23e43c33..b12a9f234d0 100644 --- a/public/app/containers/AlertRuleList/AlertRuleList.tsx +++ b/public/app/containers/AlertRuleList/AlertRuleList.tsx @@ -2,17 +2,13 @@ import React from 'react'; import classNames from 'classnames'; import { inject, observer } from 'mobx-react'; import PageHeader from 'app/core/components/PageHeader/PageHeader'; -import { IRootStore } from 'app/stores/RootStore'; -import { IAlertRule } from 'app/stores/AlertListStore'; +import { IAlertRule } from 'app/stores/AlertListStore/AlertListStore'; import appEvents from 'app/core/app_events'; +import IContainerProps from 'app/containers/IContainerProps'; -export interface AlertRuleListProps { - store: IRootStore; -} - -@inject('store') +@inject('view', 'nav', 'alertList') @observer -export class AlertRuleList extends React.Component { +export class AlertRuleList extends React.Component { stateFilters = [ { text: 'All', value: 'all' }, { text: 'OK', value: 'ok' }, @@ -25,18 +21,18 @@ export class AlertRuleList extends React.Component { constructor(props) { super(props); - this.props.store.nav.load('alerting', 'alert-list'); + this.props.nav.load('alerting', 'alert-list'); this.fetchRules(); } onStateFilterChanged = evt => { - this.props.store.view.updateQuery({ state: evt.target.value }); + this.props.view.updateQuery({ state: evt.target.value }); this.fetchRules(); }; fetchRules() { - this.props.store.alertList.loadRules({ - state: this.props.store.view.query.get('state') || 'all', + this.props.alertList.loadRules({ + state: this.props.view.query.get('state') || 'all', }); } @@ -49,7 +45,7 @@ export class AlertRuleList extends React.Component { }; render() { - const { nav, alertList } = this.props.store; + const { nav, alertList } = this.props; return (
    diff --git a/public/app/containers/IContainerProps.ts b/public/app/containers/IContainerProps.ts new file mode 100644 index 00000000000..aecba4e8ad3 --- /dev/null +++ b/public/app/containers/IContainerProps.ts @@ -0,0 +1,15 @@ +import { SearchStore } from './../stores/SearchStore/SearchStore'; +import { ServerStatsStore } from './../stores/ServerStatsStore/ServerStatsStore'; +import { NavStore } from './../stores/NavStore/NavStore'; +import { AlertListStore } from './../stores/AlertListStore/AlertListStore'; +import { ViewStore } from './../stores/ViewStore/ViewStore'; + +interface IContainerProps { + search: typeof SearchStore.Type; + serverStats: typeof ServerStatsStore.Type; + nav: typeof NavStore.Type; + alertList: typeof AlertListStore.Type; + view: typeof ViewStore.Type; +} + +export default IContainerProps; diff --git a/public/app/containers/ServerStats/ServerStats.jest.tsx b/public/app/containers/ServerStats/ServerStats.jest.tsx index 07b938c4d0f..ae5cb736ad6 100644 --- a/public/app/containers/ServerStats/ServerStats.jest.tsx +++ b/public/app/containers/ServerStats/ServerStats.jest.tsx @@ -1,7 +1,7 @@ import React from 'react'; import renderer from 'react-test-renderer'; import { ServerStats } from './ServerStats'; -import { RootStore } from 'app/stores/RootStore'; +import { RootStore } from 'app/stores/RootStore/RootStore'; import { backendSrv, createNavTree } from 'test/mocks/common'; describe('ServerStats', () => { @@ -20,7 +20,7 @@ describe('ServerStats', () => { } ); - const page = renderer.create(); + const page = renderer.create(); setTimeout(() => { expect(page.toJSON()).toMatchSnapshot(); diff --git a/public/app/containers/ServerStats/ServerStats.tsx b/public/app/containers/ServerStats/ServerStats.tsx index 60db299ab5a..e40b441d967 100644 --- a/public/app/containers/ServerStats/ServerStats.tsx +++ b/public/app/containers/ServerStats/ServerStats.tsx @@ -1,25 +1,24 @@ import React from 'react'; import { inject, observer } from 'mobx-react'; import PageHeader from 'app/core/components/PageHeader/PageHeader'; +import IContainerProps from 'app/containers/IContainerProps'; -export interface IProps { - store: any; -} - -@inject('store') +@inject('nav', 'serverStats') @observer -export class ServerStats extends React.Component { +export class ServerStats extends React.Component { constructor(props) { super(props); + const { nav, serverStats } = this.props; - this.props.store.nav.load('cfg', 'admin', 'server-stats'); - this.props.store.serverStats.load(); + nav.load('cfg', 'admin', 'server-stats'); + serverStats.load(); } render() { + const { nav, serverStats } = this.props; return (
    - +
    @@ -28,7 +27,7 @@ export class ServerStats extends React.Component { - {this.props.store.serverStats.stats.map(StatItem)} + {serverStats.stats.map(StatItem)}
    Value
    diff --git a/public/app/routes/ReactContainer.tsx b/public/app/routes/ReactContainer.tsx index b0f4e6b6ee5..72993661ec4 100644 --- a/public/app/routes/ReactContainer.tsx +++ b/public/app/routes/ReactContainer.tsx @@ -6,7 +6,7 @@ import { Provider } from 'mobx-react'; function WrapInProvider(store, Component, props) { return ( - + ); diff --git a/public/app/stores/AlertListStore.ts b/public/app/stores/AlertListStore.ts deleted file mode 100644 index a581ec0fedc..00000000000 --- a/public/app/stores/AlertListStore.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { types, getEnv, flow } from 'mobx-state-tree'; -import moment from 'moment'; -import alertDef from 'app/features/alerting/alert_def'; - -function setStateFields(rule, state) { - let stateModel = alertDef.getStateDisplayModel(state); - rule.state = state; - rule.stateText = stateModel.text; - rule.stateIcon = stateModel.iconClass; - rule.stateClass = stateModel.stateClass; - rule.stateAge = moment(rule.newStateDate) - .fromNow() - .replace(' ago', ''); -} - -export const AlertRule = types - .model('AlertRule', { - id: types.identifier(types.number), - dashboardId: types.number, - panelId: types.number, - name: types.string, - state: types.string, - stateText: types.string, - stateIcon: types.string, - stateClass: types.string, - stateAge: types.string, - info: types.optional(types.string, ''), - dashboardUri: types.string, - }) - .views(self => ({ - get isPaused() { - return self.state === 'paused'; - }, - })) - .actions(self => ({ - /** - * will toggle alert rule paused state - */ - togglePaused: flow(function* togglePaused() { - let backendSrv = getEnv(self).backendSrv; - - var payload = { paused: self.isPaused }; - let res = yield backendSrv.post(`/api/alerts/${self.id}/pause`, payload); - setStateFields(self, res.state); - self.info = ''; - }), - })); - -type IAlertRuleType = typeof AlertRule.Type; -export interface IAlertRule extends IAlertRuleType {} - -export const AlertListStore = types - .model('AlertListStore', { - rules: types.array(AlertRule), - stateFilter: types.optional(types.string, 'all'), - }) - .actions(self => ({ - loadRules: flow(function* load(filters) { - let backendSrv = getEnv(self).backendSrv; - - // store state filter used in api query - self.stateFilter = filters.state; - - let apiRules = yield backendSrv.get('/api/alerts', filters); - - self.rules.clear(); - - for (let rule of apiRules) { - setStateFields(rule, rule.state); - - if (rule.executionError) { - rule.info = 'Execution Error: ' + rule.executionError; - } - - if (rule.evalData && rule.evalData.noData) { - rule.info = 'Query returned no data'; - } - - self.rules.push(AlertRule.create(rule)); - } - }), - })); diff --git a/public/app/stores/AlertListStore/AlertListStore.ts b/public/app/stores/AlertListStore/AlertListStore.ts new file mode 100644 index 00000000000..78799f6dfd8 --- /dev/null +++ b/public/app/stores/AlertListStore/AlertListStore.ts @@ -0,0 +1,34 @@ +import { types, getEnv, flow } from 'mobx-state-tree'; +import { AlertRule } from './AlertRule'; +import { setStateFields } from './helpers'; + +type IAlertRuleType = typeof AlertRule.Type; +export interface IAlertRule extends IAlertRuleType {} + +export const AlertListStore = types + .model('AlertListStore', { + rules: types.array(AlertRule), + stateFilter: types.optional(types.string, 'all'), + }) + .actions(self => ({ + loadRules: flow(function* load(filters) { + const backendSrv = getEnv(self).backendSrv; + self.stateFilter = filters.state; // store state filter used in api query + const apiRules = yield backendSrv.get('/api/alerts', filters); + self.rules.clear(); + + for (let rule of apiRules) { + setStateFields(rule, rule.state); + + if (rule.executionError) { + rule.info = 'Execution Error: ' + rule.executionError; + } + + if (rule.evalData && rule.evalData.noData) { + rule.info = 'Query returned no data'; + } + + self.rules.push(AlertRule.create(rule)); + } + }), + })); diff --git a/public/app/stores/AlertListStore/AlertRule.ts b/public/app/stores/AlertListStore/AlertRule.ts new file mode 100644 index 00000000000..63b572555cb --- /dev/null +++ b/public/app/stores/AlertListStore/AlertRule.ts @@ -0,0 +1,34 @@ +import { types, getEnv, flow } from 'mobx-state-tree'; +import { setStateFields } from './helpers'; + +export const AlertRule = types + .model('AlertRule', { + id: types.identifier(types.number), + dashboardId: types.number, + panelId: types.number, + name: types.string, + state: types.string, + stateText: types.string, + stateIcon: types.string, + stateClass: types.string, + stateAge: types.string, + info: types.optional(types.string, ''), + dashboardUri: types.string, + }) + .views(self => ({ + get isPaused() { + return self.state === 'paused'; + }, + })) + .actions(self => ({ + /** + * will toggle alert rule paused state + */ + togglePaused: flow(function* togglePaused() { + const backendSrv = getEnv(self).backendSrv; + const payload = { paused: self.isPaused }; + const res = yield backendSrv.post(`/api/alerts/${self.id}/pause`, payload); + setStateFields(self, res.state); + self.info = ''; + }), + })); diff --git a/public/app/stores/AlertListStore/helpers.ts b/public/app/stores/AlertListStore/helpers.ts new file mode 100644 index 00000000000..bf3c81ca11c --- /dev/null +++ b/public/app/stores/AlertListStore/helpers.ts @@ -0,0 +1,13 @@ +import moment from 'moment'; +import alertDef from 'app/features/alerting/alert_def'; + +export function setStateFields(rule, state) { + const stateModel = alertDef.getStateDisplayModel(state); + rule.state = state; + rule.stateText = stateModel.text; + rule.stateIcon = stateModel.iconClass; + rule.stateClass = stateModel.stateClass; + rule.stateAge = moment(rule.newStateDate) + .fromNow() + .replace(' ago', ''); +} diff --git a/public/app/stores/NavStore/NavItem.ts b/public/app/stores/NavStore/NavItem.ts new file mode 100644 index 00000000000..cbd0f269f01 --- /dev/null +++ b/public/app/stores/NavStore/NavItem.ts @@ -0,0 +1,12 @@ +import { types } from 'mobx-state-tree'; + +export const NavItem = types.model('NavItem', { + id: types.identifier(types.string), + text: types.string, + url: types.optional(types.string, ''), + subTitle: 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)), []), +}); diff --git a/public/app/stores/NavStore.ts b/public/app/stores/NavStore/NavStore.ts similarity index 60% rename from public/app/stores/NavStore.ts rename to public/app/stores/NavStore/NavStore.ts index edd25d965ee..1cf622fc3df 100644 --- a/public/app/stores/NavStore.ts +++ b/public/app/stores/NavStore/NavStore.ts @@ -1,16 +1,5 @@ import { types, getEnv } from 'mobx-state-tree'; -import _ from 'lodash'; - -export const NavItem = types.model('NavItem', { - id: types.identifier(types.string), - text: types.string, - url: types.optional(types.string, ''), - subTitle: 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)), []), -}); +import { NavItem } from './NavItem'; export const NavStore = types .model('NavStore', { @@ -19,12 +8,13 @@ export const NavStore = types }) .actions(self => ({ load(...args) { - var children = getEnv(self).navTree; + let children = getEnv(self).navTree; let main, node; let parents = []; for (let id of args) { - node = _.find(children, { id: id }); + node = children.find(el => el.id === id); + if (!node) { throw new Error(`NavItem with id ${id} not found`); } diff --git a/public/app/stores/RootStore.ts b/public/app/stores/RootStore/RootStore.ts similarity index 61% rename from public/app/stores/RootStore.ts rename to public/app/stores/RootStore/RootStore.ts index 1b0640d4c71..88221c0ebd5 100644 --- a/public/app/stores/RootStore.ts +++ b/public/app/stores/RootStore/RootStore.ts @@ -1,9 +1,9 @@ import { types } from 'mobx-state-tree'; -import { SearchStore } from './SearchStore'; -import { ServerStatsStore } from './ServerStatsStore'; -import { NavStore } from './NavStore'; -import { AlertListStore } from './AlertListStore'; -import { ViewStore } from './ViewStore'; +import { SearchStore } from './../SearchStore/SearchStore'; +import { ServerStatsStore } from './../ServerStatsStore/ServerStatsStore'; +import { NavStore } from './../NavStore/NavStore'; +import { AlertListStore } from './../AlertListStore/AlertListStore'; +import { ViewStore } from './../ViewStore/ViewStore'; export const RootStore = types.model({ search: types.optional(SearchStore, { diff --git a/public/app/stores/SearchStore.ts b/public/app/stores/SearchStore.ts deleted file mode 100644 index 1779462a36d..00000000000 --- a/public/app/stores/SearchStore.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { types } from "mobx-state-tree"; - -export const ResultItem = types.model("ResultItem", { - id: types.identifier(types.number), - folderId: types.optional(types.number, 0), - title: types.string, - url: types.string, - icon: types.string, - folderTitle: types.optional(types.string, "") -}); - -export const SearchResultSection = types - .model("SearchResultSection", { - id: types.identifier(), - title: types.string, - icon: types.string, - expanded: types.boolean, - items: types.array(ResultItem) - }) - .actions(self => ({ - toggle() { - self.expanded = !self.expanded; - - for (let i = 0; i < 100; i++) { - self.items.push( - ResultItem.create({ - id: i, - title: "Dashboard " + self.items.length, - icon: "gicon gicon-dashboard", - url: "asd" - }) - ); - } - } - })); - -export const SearchStore = types - .model("SearchStore", { - sections: types.array(SearchResultSection) - }) - .actions(self => ({ - query() { - for (let i = 0; i < 100; i++) { - self.sections.push( - SearchResultSection.create({ - id: "starred" + i, - title: "starred", - icon: "fa fa-fw fa-star-o", - expanded: false, - items: [] - }) - ); - } - } - })); diff --git a/public/app/stores/SearchStore/ResultItem.ts b/public/app/stores/SearchStore/ResultItem.ts new file mode 100644 index 00000000000..eb0ff021526 --- /dev/null +++ b/public/app/stores/SearchStore/ResultItem.ts @@ -0,0 +1,10 @@ +import { types } from 'mobx-state-tree'; + +export const ResultItem = types.model('ResultItem', { + id: types.identifier(types.number), + folderId: types.optional(types.number, 0), + title: types.string, + url: types.string, + icon: types.string, + folderTitle: types.optional(types.string, ''), +}); diff --git a/public/app/stores/SearchStore/SearchResultSection.ts b/public/app/stores/SearchStore/SearchResultSection.ts new file mode 100644 index 00000000000..70b3ad48e96 --- /dev/null +++ b/public/app/stores/SearchStore/SearchResultSection.ts @@ -0,0 +1,27 @@ +import { types } from 'mobx-state-tree'; +import { ResultItem } from './ResultItem'; + +export const SearchResultSection = types + .model('SearchResultSection', { + id: types.identifier(), + title: types.string, + icon: types.string, + expanded: types.boolean, + items: types.array(ResultItem), + }) + .actions(self => ({ + toggle() { + self.expanded = !self.expanded; + + for (let i = 0; i < 100; i++) { + self.items.push( + ResultItem.create({ + id: i, + title: 'Dashboard ' + self.items.length, + icon: 'gicon gicon-dashboard', + url: 'asd', + }) + ); + } + }, + })); diff --git a/public/app/stores/SearchStore/SearchStore.ts b/public/app/stores/SearchStore/SearchStore.ts new file mode 100644 index 00000000000..36897f05f38 --- /dev/null +++ b/public/app/stores/SearchStore/SearchStore.ts @@ -0,0 +1,22 @@ +import { types } from 'mobx-state-tree'; +import { SearchResultSection } from './SearchResultSection'; + +export const SearchStore = types + .model('SearchStore', { + sections: types.array(SearchResultSection), + }) + .actions(self => ({ + query() { + for (let i = 0; i < 100; i++) { + self.sections.push( + SearchResultSection.create({ + id: 'starred' + i, + title: 'starred', + icon: 'fa fa-fw fa-star-o', + expanded: false, + items: [], + }) + ); + } + }, + })); diff --git a/public/app/stores/ServerStatsStore/ServerStat.ts b/public/app/stores/ServerStatsStore/ServerStat.ts new file mode 100644 index 00000000000..bd819a51e76 --- /dev/null +++ b/public/app/stores/ServerStatsStore/ServerStat.ts @@ -0,0 +1,6 @@ +import { types } from 'mobx-state-tree'; + +export const ServerStat = types.model('ServerStat', { + name: types.string, + value: types.optional(types.number, 0), +}); diff --git a/public/app/stores/ServerStatsStore.tsx b/public/app/stores/ServerStatsStore/ServerStatsStore.ts similarity index 79% rename from public/app/stores/ServerStatsStore.tsx rename to public/app/stores/ServerStatsStore/ServerStatsStore.ts index 4f67eed0d86..d27285d7a3b 100644 --- a/public/app/stores/ServerStatsStore.tsx +++ b/public/app/stores/ServerStatsStore/ServerStatsStore.ts @@ -1,9 +1,5 @@ -import { types, getEnv, flow } from 'mobx-state-tree'; - -export const ServerStat = types.model('ServerStat', { - name: types.string, - value: types.optional(types.number, 0), -}); +import { types, getEnv, flow } from 'mobx-state-tree'; +import { ServerStat } from './ServerStat'; export const ServerStatsStore = types .model('ServerStatsStore', { @@ -12,9 +8,8 @@ export const ServerStatsStore = types }) .actions(self => ({ load: flow(function* load() { - let backendSrv = getEnv(self).backendSrv; - - let res = yield backendSrv.get('/api/admin/stats'); + const backendSrv = getEnv(self).backendSrv; + const 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 })); diff --git a/public/app/stores/ViewStore.ts b/public/app/stores/ViewStore.ts deleted file mode 100644 index 6095e45fc9d..00000000000 --- a/public/app/stores/ViewStore.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { types } from 'mobx-state-tree'; -import _ from 'lodash'; -import $ from 'jquery'; - -let QueryValueType = types.union(types.string, types.boolean, types.number); - -export const ViewStore = types - .model({ - path: types.string, - query: types.map(QueryValueType), - }) - .views(self => ({ - get currentUrl() { - let path = self.path; - if (self.query.size) { - path += '?' + $.param(self.query.toJS()); - } - return path; - }, - })) - .actions(self => ({ - updatePathAndQuery(path: string, query: any) { - self.path = path; - self.query.clear(); - - for (let key of _.keys(query)) { - self.query.set(key, query[key]); - } - }, - - updateQuery(query: any) { - self.query.clear(); - for (let key of _.keys(query)) { - self.query.set(key, query[key]); - } - }, - })); diff --git a/public/app/stores/ViewStore/ViewStore.ts b/public/app/stores/ViewStore/ViewStore.ts new file mode 100644 index 00000000000..fb1111cf108 --- /dev/null +++ b/public/app/stores/ViewStore/ViewStore.ts @@ -0,0 +1,46 @@ +import { types } from 'mobx-state-tree'; + +const QueryValueType = types.union(types.string, types.boolean, types.number); +const urlParameterize = queryObj => { + const keys = Object.keys(queryObj); + const newQuery = keys.reduce((acc: string, key: string, idx: number) => { + const preChar = idx === 0 ? '?' : '&'; + return acc + preChar + key + '=' + queryObj[key]; + }, ''); + + return newQuery; +}; + +export const ViewStore = types + .model({ + path: types.string, + query: types.map(QueryValueType), + }) + .views(self => ({ + get currentUrl() { + let path = self.path; + + if (self.query.size) { + path += urlParameterize(self.query.toJS()); + } + return path; + }, + })) + .actions(self => { + function updateQuery(query: any) { + self.query.clear(); + for (let key of Object.keys(query)) { + self.query.set(key, query[key]); + } + } + + function updatePathAndQuery(path: string, query: any) { + self.path = path; + updateQuery(query); + } + + return { + updateQuery, + updatePathAndQuery, + }; + }); diff --git a/public/app/stores/store.ts b/public/app/stores/store.ts index 3405dc38157..8ad53607ac2 100644 --- a/public/app/stores/store.ts +++ b/public/app/stores/store.ts @@ -1,4 +1,4 @@ -import { RootStore, IRootStore } from './RootStore'; +import { RootStore, IRootStore } from './RootStore/RootStore'; import config from 'app/core/config'; export let store: IRootStore;