grafana/public/app/features/scenes/dashboard/DashboardScene.tsx
Torkel Ödegaard e7797ac439
SceneDashboard: Adds menu to panels, a start for inspect drawer state (#71194)
* Began work on panel menu

* SceneDashboard: Basic state handling for inspect panel

* Switched to using scene url sync instead

* Updated

* Update comment on hack

* Fixed url synnc issues and more / better DashboardsLoader tests

* Progress on test

* Updates

* Progress

* Progress

* Update

* Update

* Update

* Update

* Update scenes lib

* Update

* Update

---------

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
2023-07-12 13:37:26 +02:00

156 lines
3.9 KiB
TypeScript

import * as H from 'history';
import { AppEvents, locationUtil, NavModelItem } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import {
getUrlSyncManager,
sceneGraph,
SceneGridItem,
SceneObject,
SceneObjectBase,
SceneObjectState,
SceneObjectStateChangedEvent,
SceneObjectUrlSyncHandler,
SceneObjectUrlValues,
VizPanel,
} from '@grafana/scenes';
import appEvents from 'app/core/app_events';
import { DashboardSceneRenderer } from './DashboardSceneRenderer';
export interface DashboardSceneState extends SceneObjectState {
title: string;
uid?: string;
body: SceneObject;
actions?: SceneObject[];
controls?: SceneObject[];
isEditing?: boolean;
isDirty?: boolean;
/** Scene object key for object to inspect */
inspectPanelKey?: string;
/** Scene object key for object to view in fullscreen */
viewPanelKey?: string;
}
export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
static Component = DashboardSceneRenderer;
protected _urlSync = new DashboardSceneUrlSync(this);
constructor(state: DashboardSceneState) {
super(state);
this.addActivationHandler(() => {
return () => {
getUrlSyncManager().cleanUp(this);
};
});
this.subscribeToEvent(SceneObjectStateChangedEvent, this.onChildStateChanged);
}
findPanel(key: string | undefined): VizPanel | null {
if (!key) {
return null;
}
const obj = sceneGraph.findObject(this, (obj) => obj.state.key === key);
if (obj instanceof VizPanel) {
return obj;
}
return null;
}
onChildStateChanged = (event: SceneObjectStateChangedEvent) => {
// Temporary hacky way to detect changes
if (event.payload.changedObject instanceof SceneGridItem) {
this.setState({ isDirty: true });
}
};
initUrlSync() {
getUrlSyncManager().initSync(this);
}
onEnterEditMode = () => {
this.setState({ isEditing: true });
};
onDiscard = () => {
// TODO open confirm modal if dirty
// TODO actually discard changes
this.setState({ isEditing: false });
};
onCloseInspectDrawer = () => {
locationService.partial({ inspect: null });
};
getPageNav(location: H.Location) {
let pageNav: NavModelItem = {
text: this.state.title,
url: locationUtil.getUrlForPartial(location, { viewPanel: null, inspect: null }),
};
if (this.state.viewPanelKey) {
pageNav = {
text: 'View panel',
parentItem: pageNav,
};
}
return pageNav;
}
}
class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
constructor(private _scene: DashboardScene) {}
getKeys(): string[] {
return ['inspect', 'viewPanel'];
}
getUrlState(): SceneObjectUrlValues {
const state = this._scene.state;
return { inspect: state.inspectPanelKey, viewPanel: state.viewPanelKey };
}
updateFromUrl(values: SceneObjectUrlValues): void {
const { inspectPanelKey, viewPanelKey } = this._scene.state;
const update: Partial<DashboardSceneState> = {};
// Handle inspect object state
if (typeof values.inspect === 'string') {
const panel = this._scene.findPanel(values.inspect);
if (!panel) {
appEvents.emit(AppEvents.alertError, ['Panel not found']);
locationService.partial({ inspect: null });
return;
}
update.inspectPanelKey = values.inspect;
} else if (inspectPanelKey) {
update.inspectPanelKey = undefined;
}
// Handle view panel state
if (typeof values.viewPanel === 'string') {
const panel = this._scene.findPanel(values.viewPanel);
if (!panel) {
appEvents.emit(AppEvents.alertError, ['Panel not found']);
locationService.partial({ viewPanel: null });
return;
}
update.viewPanelKey = values.viewPanel;
} else if (viewPanelKey) {
update.viewPanelKey = undefined;
}
if (Object.keys(update).length > 0) {
this._scene.setState(update);
}
}
}