Don't use proxy for rendering dashboard page

This commit is contained in:
Dominik Prokop 2023-10-19 09:27:56 +02:00
parent bf14c0b125
commit 95836bdb2c
8 changed files with 76 additions and 56 deletions

View File

@ -6,27 +6,39 @@ import { Page } from 'app/core/components/Page/Page';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { DashboardPageRouteParams } from 'app/features/dashboard/containers/types';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardRoutes } from 'app/types';
import { getDashboardScenePageStateManager } from './DashboardScenePageStateManager';
export interface Props extends GrafanaRouteComponentProps<DashboardPageRouteParams> {}
export interface Props extends GrafanaRouteComponentProps<DashboardPageRouteParams> {
preloadedDashboard?: DashboardModel;
}
export function DashboardScenePage({ match, route }: Props) {
export function DashboardScenePage({ match, route, preloadedDashboard }: Props) {
const stateManager = getDashboardScenePageStateManager();
const { dashboard, isLoading, loadError } = stateManager.useState();
useEffect(() => {
if (route.routeName === DashboardRoutes.Home) {
stateManager.loadDashboard(route.routeName);
} else {
stateManager.loadDashboard(match.params.uid);
if (!preloadedDashboard) {
if (route.routeName === DashboardRoutes.Home) {
stateManager.loadDashboard(route.routeName);
} else {
stateManager.loadDashboard(match.params.uid);
}
}
if (
(preloadedDashboard && preloadedDashboard.uid === match.params.uid) ||
(preloadedDashboard && preloadedDashboard.uid === null && route.routeName === DashboardRoutes.Home)
) {
stateManager.loadSceneFromDashboardModel(preloadedDashboard, route.routeName === DashboardRoutes.Home);
}
return () => {
stateManager.clearState();
};
}, [stateManager, match.params.uid, route.routeName]);
}, [stateManager, match.params.uid, route.routeName, preloadedDashboard]);
if (!dashboard) {
return (

View File

@ -2,11 +2,15 @@ import { getBackendSrv } from '@grafana/runtime';
import { StateManagerBase } from 'app/core/services/StateManagerBase';
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { DashboardModel } from 'app/features/dashboard/state';
import { DashboardDTO, DashboardRoutes } from 'app/types';
import { buildPanelEditScene, PanelEditor } from '../panel-edit/PanelEditor';
import { DashboardScene } from '../scene/DashboardScene';
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
import {
createDashboardSceneFromDashboardModel,
transformSaveModelToScene,
} from '../serialization/transformSaveModelToScene';
import { getVizPanelKeyForPanelId, findVizPanelByKey } from '../utils/utils';
export interface DashboardScenePageState {
@ -88,6 +92,22 @@ export class DashboardScenePageStateManager extends StateManagerBase<DashboardSc
throw new Error('Dashboard not found');
}
public loadSceneFromDashboardModel(model: DashboardModel, isHome?: boolean) {
const uid = isHome ? 'home' : model.uid;
if (!uid) {
return;
}
let dashboard: DashboardScene = this.cache[uid];
if (!dashboard) {
dashboard = createDashboardSceneFromDashboardModel(model);
this.cache[uid] = dashboard;
}
this.setState({ dashboard, isLoading: false });
dashboard.startUrlSync();
}
public clearState() {
getDashboardSrv().setCurrent(undefined);
this.setState({ dashboard: undefined, loadError: undefined, isLoading: false, panelEditor: undefined });

View File

@ -14,9 +14,8 @@ import {
SceneObjectStateChangedEvent,
sceneUtils,
} from '@grafana/scenes';
import { contextSrv } from 'app/core/core';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
import { AccessControlAction, DashboardMeta } from 'app/types';
import { DashboardMeta } from 'app/types';
import { DashboardSceneRenderer } from '../scene/DashboardSceneRenderer';
import { SaveDashboardDrawer } from '../serialization/SaveDashboardDrawer';
@ -254,8 +253,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
canEditDashboard() {
const { meta } = this.state;
return (
contextSrv.hasPermission(AccessControlAction.DashboardsWrite) && Boolean(meta.canEdit || meta.canMakeEditable)
);
return Boolean(meta.canEdit || meta.canMakeEditable);
}
}

View File

@ -17,15 +17,13 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
const pageNav = model.getPageNav(location);
const bodyToRender = model.getBodyToRender(viewPanelId);
const hasControls = model.canEditDashboard() && controls;
return (
<Page navId="scenes" pageNav={pageNav} layout={PageLayoutType.Custom}>
<CustomScrollbar autoHeightMin={'100%'}>
<div className={styles.canvasContent}>
<NavToolbarActions dashboard={model} />
{hasControls && (
{controls && (
<div className={styles.controls}>
{controls.map((control) => (
<control.Component key={control.state.key} model={control} />
@ -33,7 +31,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
<SceneDebugger scene={model} key={'scene-debugger'} />
</div>
)}
<div className={cx(styles.body, !hasControls && styles.bodyNoControls)}>
<div className={cx(styles.body)}>
<bodyToRender.Component model={bodyToRender} />
</div>
</div>
@ -60,9 +58,7 @@ function getStyles(theme: GrafanaTheme2) {
gap: '8px',
marginBottom: theme.spacing(2),
}),
bodyNoControls: css({
paddingTop: theme.spacing(2),
}),
controls: css({
display: 'flex',
flexWrap: 'wrap',

View File

@ -202,18 +202,25 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
});
}
const controls: SceneObject[] = [
let controls: SceneObject[] = [
new VariableValueSelectors({}),
...filtersSets,
new SceneDataLayerControls(),
new SceneControlsSpacer(),
new SceneTimePicker({}),
new SceneRefreshPicker({
refresh: oldModel.refresh,
intervals: oldModel.timepicker.refresh_intervals,
}),
];
if (!Boolean(oldModel.timepicker.hidden)) {
controls = controls.concat([
new SceneTimePicker({
hidePicker: Boolean(oldModel.timepicker.hidden),
}),
new SceneRefreshPicker({
refresh: oldModel.refresh,
intervals: oldModel.timepicker.refresh_intervals,
}),
]);
}
return new DashboardScene({
title: oldModel.title,
uid: oldModel.uid,

View File

@ -16,6 +16,7 @@ import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { getNavModel } from 'app/core/selectors/navModel';
import { newBrowseDashboardsEnabled } from 'app/features/browse-dashboards/featureFlag';
import { PanelModel } from 'app/features/dashboard/state';
import DashboardScenePage from 'app/features/dashboard-scene/pages/DashboardScenePage';
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
import { AngularDeprecationNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationNotice';
import { getPageNavFromSlug, getRootContentNavModel } from 'app/features/storage/StorageFolderPage';
@ -339,6 +340,21 @@ export class UnthemedDashboardPage extends PureComponent<Props, State> {
);
}
if (config.featureToggles.dashboardSceneForViewers) {
if (dashboard && !dashboard.meta.canEdit) {
return (
<DashboardScenePage
history={this.props.history}
location={this.props.location}
match={this.props.match}
queryParams={this.props.queryParams}
route={this.props.route}
preloadedDashboard={dashboard}
/>
);
}
}
return (
<>
<Page

View File

@ -1,28 +0,0 @@
import React from 'react';
import { config } from '@grafana/runtime';
import { contextSrv } from 'app/core/core';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import DashboardScenePage from 'app/features/dashboard-scene/pages/DashboardScenePage';
import { AccessControlAction } from 'app/types';
import DashboardPage from './DashboardPage';
import { DashboardPageRouteParams, DashboardPageRouteSearchParams } from './types';
type Props = GrafanaRouteComponentProps<DashboardPageRouteParams, DashboardPageRouteSearchParams>;
// This proxy component is used for Dashboard -> Scenes migration.
// It will render DashboardScenePage if user does not have write permissions to a dashboard.
function DashboardPageProxy(props: Props) {
if (config.featureToggles.dashboardSceneForViewers) {
if (contextSrv.hasPermission(AccessControlAction.DashboardsWrite)) {
return <DashboardPage {...props} />;
} else {
return <DashboardScenePage {...props} />;
}
}
return <DashboardPage {...props} />;
}
export default DashboardPageProxy;

View File

@ -36,7 +36,7 @@ export function getAppRoutes(): RouteDescriptor[] {
pageClass: 'page-dashboard',
routeName: DashboardRoutes.Home,
component: SafeDynamicImport(
() => import(/* webpackChunkName: "DashboardPageProxy" */ '../features/dashboard/containers/DashboardPageProxy')
() => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage')
),
},
{
@ -44,7 +44,7 @@ export function getAppRoutes(): RouteDescriptor[] {
pageClass: 'page-dashboard',
routeName: DashboardRoutes.Normal,
component: SafeDynamicImport(
() => import(/* webpackChunkName: "DashboardPageProxy" */ '../features/dashboard/containers/DashboardPageProxy')
() => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage')
),
},
{