mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Don't use proxy for rendering dashboard page
This commit is contained in:
@@ -6,27 +6,39 @@ import { Page } from 'app/core/components/Page/Page';
|
|||||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
import { DashboardPageRouteParams } from 'app/features/dashboard/containers/types';
|
import { DashboardPageRouteParams } from 'app/features/dashboard/containers/types';
|
||||||
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
import { DashboardRoutes } from 'app/types';
|
import { DashboardRoutes } from 'app/types';
|
||||||
|
|
||||||
import { getDashboardScenePageStateManager } from './DashboardScenePageStateManager';
|
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 stateManager = getDashboardScenePageStateManager();
|
||||||
const { dashboard, isLoading, loadError } = stateManager.useState();
|
const { dashboard, isLoading, loadError } = stateManager.useState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (route.routeName === DashboardRoutes.Home) {
|
if (!preloadedDashboard) {
|
||||||
stateManager.loadDashboard(route.routeName);
|
if (route.routeName === DashboardRoutes.Home) {
|
||||||
} else {
|
stateManager.loadDashboard(route.routeName);
|
||||||
stateManager.loadDashboard(match.params.uid);
|
} 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 () => {
|
return () => {
|
||||||
stateManager.clearState();
|
stateManager.clearState();
|
||||||
};
|
};
|
||||||
}, [stateManager, match.params.uid, route.routeName]);
|
}, [stateManager, match.params.uid, route.routeName, preloadedDashboard]);
|
||||||
|
|
||||||
if (!dashboard) {
|
if (!dashboard) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ import { getBackendSrv } from '@grafana/runtime';
|
|||||||
import { StateManagerBase } from 'app/core/services/StateManagerBase';
|
import { StateManagerBase } from 'app/core/services/StateManagerBase';
|
||||||
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
|
import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv';
|
||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
import { DashboardDTO, DashboardRoutes } from 'app/types';
|
import { DashboardDTO, DashboardRoutes } from 'app/types';
|
||||||
|
|
||||||
import { buildPanelEditScene, PanelEditor } from '../panel-edit/PanelEditor';
|
import { buildPanelEditScene, PanelEditor } from '../panel-edit/PanelEditor';
|
||||||
import { DashboardScene } from '../scene/DashboardScene';
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
import {
|
||||||
|
createDashboardSceneFromDashboardModel,
|
||||||
|
transformSaveModelToScene,
|
||||||
|
} from '../serialization/transformSaveModelToScene';
|
||||||
import { getVizPanelKeyForPanelId, findVizPanelByKey } from '../utils/utils';
|
import { getVizPanelKeyForPanelId, findVizPanelByKey } from '../utils/utils';
|
||||||
|
|
||||||
export interface DashboardScenePageState {
|
export interface DashboardScenePageState {
|
||||||
@@ -88,6 +92,22 @@ export class DashboardScenePageStateManager extends StateManagerBase<DashboardSc
|
|||||||
throw new Error('Dashboard not found');
|
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() {
|
public clearState() {
|
||||||
getDashboardSrv().setCurrent(undefined);
|
getDashboardSrv().setCurrent(undefined);
|
||||||
this.setState({ dashboard: undefined, loadError: undefined, isLoading: false, panelEditor: undefined });
|
this.setState({ dashboard: undefined, loadError: undefined, isLoading: false, panelEditor: undefined });
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import {
|
|||||||
SceneObjectStateChangedEvent,
|
SceneObjectStateChangedEvent,
|
||||||
sceneUtils,
|
sceneUtils,
|
||||||
} from '@grafana/scenes';
|
} from '@grafana/scenes';
|
||||||
import { contextSrv } from 'app/core/core';
|
|
||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
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 { DashboardSceneRenderer } from '../scene/DashboardSceneRenderer';
|
||||||
import { SaveDashboardDrawer } from '../serialization/SaveDashboardDrawer';
|
import { SaveDashboardDrawer } from '../serialization/SaveDashboardDrawer';
|
||||||
@@ -254,8 +253,6 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
|||||||
canEditDashboard() {
|
canEditDashboard() {
|
||||||
const { meta } = this.state;
|
const { meta } = this.state;
|
||||||
|
|
||||||
return (
|
return Boolean(meta.canEdit || meta.canMakeEditable);
|
||||||
contextSrv.hasPermission(AccessControlAction.DashboardsWrite) && Boolean(meta.canEdit || meta.canMakeEditable)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
|||||||
const pageNav = model.getPageNav(location);
|
const pageNav = model.getPageNav(location);
|
||||||
const bodyToRender = model.getBodyToRender(viewPanelId);
|
const bodyToRender = model.getBodyToRender(viewPanelId);
|
||||||
|
|
||||||
const hasControls = model.canEditDashboard() && controls;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page navId="scenes" pageNav={pageNav} layout={PageLayoutType.Custom}>
|
<Page navId="scenes" pageNav={pageNav} layout={PageLayoutType.Custom}>
|
||||||
<CustomScrollbar autoHeightMin={'100%'}>
|
<CustomScrollbar autoHeightMin={'100%'}>
|
||||||
<div className={styles.canvasContent}>
|
<div className={styles.canvasContent}>
|
||||||
<NavToolbarActions dashboard={model} />
|
<NavToolbarActions dashboard={model} />
|
||||||
|
|
||||||
{hasControls && (
|
{controls && (
|
||||||
<div className={styles.controls}>
|
<div className={styles.controls}>
|
||||||
{controls.map((control) => (
|
{controls.map((control) => (
|
||||||
<control.Component key={control.state.key} model={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'} />
|
<SceneDebugger scene={model} key={'scene-debugger'} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={cx(styles.body, !hasControls && styles.bodyNoControls)}>
|
<div className={cx(styles.body)}>
|
||||||
<bodyToRender.Component model={bodyToRender} />
|
<bodyToRender.Component model={bodyToRender} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,9 +58,7 @@ function getStyles(theme: GrafanaTheme2) {
|
|||||||
gap: '8px',
|
gap: '8px',
|
||||||
marginBottom: theme.spacing(2),
|
marginBottom: theme.spacing(2),
|
||||||
}),
|
}),
|
||||||
bodyNoControls: css({
|
|
||||||
paddingTop: theme.spacing(2),
|
|
||||||
}),
|
|
||||||
controls: css({
|
controls: css({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
|
|||||||
@@ -202,18 +202,25 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const controls: SceneObject[] = [
|
let controls: SceneObject[] = [
|
||||||
new VariableValueSelectors({}),
|
new VariableValueSelectors({}),
|
||||||
...filtersSets,
|
...filtersSets,
|
||||||
new SceneDataLayerControls(),
|
new SceneDataLayerControls(),
|
||||||
new SceneControlsSpacer(),
|
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({
|
return new DashboardScene({
|
||||||
title: oldModel.title,
|
title: oldModel.title,
|
||||||
uid: oldModel.uid,
|
uid: oldModel.uid,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
|||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { newBrowseDashboardsEnabled } from 'app/features/browse-dashboards/featureFlag';
|
import { newBrowseDashboardsEnabled } from 'app/features/browse-dashboards/featureFlag';
|
||||||
import { PanelModel } from 'app/features/dashboard/state';
|
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 { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
|
||||||
import { AngularDeprecationNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationNotice';
|
import { AngularDeprecationNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationNotice';
|
||||||
import { getPageNavFromSlug, getRootContentNavModel } from 'app/features/storage/StorageFolderPage';
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Page
|
<Page
|
||||||
|
|||||||
@@ -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;
|
|
||||||
@@ -36,7 +36,7 @@ export function getAppRoutes(): RouteDescriptor[] {
|
|||||||
pageClass: 'page-dashboard',
|
pageClass: 'page-dashboard',
|
||||||
routeName: DashboardRoutes.Home,
|
routeName: DashboardRoutes.Home,
|
||||||
component: SafeDynamicImport(
|
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',
|
pageClass: 'page-dashboard',
|
||||||
routeName: DashboardRoutes.Normal,
|
routeName: DashboardRoutes.Normal,
|
||||||
component: SafeDynamicImport(
|
component: SafeDynamicImport(
|
||||||
() => import(/* webpackChunkName: "DashboardPageProxy" */ '../features/dashboard/containers/DashboardPageProxy')
|
() => import(/* webpackChunkName: "DashboardPage" */ '../features/dashboard/containers/DashboardPage')
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user