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 {
| Value |
- {this.props.store.serverStats.stats.map(StatItem)}
+ {serverStats.stats.map(StatItem)}
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;