Browse Source

ux: worked on add panel function

Torkel Ödegaard 8 years ago
parent
commit
772ab7812f

+ 72 - 0
public/app/features/dashboard/dashgrid/AddPanelPanel.tsx

@@ -0,0 +1,72 @@
+import React from 'react';
+import config from 'app/core/config';
+import {PanelModel} from '../panel_model';
+import {PanelContainer} from './PanelContainer';
+import _ from 'lodash';
+
+export interface AddPanelPanelProps {
+  panel: PanelModel;
+  getPanelContainer: () => PanelContainer;
+}
+
+export interface AddPanelPanelState {
+  filter: string;
+  panelPlugins: any[];
+}
+
+export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelPanelState> {
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      panelPlugins: this.getPanelPlugins(),
+      filter: '',
+    };
+
+    this.onPanelSelected = this.onPanelSelected.bind(this);
+  }
+
+  getPanelPlugins() {
+    return _.chain(config.panels)
+      .filter({hideFromList: false})
+      .map(item => item)
+      .orderBy('sort')
+      .value();
+  }
+
+  onPanelSelected(panelPluginInfo) {
+    const panelContainer = this.props.getPanelContainer();
+    const dashboard = panelContainer.getDashboard();
+
+    // remove add-panel panel
+    dashboard.removePanel(this.props.panel);
+
+    dashboard.addPanel({
+      type: panelPluginInfo.id,
+      title: 'Panel Title',
+      gridPos: {
+        x: this.props.panel.gridPos.x,
+        y: this.props.panel.gridPos.y,
+        w: this.props.panel.gridPos.w,
+        h: this.props.panel.gridPos.h
+      }
+    });
+  }
+
+  renderPanelItem(panel) {
+    return (
+      <div key={panel.id} className="add-panel__item" onClick={() => this.onPanelSelected(panel)} title={panel.name}>
+        <img className="add-panel__item-img" src={panel.info.logos.small} />
+        <div className="add-panel__item-name">{panel.name}</div>
+      </div>
+    );
+  }
+
+  render() {
+    return (
+      <div className="panel-container">
+        <div className="add-panel">{this.state.panelPlugins.map(this.renderPanelItem.bind(this))}</div>
+      </div>
+    );
+  }
+}

+ 1 - 0
public/app/features/dashboard/dashgrid/DashboardGrid.tsx

@@ -91,6 +91,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
         y: panel.gridPos.y,
         w: panel.gridPos.w,
         h: panel.gridPos.h,
+        static: panel.gridPos.static,
       });
     }
 

+ 14 - 2
public/app/features/dashboard/dashgrid/DashboardPanel.tsx

@@ -2,6 +2,8 @@ import React from 'react';
 import {PanelModel} from '../panel_model';
 import {PanelContainer} from './PanelContainer';
 import {AttachedPanel} from './PanelLoader';
+import {DashboardRow} from './DashboardRow';
+import {AddPanelPanel} from './AddPanelPanel';
 
 export interface DashboardPanelProps {
   panel: PanelModel;
@@ -18,10 +20,13 @@ export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
   }
 
   componentDidMount() {
+    if (!this.element) {
+      return;
+    }
+
     const panelContainer = this.props.getPanelContainer();
     const dashboard = panelContainer.getDashboard();
     const loader = panelContainer.getPanelLoader();
-
     this.attachedPanel = loader.load(this.element, this.props.panel, dashboard);
   }
 
@@ -31,9 +36,16 @@ export class DashboardPanel extends React.Component<DashboardPanelProps, any> {
     }
   }
 
