Browse Source

Url state -> dashboard model state sync starting to work

Torkel Ödegaard 6 years ago
parent
commit
cba2ca5531

+ 3 - 0
public/app/features/dashboard/components/DashNav/DashNav.tsx

@@ -13,6 +13,9 @@ import { DashboardModel } from '../../state/DashboardModel';
 
 export interface Props {
   dashboard: DashboardModel | null;
+  editview: string;
+  isEditing: boolean;
+  isFullscreen: boolean;
   updateLocation: typeof updateLocation;
 }
 

+ 0 - 2
public/app/features/dashboard/components/DashNav/template.html

@@ -55,7 +55,5 @@
 			<i class="fa fa-reply"></i>
 		</button>
 	</div>
-
 </div>
 
-<dashboard-search></dashboard-search>

+ 91 - 33
public/app/features/dashboard/containers/DashboardPage.tsx

@@ -5,6 +5,9 @@ import { hot } from 'react-hot-loader';
 import { connect } from 'react-redux';
 import classNames from 'classnames';
 
+// Services & Utils
+import { createErrorNotification } from 'app/core/copy/appNotification';
+
 // Components
 import { LoadingPlaceholder } from '@grafana/ui';
 import { DashboardGrid } from '../dashgrid/DashboardGrid';
@@ -14,34 +17,45 @@ import { DashboardSettings } from '../components/DashboardSettings';
 // Redux
 import { initDashboard } from '../state/initDashboard';
 import { setDashboardModel } from '../state/actions';
+import { updateLocation } from 'app/core/actions';
+import { notifyApp } from 'app/core/actions';
 
 // Types
 import { StoreState } from 'app/types';
