mobx: progress on poc

This commit is contained in:
Torkel Ödegaard 2017-12-20 17:24:04 +01:00
parent ee216ba6fb
commit 354913a704
10 changed files with 211 additions and 124 deletions

View File

@ -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

View File

@ -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>
);
}
}

View File

@ -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, []);
}

View 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>
);
}
}

View File

@ -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&#45;search&#45;results -->
<!-- results="ctrl.results" -->
<!-- on&#45;tag&#45;selected="ctrl.filterByTag($tag)" -->
<!-- on&#45;folder&#45;expanding="ctrl.folderExpanding()" -->
<!-- on&#45;folder&#45;expanded="ctrl.folderExpanded($folder)" /> -->
</div>
</div>

View File

@ -1,55 +1,54 @@
<container-server-stats />
<!-- <page&#45;header model="ctrl.navModel"></page&#45;header> -->
<!-- -->
<!-- <div class="page&#45;container page&#45;body"> -->
<!-- <table class="filter&#45;table form&#45;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>

View File

@ -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 };

View 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 {}

View 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: []
})
);
}
}
}));

View File

@ -0,0 +1,7 @@
import { RootStore, IRootStore } from "./RootStore";
export let store: IRootStore;
export function createStore() {
store = RootStore.create({});
}