From fc82b0286f7c45fc23a5d88047fbbba5085d949f Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Mon, 29 Jan 2024 08:13:51 -0700 Subject: [PATCH] Dashboard-Scene: Add and remove Panel Editor queries and expressions (#81027) * wip * Functionality for adding and deleting queries and expressions * Remove console.log * handle counter updates * revert unintended change * Revert tsconfig.json * revert --- .betterer.results | 3 + .../PanelDataPane/PanelDataAlertingTab.tsx | 8 +- .../PanelDataPane/PanelDataPane.tsx | 17 ++-- .../PanelDataPane/PanelDataQueriesTab.tsx | 85 ++++++++++++++++++- .../PanelDataTransformationsTab.tsx | 8 +- .../panel-edit/PanelDataPane/types.ts | 9 +- 6 files changed, 107 insertions(+), 23 deletions(-) diff --git a/.betterer.results b/.betterer.results index e60a71edb7b..948e4dab4bd 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2387,6 +2387,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/panel-edit/PanelDataPane/PanelDataPane.tsx:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], "public/app/features/dashboard-scene/panel-edit/VizPanelManager.test.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx index e7d147c19c0..5c32aab35d6 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx @@ -5,11 +5,11 @@ import { SceneObjectBase, SceneComponentProps } from '@grafana/scenes'; import { VizPanelManager } from '../VizPanelManager'; -import { PanelDataPaneTabState, PanelDataPaneTab } from './types'; +import { PanelDataPaneTabState, PanelDataPaneTab, TabId } from './types'; export class PanelDataAlertingTab extends SceneObjectBase implements PanelDataPaneTab { static Component = PanelDataAlertingTabRendered; - tabId = 'alert'; + tabId = TabId.Alert; icon: IconName = 'bell'; private _panelManager: VizPanelManager; @@ -22,10 +22,6 @@ export class PanelDataAlertingTab extends SceneObjectBase return 'Alert'; } - getItemsCount() { - return 0; - } - get panelManager() { return this._panelManager; } diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx index c85e413b18a..115e9506979 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx @@ -19,11 +19,11 @@ import { VizPanelManager } from '../VizPanelManager'; import { PanelDataAlertingTab } from './PanelDataAlertingTab'; import { PanelDataQueriesTab } from './PanelDataQueriesTab'; import { PanelDataTransformationsTab } from './PanelDataTransformationsTab'; -import { PanelDataPaneTab } from './types'; +import { PanelDataPaneTab, TabId } from './types'; export interface PanelDataPaneState extends SceneObjectState { tabs?: PanelDataPaneTab[]; - tab?: string; + tab?: TabId; } export class PanelDataPane extends SceneObjectBase { @@ -44,13 +44,13 @@ export class PanelDataPane extends SceneObjectBase { return; } if (typeof values.tab === 'string') { - this.setState({ tab: values.tab }); + this.setState({ tab: values.tab as TabId }); } } constructor(panelMgr: VizPanelManager) { super({ - tab: 'queries', + tab: TabId.Queries, }); this.panelManager = panelMgr; @@ -135,6 +135,7 @@ export class PanelDataPane extends SceneObjectBase { function PanelDataPaneRendered({ model }: SceneComponentProps) { const { tab, tabs } = model.useState(); const styles = useStyles2(getStyles); + const { queries } = model.panelManager.queryRunner.useState(); if (!tabs) { return; @@ -142,6 +143,12 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) { const currentTab = tabs.find((t) => t.tabId === tab); + const tabCounters = { + [TabId.Queries]: queries.length, + [TabId.Transformations]: 0, //TODO + [TabId.Alert]: 0, //TODO + }; + return ( <> @@ -151,7 +158,7 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) { key={`${t.getTabLabel()}-${index}`} label={t.getTabLabel()} icon={t.icon} - counter={t.getItemsCount?.()} + counter={tabCounters[t.tabId]} active={t.tabId === tab} onChangeTab={() => model.onChangeTab(t)} /> diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx index 54ec7264f33..7ddae1e3d87 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx @@ -1,17 +1,24 @@ import React from 'react'; -import { DataSourceApi, DataSourceInstanceSettings, IconName } from '@grafana/data'; +import { CoreApp, DataSourceApi, DataSourceInstanceSettings, IconName } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; +import { config } from '@grafana/runtime'; import { SceneObjectBase, SceneComponentProps, sceneGraph } from '@grafana/scenes'; import { DataQuery } from '@grafana/schema'; +import { Button, HorizontalGroup } from '@grafana/ui'; +import { addQuery } from 'app/core/utils/query'; +import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource'; +import { GroupActionComponents } from 'app/features/query/components/QueryActionComponent'; import { QueryEditorRows } from 'app/features/query/components/QueryEditorRows'; import { QueryGroupTopSection } from 'app/features/query/components/QueryGroup'; +import { isSharedDashboardQuery } from 'app/plugins/datasource/dashboard'; import { GrafanaQuery } from 'app/plugins/datasource/grafana/types'; import { QueryGroupOptions } from 'app/types'; import { PanelTimeRange } from '../../scene/PanelTimeRange'; import { VizPanelManager } from '../VizPanelManager'; -import { PanelDataPaneTabState, PanelDataPaneTab } from './types'; +import { PanelDataPaneTabState, PanelDataPaneTab, TabId } from './types'; interface PanelDataQueriesTabState extends PanelDataPaneTabState { datasource?: DataSourceApi; @@ -19,7 +26,8 @@ interface PanelDataQueriesTabState extends PanelDataPaneTabState { } export class PanelDataQueriesTab extends SceneObjectBase implements PanelDataPaneTab { static Component = PanelDataQueriesTabRendered; - tabId = 'queries'; + + tabId = TabId.Queries; icon: IconName = 'database'; private _panelManager: VizPanelManager; @@ -102,6 +110,49 @@ export class PanelDataQueriesTab extends SceneObjectBase { + const { dsSettings, datasource } = this._panelManager.state; + + const ds = !dsSettings?.meta.mixed ? dsSettings : datasource; + + return { + ...datasource?.getDefaultQuery?.(CoreApp.PanelEditor), + datasource: { uid: ds?.uid, type: ds?.type }, + }; + } + + addQueryClick = () => { + const queries = this.getQueries(); + this.onQueriesChange(addQuery(queries, this.newQuery())); + }; + + onAddQuery = (query: Partial) => { + const queries = this.getQueries(); + const dsSettings = this._panelManager.state.dsSettings; + this.onQueriesChange(addQuery(queries, query, { type: dsSettings?.type, uid: dsSettings?.uid })); + }; + + isExpressionsSupported(dsSettings: DataSourceInstanceSettings): boolean { + return (dsSettings.meta.alerting || dsSettings.meta.mixed) === true; + } + + onAddExpressionClick = () => { + const queries = this.getQueries(); + this.onQueriesChange(addQuery(queries, expressionDatasource.newQuery())); + }; + + renderExtraActions() { + return GroupActionComponents.getAllExtraRenderAction() + .map((action, index) => + action({ + onAddQuery: this.onAddQuery, + onChangeDataSource: this.onChangeDataSource, + key: index, + }) + ) + .filter(Boolean); + } + get panelManager() { return this._panelManager; } @@ -115,6 +166,8 @@ function PanelDataQueriesTabRendered({ model }: SceneComponentProps {}} + onAddQuery={model.onAddQuery} onQueriesChange={model.onQueriesChange} onRunQueries={model.onRunQueries} /> + + + {showAddButton && ( + + )} + {config.expressionsEnabled && model.isExpressionsSupported(dsSettings) && ( + + )} + {model.renderExtraActions()} + ); } diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx index 857eee7de72..4565ea6694d 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx @@ -12,7 +12,7 @@ import { VizPanelManager } from '../VizPanelManager'; import { EmptyTransformationsMessage } from './EmptyTransformationsMessage'; import { TransformationsDrawer } from './TransformationsDrawer'; -import { PanelDataPaneTabState, PanelDataPaneTab } from './types'; +import { PanelDataPaneTabState, PanelDataPaneTab, TabId } from './types'; interface PanelDataTransformationsTabState extends PanelDataPaneTabState {} @@ -21,7 +21,7 @@ export class PanelDataTransformationsTab implements PanelDataPaneTab { static Component = PanelDataTransformationsTabRendered; - tabId = 'transformations'; + tabId = TabId.Transformations; icon: IconName = 'process'; private _panelManager: VizPanelManager; @@ -29,10 +29,6 @@ export class PanelDataTransformationsTab return 'Transformations'; } - getItemsCount() { - return this._panelManager.dataTransformer.state.transformations.length; - } - constructor(panelManager: VizPanelManager) { super({}); diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/types.ts b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/types.ts index 973251b6287..783ed287dcd 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/types.ts +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/types.ts @@ -3,9 +3,14 @@ import { SceneObject, SceneObjectState } from '@grafana/scenes'; export interface PanelDataPaneTabState extends SceneObjectState {} +export enum TabId { + Queries = 'queries', + Transformations = 'transformations', + Alert = 'alert', +} + export interface PanelDataPaneTab extends SceneObject { getTabLabel(): string; - getItemsCount?(): number | null; - tabId: string; + tabId: TabId; icon: IconName; }