Files
grafana/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
Dominik Prokop a385ae4fa5 DashboardScene: Do not show data pane for panels with skipDataQuery (#81934)
* Bump scenes

* Don't show data pane for panels without data support

* Add tests

* Review
2024-02-07 00:51:25 -08:00

186 lines
4.7 KiB
TypeScript

import { css } from '@emotion/css';
import React from 'react';
import { Unsubscribable } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data';
import {
SceneComponentProps,
SceneObjectBase,
SceneObjectState,
SceneObjectUrlSyncConfig,
SceneObjectUrlValues,
VizPanel,
} from '@grafana/scenes';
import { Container, CustomScrollbar, TabContent, TabsBar, useStyles2 } from '@grafana/ui';
import { shouldShowAlertingTab } from 'app/features/dashboard/components/PanelEditor/state/selectors';
import { VizPanelManager } from '../VizPanelManager';
import { PanelDataAlertingTab } from './PanelDataAlertingTab';
import { PanelDataQueriesTab } from './PanelDataQueriesTab';
import { PanelDataTransformationsTab } from './PanelDataTransformationsTab';
import { PanelDataPaneTab, TabId } from './types';
export interface PanelDataPaneState extends SceneObjectState {
tabs?: PanelDataPaneTab[];
tab?: TabId;
}
export class PanelDataPane extends SceneObjectBase<PanelDataPaneState> {
static Component = PanelDataPaneRendered;
protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['tab'] });
private _initialTabsBuilt = false;
private panelSubscription: Unsubscribable | undefined;
public panelManager: VizPanelManager;
getUrlState() {
return {
tab: this.state.tab,
};
}
updateFromUrl(values: SceneObjectUrlValues) {
if (!values.tab) {
return;
}
if (typeof values.tab === 'string') {
this.setState({ tab: values.tab as TabId });
}
}
constructor(panelMgr: VizPanelManager) {
super({
tab: TabId.Queries,
tabs: [],
});
this.panelManager = panelMgr;
this.addActivationHandler(() => this.onActivate());
}
private onActivate() {
const panel = this.panelManager.state.panel;
this.setupPanelSubscription(panel);
this.buildTabs();
this._subs.add(
// Setup subscription for the case when panel type changed
this.panelManager.subscribeToState((n, p) => {
if (n.panel !== p.panel) {
this.buildTabs();
this.setupPanelSubscription(n.panel);
}
})
);
return () => {
if (this.panelSubscription) {
this.panelSubscription.unsubscribe();
this.panelSubscription = undefined;
}
};
}
private setupPanelSubscription(panel: VizPanel) {
if (this.panelSubscription) {
this._initialTabsBuilt = false;
this.panelSubscription.unsubscribe();
}
this.panelSubscription = panel.subscribeToState(() => {
if (panel.getPlugin() && !this._initialTabsBuilt) {
this.buildTabs();
this._initialTabsBuilt = true;
}
});
}
private buildTabs() {
const panelManager = this.panelManager;
const panel = panelManager.state.panel;
const runner = this.panelManager.queryRunner;
const tabs: PanelDataPaneTab[] = [];
if (panel) {
const plugin = panel.getPlugin();
if (!plugin) {
return;
}
if (plugin.meta.skipDataQuery) {
this.setState({ tabs });
return;
} else {
if (runner) {
tabs.push(new PanelDataQueriesTab(this.panelManager));
}
tabs.push(new PanelDataTransformationsTab(this.panelManager));
if (shouldShowAlertingTab(plugin)) {
tabs.push(new PanelDataAlertingTab(this.panelManager));
}
}
}
this.setState({ tabs });
}
onChangeTab = (tab: PanelDataPaneTab) => {
this.setState({ tab: tab.tabId });
};
}
function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
const { tab, tabs } = model.useState();
const styles = useStyles2(getStyles);
if (!tabs) {
return;
}
const currentTab = tabs.find((t) => t.tabId === tab);
return (
<>
<TabsBar hideBorder={true} className={styles.tabsBar}>
{tabs.map((t, index) => {
return (
<t.TabComponent
key={`${t.getTabLabel()}-${index}`}
active={t.tabId === tab}
onChangeTab={() => model.onChangeTab(t)}
></t.TabComponent>
);
})}
</TabsBar>
<CustomScrollbar className={styles.scroll}>
<TabContent className={styles.tabContent}>
<Container>{currentTab && <currentTab.Component model={currentTab} />}</Container>
</TabContent>
</CustomScrollbar>
</>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
tabContent: css({
padding: theme.spacing(2),
border: `1px solid ${theme.colors.border.weak}`,
borderLeft: 'none',
borderBottom: 'none',
borderTopRightRadius: theme.shape.radius.default,
flexGrow: 1,
}),
tabsBar: css({
flexShrink: 0,
}),
scroll: css({
background: theme.colors.background.primary,
}),
};
}