diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx index e1fb70e5d68..f9df483bf5f 100644 --- a/public/app/features/dashboard/components/DashNav/DashNav.tsx +++ b/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; } diff --git a/public/app/features/dashboard/components/DashNav/template.html b/public/app/features/dashboard/components/DashNav/template.html index e50a8cd0bff..7e53267cbfd 100644 --- a/public/app/features/dashboard/components/DashNav/template.html +++ b/public/app/features/dashboard/components/DashNav/template.html @@ -55,7 +55,5 @@ - - diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index 9b088b4735f..281916acb14 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/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 { state: State = { isSettingsOpening: false, - isSettingsOpen: false, + isEditing: false, + isFullscreen: false, + fullscreenPanel: null, }; async componentDidMount() { @@ -55,30 +69,66 @@ export class DashboardPage extends PureComponent { } componentDidUpdate(prevProps: Props) { - const { dashboard, editview } = this.props; + const { dashboard, editview, urlEdit, urlFullscreen, urlPanelId } = this.props; - // when dashboard has loaded subscribe to somme events - if (prevProps.dashboard === null && dashboard) { - dashboard.events.on('view-mode-changed', this.onViewModeChanged); - - // 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 { 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 { {dashboard && editview && }
- +
); @@ -113,7 +164,7 @@ export class DashboardPage extends PureComponent { 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 { return (
- + {!dashboard && this.renderLoadingState()} {dashboard && this.renderDashboard()}
@@ -130,19 +181,26 @@ export class DashboardPage extends PureComponent { } } -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)); diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 658bfad3816..27f699ff3e6 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/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 { +export class DashboardGrid extends PureComponent { 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 { 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 { onViewModeChanged = () => { ignoreNextWidthChange = true; - this.forceUpdate(); } updateGridPos = (item: ReactGridLayout.Layout, layout: ReactGridLayout.Layout[]) => { @@ -197,18 +208,20 @@ export class DashboardGrid extends React.Component { } render() { + const { dashboard, isFullscreen } = this.props; + return ( {this.renderPanels()} diff --git a/public/app/features/dashboard/services/DashboardViewStateSrv.ts b/public/app/features/dashboard/services/DashboardViewStateSrv.ts index fc38c3b241f..f5a68d6f647 100644 --- a/public/app/features/dashboard/services/DashboardViewStateSrv.ts +++ b/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; diff --git a/public/app/routes/GrafanaCtrl.ts b/public/app/routes/GrafanaCtrl.ts index 70bdf49e5e4..817e6452f44 100644 --- a/public/app/routes/GrafanaCtrl.ts +++ b/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 diff --git a/public/app/types/dashboard.ts b/public/app/types/dashboard.ts index bdea5b04bac..713cd28efb1 100644 --- a/public/app/types/dashboard.ts +++ b/public/app/types/dashboard.ts @@ -1,6 +1,10 @@ import { DashboardAcl } from './acl'; export interface MutableDashboard { + meta: { + fullscreen: boolean; + isEditing: boolean; + } } export enum DashboardLoadingState { diff --git a/public/views/index-template.html b/public/views/index-template.html index a1c955d45d6..770ab74eccc 100644 --- a/public/views/index-template.html +++ b/public/views/index-template.html @@ -189,7 +189,7 @@ - +