mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 06:51:49 +08:00
DashboardScene: Pass panel id to PanelProps.id (#77927)
* Panel props id * Removing panel works * Update
This commit is contained in:
@ -161,6 +161,7 @@ Experimental features might be changed or removed without prior notice.
|
|||||||
| `annotationPermissionUpdate` | Separate annotation permissions from dashboard permissions to allow for more granular control. |
|
| `annotationPermissionUpdate` | Separate annotation permissions from dashboard permissions to allow for more granular control. |
|
||||||
| `extractFieldsNameDeduplication` | Make sure extracted field names are unique in the dataframe |
|
| `extractFieldsNameDeduplication` | Make sure extracted field names are unique in the dataframe |
|
||||||
| `dashboardSceneForViewers` | Enables dashboard rendering using Scenes for viewer roles |
|
| `dashboardSceneForViewers` | Enables dashboard rendering using Scenes for viewer roles |
|
||||||
|
| `dashboardScene` | Enables dashboard rendering using scenes for all roles |
|
||||||
| `logsInfiniteScrolling` | Enables infinite scrolling for the Logs panel in Explore and Dashboards |
|
| `logsInfiniteScrolling` | Enables infinite scrolling for the Logs panel in Explore and Dashboards |
|
||||||
| `flameGraphItemCollapsing` | Allow collapsing of flame graph items |
|
| `flameGraphItemCollapsing` | Allow collapsing of flame graph items |
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@
|
|||||||
"@grafana/lezer-traceql": "0.0.10",
|
"@grafana/lezer-traceql": "0.0.10",
|
||||||
"@grafana/monaco-logql": "^0.0.7",
|
"@grafana/monaco-logql": "^0.0.7",
|
||||||
"@grafana/runtime": "workspace:*",
|
"@grafana/runtime": "workspace:*",
|
||||||
"@grafana/scenes": "^1.20.1",
|
"@grafana/scenes": "^1.21.1",
|
||||||
"@grafana/schema": "workspace:*",
|
"@grafana/schema": "workspace:*",
|
||||||
"@grafana/ui": "workspace:*",
|
"@grafana/ui": "workspace:*",
|
||||||
"@kusto/monaco-kusto": "^7.4.0",
|
"@kusto/monaco-kusto": "^7.4.0",
|
||||||
|
@ -155,6 +155,7 @@ export interface FeatureToggles {
|
|||||||
annotationPermissionUpdate?: boolean;
|
annotationPermissionUpdate?: boolean;
|
||||||
extractFieldsNameDeduplication?: boolean;
|
extractFieldsNameDeduplication?: boolean;
|
||||||
dashboardSceneForViewers?: boolean;
|
dashboardSceneForViewers?: boolean;
|
||||||
|
dashboardScene?: boolean;
|
||||||
panelFilterVariable?: boolean;
|
panelFilterVariable?: boolean;
|
||||||
pdfTables?: boolean;
|
pdfTables?: boolean;
|
||||||
ssoSettingsApi?: boolean;
|
ssoSettingsApi?: boolean;
|
||||||
|
@ -993,6 +993,13 @@ var (
|
|||||||
FrontendOnly: true,
|
FrontendOnly: true,
|
||||||
Owner: grafanaDashboardsSquad,
|
Owner: grafanaDashboardsSquad,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "dashboardScene",
|
||||||
|
Description: "Enables dashboard rendering using scenes for all roles",
|
||||||
|
Stage: FeatureStageExperimental,
|
||||||
|
FrontendOnly: true,
|
||||||
|
Owner: grafanaDashboardsSquad,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "panelFilterVariable",
|
Name: "panelFilterVariable",
|
||||||
Description: "Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard",
|
Description: "Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard",
|
||||||
|
@ -136,6 +136,7 @@ alertmanagerRemoteOnly,experimental,@grafana/alerting-squad,false,false,false,fa
|
|||||||
annotationPermissionUpdate,experimental,@grafana/identity-access-team,false,false,false,false
|
annotationPermissionUpdate,experimental,@grafana/identity-access-team,false,false,false,false
|
||||||
extractFieldsNameDeduplication,experimental,@grafana/grafana-bi-squad,false,false,false,true
|
extractFieldsNameDeduplication,experimental,@grafana/grafana-bi-squad,false,false,false,true
|
||||||
dashboardSceneForViewers,experimental,@grafana/dashboards-squad,false,false,false,true
|
dashboardSceneForViewers,experimental,@grafana/dashboards-squad,false,false,false,true
|
||||||
|
dashboardScene,experimental,@grafana/dashboards-squad,false,false,false,true
|
||||||
panelFilterVariable,experimental,@grafana/dashboards-squad,false,false,false,true
|
panelFilterVariable,experimental,@grafana/dashboards-squad,false,false,false,true
|
||||||
pdfTables,privatePreview,@grafana/sharing-squad,false,false,false,false
|
pdfTables,privatePreview,@grafana/sharing-squad,false,false,false,false
|
||||||
ssoSettingsApi,experimental,@grafana/identity-access-team,true,false,false,false
|
ssoSettingsApi,experimental,@grafana/identity-access-team,true,false,false,false
|
||||||
|
|
@ -555,6 +555,10 @@ const (
|
|||||||
// Enables dashboard rendering using Scenes for viewer roles
|
// Enables dashboard rendering using Scenes for viewer roles
|
||||||
FlagDashboardSceneForViewers = "dashboardSceneForViewers"
|
FlagDashboardSceneForViewers = "dashboardSceneForViewers"
|
||||||
|
|
||||||
|
// FlagDashboardScene
|
||||||
|
// Enables dashboard rendering using scenes for all roles
|
||||||
|
FlagDashboardScene = "dashboardScene"
|
||||||
|
|
||||||
// FlagPanelFilterVariable
|
// FlagPanelFilterVariable
|
||||||
// Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard
|
// Enables use of the `systemPanelFilterVar` variable to filter panels in a dashboard
|
||||||
FlagPanelFilterVariable = "panelFilterVariable"
|
FlagPanelFilterVariable = "panelFilterVariable"
|
||||||
|
@ -120,6 +120,11 @@ export function setDashboardPanelContext(vizPanel: VizPanel, context: PanelConte
|
|||||||
//return onUpdatePanelSnapshotData(this.props.panel, frames);
|
//return onUpdatePanelSnapshotData(this.props.panel, frames);
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Backward compatibility with id
|
||||||
|
context.instanceState = {
|
||||||
|
legacyPanelId: getPanelIdForVizPanel(vizPanel),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBuiltInAnnotationsLayer(scene: DashboardScene): dataLayers.AnnotationsDataLayer | undefined {
|
function getBuiltInAnnotationsLayer(scene: DashboardScene): dataLayers.AnnotationsDataLayer | undefined {
|
||||||
|
@ -47,6 +47,14 @@ describe('DashboardModelCompatibilityWrapper', () => {
|
|||||||
expect(wrapper.getPanelById(1)!.title).toBe('Panel A');
|
expect(wrapper.getPanelById(1)!.title).toBe('Panel A');
|
||||||
expect(wrapper.getPanelById(2)!.title).toBe('Panel B');
|
expect(wrapper.getPanelById(2)!.title).toBe('Panel B');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Can remove panel', () => {
|
||||||
|
const { wrapper, scene } = setup();
|
||||||
|
|
||||||
|
wrapper.removePanel(wrapper.getPanelById(1)!);
|
||||||
|
|
||||||
|
expect((scene.state.body as SceneGridLayout).state.children.length).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
|
@ -2,11 +2,19 @@ import { Subscription } from 'rxjs';
|
|||||||
|
|
||||||
import { AnnotationQuery, DashboardCursorSync, dateTimeFormat, DateTimeInput, EventBusSrv } from '@grafana/data';
|
import { AnnotationQuery, DashboardCursorSync, dateTimeFormat, DateTimeInput, EventBusSrv } from '@grafana/data';
|
||||||
import { TimeRangeUpdatedEvent } from '@grafana/runtime';
|
import { TimeRangeUpdatedEvent } from '@grafana/runtime';
|
||||||
import { behaviors, SceneDataTransformer, sceneGraph, VizPanel } from '@grafana/scenes';
|
import {
|
||||||
|
behaviors,
|
||||||
|
SceneDataTransformer,
|
||||||
|
sceneGraph,
|
||||||
|
SceneGridItem,
|
||||||
|
SceneGridLayout,
|
||||||
|
SceneGridRow,
|
||||||
|
VizPanel,
|
||||||
|
} from '@grafana/scenes';
|
||||||
|
|
||||||
import { DashboardScene } from '../scene/DashboardScene';
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
|
|
||||||
import { findVizPanelByKey, getVizPanelKeyForPanelId } from './utils';
|
import { findVizPanelByKey, getPanelIdForVizPanel, getVizPanelKeyForPanelId } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will move this to make it the main way we remain somewhat compatible with getDashboardSrv().getCurrent
|
* Will move this to make it the main way we remain somewhat compatible with getDashboardSrv().getCurrent
|
||||||
@ -104,9 +112,49 @@ export class DashboardModelCompatibilityWrapper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mainly implemented to support Getting started panel's dissmis button.
|
||||||
|
*/
|
||||||
public removePanel(panel: PanelCompatibilityWrapper) {
|
public removePanel(panel: PanelCompatibilityWrapper) {
|
||||||
// TODO
|
const vizPanel = findVizPanelByKey(this._scene, getVizPanelKeyForPanelId(panel.id));
|
||||||
console.error('Scenes DashboardModelCompatibilityWrapper.removePanel not implemented (yet)');
|
if (!vizPanel) {
|
||||||
|
console.error('Trying to remove a panel that was not found in scene', panel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gridItem = vizPanel.parent;
|
||||||
|
if (!(gridItem instanceof SceneGridItem)) {
|
||||||
|
console.error('Trying to remove a panel that is not wrapped in SceneGridItem');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const layout = sceneGraph.getLayout(vizPanel);
|
||||||
|
if (!(layout instanceof SceneGridLayout)) {
|
||||||
|
console.error('Trying to remove a panel in a layout that is not SceneGridLayout ');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if grid item is directly in the layout just remove it
|
||||||
|
if (layout === gridItem.parent) {
|
||||||
|
layout.setState({
|
||||||
|
children: layout.state.children.filter((child) => child !== gridItem),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing from a row is a bit more complicated
|
||||||
|
if (gridItem.parent instanceof SceneGridRow) {
|
||||||
|
// Clone the row and remove the grid item
|
||||||
|
const newRow = layout.clone({
|
||||||
|
children: layout.state.children.filter((child) => child !== gridItem),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now update the grid layout and replace the row with the updated one
|
||||||
|
if (layout.parent instanceof SceneGridLayout) {
|
||||||
|
layout.parent.setState({
|
||||||
|
children: layout.parent.state.children.map((child) => (child === layout ? newRow : child)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public canEditAnnotations(dashboardUID?: string) {
|
public canEditAnnotations(dashboardUID?: string) {
|
||||||
@ -125,6 +173,17 @@ export class DashboardModelCompatibilityWrapper {
|
|||||||
class PanelCompatibilityWrapper {
|
class PanelCompatibilityWrapper {
|
||||||
constructor(private _vizPanel: VizPanel) {}
|
constructor(private _vizPanel: VizPanel) {}
|
||||||
|
|
||||||
|
public get id() {
|
||||||
|
const id = getPanelIdForVizPanel(this._vizPanel);
|
||||||
|
|
||||||
|
if (isNaN(id)) {
|
||||||
|
console.error('VizPanel key could not be translated to a legacy numeric panel id', this._vizPanel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public get type() {
|
public get type() {
|
||||||
return this._vizPanel.state.pluginId;
|
return this._vizPanel.state.pluginId;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ export type DashboardPageProxyProps = GrafanaRouteComponentProps<
|
|||||||
// This proxy component is used for Dashboard -> Scenes migration.
|
// This proxy component is used for Dashboard -> Scenes migration.
|
||||||
// It will render DashboardScenePage if the user is only allowed to view the dashboard.
|
// It will render DashboardScenePage if the user is only allowed to view the dashboard.
|
||||||
function DashboardPageProxy(props: DashboardPageProxyProps) {
|
function DashboardPageProxy(props: DashboardPageProxyProps) {
|
||||||
|
if (config.featureToggles.dashboardScene) {
|
||||||
|
return <DashboardScenePage {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
const stateManager = getDashboardScenePageStateManager();
|
const stateManager = getDashboardScenePageStateManager();
|
||||||
const isScenesSupportedRoute = Boolean(
|
const isScenesSupportedRoute = Boolean(
|
||||||
props.route.routeName === DashboardRoutes.Home ||
|
props.route.routeName === DashboardRoutes.Home ||
|
||||||
@ -26,6 +30,7 @@ function DashboardPageProxy(props: DashboardPageProxyProps) {
|
|||||||
|
|
||||||
// We pre-fetch dashboard to render dashboard page component depending on dashboard permissions.
|
// We pre-fetch dashboard to render dashboard page component depending on dashboard permissions.
|
||||||
// To avoid querying single dashboard multiple times, stateManager.fetchDashboard uses a simple, short-lived cache.
|
// To avoid querying single dashboard multiple times, stateManager.fetchDashboard uses a simple, short-lived cache.
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const dashboard = useAsync(async () => {
|
const dashboard = useAsync(async () => {
|
||||||
const dashToFetch = props.route.routeName === DashboardRoutes.Home ? props.route.routeName : props.match.params.uid;
|
const dashToFetch = props.route.routeName === DashboardRoutes.Home ? props.route.routeName : props.match.params.uid;
|
||||||
|
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -3320,9 +3320,9 @@ __metadata:
|
|||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@grafana/scenes@npm:^1.20.1":
|
"@grafana/scenes@npm:^1.21.1":
|
||||||
version: 1.20.1
|
version: 1.21.1
|
||||||
resolution: "@grafana/scenes@npm:1.20.1"
|
resolution: "@grafana/scenes@npm:1.21.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@grafana/e2e-selectors": "npm:10.0.2"
|
"@grafana/e2e-selectors": "npm:10.0.2"
|
||||||
react-grid-layout: "npm:1.3.4"
|
react-grid-layout: "npm:1.3.4"
|
||||||
@ -3334,7 +3334,7 @@ __metadata:
|
|||||||
"@grafana/runtime": 10.0.3
|
"@grafana/runtime": 10.0.3
|
||||||
"@grafana/schema": 10.0.3
|
"@grafana/schema": 10.0.3
|
||||||
"@grafana/ui": 10.0.3
|
"@grafana/ui": 10.0.3
|
||||||
checksum: 0edf9985ae61d5ddd0b6c015684fe06aa7c0ab3c085e0eeb0377bb5b65dccc6e91f3e53e0886d832a3e31b9b20b368027a6b1bf508e8d8ac1779cfd4789e7d20
|
checksum: f9621b0edcc5a9da2cfeac679bf9ea8d2ae6fc64c635f5bf8ee90c47cdf7a8e8799b4ef4d41b1fdee056371e9f5bfc73f5e5b2dc23852a1b05963748559fd6e9
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -17325,7 +17325,7 @@ __metadata:
|
|||||||
"@grafana/lezer-traceql": "npm:0.0.10"
|
"@grafana/lezer-traceql": "npm:0.0.10"
|
||||||
"@grafana/monaco-logql": "npm:^0.0.7"
|
"@grafana/monaco-logql": "npm:^0.0.7"
|
||||||
"@grafana/runtime": "workspace:*"
|
"@grafana/runtime": "workspace:*"
|
||||||
"@grafana/scenes": "npm:^1.20.1"
|
"@grafana/scenes": "npm:^1.21.1"
|
||||||
"@grafana/schema": "workspace:*"
|
"@grafana/schema": "workspace:*"
|
||||||
"@grafana/tsconfig": "npm:^1.3.0-rc1"
|
"@grafana/tsconfig": "npm:^1.3.0-rc1"
|
||||||
"@grafana/ui": "workspace:*"
|
"@grafana/ui": "workspace:*"
|
||||||
|
Reference in New Issue
Block a user