-import { DashboardModel } from 'app/features/dashboard/state';
+import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
 import { DashboardLoadingState } from 'app/types/dashboard';
 
 interface Props {
-  panelId: string;
   urlUid?: string;
   urlSlug?: string;
   urlType?: string;
-  editview: string;
+  editview?: string;
+  urlPanelId?: string;
   $scope: any;
   $injector: any;
-  initDashboard: typeof initDashboard;
-  setDashboardModel: typeof setDashboardModel;
+  urlEdit: boolean;
+  urlFullscreen: boolean;
   loadingState: DashboardLoadingState;
   dashboard: DashboardModel;
+  initDashboard: typeof initDashboard;
+  setDashboardModel: typeof setDashboardModel;
+  notifyApp: typeof notifyApp;
+  updateLocation: typeof updateLocation;
 }
 
 interface State {
   isSettingsOpening: boolean;
+  isEditing: boolean;
+  isFullscreen: boolean;
+  fullscreenPanel: PanelModel | null;
 }
 
 export class DashboardPage extends PureComponent<Props, State> {
   state: State = {
     isSettingsOpening: false,
-    isSettingsOpen: false,
+    isEditing: false,
+    isFullscreen: false,
+    fullscreenPanel: null,
   };
 
   async componentDidMount() {
@@ -55,30 +69,66 @@ export class DashboardPage extends PureComponent<Props, State> {
   }
 
   componentDidUpdate(prevProps: Props) {
-    const { dashboard, editview } = this.props;
-
-    // when dashboard has loaded subscribe to somme events
-    if (prevProps.dashboard === null && dashboard) {
-      dashboard.events.on('view-mode-changed', this.onViewModeChanged);
+    const { dashboard, editview, urlEdit, urlFullscreen, urlPanelId } = this.props;
 
-      // set initial fullscreen class state
-      this.setPanelFullscreenClass();
+    if (!dashboard) {
+      return;
     }
 
+    // handle animation states when opening dashboard settings
     if (!prevProps.editview && editview) {
       this.setState({ isSettingsOpening: true });
       setTimeout(() => {
-        this.setState({ isSettingsOpening: false});
+        this.setState({ isSettingsOpening: false });
       }, 10);
     }
+
+    // // when dashboard has loaded subscribe to somme events
+    // if (prevProps.dashboard === null) {
+    //   // set initial fullscreen class state
+    //   this.setPanelFullscreenClass();
+    // }
+
+    // Sync url state with model
+    if (urlFullscreen !== dashboard.meta.isFullscreen || urlEdit !== dashboard.meta.isEditing) {
+      // entering fullscreen/edit mode
+      if (urlPanelId) {
+        const panel = dashboard.getPanelById(parseInt(urlPanelId, 10));
+
+        if (panel) {
+          dashboard.setViewMode(panel, urlFullscreen, urlEdit);
+          this.setState({ isEditing: urlEdit, isFullscreen: urlFullscreen, fullscreenPanel: panel });
+        } else {
+          this.handleFullscreenPanelNotFound(urlPanelId);
+        }
+      } else {
+        // handle leaving fullscreen mode
+        if (this.state.fullscreenPanel) {
+          dashboard.setViewMode(this.state.fullscreenPanel, urlFullscreen, urlEdit);
+        }
+        this.setState({ isEditing: urlEdit, isFullscreen: urlFullscreen, fullscreenPanel: null });
+      }
+
+      this.setPanelFullscreenClass(urlFullscreen);
+    }
   }
 
-  onViewModeChanged = () => {
-    this.setPanelFullscreenClass();
-  };
+  handleFullscreenPanelNotFound(urlPanelId: string) {
+    // Panel not found
+    this.props.notifyApp(createErrorNotification(`Panel with id ${urlPanelId} not found`));
+    // Clear url state
+    this.props.updateLocation({
+      query: {
+        edit: null,
+        fullscreen: null,
+        panelId: null,
+      },
+      partial: true
+    });
+  }
 
-  setPanelFullscreenClass() {
-    $('body').toggleClass('panel-in-fullscreen', this.props.dashboard.meta.fullscreen === true);
+  setPanelFullscreenClass(isFullscreen: boolean) {
+    $('body').toggleClass('panel-in-fullscreen', isFullscreen);
   }
 
   componentWillUnmount() {
@@ -94,10 +144,11 @@ export class DashboardPage extends PureComponent<Props, State> {
 
   renderDashboard() {
     const { dashboard, editview } = this.props;
+    const { isEditing, isFullscreen } = this.state;
 
     const classes = classNames({
       'dashboard-container': true,
-      'dashboard-container--has-submenu': dashboard.meta.submenuEnabled
+      'dashboard-container--has-submenu': dashboard.meta.submenuEnabled,
     });
 
     return (
@@ -105,7 +156,7 @@ export class DashboardPage extends PureComponent<Props, State> {
         {dashboard && editview && <DashboardSettings dashboard={dashboard} />}
 
         <div className={classes}>
-          <DashboardGrid dashboard={dashboard} />
+          <DashboardGrid dashboard={dashboard} isEditing={isEditing} isFullscreen={isFullscreen} />
         </div>
       </div>
     );
@@ -113,7 +164,7 @@ export class DashboardPage extends PureComponent<Props, State> {
 
   render() {
     const { dashboard, editview } = this.props;
-    const { isSettingsOpening } = this.state;
+    const { isSettingsOpening, isEditing, isFullscreen } = this.state;
 
     const classes = classNames({
       'dashboard-page--settings-opening': isSettingsOpening,
@@ -122,7 +173,7 @@ export class DashboardPage extends PureComponent<Props, State> {
 
     return (
       <div className={classes}>
-        <DashNav dashboard={dashboard} />
+        <DashNav dashboard={dashboard} isEditing={isEditing} isFullscreen={isFullscreen} editview={editview} />
         {!dashboard && this.renderLoadingState()}
         {dashboard && this.renderDashboard()}
       </div>
@@ -130,19 +181,26 @@ export class DashboardPage extends PureComponent<Props, State> {
   }
 }
 
-const mapStateToProps = (state: StoreState) => ({
-  urlUid: state.location.routeParams.uid,
-  urlSlug: state.location.routeParams.slug,
-  urlType: state.location.routeParams.type,
-  panelId: state.location.query.panelId,
-  editview: state.location.query.editview,
-  loadingState: state.dashboard.loadingState,
-  dashboard: state.dashboard.model as DashboardModel,
-});
+const mapStateToProps = (state: StoreState) => {
+  console.log('state location', state.location.query);
+  return {
+    urlUid: state.location.routeParams.uid,
+    urlSlug: state.location.routeParams.slug,
+    urlType: state.location.routeParams.type,
+    editview: state.location.query.editview,
+    urlPanelId: state.location.query.panelId,
+    urlFullscreen: state.location.query.fullscreen === true,
+    urlEdit: state.location.query.edit === true,
+    loadingState: state.dashboard.loadingState,
+    dashboard: state.dashboard.model as DashboardModel,
+  };
+};
 
 const mapDispatchToProps = {
   initDashboard,
-  setDashboardModel
+  setDashboardModel,
+  notifyApp,
+  updateLocation,
 };
 
 export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DashboardPage));

+ 27 - 14
public/app/features/dashboard/dashgrid/DashboardGrid.tsx

@@ -1,11 +1,14 @@
-import React from 'react';
+// Libaries
+import React, { PureComponent } from 'react';
 import { hot } from 'react-hot-loader';
 import ReactGridLayout, { ItemCallback } from 'react-grid-layout';
+import classNames from 'classnames';
+import sizeMe from 'react-sizeme';
+
+// Types
 import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
 import { DashboardPanel } from './DashboardPanel';
 import { DashboardModel, PanelModel } from '../state';
-import classNames from 'classnames';
-import sizeMe from 'react-sizeme';
 
 let lastGridWidth = 1200;
 let ignoreNextWidthChange = false;
@@ -76,19 +79,18 @@ function GridWrapper({
 
 const SizedReactLayoutGrid = sizeMe({ monitorWidth: true })(GridWrapper);
 
-export interface DashboardGridProps {
+export interface Props {
   dashboard: DashboardModel;
+  isEditing: boolean;
+  isFullscreen: boolean;
 }
 
-export class DashboardGrid extends React.Component<DashboardGridProps> {
+export class DashboardGrid extends PureComponent<Props> {
   gridToPanelMap: any;
   panelMap: { [id: string]: PanelModel };
 
-  constructor(props: DashboardGridProps) {
-    super(props);
-
-    // subscribe to dashboard events
-    const dashboard = this.props.dashboard;
+  componentDidMount() {
+    const { dashboard } = this.props;
     dashboard.on('panel-added', this.triggerForceUpdate);
     dashboard.on('panel-removed', this.triggerForceUpdate);
     dashboard.on('repeats-processed', this.triggerForceUpdate);
@@ -97,6 +99,16 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
     dashboard.on('row-expanded', this.triggerForceUpdate);
   }
 
+  componentWillUnmount() {
+    const { dashboard } = this.props;
+    dashboard.off('panel-added', this.triggerForceUpdate);
+    dashboard.off('panel-removed', this.triggerForceUpdate);
+    dashboard.off('repeats-processed', this.triggerForceUpdate);
+    dashboard.off('view-mode-changed', this.onViewModeChanged);
+    dashboard.off('row-collapsed', this.triggerForceUpdate);
+    dashboard.off('row-expanded', this.triggerForceUpdate);
+  }
+
   buildLayout() {
     const layout = [];
     this.panelMap = {};
@@ -151,7 +163,6 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
 
   onViewModeChanged = () => {
     ignoreNextWidthChange = true;
-    this.forceUpdate();
   }
 
   updateGridPos = (item: ReactGridLayout.Layout, layout: ReactGridLayout.Layout[]) => {
@@ -197,18 +208,20 @@ export class DashboardGrid extends React.Component<DashboardGridProps> {
   }
 
   render() {
+    const { dashboard, isFullscreen } = this.props;
+
     return (
       <SizedReactLayoutGrid
         className={classNames({ layout: true })}
         layout={this.buildLayout()}
-        isResizable={this.props.dashboard.meta.canEdit}
-        isDraggable={this.props.dashboard.meta.canEdit}
+        isResizable={dashboard.meta.canEdit}
+        isDraggable={dashboard.meta.canEdit}
         onLayoutChange={this.onLayoutChange}
         onWidthChange={this.onWidthChange}
         onDragStop={this.onDragStop}
         onResize={this.onResize}
         onResizeStop={this.onResizeStop}
-        isFullscreen={this.props.dashboard.meta.fullscreen}
+        isFullscreen={isFullscreen}
       >
         {this.renderPanels()}
       </SizedReactLayoutGrid>

+ 0 - 30
public/app/features/dashboard/services/DashboardViewStateSrv.ts

@@ -98,8 +98,6 @@ export class DashboardViewStateSrv {
     if (fromRouteUpdated !== true) {
       this.$location.search(this.serializeToUrl());
     }
-
-    this.syncState();
   }
 
   toggleCollapsedPanelRow(panelId) {
@@ -115,34 +113,6 @@ export class DashboardViewStateSrv {
     }
   }
 
-  syncState() {
-    if (this.state.fullscreen) {
-      const panel = this.dashboard.getPanelById(this.state.panelId);
-
-      if (!panel) {
-        this.state.fullscreen = null;
-        this.state.panelId = null;
-        this.state.edit = null;
-
-        this.update(this.state);
-
-        setTimeout(() => {
-          appEvents.emit('alert-error', ['Error', 'Panel not found']);
-        }, 100);
-
-        return;
-      }
-
-      if (!panel.fullscreen) {
-        this.enterFullscreen(panel);
-      } else if (this.dashboard.meta.isEditing !== this.state.edit) {
-        this.dashboard.setViewMode(panel, this.state.fullscreen, this.state.edit);
-      }
-    } else if (this.fullscreenPanel) {
-      this.leaveFullscreen();
-    }
-  }
-
   leaveFullscreen() {
     const panel = this.fullscreenPanel;
 

+ 2 - 0
public/app/routes/GrafanaCtrl.ts

@@ -165,6 +165,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
         for (const drop of Drop.drops) {
           drop.destroy();
         }
+
+        appEvents.emit('hide-dash-search');
       });
 
       // handle kiosk mode

+ 4 - 0
public/app/types/dashboard.ts

@@ -1,6 +1,10 @@
 import { DashboardAcl } from './acl';
 
 export interface MutableDashboard {
+  meta: {
+    fullscreen: boolean;
+    isEditing: boolean;
+  }
 }
 
 export enum DashboardLoadingState {

+ 1 - 1
public/views/index-template.html

@@ -189,7 +189,7 @@
   <grafana-app class="grafana-app" ng-cloak>
     <sidemenu class="sidemenu"></sidemenu>
     <app-notifications-list class="page-alert-list"></app-notifications-list>
-
+    <dashboard-search></dashboard-search>
 
     <div class="main-view">
       <div class="scroll-canvas" page-scrollbar>