Commit cba2ca55 by Torkel Ödegaard

Url state -> dashboard model state sync starting to work

parent 8dec7468
......@@ -13,6 +13,9 @@ import { DashboardModel } from '../../state/DashboardModel';
export interface Props {
dashboard: DashboardModel | null;
editview: string;
isEditing: boolean;
isFullscreen: boolean;
updateLocation: typeof updateLocation;
}
......
......@@ -55,7 +55,5 @@
<i class="fa fa-reply"></i>
</button>
</div>
</div>
<dashboard-search></dashboard-search>
......@@ -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));
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>
......
......@@ -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;
......
......@@ -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
......
import { DashboardAcl } from './acl';
export interface MutableDashboard {
meta: {
fullscreen: boolean;
isEditing: boolean;
}
}
export enum DashboardLoadingState {
......
......@@ -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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment