The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx

175 lines
5.7 KiB

import { CoreApp } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { SceneTimeRangeLike, VizPanel } from '@grafana/scenes';
import { DataLinksInlineEditor, Input, TextArea, Switch } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { GenAIPanelDescriptionButton } from 'app/features/dashboard/components/GenAI/GenAIPanelDescriptionButton';
import { GenAIPanelTitleButton } from 'app/features/dashboard/components/GenAI/GenAIPanelTitleButton';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
import { getPanelLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
import { VizPanelLinks } from '../scene/PanelLinks';
import { PanelTimeRange } from '../scene/PanelTimeRange';
import { useEditPaneInputAutoFocus } from '../scene/layouts-shared/utils';
import { isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem';
import { vizPanelToPanel, transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel';
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
import { getDashboardSceneFor } from '../utils/utils';
export function getPanelFrameOptions(panel: VizPanel): OptionsPaneCategoryDescriptor {
const descriptor = new OptionsPaneCategoryDescriptor({
title: 'Panel options',
id: 'Panel options',
isOpenDefault: true,
});
const panelLinksObject = dashboardSceneGraph.getPanelLinks(panel);
const links = panelLinksObject?.state.rawLinks ?? [];
const dashboard = getDashboardSceneFor(panel);
const layoutElement = panel.parent!;
descriptor
.addItem(
new OptionsPaneItemDescriptor({
title: 'Title',
value: panel.state.title,
popularRank: 1,
render: function renderTitle() {
return <PanelFrameTitleInput panel={panel} />;
},
addon: config.featureToggles.dashgpt && (
<GenAIPanelTitleButton
onGenerate={(title) => setPanelTitle(panel, title)}
panel={vizPanelToPanel(panel)}
dashboard={transformSceneToSaveModel(dashboard)}
/>
),
})
)
.addItem(
new OptionsPaneItemDescriptor({
title: 'Description',
value: panel.state.description,
render: function renderDescription() {
return <PanelDescriptionTextArea panel={panel} />;
},
addon: config.featureToggles.dashgpt && (
<GenAIPanelDescriptionButton
onGenerate={(description) => panel.setState({ description })}
panel={vizPanelToPanel(panel)}
/>
),
})
)
.addItem(
new OptionsPaneItemDescriptor({
title: 'Transparent background',
render: function renderTransparent() {
return <PanelBackgroundSwitch panel={panel} />;
},
})
)
.addCategory(
new OptionsPaneCategoryDescriptor({
title: 'Panel links',
id: 'Panel links',
isOpenDefault: false,
itemsCount: links?.length,
}).addItem(
new OptionsPaneItemDescriptor({
title: 'Panel links',
render: () => <ScenePanelLinksEditor panelLinks={panelLinksObject ?? undefined} />,
})
)
);
if (isDashboardLayoutItem(layoutElement)) {
layoutElement.getOptions?.().forEach((category) => descriptor.addCategory(category));
}
return descriptor;
}
interface ScenePanelLinksEditorProps {
panelLinks?: VizPanelLinks;
}
function ScenePanelLinksEditor({ panelLinks }: ScenePanelLinksEditorProps) {
const { rawLinks: links } = panelLinks ? panelLinks.useState() : { rawLinks: [] };
return (
<DataLinksInlineEditor
links={links}
onChange={(links) => panelLinks?.setState({ rawLinks: links })}
getSuggestions={getPanelLinksVariableSuggestions}
data={[]}
/>
);
}
export function PanelFrameTitleInput({ panel }: { panel: VizPanel }) {
const { title } = panel.useState();
const notInPanelEdit = panel.getPanelContext().app !== CoreApp.PanelEditor;
const newPanelTitle = t('dashboard.new-panel-title', 'New panel');
let ref = useEditPaneInputAutoFocus({
autoFocus: notInPanelEdit && title === newPanelTitle,
});
return (
<Input
ref={ref}
data-testid={selectors.components.PanelEditor.OptionsPane.fieldInput('Title')}
value={title}
onChange={(e) => setPanelTitle(panel, e.currentTarget.value)}
/>
);
}
export function PanelDescriptionTextArea({ panel }: { panel: VizPanel }) {
const { description } = panel.useState();
return (
<TextArea
id="description-text-area"
value={description}
onChange={(e) => panel.setState({ description: e.currentTarget.value })}
/>
);
}
export function PanelBackgroundSwitch({ panel }: { panel: VizPanel }) {
const { displayMode } = panel.useState();
return (
<Switch
value={displayMode === 'transparent'}
id="transparent-background"
onChange={() => {
panel.setState({
displayMode: panel.state.displayMode === 'transparent' ? 'default' : 'transparent',
});
}}
/>
);
}
function setPanelTitle(panel: VizPanel, title: string) {
panel.setState({ title: title, hoverHeader: getUpdatedHoverHeader(title, panel.state.$timeRange) });
}
export function getUpdatedHoverHeader(title: string, timeRange: SceneTimeRangeLike | undefined): boolean {
if (title !== '') {
return false;
}
if (timeRange instanceof PanelTimeRange && !timeRange.state.hideTimeOverride) {
if (timeRange.state.timeFrom || timeRange.state.timeShift) {
return false;
}
}
return true;
}