+  render() {
+    // special handling for rows
+    if (this.props.panel.type === 'row') {
+      return <DashboardRow panel={this.props.panel} />;
+    }
 
+    if (this.props.panel.type === 'add-panel') {
+      return <AddPanelPanel panel={this.props.panel} getPanelContainer={this.props.getPanelContainer} />;
+    }
 
-  render() {
     return (
       <div ref={element => this.element = element} />
     );

+ 1 - 1
public/app/features/dashboard/dashgrid/DashboardRow.tsx

@@ -5,7 +5,7 @@ export interface DashboardRowProps {
   panel: PanelModel;
 }
 
-export class DashboardPanel extends React.Component<DashboardRowProps, any> {
+export class DashboardRow extends React.Component<DashboardRowProps, any> {
   constructor(props) {
     super(props);
 

+ 27 - 26
public/app/features/dashboard/dashnav/dashnav.html

@@ -22,32 +22,33 @@
 		</ul>
 
 		<ul class="nav dashnav-action-icons">
-			<li ng-show="::ctrl.dashboard.meta.canShare" class="dropdown">
-				<a class="pointer" ng-click="ctrl.hideTooltip($event)" bs-tooltip="'Share dashboard'" data-placement="bottom" data-toggle="dropdown"><i class="fa fa-share-square-o"></i></a>
-				<ul class="dropdown-menu">
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(0)">
-							<i class="fa fa-link"></i> Link to Dashboard
-							<div class="dropdown-desc">Share an internal link to the current dashboard. Some configuration options available.</div>
-						</a>
-					</li>
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(1)">
-							<i class="icon-gf icon-gf-snapshot"></i>Snapshot
-							<div class="dropdown-desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div>
-						</a>
-					</li>
-					<li>
-						<a class="pointer" ng-click="ctrl.shareDashboard(2)">
-							<i class="fa fa-cloud-upload"></i>Export
-							<div class="dropdown-desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div>
-						</a>
-					</li>
-				</ul>
-			</li>
-			<li ng-show="::ctrl.dashboard.meta.canSave">
-				<a ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom"><i class="fa fa-save"></i></a>
-			</li>
+		<!-- 	<li ng&#45;show="::ctrl.dashboard.meta.canShare" class="dropdown"> -->
+		<!-- 		<a class="pointer" ng&#45;click="ctrl.hideTooltip($event)" bs&#45;tooltip="'Share dashboard'" data&#45;placement="bottom" data&#45;toggle="dropdown"><i class="fa fa&#45;share&#45;square&#45;o"></i></a> -->
+		<!-- 		<ul class="dropdown&#45;menu"> -->
+		<!-- 			<li> -->
+		<!-- 				<a class="pointer" ng&#45;click="ctrl.shareDashboard(0)"> -->
+		<!-- 					<i class="fa fa&#45;link"></i> Link to Dashboard -->
+		<!-- 					<div class="dropdown&#45;desc">Share an internal link to the current dashboard. Some configuration options available.</div> -->
+		<!-- 				</a> -->
+		<!-- 			</li> -->
+		<!-- 			<li> -->
+		<!-- 				<a class="pointer" ng&#45;click="ctrl.shareDashboard(1)"> -->
+		<!-- 					<i class="icon&#45;gf icon&#45;gf&#45;snapshot"></i>Snapshot -->
+		<!-- 					<div class="dropdown&#45;desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div> -->
+		<!-- 				</a> -->
+		<!-- 			</li> -->
+		<!-- 			<li> -->
+		<!-- 				<a class="pointer" ng&#45;click="ctrl.shareDashboard(2)"> -->
+		<!-- 					<i class="fa fa&#45;cloud&#45;upload"></i>Export -->
+		<!-- 					<div class="dropdown&#45;desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div> -->
+		<!-- 				</a> -->
+		<!-- 			</li> -->
+		<!-- 		</ul> -->
+		<!-- 	</li> -->
+		<!-- 	<li ng&#45;show="::ctrl.dashboard.meta.canSave"> -->
+		<!-- 		<a ng&#45;click="ctrl.saveDashboard()" bs&#45;tooltip="'Save dashboard <br> CTRL+S'" data&#45;placement="bottom"><i class="fa fa&#45;save"></i></a> -->
+		<!-- 	</li> -->
+
 			<li ng-if="::ctrl.dashboard.snapshot.originalUrl">
 				<a ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom"><i class="fa fa-link"></i></a>
 			</li>

+ 2 - 2
public/app/features/dashboard/dashnav/dashnav.ts

@@ -147,8 +147,8 @@ export class DashNavCtrl {
 
     addPanel() {
       this.dashboard.addPanel({
-        type: 'graph',
-        gridPos: {x: 0, y: 0, w: 12, h: 9},
+        type: 'add-panel',
+        gridPos: {x: 0, y: 0, w: 12, h: 9, static: true},
         title: 'New Graph',
       });
     }

+ 1 - 0
public/app/features/dashboard/panel_model.ts

@@ -6,6 +6,7 @@ export interface GridPos {
   y: number;
   w: number;
   h: number;
+  static?: boolean;
 }
 
 const notPersistedProperties: {[str: string]: boolean} = {

+ 1 - 0
public/sass/_grafana.scss

@@ -54,6 +54,7 @@
 @import "components/panel_table";
 @import "components/panel_text";
 @import "components/panel_heatmap";
+@import "components/panel_add_panel";
 @import "components/settings_permissions";
 @import "components/tagsinput";
 @import "components/tables_lists";

+ 41 - 0
public/sass/components/_panel_add_panel.scss

@@ -0,0 +1,41 @@
+
+.add-panel {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+  overflow: hidden;
+  height: 100%;
+  align-content: flex-start;
+  justify-content: space-around;
+  padding: 3px 0;
+}
+
+.add-panel__item {
+  background: $card-background;
+  box-shadow: $card-shadow;
+
+  border: $panel-border;
+  padding: $spacer/3 $spacer;
+  width: 31%;
+  height: 60px;
+  text-align: center;
+  margin: $gf-form-margin;
+  cursor: pointer;
+
+  &.active,
+  &:hover {
+    background: $card-background-hover;
+  }
+}
+
+.add-panel__item-name {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  font-size: $font-size-sm;
+}
+
+.add-panel__item-img {
+  height: calc(100% - 15px);
+}
+

+ 0 - 124
public/sass/components/_row.scss

@@ -101,127 +101,3 @@ $dashboard-row-height: 30px;
   right: 0;
 }
 
-.panels-wrapper {
-  flex-grow: 1;
-  position: relative;
-}
-
-.dash-row-dropview {
-  position: relative;
-  background:  $panel-bg;
-  border: $panel-border;
-  margin: 0 $panel-margin $panel-margin*2 $panel-margin;
-  padding: $panel-margin*2;
-  display: flex;
-}
-
-.dash-row-dropview-close {
-  position: absolute;
-  right: -12px;
-  top: -10px;
-  width: 20px;
-  height: 20px;
-}
-
-.add-panel-panels-scroll {
-  width: 100%;
-  overflow: auto;
-  -ms-overflow-style: none;
-
-  &::-webkit-scrollbar {
-    display: none
-  }
-}
-
-.add-panel-panels {
-  display: flex;
-  flex-direction: row;
-}
-
-.add-panel-item {
-  background: $input-label-bg;
-  border: $panel-border;
-  padding: $spacer/3 $spacer;
-  min-width: 9rem;
-  max-width: 9rem;
-  text-align: center;
-  margin: $gf-form-margin;
-  cursor: pointer;
-
-  &.active,
-  &:hover {
-    box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 1px rgba(82,168,236,5.8)
-  }
-}
-
-.add-panel-item-name {
-  text-overflow: ellipsis;
-  overflow: hidden;
-  white-space: nowrap;
-  font-size: $font-size-sm;
-}
-
-.add-panel-item-img {
-  width: 2rem;
-}
-
-$dash-row-menu-animation-speed: 0.20s;
-
-.dash-row-menu-container {
-  position: absolute;
-  top: 0px;
-  width: 138px;
-  min-height: 100%;
-  transform: translate(-131px, 0);
-  transition: 0.1s ease-out 0.4s;
-  z-index: 0;
-  display: flex;
-  flex-direction: row;
-
-  &:hover {
-    transform: translate(-$panel-margin, 0);
-    transition: $dash-row-menu-animation-speed ease-in 0.05s;
-    z-index: 101;
-
-    .dash-row-menu-grip {
-      opacity: 0;
-      transition: $dash-row-menu-animation-speed ease-in 0.05s;
-    }
-  }
-}
-
-.dash-row-menu {
-  list-style: none;
-  flex-grow: 1;
-  box-shadow: $menu-dropdown-shadow;
-  background: $menu-dropdown-bg;
-
-  li a {
-    display: block;
-    white-space: nowrap;
-    color: $dropdownLinkColor;
-    font-size: $font-size-sm;
-    padding: $spacer/2 $spacer;
-    border-left: 2px solid $menu-dropdown-bg;
-    i {
-      display: inline-block;
-      padding-right: $spacer/2;
-    }
-
-    &:hover {
-      @include left-brand-border-gradient();
-      color: $link-color;
-      background: $input-label-bg;
-    }
-  }
-}
-
-.dash-row-menu-grip {
-  text-align: center;
-  font-size: 130%;
-  color: $text-color-weak;
-  opacity: 1;
-  transition: $dash-row-menu-animation-speed ease-out 0.5s;
-  width: 1rem;
-}
-

+ 1 - 1
public/sass/components/_sidemenu.scss

@@ -169,7 +169,7 @@ li.sidemenu-org-switcher {
   img {
     width: 30px;
     position: relative;
-    top: 3px;
+    top: 5px;
     left: 4px;
   }
 }

+ 2 - 0
public/sass/pages/_dashboard.scss

@@ -14,6 +14,8 @@ div.flot-text {
 }
 
 .panel {
+  height: 100%;
+
   &--solo {
     .panel-container {
       border: none;