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
This commit is contained in:
Haris Rozajac 2024-01-29 08:13:51 -07:00 committed by GitHub
parent 26e71953a4
commit fc82b0286f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 107 additions and 23 deletions

View File

@ -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"],

View File

@ -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<PanelDataPaneTabState> 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<PanelDataPaneTabState>
return 'Alert';
}
getItemsCount() {
return 0;
}
get panelManager() {
return this._panelManager;
}

View File

@ -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<PanelDataPaneState> {
@ -44,13 +44,13 @@ export class PanelDataPane extends SceneObjectBase<PanelDataPaneState> {
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<PanelDataPaneState> {
function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
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<PanelDataPane>) {
const currentTab = tabs.find((t) => t.tabId === tab);
const tabCounters = {
[TabId.Queries]: queries.length,
[TabId.Transformations]: 0, //TODO
[TabId.Alert]: 0, //TODO
};
return (
<>
<TabsBar hideBorder={true} className={styles.tabsBar}>
@ -151,7 +158,7 @@ function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
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)}
/>

View File

@ -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<PanelDataQueriesTabState> 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<PanelDataQueriesTabStat
return this._panelManager.queryRunner.state.queries;
}
newQuery(): Partial<DataQuery> {
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<DataQuery>) => {
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<PanelDataQue
return null;
}
const showAddButton = !isSharedDashboardQuery(dsSettings.name);
return (
<>
<QueryGroupTopSection
@ -131,10 +184,34 @@ function PanelDataQueriesTabRendered({ model }: SceneComponentProps<PanelDataQue
data={data}
queries={model.getQueries()}
dsSettings={dsSettings}
onAddQuery={() => {}}
onAddQuery={model.onAddQuery}
onQueriesChange={model.onQueriesChange}
onRunQueries={model.onRunQueries}
/>
<HorizontalGroup spacing="md" align="flex-start">
{showAddButton && (
<Button
icon="plus"
onClick={model.addQueryClick}
variant="secondary"
data-testid={selectors.components.QueryTab.addQuery}
>
Add query
</Button>
)}
{config.expressionsEnabled && model.isExpressionsSupported(dsSettings) && (
<Button
icon="plus"
onClick={model.onAddExpressionClick}
variant="secondary"
data-testid="query-tab-add-expression"
>
<span>Expression&nbsp;</span>
</Button>
)}
{model.renderExtraActions()}
</HorizontalGroup>
</>
);
}

View File

@ -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({});

View File

@ -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;
}