mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Support for dashboard PanelContext actions via state hook (#76192)
* DashboardScene: Support for dashboard PanelContext actions via state hook * Update * Progress * Update * Update * update
This commit is contained in:
parent
b6fb1e52f2
commit
de8ab7efe7
@ -2999,6 +2999,9 @@ exports[`better eslint`] = {
|
||||
"public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx:5381": [
|
||||
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/serialization/angularMigration.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
|
@ -117,6 +117,7 @@ FROM: AnnotationQuery in grafana-data/src/types/annotations.ts
|
||||
| `enable` | boolean | **Yes** | `true` | When enabled the annotation query is issued with every dashboard refresh |
|
||||
| `iconColor` | string | **Yes** | | Color to use for the annotation event markers |
|
||||
| `name` | string | **Yes** | | Name of annotation. |
|
||||
| `builtIn` | number | No | `0` | Set to 1 for the standard annotation query all dashboards have by default. |
|
||||
| `filter` | [AnnotationPanelFilter](#annotationpanelfilter) | No | | |
|
||||
| `hide` | boolean | No | `false` | Annotation queries can be toggled on or off at the top of the dashboard.<br/>When hide is true, the toggle is not shown in the dashboard. |
|
||||
| `target` | [AnnotationTarget](#annotationtarget) | No | | TODO: this should be a regular DataQuery that depends on the selected dashboard<br/>these match the properties of the "grafana" datasouce that is default in most dashboards |
|
||||
|
@ -176,6 +176,9 @@ lineage: schemas: [{
|
||||
// TODO -- this should not exist here, it is based on the --grafana-- datasource
|
||||
type?: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// Set to 1 for the standard annotation query all dashboards have by default.
|
||||
builtIn?: number | *0
|
||||
|
||||
// unless datasources have migrated to the target+mapping,
|
||||
// they just spread their query into the base object :(
|
||||
...
|
||||
|
@ -251,7 +251,7 @@
|
||||
"@grafana/lezer-traceql": "0.0.7",
|
||||
"@grafana/monaco-logql": "^0.0.7",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^1.15.0",
|
||||
"@grafana/scenes": "^1.18.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"@kusto/monaco-kusto": "^7.4.0",
|
||||
|
@ -77,6 +77,10 @@ export const defaultAnnotationContainer: Partial<AnnotationContainer> = {
|
||||
* FROM: AnnotationQuery in grafana-data/src/types/annotations.ts
|
||||
*/
|
||||
export interface AnnotationQuery {
|
||||
/**
|
||||
* Set to 1 for the standard annotation query all dashboards have by default.
|
||||
*/
|
||||
builtIn?: number;
|
||||
/**
|
||||
* Datasource where the annotations data is
|
||||
*/
|
||||
@ -113,6 +117,7 @@ export interface AnnotationQuery {
|
||||
}
|
||||
|
||||
export const defaultAnnotationQuery: Partial<AnnotationQuery> = {
|
||||
builtIn: 0,
|
||||
enable: true,
|
||||
hide: false,
|
||||
};
|
||||
|
@ -187,6 +187,9 @@ type AnnotationPanelFilter struct {
|
||||
// TODO docs
|
||||
// FROM: AnnotationQuery in grafana-data/src/types/annotations.ts
|
||||
type AnnotationQuery struct {
|
||||
// Set to 1 for the standard annotation query all dashboards have by default.
|
||||
BuiltIn *float32 `json:"builtIn,omitempty"`
|
||||
|
||||
// Ref to a DataSource instance
|
||||
Datasource DataSourceRef `json:"datasource"`
|
||||
|
||||
|
@ -213,4 +213,8 @@ export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
panelId: (panel && getPanelIdForVizPanel(panel)) ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
canEditDashboard() {
|
||||
return Boolean(this.state.meta.canEdit || this.state.meta.canMakeEditable);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export class LibraryVizPanel extends SceneObjectBase<LibraryVizPanelState> {
|
||||
});
|
||||
} catch (err) {
|
||||
vizPanel.setState({
|
||||
pluginLoadError: 'Unable to load library panel: ' + this.state.uid,
|
||||
_pluginLoadError: 'Unable to load library panel: ' + this.state.uid,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,238 @@
|
||||
import { EventBusSrv } from '@grafana/data';
|
||||
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
import { PanelContext } from '@grafana/ui';
|
||||
|
||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
||||
import { findVizPanelByKey } from '../utils/utils';
|
||||
|
||||
import { getAdHocFilterSetFor, setDashboardPanelContext } from './setDashboardPanelContext';
|
||||
|
||||
const postFn = jest.fn();
|
||||
const putFn = jest.fn();
|
||||
const deleteFn = jest.fn();
|
||||
|
||||
setBackendSrv({
|
||||
post: postFn,
|
||||
put: putFn,
|
||||
delete: deleteFn,
|
||||
} as any as BackendSrv);
|
||||
|
||||
describe('setDashboardPanelContext', () => {
|
||||
describe('canAddAnnotations', () => {
|
||||
it('Can add when builtIn is enabled and permissions allow', () => {
|
||||
const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: true });
|
||||
expect(context.canAddAnnotations!()).toBe(true);
|
||||
});
|
||||
|
||||
it('Can not when builtIn is disabled', () => {
|
||||
const { context } = buildTestScene({ builtInAnnotationsEnabled: false, dashboardCanEdit: true, canAdd: true });
|
||||
expect(context.canAddAnnotations!()).toBe(false);
|
||||
});
|
||||
|
||||
it('Can not when permission do not allow', () => {
|
||||
const { context } = buildTestScene({ builtInAnnotationsEnabled: true, dashboardCanEdit: true, canAdd: false });
|
||||
expect(context.canAddAnnotations!()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canEditAnnotations', () => {
|
||||
it('Can edit global event when user has org permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: true });
|
||||
expect(context.canEditAnnotations!()).toBe(true);
|
||||
});
|
||||
|
||||
it('Can not edit global event when has no org permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, orgCanEdit: false });
|
||||
expect(context.canEditAnnotations!()).toBe(false);
|
||||
});
|
||||
|
||||
it('Can edit dashboard event when has dashboard permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: true });
|
||||
expect(context.canEditAnnotations!('dash-uid')).toBe(true);
|
||||
});
|
||||
|
||||
it('Can not edit dashboard event when has no dashboard permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canEdit: false });
|
||||
expect(context.canEditAnnotations!('dash-uid')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canDeleteAnnotations', () => {
|
||||
it('Can delete global event when user has org permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true });
|
||||
expect(context.canDeleteAnnotations!()).toBe(true);
|
||||
});
|
||||
|
||||
it('Can not delete global event when has no org permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false });
|
||||
expect(context.canDeleteAnnotations!()).toBe(false);
|
||||
});
|
||||
|
||||
it('Can delete dashboard event when has dashboard permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: true });
|
||||
expect(context.canDeleteAnnotations!('dash-uid')).toBe(true);
|
||||
});
|
||||
|
||||
it('Can not delete dashboard event when has no dashboard permission', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canDelete: false });
|
||||
expect(context.canDeleteAnnotations!('dash-uid')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAnnotationCreate', () => {
|
||||
it('should create annotation', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
|
||||
|
||||
context.onAnnotationCreate!({ from: 100, to: 200, description: 'save it', tags: [] });
|
||||
|
||||
expect(postFn).toHaveBeenCalledWith('/api/annotations', {
|
||||
dashboardUID: 'dash-1',
|
||||
isRegion: true,
|
||||
panelId: 4,
|
||||
tags: [],
|
||||
text: 'save it',
|
||||
time: 100,
|
||||
timeEnd: 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAnnotationUpdate', () => {
|
||||
it('should update annotation', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
|
||||
|
||||
context.onAnnotationUpdate!({ from: 100, to: 200, id: 'event-id-123', description: 'updated', tags: [] });
|
||||
|
||||
expect(putFn).toHaveBeenCalledWith('/api/annotations/event-id-123', {
|
||||
id: 'event-id-123',
|
||||
dashboardUID: 'dash-1',
|
||||
isRegion: true,
|
||||
panelId: 4,
|
||||
tags: [],
|
||||
text: 'updated',
|
||||
time: 100,
|
||||
timeEnd: 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAnnotationDelete', () => {
|
||||
it('should update annotation', () => {
|
||||
const { context } = buildTestScene({ dashboardCanEdit: true, canAdd: true });
|
||||
|
||||
context.onAnnotationDelete!('I-do-not-want-you');
|
||||
|
||||
expect(deleteFn).toHaveBeenCalledWith('/api/annotations/I-do-not-want-you');
|
||||
});
|
||||
});
|
||||
|
||||
describe('onAddAdHocFilter', () => {
|
||||
it('Should add new filter set', () => {
|
||||
const { scene, context } = buildTestScene({});
|
||||
|
||||
context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' });
|
||||
|
||||
const set = getAdHocFilterSetFor(scene, { uid: 'my-ds-uid' });
|
||||
|
||||
expect(set.state.filters).toEqual([{ key: 'hello', value: 'world', operator: '=' }]);
|
||||
});
|
||||
|
||||
it('Should update and add filter to existing set', () => {
|
||||
const { scene, context } = buildTestScene({ existingFilterSet: true });
|
||||
|
||||
const set = getAdHocFilterSetFor(scene, { uid: 'my-ds-uid' });
|
||||
|
||||
set.setState({ filters: [{ key: 'existing', value: 'world', operator: '=' }] });
|
||||
|
||||
context.onAddAdHocFilter!({ key: 'hello', value: 'world', operator: '=' });
|
||||
|
||||
expect(set.state.filters.length).toBe(2);
|
||||
|
||||
// Can update existing filter value without adding a new filter
|
||||
context.onAddAdHocFilter!({ key: 'hello', value: 'world2', operator: '=' });
|
||||
// Verify existing filter value updated
|
||||
expect(set.state.filters[1].value).toBe('world2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
interface SceneOptions {
|
||||
builtInAnnotationsEnabled?: boolean;
|
||||
dashboardCanEdit?: boolean;
|
||||
canAdd?: boolean;
|
||||
canEdit?: boolean;
|
||||
canDelete?: boolean;
|
||||
orgCanEdit?: boolean;
|
||||
existingFilterSet?: boolean;
|
||||
}
|
||||
|
||||
function buildTestScene(options: SceneOptions) {
|
||||
const scene = transformSaveModelToScene({
|
||||
dashboard: {
|
||||
title: 'hello',
|
||||
uid: 'dash-1',
|
||||
schemaVersion: 38,
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
builtIn: 1,
|
||||
datasource: {
|
||||
type: 'grafana',
|
||||
uid: '-- Grafana --',
|
||||
},
|
||||
enable: options.builtInAnnotationsEnabled ?? false,
|
||||
hide: true,
|
||||
iconColor: 'rgba(0, 211, 255, 1)',
|
||||
name: 'Annotations & Alerts',
|
||||
target: { refId: 'A' },
|
||||
type: 'dashboard',
|
||||
},
|
||||
],
|
||||
},
|
||||
panels: [
|
||||
{
|
||||
type: 'timeseries',
|
||||
id: 4,
|
||||
datasource: { uid: 'my-ds-uid', type: 'prometheus' },
|
||||
targets: [],
|
||||
},
|
||||
],
|
||||
templating: {
|
||||
list: options.existingFilterSet
|
||||
? [
|
||||
{
|
||||
type: 'adhoc',
|
||||
name: 'Filters',
|
||||
datasource: { uid: 'my-ds-uid' },
|
||||
},
|
||||
]
|
||||
: [],
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
canEdit: options.dashboardCanEdit,
|
||||
annotationsPermissions: {
|
||||
dashboard: {
|
||||
canAdd: options.canAdd ?? false,
|
||||
canEdit: options.canEdit ?? false,
|
||||
canDelete: options.canDelete ?? false,
|
||||
},
|
||||
organization: {
|
||||
canAdd: false,
|
||||
canEdit: options.orgCanEdit ?? false,
|
||||
canDelete: options.canDelete ?? false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const vizPanel = findVizPanelByKey(scene, 'panel-4')!;
|
||||
const context: PanelContext = {
|
||||
eventBus: new EventBusSrv(),
|
||||
eventsScope: 'global',
|
||||
};
|
||||
|
||||
setDashboardPanelContext(vizPanel, context);
|
||||
|
||||
return { scene, vizPanel, context };
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
import { AnnotationChangeEvent, AnnotationEventUIModel, CoreApp, DataFrame } from '@grafana/data';
|
||||
import { AdHocFilterSet, dataLayers, SceneDataLayers, VizPanel } from '@grafana/scenes';
|
||||
import { DataSourceRef } from '@grafana/schema';
|
||||
import { AdHocFilterItem, PanelContext } from '@grafana/ui';
|
||||
import { deleteAnnotation, saveAnnotation, updateAnnotation } from 'app/features/annotations/api';
|
||||
|
||||
import { getDashboardSceneFor, getPanelIdForVizPanel, getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
|
||||
export function setDashboardPanelContext(vizPanel: VizPanel, context: PanelContext) {
|
||||
context.app = CoreApp.Dashboard;
|
||||
|
||||
context.canAddAnnotations = () => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
const builtInLayer = getBuiltInAnnotationsLayer(dashboard);
|
||||
|
||||
// When there is no builtin annotations query we disable the ability to add annotations
|
||||
if (!builtInLayer || !dashboard.canEditDashboard()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If RBAC is enabled there are additional conditions to check.
|
||||
return Boolean(dashboard.state.meta.annotationsPermissions?.dashboard.canAdd);
|
||||
};
|
||||
|
||||
context.canEditAnnotations = (dashboardUID?: string) => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
|
||||
if (!dashboard.canEditDashboard()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dashboardUID) {
|
||||
return Boolean(dashboard.state.meta.annotationsPermissions?.dashboard.canEdit);
|
||||
}
|
||||
|
||||
return Boolean(dashboard.state.meta.annotationsPermissions?.organization.canEdit);
|
||||
};
|
||||
|
||||
context.canDeleteAnnotations = (dashboardUID?: string) => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
|
||||
if (!dashboard.canEditDashboard()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dashboardUID) {
|
||||
return Boolean(dashboard.state.meta.annotationsPermissions?.dashboard.canDelete);
|
||||
}
|
||||
|
||||
return Boolean(dashboard.state.meta.annotationsPermissions?.organization.canDelete);
|
||||
};
|
||||
|
||||
context.onAnnotationCreate = async (event: AnnotationEventUIModel) => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
|
||||
const isRegion = event.from !== event.to;
|
||||
const anno = {
|
||||
dashboardUID: dashboard.state.uid,
|
||||
panelId: getPanelIdForVizPanel(vizPanel),
|
||||
isRegion,
|
||||
time: event.from,
|
||||
timeEnd: isRegion ? event.to : 0,
|
||||
tags: event.tags,
|
||||
text: event.description,
|
||||
};
|
||||
|
||||
await saveAnnotation(anno);
|
||||
|
||||
reRunBuiltInAnnotationsLayer(dashboard);
|
||||
|
||||
context.eventBus.publish(new AnnotationChangeEvent(anno));
|
||||
};
|
||||
|
||||
context.onAnnotationUpdate = async (event: AnnotationEventUIModel) => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
|
||||
const isRegion = event.from !== event.to;
|
||||
const anno = {
|
||||
id: event.id,
|
||||
dashboardUID: dashboard.state.uid,
|
||||
panelId: getPanelIdForVizPanel(vizPanel),
|
||||
isRegion,
|
||||
time: event.from,
|
||||
timeEnd: isRegion ? event.to : 0,
|
||||
tags: event.tags,
|
||||
text: event.description,
|
||||
};
|
||||
|
||||
await updateAnnotation(anno);
|
||||
|
||||
reRunBuiltInAnnotationsLayer(dashboard);
|
||||
|
||||
context.eventBus.publish(new AnnotationChangeEvent(anno));
|
||||
};
|
||||
|
||||
context.onAnnotationDelete = async (id: string) => {
|
||||
await deleteAnnotation({ id });
|
||||
|
||||
reRunBuiltInAnnotationsLayer(getDashboardSceneFor(vizPanel));
|
||||
|
||||
context.eventBus.publish(new AnnotationChangeEvent({ id }));
|
||||
};
|
||||
|
||||
context.onAddAdHocFilter = (newFilter: AdHocFilterItem) => {
|
||||
const dashboard = getDashboardSceneFor(vizPanel);
|
||||
|
||||
const queryRunner = getQueryRunnerFor(vizPanel);
|
||||
if (!queryRunner) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filterSet = getAdHocFilterSetFor(dashboard, queryRunner.state.datasource);
|
||||
updateAdHocFilterSet(filterSet, newFilter);
|
||||
};
|
||||
|
||||
context.onUpdateData = (frames: DataFrame[]): Promise<boolean> => {
|
||||
// TODO
|
||||
//return onUpdatePanelSnapshotData(this.props.panel, frames);
|
||||
return Promise.resolve(true);
|
||||
};
|
||||
}
|
||||
|
||||
function getBuiltInAnnotationsLayer(scene: DashboardScene): dataLayers.AnnotationsDataLayer | undefined {
|
||||
// When there is no builtin annotations query we disable the ability to add annotations
|
||||
if (scene.state.$data instanceof SceneDataLayers) {
|
||||
for (const layer of scene.state.$data.state.layers) {
|
||||
if (layer instanceof dataLayers.AnnotationsDataLayer) {
|
||||
if (layer.state.isEnabled && layer.state.query.builtIn) {
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function reRunBuiltInAnnotationsLayer(scene: DashboardScene) {
|
||||
const layer = getBuiltInAnnotationsLayer(scene);
|
||||
if (layer) {
|
||||
layer.runLayer();
|
||||
}
|
||||
}
|
||||
|
||||
export function getAdHocFilterSetFor(scene: DashboardScene, ds: DataSourceRef | null | undefined) {
|
||||
const controls = scene.state.controls ?? [];
|
||||
|
||||
for (const control of controls) {
|
||||
if (control instanceof AdHocFilterSet) {
|
||||
if (control.state.datasource === ds || control.state.datasource?.uid === ds?.uid) {
|
||||
return control;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newSet = new AdHocFilterSet({ datasource: ds });
|
||||
|
||||
// Add it to the scene
|
||||
scene.setState({
|
||||
controls: [controls[0], newSet, ...controls.slice(1)],
|
||||
});
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
function updateAdHocFilterSet(filterSet: AdHocFilterSet, newFilter: AdHocFilterItem) {
|
||||
// Check if we need to update an existing filter
|
||||
for (const filter of filterSet.state.filters) {
|
||||
if (filter.key === newFilter.key) {
|
||||
filterSet.setState({
|
||||
filters: filterSet.state.filters.map((f) => {
|
||||
if (f.key === newFilter.key) {
|
||||
return newFilter;
|
||||
}
|
||||
return f;
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add new filter
|
||||
filterSet.setState({
|
||||
filters: [...filterSet.state.filters, newFilter],
|
||||
});
|
||||
}
|
@ -91,8 +91,8 @@ describe('transformSaveModelToScene', () => {
|
||||
expect(scene.state?.$timeRange?.state.weekStart).toEqual('saturday');
|
||||
expect(scene.state?.$variables?.state.variables).toHaveLength(1);
|
||||
expect(scene.state.controls).toBeDefined();
|
||||
expect(scene.state.controls![2]).toBeInstanceOf(AdHocFilterSet);
|
||||
expect((scene.state.controls![2] as AdHocFilterSet).state.name).toBe('CoolFilters');
|
||||
expect(scene.state.controls![1]).toBeInstanceOf(AdHocFilterSet);
|
||||
expect((scene.state.controls![1] as AdHocFilterSet).state.name).toBe('CoolFilters');
|
||||
});
|
||||
|
||||
it('should apply cursor sync behavior', () => {
|
||||
@ -668,7 +668,7 @@ describe('transformSaveModelToScene', () => {
|
||||
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
|
||||
|
||||
expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
|
||||
expect(scene.state.controls![0]).toBeInstanceOf(SceneDataLayerControls);
|
||||
expect(scene.state.controls![2]).toBeInstanceOf(SceneDataLayerControls);
|
||||
|
||||
const dataLayers = scene.state.$data as SceneDataLayers;
|
||||
expect(dataLayers.state.layers).toHaveLength(4);
|
||||
|
@ -43,6 +43,7 @@ import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { RowRepeaterBehavior } from '../scene/RowRepeaterBehavior';
|
||||
import { setDashboardPanelContext } from '../scene/setDashboardPanelContext';
|
||||
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
@ -200,9 +201,9 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
|
||||
}
|
||||
|
||||
const controls: SceneObject[] = [
|
||||
new SceneDataLayerControls(),
|
||||
new VariableValueSelectors({}),
|
||||
...filtersSets,
|
||||
new SceneDataLayerControls(),
|
||||
new SceneControlsSpacer(),
|
||||
new SceneTimePicker({}),
|
||||
new SceneRefreshPicker({
|
||||
@ -340,6 +341,7 @@ export function buildGridItemForPanel(panel: PanelModel): SceneGridItemLike {
|
||||
menu: new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
}),
|
||||
extendPanelContext: setDashboardPanelContext,
|
||||
_UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel),
|
||||
};
|
||||
|
||||
|
@ -336,7 +336,6 @@ export function trimDashboardForSnapshot(title: string, time: TimeRange, dash: D
|
||||
enable: annotation.enable,
|
||||
iconColor: annotation.iconColor,
|
||||
type: annotation.type,
|
||||
// @ts-expect-error
|
||||
builtIn: annotation.builtIn,
|
||||
hide: annotation.hide,
|
||||
// TODO: Remove when we migrate snapshots to snapshot queries.
|
||||
|
10
yarn.lock
10
yarn.lock
@ -3226,9 +3226,9 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes@npm:^1.15.0":
|
||||
version: 1.17.0
|
||||
resolution: "@grafana/scenes@npm:1.17.0"
|
||||
"@grafana/scenes@npm:^1.18.0":
|
||||
version: 1.18.0
|
||||
resolution: "@grafana/scenes@npm:1.18.0"
|
||||
dependencies:
|
||||
"@grafana/e2e-selectors": 10.0.2
|
||||
react-grid-layout: 1.3.4
|
||||
@ -3240,7 +3240,7 @@ __metadata:
|
||||
"@grafana/runtime": 10.0.3
|
||||
"@grafana/schema": 10.0.3
|
||||
"@grafana/ui": 10.0.3
|
||||
checksum: 0bd8603ae59c199c595a45a7bc31e318a1928b18307469bcd5ee5f83c3aaee89c5c27a1341a479440d928505681ab6a2479809a5cac56e8e93ba7acf06adff93
|
||||
checksum: 395e4ef7a01b963df5f3aac3adc2e82c8d409e2679c8ed428137f66ebbbc84570458d1a36db31080622848e86c8e2e82f780e2a1257de0ea61152a41e8650516
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -17521,7 +17521,7 @@ __metadata:
|
||||
"@grafana/lezer-traceql": 0.0.7
|
||||
"@grafana/monaco-logql": ^0.0.7
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/scenes": ^1.15.0
|
||||
"@grafana/scenes": ^1.18.0
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/tsconfig": ^1.3.0-rc1
|
||||
"@grafana/ui": "workspace:*"
|
||||
|
Loading…
Reference in New Issue
Block a user