diff --git a/.betterer.results b/.betterer.results
index d20cfea18c1..e768dc7999e 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -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"]
diff --git a/docs/sources/developers/kinds/core/dashboard/schema-reference.md b/docs/sources/developers/kinds/core/dashboard/schema-reference.md
index 37206a725c2..42b36f9f486 100644
--- a/docs/sources/developers/kinds/core/dashboard/schema-reference.md
+++ b/docs/sources/developers/kinds/core/dashboard/schema-reference.md
@@ -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.
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
these match the properties of the "grafana" datasouce that is default in most dashboards |
diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue
index 0b32ebff3da..1fb83373166 100644
--- a/kinds/dashboard/dashboard_kind.cue
+++ b/kinds/dashboard/dashboard_kind.cue
@@ -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 :(
...
diff --git a/package.json b/package.json
index 59dbf0ae61e..6cb3d51ca65 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
index 99c9b16090d..d16491351f7 100644
--- a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
+++ b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
@@ -77,6 +77,10 @@ export const defaultAnnotationContainer: Partial = {
* 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 = {
+ builtIn: 0,
enable: true,
hide: false,
};
diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go
index ca5b81891a3..e5be145cffa 100644
--- a/pkg/kinds/dashboard/dashboard_spec_gen.go
+++ b/pkg/kinds/dashboard/dashboard_spec_gen.go
@@ -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"`
diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
index a31f99b2423..2ccfde78141 100644
--- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
@@ -213,4 +213,8 @@ export class DashboardScene extends SceneObjectBase {
panelId: (panel && getPanelIdForVizPanel(panel)) ?? 0,
};
}
+
+ canEditDashboard() {
+ return Boolean(this.state.meta.canEdit || this.state.meta.canMakeEditable);
+ }
}
diff --git a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
index b15c8ef7894..ce09b6269f6 100644
--- a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
+++ b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
@@ -42,7 +42,7 @@ export class LibraryVizPanel extends SceneObjectBase {
});
} catch (err) {
vizPanel.setState({
- pluginLoadError: 'Unable to load library panel: ' + this.state.uid,
+ _pluginLoadError: 'Unable to load library panel: ' + this.state.uid,
});
}
diff --git a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts
new file mode 100644
index 00000000000..149dce0d119
--- /dev/null
+++ b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts
@@ -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 };
+}
diff --git a/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts
new file mode 100644
index 00000000000..5689ee6c4e8
--- /dev/null
+++ b/public/app/features/dashboard-scene/scene/setDashboardPanelContext.ts
@@ -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 => {
+ // 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],
+ });
+}
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
index 21470a4c2f7..17cc17ea60f 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
@@ -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);
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
index feb796f7b89..036aeaa44d2 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
@@ -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),
};
diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
index 795a7a50b67..c3ad9af03a4 100644
--- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
@@ -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.
diff --git a/yarn.lock b/yarn.lock
index 2a636b6a515..1f2cf16e54c 100644
--- a/yarn.lock
+++ b/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:*"