mirror of https://github.com/grafana/grafana.git
				
				
				
			DashboardScene: Alert states data layer (#77945)
* Add AlertStates data topic * DashboardScene: Alert states data layer * TMP package json * Remove duplicated function * Use latest scenes canry * Use latest scenes and add transformation test
This commit is contained in:
		
							parent
							
								
									ea12eecac5
								
							
						
					
					
						commit
						a3ae9d418d
					
				| 
						 | 
				
			
			@ -2873,7 +2873,9 @@ exports[`better eslint`] = {
 | 
			
		|||
    ],
 | 
			
		||||
    "public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts:5381": [
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "1"]
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "1"],
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "2"],
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "3"]
 | 
			
		||||
    ],
 | 
			
		||||
    "public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.test.ts:5381": [
 | 
			
		||||
      [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -254,7 +254,7 @@
 | 
			
		|||
    "@grafana/lezer-traceql": "0.0.10",
 | 
			
		||||
    "@grafana/monaco-logql": "^0.0.7",
 | 
			
		||||
    "@grafana/runtime": "workspace:*",
 | 
			
		||||
    "@grafana/scenes": "^1.21.1",
 | 
			
		||||
    "@grafana/scenes": "^1.22.0",
 | 
			
		||||
    "@grafana/schema": "workspace:*",
 | 
			
		||||
    "@grafana/ui": "workspace:*",
 | 
			
		||||
    "@kusto/monaco-kusto": "^7.4.0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ export interface DataSourceRef extends SchemaDataSourceRef {}
 | 
			
		|||
 */
 | 
			
		||||
export enum DataTopic {
 | 
			
		||||
  Annotations = 'annotations',
 | 
			
		||||
  AlertStates = 'alertStates',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,227 @@
 | 
			
		|||
import { from, map, Unsubscribable, Observable } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
import { AlertState, AlertStateInfo, DataTopic, LoadingState, toDataFrame } from '@grafana/data';
 | 
			
		||||
import { config, getBackendSrv } from '@grafana/runtime';
 | 
			
		||||
import {
 | 
			
		||||
  SceneDataLayerBase,
 | 
			
		||||
  SceneDataLayerProvider,
 | 
			
		||||
  SceneDataLayerProviderState,
 | 
			
		||||
  sceneGraph,
 | 
			
		||||
  SceneTimeRangeLike,
 | 
			
		||||
} from '@grafana/scenes';
 | 
			
		||||
import { notifyApp } from 'app/core/actions';
 | 
			
		||||
import { createErrorNotification } from 'app/core/copy/appNotification';
 | 
			
		||||
import { contextSrv } from 'app/core/core';
 | 
			
		||||
import { getMessageFromError } from 'app/core/utils/errors';
 | 
			
		||||
import { Annotation } from 'app/features/alerting/unified/utils/constants';
 | 
			
		||||
import { isAlertingRule } from 'app/features/alerting/unified/utils/rules';
 | 
			
		||||
import { dispatch } from 'app/store/store';
 | 
			
		||||
import { AccessControlAction } from 'app/types';
 | 
			
		||||
import { PromAlertingRuleState, PromRulesResponse } from 'app/types/unified-alerting-dto';
 | 
			
		||||
 | 
			
		||||
import { getDashboardSceneFor } from '../utils/utils';
 | 
			
		||||
 | 
			
		||||
interface AlertStatesDataLayerState extends SceneDataLayerProviderState {}
 | 
			
		||||
 | 
			
		||||
export class AlertStatesDataLayer
 | 
			
		||||
  extends SceneDataLayerBase<AlertStatesDataLayerState>
 | 
			
		||||
  implements SceneDataLayerProvider
 | 
			
		||||
{
 | 
			
		||||
  private hasAlertRules = true;
 | 
			
		||||
  private _timeRangeSub: Unsubscribable | undefined;
 | 
			
		||||
  public topic = DataTopic.AlertStates;
 | 
			
		||||
 | 
			
		||||
  public constructor(initialState: AlertStatesDataLayerState) {
 | 
			
		||||
    super({
 | 
			
		||||
      isEnabled: true,
 | 
			
		||||
      ...initialState,
 | 
			
		||||
      isHidden: true,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onEnable(): void {
 | 
			
		||||
    const timeRange = sceneGraph.getTimeRange(this);
 | 
			
		||||
 | 
			
		||||
    this._timeRangeSub = timeRange.subscribeToState(() => {
 | 
			
		||||
      this.runWithTimeRange(timeRange);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public onDisable(): void {
 | 
			
		||||
    this._timeRangeSub?.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public runLayer() {
 | 
			
		||||
    const timeRange = sceneGraph.getTimeRange(this);
 | 
			
		||||
    this.runWithTimeRange(timeRange);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async runWithTimeRange(timeRange: SceneTimeRangeLike) {
 | 
			
		||||
    const dashboard = getDashboardSceneFor(this);
 | 
			
		||||
    const { uid, id } = dashboard.state;
 | 
			
		||||
 | 
			
		||||
    if (this.querySub) {
 | 
			
		||||
      this.querySub.unsubscribe();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!this.canWork(timeRange)) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let alerStatesExecution: Observable<AlertStateInfo[]> | undefined;
 | 
			
		||||
 | 
			
		||||
    if (this.isUsingLegacyAlerting()) {
 | 
			
		||||
      alerStatesExecution = from(
 | 
			
		||||
        getBackendSrv().get(
 | 
			
		||||
          '/api/alerts/states-for-dashboard',
 | 
			
		||||
          {
 | 
			
		||||
            dashboardId: id,
 | 
			
		||||
          },
 | 
			
		||||
          `dashboard-query-runner-alert-states-${id}`
 | 
			
		||||
        )
 | 
			
		||||
      ).pipe(map((alertStates) => alertStates));
 | 
			
		||||
    } else {
 | 
			
		||||
      alerStatesExecution = from(
 | 
			
		||||
        getBackendSrv().get(
 | 
			
		||||
          '/api/prometheus/grafana/api/v1/rules',
 | 
			
		||||
          {
 | 
			
		||||
            dashboard_uid: uid!,
 | 
			
		||||
          },
 | 
			
		||||
          `dashboard-query-runner-unified-alert-states-${id}`
 | 
			
		||||
        )
 | 
			
		||||
      ).pipe(
 | 
			
		||||
        map((result: PromRulesResponse) => {
 | 
			
		||||
          if (result.status === 'success') {
 | 
			
		||||
            this.hasAlertRules = false;
 | 
			
		||||
            const panelIdToAlertState: Record<number, AlertStateInfo> = {};
 | 
			
		||||
 | 
			
		||||
            result.data.groups.forEach((group) =>
 | 
			
		||||
              group.rules.forEach((rule) => {
 | 
			
		||||
                if (isAlertingRule(rule) && rule.annotations && rule.annotations[Annotation.panelID]) {
 | 
			
		||||
                  this.hasAlertRules = true;
 | 
			
		||||
                  const panelId = Number(rule.annotations[Annotation.panelID]);
 | 
			
		||||
                  const state = promAlertStateToAlertState(rule.state);
 | 
			
		||||
 | 
			
		||||
                  // there can be multiple alerts per panel, so we make sure we get the most severe state:
 | 
			
		||||
                  // alerting > pending > ok
 | 
			
		||||
                  if (!panelIdToAlertState[panelId]) {
 | 
			
		||||
                    panelIdToAlertState[panelId] = {
 | 
			
		||||
                      state,
 | 
			
		||||
                      id: Object.keys(panelIdToAlertState).length,
 | 
			
		||||
                      panelId,
 | 
			
		||||
                      dashboardId: id!,
 | 
			
		||||
                    };
 | 
			
		||||
                  } else if (
 | 
			
		||||
                    state === AlertState.Alerting &&
 | 
			
		||||
                    panelIdToAlertState[panelId].state !== AlertState.Alerting
 | 
			
		||||
                  ) {
 | 
			
		||||
                    panelIdToAlertState[panelId].state = AlertState.Alerting;
 | 
			
		||||
                  } else if (
 | 
			
		||||
                    state === AlertState.Pending &&
 | 
			
		||||
                    panelIdToAlertState[panelId].state !== AlertState.Alerting &&
 | 
			
		||||
                    panelIdToAlertState[panelId].state !== AlertState.Pending
 | 
			
		||||
                  ) {
 | 
			
		||||
                    panelIdToAlertState[panelId].state = AlertState.Pending;
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              })
 | 
			
		||||
            );
 | 
			
		||||
            return Object.values(panelIdToAlertState);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          throw new Error(`Unexpected alert rules response.`);
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    this.querySub = alerStatesExecution.subscribe({
 | 
			
		||||
      next: (stateUpdate) => {
 | 
			
		||||
        this.publishResults(
 | 
			
		||||
          {
 | 
			
		||||
            state: LoadingState.Done,
 | 
			
		||||
            series: [toDataFrame(stateUpdate)],
 | 
			
		||||
            timeRange: timeRange.state.value,
 | 
			
		||||
          },
 | 
			
		||||
          DataTopic.AlertStates
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
      error: (err) => {
 | 
			
		||||
        this.handleError(err);
 | 
			
		||||
        this.publishResults(
 | 
			
		||||
          {
 | 
			
		||||
            state: LoadingState.Error,
 | 
			
		||||
            series: [],
 | 
			
		||||
            errors: [
 | 
			
		||||
              {
 | 
			
		||||
                message: getMessageFromError(err),
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
            timeRange: timeRange.state.value,
 | 
			
		||||
          },
 | 
			
		||||
          DataTopic.AlertStates
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private canWork(timeRange: SceneTimeRangeLike): boolean {
 | 
			
		||||
    const dashboard = getDashboardSceneFor(this);
 | 
			
		||||
    const { uid, id } = dashboard.state;
 | 
			
		||||
 | 
			
		||||
    if (this.isUsingLegacyAlerting()) {
 | 
			
		||||
      if (!id) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (timeRange.state.value.raw.to !== 'now') {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (!uid) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Cannot fetch rules while on a public dashboard since it's unauthenticated
 | 
			
		||||
      if (config.publicDashboardAccessToken) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (timeRange.state.value.raw.to !== 'now') {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.hasAlertRules === false) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const hasRuleReadPermission =
 | 
			
		||||
        contextSrv.hasPermission(AccessControlAction.AlertingRuleRead) &&
 | 
			
		||||
        contextSrv.hasPermission(AccessControlAction.AlertingRuleExternalRead);
 | 
			
		||||
 | 
			
		||||
      if (!hasRuleReadPermission) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private isUsingLegacyAlerting(): boolean {
 | 
			
		||||
    return !config.unifiedAlertingEnabled;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private handleError = (err: unknown) => {
 | 
			
		||||
    const notification = createErrorNotification('AlertStatesDataLayer', getMessageFromError(err));
 | 
			
		||||
    dispatch(notifyApp(notification));
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function promAlertStateToAlertState(state: PromAlertingRuleState): AlertState {
 | 
			
		||||
  if (state === PromAlertingRuleState.Firing) {
 | 
			
		||||
    return AlertState.Alerting;
 | 
			
		||||
  } else if (state === PromAlertingRuleState.Pending) {
 | 
			
		||||
    return AlertState.Pending;
 | 
			
		||||
  }
 | 
			
		||||
  return AlertState.OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
 | 
			
		|||
import { createPanelSaveModel } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
 | 
			
		||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
 | 
			
		||||
import { DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plugins/datasource/dashboard/types';
 | 
			
		||||
import { DashboardDataDTO } from 'app/types';
 | 
			
		||||
 | 
			
		||||
import { PanelRepeaterGridItem } from '../scene/PanelRepeaterGridItem';
 | 
			
		||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
 | 
			
		||||
| 
						 | 
				
			
			@ -743,6 +744,34 @@ describe('transformSaveModelToScene', () => {
 | 
			
		|||
      expect(dataLayers.state.layers[3].state.isHidden).toBe(true);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('Alerting data layer', () => {
 | 
			
		||||
    it('Should add alert states data layer if unified alerting enabled', () => {
 | 
			
		||||
      config.unifiedAlertingEnabled = true;
 | 
			
		||||
      const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
 | 
			
		||||
 | 
			
		||||
      expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
 | 
			
		||||
      expect(scene.state.controls![2]).toBeInstanceOf(SceneDataLayerControls);
 | 
			
		||||
 | 
			
		||||
      const dataLayers = scene.state.$data as SceneDataLayers;
 | 
			
		||||
      expect(dataLayers.state.layers).toHaveLength(5);
 | 
			
		||||
      expect(dataLayers.state.layers[4].state.name).toBe('Alert States');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('Should add alert states data layer if any panel has a legacy alert defined', () => {
 | 
			
		||||
      config.unifiedAlertingEnabled = false;
 | 
			
		||||
      const dashboard = { ...dashboard_to_load1 } as unknown as DashboardDataDTO;
 | 
			
		||||
      dashboard.panels![0].alert = {};
 | 
			
		||||
      const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
 | 
			
		||||
 | 
			
		||||
      expect(scene.state.$data).toBeInstanceOf(SceneDataLayers);
 | 
			
		||||
      expect(scene.state.controls![2]).toBeInstanceOf(SceneDataLayerControls);
 | 
			
		||||
 | 
			
		||||
      const dataLayers = scene.state.$data as SceneDataLayers;
 | 
			
		||||
      expect(dataLayers.state.layers).toHaveLength(5);
 | 
			
		||||
      expect(dataLayers.state.layers[4].state.name).toBe('Alert States');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function buildGridItemForTest(saveModel: Partial<Panel>): { gridItem: SceneGridItem; vizPanel: VizPanel } {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import { AdHocVariableModel, TypedVariableModel, VariableModel } from '@grafana/data';
 | 
			
		||||
import { config } from '@grafana/runtime';
 | 
			
		||||
import {
 | 
			
		||||
  VizPanel,
 | 
			
		||||
  SceneTimePicker,
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +30,7 @@ import {
 | 
			
		|||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
 | 
			
		||||
import { DashboardDTO } from 'app/types';
 | 
			
		||||
 | 
			
		||||
import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer';
 | 
			
		||||
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
 | 
			
		||||
import { DashboardScene } from '../scene/DashboardScene';
 | 
			
		||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +189,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
 | 
			
		|||
    layers = oldModel.annotations?.list.map((a) => {
 | 
			
		||||
      // Each annotation query is an individual data layer
 | 
			
		||||
      return new DashboardAnnotationsDataLayer({
 | 
			
		||||
        key: `annnotations-${a.name}`,
 | 
			
		||||
        query: a,
 | 
			
		||||
        name: a.name,
 | 
			
		||||
        isEnabled: Boolean(a.enable),
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +198,22 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let shouldUseAlertStatesLayer = config.unifiedAlertingEnabled;
 | 
			
		||||
  if (!shouldUseAlertStatesLayer) {
 | 
			
		||||
    if (oldModel.panels.find((panel) => Boolean(panel.alert))) {
 | 
			
		||||
      shouldUseAlertStatesLayer = true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (shouldUseAlertStatesLayer) {
 | 
			
		||||
    layers.push(
 | 
			
		||||
      new AlertStatesDataLayer({
 | 
			
		||||
        key: 'alert-states',
 | 
			
		||||
        name: 'Alert States',
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let controls: SceneObject[] = [
 | 
			
		||||
    new VariableValueSelectors({}),
 | 
			
		||||
    ...filtersSets,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,8 +6,9 @@ import { config, getBackendSrv } from '@grafana/runtime';
 | 
			
		|||
import { contextSrv } from 'app/core/services/context_srv';
 | 
			
		||||
import { Annotation } from 'app/features/alerting/unified/utils/constants';
 | 
			
		||||
import { isAlertingRule } from 'app/features/alerting/unified/utils/rules';
 | 
			
		||||
import { promAlertStateToAlertState } from 'app/features/dashboard-scene/scene/AlertStatesDataLayer';
 | 
			
		||||
import { AccessControlAction } from 'app/types';
 | 
			
		||||
import { PromAlertingRuleState, PromRulesResponse } from 'app/types/unified-alerting-dto';
 | 
			
		||||
import { PromRulesResponse } from 'app/types/unified-alerting-dto';
 | 
			
		||||
 | 
			
		||||
import { DashboardQueryRunnerOptions, DashboardQueryRunnerWorker, DashboardQueryRunnerWorkerResult } from './types';
 | 
			
		||||
import { emptyResult, handleDashboardQueryRunnerWorkerError } from './utils';
 | 
			
		||||
| 
						 | 
				
			
			@ -105,12 +106,3 @@ export class UnifiedAlertStatesWorker implements DashboardQueryRunnerWorker {
 | 
			
		|||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function promAlertStateToAlertState(state: PromAlertingRuleState): AlertState {
 | 
			
		||||
  if (state === PromAlertingRuleState.Firing) {
 | 
			
		||||
    return AlertState.Alerting;
 | 
			
		||||
  } else if (state === PromAlertingRuleState.Pending) {
 | 
			
		||||
    return AlertState.Pending;
 | 
			
		||||
  }
 | 
			
		||||
  return AlertState.OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										10
									
								
								yarn.lock
								
								
								
								
							| 
						 | 
				
			
			@ -3320,9 +3320,9 @@ __metadata:
 | 
			
		|||
  languageName: unknown
 | 
			
		||||
  linkType: soft
 | 
			
		||||
 | 
			
		||||
"@grafana/scenes@npm:^1.21.1":
 | 
			
		||||
  version: 1.21.1
 | 
			
		||||
  resolution: "@grafana/scenes@npm:1.21.1"
 | 
			
		||||
"@grafana/scenes@npm:^1.22.0":
 | 
			
		||||
  version: 1.22.0
 | 
			
		||||
  resolution: "@grafana/scenes@npm:1.22.0"
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@grafana/e2e-selectors": "npm:10.0.2"
 | 
			
		||||
    react-grid-layout: "npm:1.3.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -3334,7 +3334,7 @@ __metadata:
 | 
			
		|||
    "@grafana/runtime": 10.0.3
 | 
			
		||||
    "@grafana/schema": 10.0.3
 | 
			
		||||
    "@grafana/ui": 10.0.3
 | 
			
		||||
  checksum: f9621b0edcc5a9da2cfeac679bf9ea8d2ae6fc64c635f5bf8ee90c47cdf7a8e8799b4ef4d41b1fdee056371e9f5bfc73f5e5b2dc23852a1b05963748559fd6e9
 | 
			
		||||
  checksum: 6067bccec76de3f5aeab15c943095cf11e407b5734ddab4dc52ed40e469f65b096d69b7b0f46e5abe0a51c6691651c8ca8609177b95a32a2419239068a337952
 | 
			
		||||
  languageName: node
 | 
			
		||||
  linkType: hard
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17325,7 +17325,7 @@ __metadata:
 | 
			
		|||
    "@grafana/lezer-traceql": "npm:0.0.10"
 | 
			
		||||
    "@grafana/monaco-logql": "npm:^0.0.7"
 | 
			
		||||
    "@grafana/runtime": "workspace:*"
 | 
			
		||||
    "@grafana/scenes": "npm:^1.21.1"
 | 
			
		||||
    "@grafana/scenes": "npm:^1.22.0"
 | 
			
		||||
    "@grafana/schema": "workspace:*"
 | 
			
		||||
    "@grafana/tsconfig": "npm:^1.3.0-rc1"
 | 
			
		||||
    "@grafana/ui": "workspace:*"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue