mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Skeleton for Panel edit data tabs (#79130)
This commit is contained in:
parent
dfc139b2ff
commit
f6bd390bc1
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { IconName } from '@grafana/data';
|
||||||
|
import { SceneObjectBase, SceneComponentProps } from '@grafana/scenes';
|
||||||
|
|
||||||
|
import { PanelDataPaneTabState, PanelDataPaneTab } from './types';
|
||||||
|
|
||||||
|
export class PanelDataAlertingTab extends SceneObjectBase<PanelDataPaneTabState> implements PanelDataPaneTab {
|
||||||
|
static Component = PanelDataAlertingTabRendered;
|
||||||
|
tabId = 'alert';
|
||||||
|
icon: IconName = 'bell';
|
||||||
|
|
||||||
|
getTabLabel() {
|
||||||
|
return 'Alert';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PanelDataAlertingTabRendered(props: SceneComponentProps<PanelDataAlertingTab>) {
|
||||||
|
return <div>TODO Alerting</div>;
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
SceneComponentProps,
|
||||||
|
SceneObjectBase,
|
||||||
|
SceneObjectRef,
|
||||||
|
SceneObjectState,
|
||||||
|
SceneObjectUrlSyncConfig,
|
||||||
|
SceneObjectUrlValues,
|
||||||
|
VizPanel,
|
||||||
|
} from '@grafana/scenes';
|
||||||
|
import { Tab, TabContent, TabsBar } from '@grafana/ui';
|
||||||
|
import { shouldShowAlertingTab } from 'app/features/dashboard/components/PanelEditor/state/selectors';
|
||||||
|
|
||||||
|
import { PanelDataAlertingTab } from './PanelDataAlertingTab';
|
||||||
|
import { PanelDataQueriesTab } from './PanelDataQueriesTab';
|
||||||
|
import { PanelDataTransformationsTab } from './PanelDataTransformationsTab';
|
||||||
|
import { PanelDataPaneTab } from './types';
|
||||||
|
|
||||||
|
export interface PanelDataPaneState extends SceneObjectState {
|
||||||
|
panelRef: SceneObjectRef<VizPanel>;
|
||||||
|
tabs?: PanelDataPaneTab[];
|
||||||
|
tab?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PanelDataPane extends SceneObjectBase<PanelDataPaneState> {
|
||||||
|
static Component = PanelDataPaneRendered;
|
||||||
|
protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['tab'] });
|
||||||
|
|
||||||
|
getUrlState() {
|
||||||
|
return {
|
||||||
|
tab: this.state.tab,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFromUrl(values: SceneObjectUrlValues) {
|
||||||
|
if (!values.tab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof values.tab === 'string') {
|
||||||
|
this.setState({ tab: values.tab });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(state: Omit<PanelDataPaneState, 'tab'> & { tab?: string }) {
|
||||||
|
super({
|
||||||
|
tab: 'queries',
|
||||||
|
...state,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { panelRef } = this.state;
|
||||||
|
const panel = panelRef.resolve();
|
||||||
|
|
||||||
|
if (panel) {
|
||||||
|
// The subscription below is needed because the plugin may not be loaded when this pane is mounted.
|
||||||
|
// This can happen i.e. when the user opens the panel editor directly via an URL.
|
||||||
|
this._subs.add(
|
||||||
|
panel.subscribeToState((n, p) => {
|
||||||
|
if (n.pluginVersion || p.pluginId !== n.pluginId) {
|
||||||
|
this.buildTabs();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addActivationHandler(() => this.buildTabs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildTabs() {
|
||||||
|
const { panelRef } = this.state;
|
||||||
|
const tabs: PanelDataPaneTab[] = [];
|
||||||
|
|
||||||
|
if (panelRef) {
|
||||||
|
const plugin = panelRef.resolve().getPlugin();
|
||||||
|
if (!plugin) {
|
||||||
|
this.setState({ tabs });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (plugin.meta.skipDataQuery) {
|
||||||
|
this.setState({ tabs });
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
tabs.push(new PanelDataQueriesTab({}));
|
||||||
|
tabs.push(new PanelDataTransformationsTab({}));
|
||||||
|
|
||||||
|
if (shouldShowAlertingTab(plugin)) {
|
||||||
|
tabs.push(new PanelDataAlertingTab({}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ tabs });
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeTab = (tab: PanelDataPaneTab) => {
|
||||||
|
this.setState({ tab: tab.tabId });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function PanelDataPaneRendered({ model }: SceneComponentProps<PanelDataPane>) {
|
||||||
|
const { tab, tabs } = model.useState();
|
||||||
|
|
||||||
|
if (!tabs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTab = tabs.find((t) => t.tabId === tab);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<TabsBar hideBorder={true}>
|
||||||
|
{tabs.map((t, index) => {
|
||||||
|
return (
|
||||||
|
<Tab
|
||||||
|
key={`${t.getTabLabel()}-${index}`}
|
||||||
|
label={t.getTabLabel()}
|
||||||
|
icon={t.icon}
|
||||||
|
// suffix={}
|
||||||
|
active={t.tabId === tab}
|
||||||
|
onChangeTab={() => model.onChangeTab(t)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</TabsBar>
|
||||||
|
<TabContent>{currentTab && <currentTab.Component model={currentTab} />}</TabContent>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { IconName } from '@grafana/data';
|
||||||
|
import { SceneObjectBase, SceneComponentProps } from '@grafana/scenes';
|
||||||
|
|
||||||
|
import { PanelDataPaneTabState, PanelDataPaneTab } from './types';
|
||||||
|
|
||||||
|
export class PanelDataQueriesTab extends SceneObjectBase<PanelDataPaneTabState> implements PanelDataPaneTab {
|
||||||
|
static Component = PanelDataQueriesTabRendered;
|
||||||
|
tabId = 'queries';
|
||||||
|
icon: IconName = 'database';
|
||||||
|
|
||||||
|
getTabLabel() {
|
||||||
|
return 'Queries';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PanelDataQueriesTabRendered(props: SceneComponentProps<PanelDataQueriesTab>) {
|
||||||
|
return <div>TODO Queries</div>;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { IconName } from '@grafana/data';
|
||||||
|
import { SceneObjectBase, SceneComponentProps } from '@grafana/scenes';
|
||||||
|
|
||||||
|
import { PanelDataPaneTabState, PanelDataPaneTab } from './types';
|
||||||
|
|
||||||
|
export class PanelDataTransformationsTab extends SceneObjectBase<PanelDataPaneTabState> implements PanelDataPaneTab {
|
||||||
|
static Component = PanelDataTransformationsTabRendered;
|
||||||
|
tabId = 'transformations';
|
||||||
|
icon: IconName = 'process';
|
||||||
|
|
||||||
|
getTabLabel() {
|
||||||
|
return 'Transformations';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function PanelDataTransformationsTabRendered(props: SceneComponentProps<PanelDataTransformationsTab>) {
|
||||||
|
return <div>TODO Transformations</div>;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { IconName } from '@grafana/data';
|
||||||
|
import { SceneObject, SceneObjectState } from '@grafana/scenes';
|
||||||
|
|
||||||
|
export interface PanelDataPaneTabState extends SceneObjectState {}
|
||||||
|
|
||||||
|
export interface PanelDataPaneTab extends SceneObject {
|
||||||
|
getTabLabel(): string;
|
||||||
|
tabId: string;
|
||||||
|
icon: IconName;
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { NavIndex } from '@grafana/data';
|
|||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import {
|
import {
|
||||||
getUrlSyncManager,
|
getUrlSyncManager,
|
||||||
|
SceneFlexItem,
|
||||||
SceneFlexLayout,
|
SceneFlexLayout,
|
||||||
SceneObject,
|
SceneObject,
|
||||||
SceneObjectBase,
|
SceneObjectBase,
|
||||||
@ -17,6 +18,7 @@ import {
|
|||||||
import { DashboardScene } from '../scene/DashboardScene';
|
import { DashboardScene } from '../scene/DashboardScene';
|
||||||
import { getDashboardUrl } from '../utils/urlBuilders';
|
import { getDashboardUrl } from '../utils/urlBuilders';
|
||||||
|
|
||||||
|
import { PanelDataPane } from './PanelDataPane/PanelDataPane';
|
||||||
import { PanelEditorRenderer } from './PanelEditorRenderer';
|
import { PanelEditorRenderer } from './PanelEditorRenderer';
|
||||||
import { PanelOptionsPane } from './PanelOptionsPane';
|
import { PanelOptionsPane } from './PanelOptionsPane';
|
||||||
import { PanelVizTypePicker } from './PanelVizTypePicker';
|
import { PanelVizTypePicker } from './PanelVizTypePicker';
|
||||||
@ -124,9 +126,15 @@ export function buildPanelEditScene(dashboard: DashboardScene, panel: VizPanel):
|
|||||||
$timeRange: dashboardStateCloned.$timeRange,
|
$timeRange: dashboardStateCloned.$timeRange,
|
||||||
body: new SplitLayout({
|
body: new SplitLayout({
|
||||||
direction: 'row',
|
direction: 'row',
|
||||||
primary: new SceneFlexLayout({
|
primary: new SplitLayout({
|
||||||
direction: 'column',
|
direction: 'column',
|
||||||
children: [vizPanelMgr],
|
primary: new SceneFlexLayout({
|
||||||
|
direction: 'column',
|
||||||
|
children: [panelClone],
|
||||||
|
}),
|
||||||
|
secondary: new SceneFlexItem({
|
||||||
|
body: new PanelDataPane({ panelRef: panelClone.getRef() }),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
secondary: new SceneFlexLayout({
|
secondary: new SceneFlexLayout({
|
||||||
direction: 'column',
|
direction: 'column',
|
||||||
|
@ -39,14 +39,7 @@ export const getPanelEditorTabs = memoizeOne((tab?: string, plugin?: PanelPlugin
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { alertingEnabled, unifiedAlertingEnabled } = getConfig();
|
if (shouldShowAlertingTab(plugin)) {
|
||||||
const hasRuleReadPermissions = contextSrv.hasPermission(getRulesPermissions(GRAFANA_RULES_SOURCE_NAME).read);
|
|
||||||
const isAlertingAvailable = alertingEnabled || (unifiedAlertingEnabled && hasRuleReadPermissions);
|
|
||||||
|
|
||||||
const isGraph = plugin.meta.id === 'graph';
|
|
||||||
const isTimeseries = plugin.meta.id === 'timeseries';
|
|
||||||
|
|
||||||
if ((isAlertingAvailable && isGraph) || isTimeseries) {
|
|
||||||
tabs.push({
|
tabs.push({
|
||||||
id: PanelEditorTabId.Alert,
|
id: PanelEditorTabId.Alert,
|
||||||
text: 'Alert',
|
text: 'Alert',
|
||||||
@ -60,3 +53,14 @@ export const getPanelEditorTabs = memoizeOne((tab?: string, plugin?: PanelPlugin
|
|||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function shouldShowAlertingTab(plugin: PanelPlugin) {
|
||||||
|
const { alertingEnabled, unifiedAlertingEnabled } = getConfig();
|
||||||
|
const hasRuleReadPermissions = contextSrv.hasPermission(getRulesPermissions(GRAFANA_RULES_SOURCE_NAME).read);
|
||||||
|
const isAlertingAvailable = alertingEnabled || (unifiedAlertingEnabled && hasRuleReadPermissions);
|
||||||
|
|
||||||
|
const isGraph = plugin.meta.id === 'graph';
|
||||||
|
const isTimeseries = plugin.meta.id === 'timeseries';
|
||||||
|
|
||||||
|
return (isAlertingAvailable && isGraph) || isTimeseries;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user