mirror of
https://github.com/grafana/grafana.git
synced 2025-01-27 16:57:14 -06:00
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
This commit is contained in:
parent
f049fc4816
commit
8abef88b94
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { AlertRuleList } from './AlertRuleList';
|
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 { backendSrv, createNavTree } from 'test/mocks/common';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import toJson from 'enzyme-to-json';
|
import toJson from 'enzyme-to-json';
|
||||||
@ -36,7 +36,7 @@ describe('AlertRuleList', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
page = mount(<AlertRuleList store={store} />);
|
page = mount(<AlertRuleList {...store} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call api to get rules', () => {
|
it('should call api to get rules', () => {
|
||||||
|
@ -2,17 +2,13 @@ import React from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||||
import { IRootStore } from 'app/stores/RootStore';
|
import { IAlertRule } from 'app/stores/AlertListStore/AlertListStore';
|
||||||
import { IAlertRule } from 'app/stores/AlertListStore';
|
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
|
import IContainerProps from 'app/containers/IContainerProps';
|
||||||
|
|
||||||
export interface AlertRuleListProps {
|
@inject('view', 'nav', 'alertList')
|
||||||
store: IRootStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
@inject('store')
|
|
||||||
@observer
|
@observer
|
||||||
export class AlertRuleList extends React.Component<AlertRuleListProps, any> {
|
export class AlertRuleList extends React.Component<IContainerProps, any> {
|
||||||
stateFilters = [
|
stateFilters = [
|
||||||
{ text: 'All', value: 'all' },
|
{ text: 'All', value: 'all' },
|
||||||
{ text: 'OK', value: 'ok' },
|
{ text: 'OK', value: 'ok' },
|
||||||
@ -25,18 +21,18 @@ export class AlertRuleList extends React.Component<AlertRuleListProps, any> {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.props.store.nav.load('alerting', 'alert-list');
|
this.props.nav.load('alerting', 'alert-list');
|
||||||
this.fetchRules();
|
this.fetchRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
onStateFilterChanged = evt => {
|
onStateFilterChanged = evt => {
|
||||||
this.props.store.view.updateQuery({ state: evt.target.value });
|
this.props.view.updateQuery({ state: evt.target.value });
|
||||||
this.fetchRules();
|
this.fetchRules();
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchRules() {
|
fetchRules() {
|
||||||
this.props.store.alertList.loadRules({
|
this.props.alertList.loadRules({
|
||||||
state: this.props.store.view.query.get('state') || 'all',
|
state: this.props.view.query.get('state') || 'all',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +45,7 @@ export class AlertRuleList extends React.Component<AlertRuleListProps, any> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { nav, alertList } = this.props.store;
|
const { nav, alertList } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
15
public/app/containers/IContainerProps.ts
Normal file
15
public/app/containers/IContainerProps.ts
Normal file
@ -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;
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { ServerStats } from './ServerStats';
|
import { ServerStats } from './ServerStats';
|
||||||
import { RootStore } from 'app/stores/RootStore';
|
import { RootStore } from 'app/stores/RootStore/RootStore';
|
||||||
import { backendSrv, createNavTree } from 'test/mocks/common';
|
import { backendSrv, createNavTree } from 'test/mocks/common';
|
||||||
|
|
||||||
describe('ServerStats', () => {
|
describe('ServerStats', () => {
|
||||||
@ -20,7 +20,7 @@ describe('ServerStats', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const page = renderer.create(<ServerStats store={store} />);
|
const page = renderer.create(<ServerStats {...store} />);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(page.toJSON()).toMatchSnapshot();
|
expect(page.toJSON()).toMatchSnapshot();
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { inject, observer } from 'mobx-react';
|
import { inject, observer } from 'mobx-react';
|
||||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||||
|
import IContainerProps from 'app/containers/IContainerProps';
|
||||||
|
|
||||||
export interface IProps {
|
@inject('nav', 'serverStats')
|
||||||
store: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
@inject('store')
|
|
||||||
@observer
|
@observer
|
||||||
export class ServerStats extends React.Component<IProps, any> {
|
export class ServerStats extends React.Component<IContainerProps, any> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
const { nav, serverStats } = this.props;
|
||||||
|
|
||||||
this.props.store.nav.load('cfg', 'admin', 'server-stats');
|
nav.load('cfg', 'admin', 'server-stats');
|
||||||
this.props.store.serverStats.load();
|
serverStats.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { nav, serverStats } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PageHeader model={this.props.store.nav} />
|
<PageHeader model={nav as any} />
|
||||||
<div className="page-container page-body">
|
<div className="page-container page-body">
|
||||||
<table className="filter-table form-inline">
|
<table className="filter-table form-inline">
|
||||||
<thead>
|
<thead>
|
||||||
@ -28,7 +27,7 @@ export class ServerStats extends React.Component<IProps, any> {
|
|||||||
<th>Value</th>
|
<th>Value</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>{this.props.store.serverStats.stats.map(StatItem)}</tbody>
|
<tbody>{serverStats.stats.map(StatItem)}</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@ import { Provider } from 'mobx-react';
|
|||||||
|
|
||||||
function WrapInProvider(store, Component, props) {
|
function WrapInProvider(store, Component, props) {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider {...store}>
|
||||||
<Component {...props} />
|
<Component {...props} />
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
@ -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));
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
}));
|
|
34
public/app/stores/AlertListStore/AlertListStore.ts
Normal file
34
public/app/stores/AlertListStore/AlertListStore.ts
Normal file
@ -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));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}));
|
34
public/app/stores/AlertListStore/AlertRule.ts
Normal file
34
public/app/stores/AlertListStore/AlertRule.ts
Normal file
@ -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 = '';
|
||||||
|
}),
|
||||||
|
}));
|
13
public/app/stores/AlertListStore/helpers.ts
Normal file
13
public/app/stores/AlertListStore/helpers.ts
Normal file
@ -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', '');
|
||||||
|
}
|
12
public/app/stores/NavStore/NavItem.ts
Normal file
12
public/app/stores/NavStore/NavItem.ts
Normal file
@ -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)), []),
|
||||||
|
});
|
@ -1,16 +1,5 @@
|
|||||||
import { types, getEnv } from 'mobx-state-tree';
|
import { types, getEnv } from 'mobx-state-tree';
|
||||||
import _ from 'lodash';
|
import { NavItem } from './NavItem';
|
||||||
|
|
||||||
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)), []),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const NavStore = types
|
export const NavStore = types
|
||||||
.model('NavStore', {
|
.model('NavStore', {
|
||||||
@ -19,12 +8,13 @@ export const NavStore = types
|
|||||||
})
|
})
|
||||||
.actions(self => ({
|
.actions(self => ({
|
||||||
load(...args) {
|
load(...args) {
|
||||||
var children = getEnv(self).navTree;
|
let children = getEnv(self).navTree;
|
||||||
let main, node;
|
let main, node;
|
||||||
let parents = [];
|
let parents = [];
|
||||||
|
|
||||||
for (let id of args) {
|
for (let id of args) {
|
||||||
node = _.find(children, { id: id });
|
node = children.find(el => el.id === id);
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
throw new Error(`NavItem with id ${id} not found`);
|
throw new Error(`NavItem with id ${id} not found`);
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { types } from 'mobx-state-tree';
|
import { types } from 'mobx-state-tree';
|
||||||
import { SearchStore } from './SearchStore';
|
import { SearchStore } from './../SearchStore/SearchStore';
|
||||||
import { ServerStatsStore } from './ServerStatsStore';
|
import { ServerStatsStore } from './../ServerStatsStore/ServerStatsStore';
|
||||||
import { NavStore } from './NavStore';
|
import { NavStore } from './../NavStore/NavStore';
|
||||||
import { AlertListStore } from './AlertListStore';
|
import { AlertListStore } from './../AlertListStore/AlertListStore';
|
||||||
import { ViewStore } from './ViewStore';
|
import { ViewStore } from './../ViewStore/ViewStore';
|
||||||
|
|
||||||
export const RootStore = types.model({
|
export const RootStore = types.model({
|
||||||
search: types.optional(SearchStore, {
|
search: types.optional(SearchStore, {
|
@ -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: []
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
10
public/app/stores/SearchStore/ResultItem.ts
Normal file
10
public/app/stores/SearchStore/ResultItem.ts
Normal file
@ -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, ''),
|
||||||
|
});
|
27
public/app/stores/SearchStore/SearchResultSection.ts
Normal file
27
public/app/stores/SearchStore/SearchResultSection.ts
Normal file
@ -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',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
22
public/app/stores/SearchStore/SearchStore.ts
Normal file
22
public/app/stores/SearchStore/SearchStore.ts
Normal file
@ -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: [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
6
public/app/stores/ServerStatsStore/ServerStat.ts
Normal file
6
public/app/stores/ServerStatsStore/ServerStat.ts
Normal file
@ -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),
|
||||||
|
});
|
@ -1,9 +1,5 @@
|
|||||||
import { types, getEnv, flow } from 'mobx-state-tree';
|
import { types, getEnv, flow } from 'mobx-state-tree';
|
||||||
|
import { ServerStat } from './ServerStat';
|
||||||
export const ServerStat = types.model('ServerStat', {
|
|
||||||
name: types.string,
|
|
||||||
value: types.optional(types.number, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ServerStatsStore = types
|
export const ServerStatsStore = types
|
||||||
.model('ServerStatsStore', {
|
.model('ServerStatsStore', {
|
||||||
@ -12,9 +8,8 @@ export const ServerStatsStore = types
|
|||||||
})
|
})
|
||||||
.actions(self => ({
|
.actions(self => ({
|
||||||
load: flow(function* load() {
|
load: flow(function* load() {
|
||||||
let backendSrv = getEnv(self).backendSrv;
|
const backendSrv = getEnv(self).backendSrv;
|
||||||
|
const res = yield backendSrv.get('/api/admin/stats');
|
||||||
let res = yield backendSrv.get('/api/admin/stats');
|
|
||||||
self.stats.clear();
|
self.stats.clear();
|
||||||
self.stats.push(ServerStat.create({ name: 'Total dashboards', value: res.dashboards }));
|
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: 'Total users', value: res.users }));
|
@ -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]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
|
46
public/app/stores/ViewStore/ViewStore.ts
Normal file
46
public/app/stores/ViewStore/ViewStore.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import { RootStore, IRootStore } from './RootStore';
|
import { RootStore, IRootStore } from './RootStore/RootStore';
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
|
|
||||||
export let store: IRootStore;
|
export let store: IRootStore;
|
||||||
|
Loading…
Reference in New Issue
Block a user