浏览代码

mobx: progress on poc

Torkel Ödegaard 8 年之前
父节点
当前提交
354913a704

+ 3 - 0
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

+ 0 - 42
public/app/containers/ServerStats.tsx

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

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

+ 84 - 0
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<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>
+    );
+  }
+}

+ 6 - 5
public/app/core/components/search/search.html

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

+ 54 - 55
public/app/features/admin/partials/stats.html

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

+ 0 - 20
public/app/store/store.ts

@@ -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 - 0
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 {}

+ 44 - 0
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: []
+          })
+        );
+      }
+    }
+  }));

+ 7 - 0
public/app/stores/store.ts

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