Dashboard: Add unconfigured panel state to new panels (#102719)
* Update * Update * Update new panel title * Update
This commit is contained in:
@@ -7,7 +7,7 @@ export enum PanelMenuItems {
|
||||
Extensions = 'Extensions',
|
||||
}
|
||||
|
||||
export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'Panel Title') => {
|
||||
export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'New panel') => {
|
||||
// we changed the way we open the panel menu in react panels with the new panel header
|
||||
detectPanelType(panelTitle, (isAngularPanel) => {
|
||||
if (isAngularPanel) {
|
||||
@@ -20,7 +20,7 @@ export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'Panel Titl
|
||||
});
|
||||
};
|
||||
|
||||
export const openPanelMenuExtension = (extensionTitle: string, panelTitle = 'Panel Title') => {
|
||||
export const openPanelMenuExtension = (extensionTitle: string, panelTitle = 'New panel') => {
|
||||
const menuItem = PanelMenuItems.Extensions;
|
||||
// we changed the way we open the panel menu in react panels with the new panel header
|
||||
detectPanelType(panelTitle, (isAngularPanel) => {
|
||||
|
||||
@@ -139,7 +139,7 @@ test.describe('edit panel plugin settings', () => {
|
||||
const panelOptions = panelEditPage.getPanelOptions();
|
||||
const title = panelOptions.getTextInput('Title');
|
||||
|
||||
await expect(title).toHaveValue('Panel Title');
|
||||
await expect(title).toHaveValue('New panel');
|
||||
await title.clear();
|
||||
await expect(title).toHaveValue('');
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ export enum PanelMenuItems {
|
||||
Extensions = 'Extensions',
|
||||
}
|
||||
|
||||
export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'Panel Title') => {
|
||||
export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'New panel') => {
|
||||
// we changed the way we open the panel menu in react panels with the new panel header
|
||||
detectPanelType(panelTitle, (isAngularPanel) => {
|
||||
if (isAngularPanel) {
|
||||
@@ -20,7 +20,7 @@ export const openPanelMenuItem = (menu: PanelMenuItems, panelTitle = 'Panel Titl
|
||||
});
|
||||
};
|
||||
|
||||
export const openPanelMenuExtension = (extensionTitle: string, panelTitle = 'Panel Title') => {
|
||||
export const openPanelMenuExtension = (extensionTitle: string, panelTitle = 'New panel') => {
|
||||
const menuItem = PanelMenuItems.Extensions;
|
||||
// we changed the way we open the panel menu in react panels with the new panel header
|
||||
detectPanelType(panelTitle, (isAngularPanel) => {
|
||||
|
||||
@@ -166,7 +166,6 @@ export interface GrafanaConfig {
|
||||
appSubUrl: string;
|
||||
windowTitlePrefix: string;
|
||||
buildInfo: BuildInfo;
|
||||
newPanelTitle: string;
|
||||
bootData: BootData;
|
||||
externalUserMngLinkUrl: string;
|
||||
externalUserMngLinkName: string;
|
||||
|
||||
@@ -68,7 +68,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
||||
namespace = 'default';
|
||||
windowTitlePrefix = '';
|
||||
buildInfo: BuildInfo;
|
||||
newPanelTitle = '';
|
||||
bootData: BootData;
|
||||
externalUserMngLinkUrl = '';
|
||||
externalUserMngLinkName = '';
|
||||
@@ -217,7 +216,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
||||
datasources: {},
|
||||
windowTitlePrefix: 'Grafana - ',
|
||||
panels: {},
|
||||
newPanelTitle: 'Panel Title',
|
||||
playlist_timespan: '1m',
|
||||
unsaved_changes_warning: true,
|
||||
appUrl: '',
|
||||
@@ -251,6 +249,9 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
||||
this.bootData.user.lightTheme = this.theme2.isLight;
|
||||
this.theme = this.theme2.v1;
|
||||
}
|
||||
geomapDefaultBaseLayer?: MapLayerOptions<any> | undefined;
|
||||
listDashboardScopesEndpoint?: string | undefined;
|
||||
listScopesEndpoint?: string | undefined;
|
||||
}
|
||||
|
||||
// localstorage key: grafana.featureToggles
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { GrafanaTheme2, textUtil } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { sceneGraph, VizPanel } from '@grafana/scenes';
|
||||
import { useStyles2, Text, Icon, Stack, Tooltip } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { Stack, Button } from '@grafana/ui';
|
||||
import { t, Trans } from 'app/core/internationalization';
|
||||
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
|
||||
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
|
||||
|
||||
@@ -104,57 +103,19 @@ type OpenPanelEditVizProps = {
|
||||
};
|
||||
|
||||
const OpenPanelEditViz = ({ panel }: OpenPanelEditVizProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
const plugin = panel.getPlugin();
|
||||
const imgSrc = plugin?.meta.info.logos.small;
|
||||
|
||||
return (
|
||||
<Stack alignItems="center" width="100%">
|
||||
{plugin ? (
|
||||
<Tooltip content={t('dashboard.viz-panel.options.open-edit', 'Open panel editor')}>
|
||||
<a
|
||||
href={textUtil.sanitizeUrl(getEditPanelUrl(getPanelIdForVizPanel(panel)))}
|
||||
className={cx(styles.pluginDescriptionWrapper)}
|
||||
>
|
||||
<img
|
||||
className={styles.panelVizImg}
|
||||
src={imgSrc}
|
||||
alt={t('dashboard.viz-panel.options.plugin-type-image', 'Image of plugin type')}
|
||||
/>
|
||||
<Text truncate>{plugin.meta.name}</Text>
|
||||
<Icon className={styles.panelVizIcon} name="sliders-v-alt" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
<Button
|
||||
onClick={() => {
|
||||
locationService.push(getEditPanelUrl(getPanelIdForVizPanel(panel)));
|
||||
}}
|
||||
icon="sliders-v-alt"
|
||||
fullWidth
|
||||
size="sm"
|
||||
tooltip={t('dashboard.viz-panel.options.configure-button-tooltip', 'Edit queries and visualization options')}
|
||||
>
|
||||
<Trans i18nKey="dashboard.new-panel.configure-button">Configure panel</Trans>
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
pluginDescriptionWrapper: css({
|
||||
display: 'flex',
|
||||
flexWrap: 'nowrap',
|
||||
alignItems: 'center',
|
||||
columnGap: theme.spacing(1),
|
||||
rowGap: theme.spacing(0.5),
|
||||
minHeight: theme.spacing(4),
|
||||
backgroundColor: theme.colors.secondary.main,
|
||||
border: `1px solid ${theme.colors.secondary.border}`,
|
||||
borderRadius: theme.shape.radius.default,
|
||||
paddingInline: theme.spacing(1),
|
||||
paddingBlock: theme.spacing(0.5),
|
||||
flexGrow: 1,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colors.secondary.shade,
|
||||
},
|
||||
}),
|
||||
panelVizImg: css({
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
marginRight: theme.spacing(1),
|
||||
}),
|
||||
panelVizIcon: css({
|
||||
marginLeft: 'auto',
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import { saveLibPanel } from 'app/features/library-panels/state/api';
|
||||
|
||||
import { DashboardSceneChangeTracker } from '../saving/DashboardSceneChangeTracker';
|
||||
import { getPanelChanges } from '../saving/getDashboardChanges';
|
||||
import { UNCONFIGURED_PANEL_PLUGIN_ID } from '../scene/UnconfiguredPanel';
|
||||
import { DashboardLayoutItem, isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem';
|
||||
import { vizPanelToPanel } from '../serialization/transformSceneToSaveModel';
|
||||
import {
|
||||
@@ -76,6 +77,11 @@ export class PanelEditor extends SceneObjectBase<PanelEditorState> {
|
||||
|
||||
private _activationHandler() {
|
||||
const panel = this.state.panelRef.resolve();
|
||||
|
||||
if (panel.state.pluginId === UNCONFIGURED_PANEL_PLUGIN_ID) {
|
||||
panel.changePluginType('timeseries');
|
||||
}
|
||||
|
||||
const deactivateParents = activateSceneObjectAndParentTree(panel);
|
||||
|
||||
this.waitForPlugin();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { PanelPlugin, PanelProps } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { sceneUtils } from '@grafana/scenes';
|
||||
import { Box, Button, Stack } from '@grafana/ui';
|
||||
import { Trans } from 'app/core/internationalization';
|
||||
|
||||
export const UNCONFIGURED_PANEL_PLUGIN_ID = '__unconfigured-panel';
|
||||
const UnconfiguredPanel = new PanelPlugin(UnconfiguredPanelComp);
|
||||
|
||||
function UnconfiguredPanelComp(props: PanelProps) {
|
||||
const onConfigure = () => {
|
||||
locationService.partial({ editPanel: props.id });
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack direction={'row'} alignItems={'center'} height={'100%'} justifyContent={'center'}>
|
||||
<Box paddingBottom={2}>
|
||||
<Button icon="sliders-v-alt" onClick={onConfigure}>
|
||||
<Trans i18nKey="dashboard.new-panel.configure-button">Configure panel</Trans>
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
sceneUtils.registerRuntimePanelPlugin({
|
||||
pluginId: UNCONFIGURED_PANEL_PLUGIN_ID,
|
||||
plugin: UnconfiguredPanel,
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getDataSourceRef, IntervalVariableModel } from '@grafana/data';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import { config, getDataSourceSrv } from '@grafana/runtime';
|
||||
import {
|
||||
CancelActivationHandler,
|
||||
CustomVariable,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
VizPanelMenu,
|
||||
} from '@grafana/scenes';
|
||||
import { useElementSelection, UseElementSelectionResult } from '@grafana/ui';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { initialIntervalVariableModelState } from 'app/features/variables/interval/reducer';
|
||||
|
||||
import { DashboardDatasourceBehaviour } from '../scene/DashboardDatasourceBehaviour';
|
||||
@@ -20,6 +21,7 @@ import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
|
||||
import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior';
|
||||
import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks';
|
||||
import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { UNCONFIGURED_PANEL_PLUGIN_ID } from '../scene/UnconfiguredPanel';
|
||||
import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem';
|
||||
import { ResponsiveGridItem } from '../scene/layout-responsive-grid/ResponsiveGridItem';
|
||||
import { RowItem } from '../scene/layout-rows/RowItem';
|
||||
@@ -322,9 +324,12 @@ export function getClosestVizPanel(sceneObject: SceneObject): VizPanel | null {
|
||||
}
|
||||
|
||||
export function getDefaultVizPanel(): VizPanel {
|
||||
const defaultPluginId = config.featureToggles.dashboardNewLayouts ? UNCONFIGURED_PANEL_PLUGIN_ID : 'timeseries';
|
||||
const newPanelTitle = t('dashboard.new-panel-title', 'New panel');
|
||||
|
||||
return new VizPanel({
|
||||
title: 'Panel Title',
|
||||
pluginId: 'timeseries',
|
||||
title: newPanelTitle,
|
||||
pluginId: defaultPluginId,
|
||||
titleItems: [new VizPanelLinks({ menu: new VizPanelLinksMenu({}) })],
|
||||
hoverHeaderOffset: 0,
|
||||
$behaviors: [],
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||
import { calculateNewPanelGridPos } from 'app/features/dashboard/utils/panel';
|
||||
|
||||
export const NEW_PANEL_TITLE = 'Panel Title';
|
||||
export const NEW_PANEL_TITLE = 'New panel';
|
||||
|
||||
export function onCreateNewPanel(dashboard: DashboardModel, datasource?: string): number | undefined {
|
||||
const newPanel: Partial<PanelModel> = {
|
||||
|
||||
@@ -1492,6 +1492,10 @@
|
||||
"layout": "Layout"
|
||||
}
|
||||
},
|
||||
"new-panel": {
|
||||
"configure-button": "Configure panel"
|
||||
},
|
||||
"new-panel-title": "New panel",
|
||||
"options": {
|
||||
"description": "Description",
|
||||
"title-option": "Title"
|
||||
@@ -1722,9 +1726,8 @@
|
||||
},
|
||||
"viz-panel": {
|
||||
"options": {
|
||||
"configure-button-tooltip": "Edit queries and visualization options",
|
||||
"description": "Description",
|
||||
"open-edit": "Open panel editor",
|
||||
"plugin-type-image": "Image of plugin type",
|
||||
"title-option": "Title",
|
||||
"transparent-background": "Transparent background"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user