mirror of
https://github.com/grafana/grafana.git
synced 2024-11-26 19:00:54 -06:00
mobx: progress on poc
This commit is contained in:
parent
ee216ba6fb
commit
354913a704
@ -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
|
||||
|
@ -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<any, any> {
|
||||
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 (
|
||||
<div>
|
||||
<PageHeader model={this.state.navModel} />
|
||||
|
||||
<div className="page-container">
|
||||
name:
|
||||
<h2 onClick={this.onClick}>{this.state.search.name}</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -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, []);
|
||||
}
|
||||
|
84
public/app/core/components/search/SearchResult.tsx
Normal file
84
public/app/core/components/search/SearchResult.tsx
Normal file
@ -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<SearchResultProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
search: store.search
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.search.sections.map(section => {
|
||||
return <SearchResultSection section={section} key={section.id} />;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface SectionProps {
|
||||
section: any;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class SearchResultSection extends React.Component<SectionProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
renderItem(item) {
|
||||
return (
|
||||
<a className="search-item" href={item.url} key={item.id}>
|
||||
<span className="search-item__icon">
|
||||
<i className="fa fa-th-large" />
|
||||
</span>
|
||||
<span className="search-item__body">
|
||||
<div className="search-item__body-title">{item.title}</div>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<div className="search-section" key={this.props.section.id}>
|
||||
<div className="search-section__header">
|
||||
<i
|
||||
className={classNames(
|
||||
"search-section__header__icon",
|
||||
this.props.section.icon
|
||||
)}
|
||||
/>
|
||||
<span className="search-section__header__text">
|
||||
{this.props.section.title}
|
||||
</span>
|
||||
<i className={collapseClassNames} onClick={this.toggleSection} />
|
||||
</div>
|
||||
{this.props.section.expanded && (
|
||||
<div className="search-section__items">
|
||||
{this.props.section.items.map(this.renderItem)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -22,11 +22,12 @@
|
||||
<div class="search-dropdown__col_1">
|
||||
<div class="search-results-container" grafana-scrollbar>
|
||||
<h6 ng-show="!ctrl.isLoading && ctrl.results.length === 0">No dashboards matching your query were found.</h6>
|
||||
<dashboard-search-results
|
||||
results="ctrl.results"
|
||||
on-tag-selected="ctrl.filterByTag($tag)"
|
||||
on-folder-expanding="ctrl.folderExpanding()"
|
||||
on-folder-expanded="ctrl.folderExpanded($folder)" />
|
||||
<search-result />
|
||||
<!-- <dashboard-search-results -->
|
||||
<!-- results="ctrl.results" -->
|
||||
<!-- on-tag-selected="ctrl.filterByTag($tag)" -->
|
||||
<!-- on-folder-expanding="ctrl.folderExpanding()" -->
|
||||
<!-- on-folder-expanded="ctrl.folderExpanded($folder)" /> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,55 +1,54 @@
|
||||
<container-server-stats />
|
||||
<!-- <page-header model="ctrl.navModel"></page-header> -->
|
||||
<!-- -->
|
||||
<!-- <div class="page-container page-body"> -->
|
||||
<!-- <table class="filter-table form-inline"> -->
|
||||
<!-- <thead> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <th>Name</th> -->
|
||||
<!-- <th>Value</th> -->
|
||||
<!-- </tr> -->
|
||||
<!-- </thead> -->
|
||||
<!-- <tbody> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total dashboards</td> -->
|
||||
<!-- <td>{{ctrl.stats.dashboards}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total users</td> -->
|
||||
<!-- <td>{{ctrl.stats.users}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Active users (seen last 14 days)</td> -->
|
||||
<!-- <td>{{ctrl.stats.activeUsers}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total organizations</td> -->
|
||||
<!-- <td>{{ctrl.stats.orgs}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total datasources</td> -->
|
||||
<!-- <td>{{ctrl.stats.datasources}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total playlists</td> -->
|
||||
<!-- <td>{{ctrl.stats.playlists}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total snapshots</td> -->
|
||||
<!-- <td>{{ctrl.stats.snapshots}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total dashboard tags</td> -->
|
||||
<!-- <td>{{ctrl.stats.tags}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total starred dashboards</td> -->
|
||||
<!-- <td>{{ctrl.stats.stars}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td>Total alerts</td> -->
|
||||
<!-- <td>{{ctrl.stats.alerts}}</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- </tbody> -->
|
||||
<!-- </table> -->
|
||||
<!-- </div> -->
|
||||
<page-header model="ctrl.navModel"></page-header>
|
||||
|
||||
<div class="page-container page-body">
|
||||
<table class="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total dashboards</td>
|
||||
<td>{{ctrl.stats.dashboards}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total users</td>
|
||||
<td>{{ctrl.stats.users}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Active users (seen last 14 days)</td>
|
||||
<td>{{ctrl.stats.activeUsers}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total organizations</td>
|
||||
<td>{{ctrl.stats.orgs}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total datasources</td>
|
||||
<td>{{ctrl.stats.datasources}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total playlists</td>
|
||||
<td>{{ctrl.stats.playlists}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total snapshots</td>
|
||||
<td>{{ctrl.stats.snapshots}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total dashboard tags</td>
|
||||
<td>{{ctrl.stats.tags}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total starred dashboards</td>
|
||||
<td>{{ctrl.stats.stars}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total alerts</td>
|
||||
<td>{{ctrl.stats.alerts}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -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 };
|
11
public/app/stores/RootStore.ts
Normal file
11
public/app/stores/RootStore.ts
Normal file
@ -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 {}
|
44
public/app/stores/SearchStore.ts
Normal file
44
public/app/stores/SearchStore.ts
Normal file
@ -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: []
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}));
|
7
public/app/stores/store.ts
Normal file
7
public/app/stores/store.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { RootStore, IRootStore } from "./RootStore";
|
||||
|
||||
export let store: IRootStore;
|
||||
|
||||
export function createStore() {
|
||||
store = RootStore.create({});
|
||||
}
|
Loading…
Reference in New Issue
Block a user