From 7f7f1b17e6465570630c1a9e7e8432ff9056715a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 12 Feb 2024 11:45:34 +0100 Subject: [PATCH] DashboardScene: Panel edit progress (#82288) --- .../PanelDataPane/PanelDataPane.tsx | 1 + .../panel-edit/PanelEditor.tsx | 1 + .../panel-edit/PanelEditorRenderer.tsx | 3 +- .../panel-edit/PanelOptionsPane.tsx | 165 +++++++++--------- .../panel-edit/VizPanelManager.tsx | 30 +++- 5 files changed, 108 insertions(+), 92 deletions(-) diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx index 2175d6eba39..9d44e50e689 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx @@ -177,6 +177,7 @@ function getStyles(theme: GrafanaTheme2) { }), tabsBar: css({ flexShrink: 0, + paddingLeft: theme.spacing(2), }), scroll: css({ background: theme.colors.background.primary, diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx index 5d4632fc58e..415c7ac7b6a 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelEditor.tsx @@ -116,6 +116,7 @@ export function buildPanelEditScene(panel: VizPanel): PanelEditor { panelRef: vizPanelMgr.getRef(), body: new SplitLayout({ direction: 'row', + initialSize: 0.75, primary: new SplitLayout({ direction: 'column', $behaviors: [conditionalDataPaneBehavior], diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx index 9f479fe01b5..a3f5922fc98 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx @@ -77,14 +77,13 @@ function getStyles(theme: GrafanaTheme2) { position: 'relative', minHeight: 0, gap: '8px', - marginBottom: theme.spacing(2), }), controls: css({ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: theme.spacing(1), - padding: theme.spacing(2, 0), + padding: theme.spacing(2), }), }; } diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx index 29aee500a9d..2e2dfe3109e 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx @@ -1,10 +1,10 @@ import { css } from '@emotion/css'; -import React, { useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { SceneComponentProps, SceneObjectBase, SceneObjectState, sceneGraph } from '@grafana/scenes'; -import { ButtonGroup, FilterInput, RadioButtonGroup, ToolbarButton, useStyles2 } from '@grafana/ui'; +import { Box, ButtonGroup, FilterInput, RadioButtonGroup, ToolbarButton, useStyles2 } from '@grafana/ui'; import { OptionFilter, RenderSearchHits } from 'app/features/dashboard/components/PanelEditor/OptionsPaneOptions'; import { getFieldOverrideCategories } from 'app/features/dashboard/components/PanelEditor/getFieldOverrideElements'; import { getPanelFrameCategory2 } from 'app/features/dashboard/components/PanelEditor/getPanelFrameOptions'; @@ -14,18 +14,40 @@ import { getAllPanelPluginMeta } from 'app/features/panel/state/util'; import { PanelVizTypePicker } from './PanelVizTypePicker'; import { VizPanelManager } from './VizPanelManager'; -export interface PanelOptionsPaneState extends SceneObjectState {} +export interface PanelOptionsPaneState extends SceneObjectState { + isVizPickerOpen?: boolean; + searchQuery: string; + listMode: OptionFilter; +} export class PanelOptionsPane extends SceneObjectBase { public panelManager: VizPanelManager; public constructor(panelMgr: VizPanelManager) { - super({}); + super({ + searchQuery: '', + listMode: OptionFilter.All, + }); this.panelManager = panelMgr; } + onToggleVizPicker = () => { + this.setState({ isVizPickerOpen: !this.state.isVizPickerOpen }); + }; + + onSetSearchQuery = (searchQuery: string) => { + this.setState({ searchQuery }); + }; + + onSetListMode = (listMode: OptionFilter) => { + this.setState({ listMode }); + }; + + onCollapsePane = () => {}; + static Component = ({ model }: SceneComponentProps) => { + const { isVizPickerOpen, searchQuery, listMode } = model.useState(); const { panelManager } = model; const { panel } = panelManager.state; const dataObject = sceneGraph.getData(panel); @@ -33,10 +55,7 @@ export class PanelOptionsPane extends SceneObjectBase { const dataWithFieldConfig = panel.applyFieldConfig(rawData.data!); const { pluginId, options, fieldConfig } = panel.useState(); const styles = useStyles2(getStyles); - const [isVizPickerOpen, setVizPickerOpen] = useState(true); - const [searchQuery, setSearchQuery] = useState(''); const panelFrameOptions = useMemo(() => getPanelFrameCategory2(panel), [panel]); - const [listMode, setListMode] = useState(OptionFilter.All); const visualizationOptions = useMemo(() => { const plugin = panel.getPlugin(); @@ -105,44 +124,42 @@ export class PanelOptionsPane extends SceneObjectBase { } return ( -
+
{!isVizPickerOpen && ( - { - setVizPickerOpen(true); - }} - /> + + + + )} + {isVizPickerOpen && } + {!isVizPickerOpen && ( + <> +
+ + {!isSearching && ( + + )} +
+
{mainBoxElements}
+ )} -
- {isVizPickerOpen && ( - setVizPickerOpen(false)} /> - )} - {!isVizPickerOpen && ( - <> -
- - {!isSearching && ( - - )} -
-
{mainBoxElements}
- - )} -
); }; @@ -150,34 +167,25 @@ export class PanelOptionsPane extends SceneObjectBase { function getStyles(theme: GrafanaTheme2) { return { - top: css({ - display: 'flex', - flexDirection: 'column', - padding: theme.spacing(1), - gap: theme.spacing(1), - border: `1px solid ${theme.colors.border.weak}`, - borderBottom: 'none', - borderTopLeftRadius: theme.shape.radius.default, - background: theme.colors.background.primary, - }), box: css({ display: 'flex', flexDirection: 'column', flexGrow: '1', background: theme.colors.background.primary, overflow: 'hidden', + border: `1px solid ${theme.colors.border.weak}`, + borderBottom: 'none', + borderTopLeftRadius: theme.shape.radius.default, }), - wrapper: css({ + top: css({ display: 'flex', flexDirection: 'column', - flexGrow: '1', - gap: theme.spacing(2), + padding: theme.spacing(1), + gap: theme.spacing(1), }), mainBox: css({ flexGrow: 1, background: theme.colors.background.primary, - border: `1px solid ${theme.components.panel.borderColor}`, - borderTop: 'none', overflow: 'auto', }), searchOptions: css({ @@ -186,24 +194,14 @@ function getStyles(theme: GrafanaTheme2) { }; } -export const VisualizationButton = ({ pluginId, onClick }: { pluginId: string; onClick: () => void }) => { - // const dispatch = useDispatch(); - // const plugin = useSelector(getPanelPluginWithFallback(panel.type)); - // const isPanelOptionsVisible = useSelector((state) => state.panelEditor.ui.isPanelOptionsVisible); - // const isVizPickerOpen = useSelector((state) => state.panelEditor.isVizPickerOpen); - - // const onToggleOpen = () => { - // dispatch(toggleVizPicker(!isVizPickerOpen)); - // }; - - // const onToggleOptionsPane = () => { - // dispatch(updatePanelEditorUIState({ isPanelOptionsVisible: !isPanelOptionsVisible })); - // }; - - // if (!plugin) { - // return null; - // } +interface VisualizationButtonProps { + pluginId: string; + onOpen: () => void; + isOpen?: boolean; + onTogglePane?: () => void; +} +export function VisualizationButton({ pluginId, onOpen, isOpen, onTogglePane }: VisualizationButtonProps) { const styles = useStyles2(getVizButtonStyles); const pluginMeta = useMemo(() => getAllPanelPluginMeta().filter((p) => p.id === pluginId)[0], [pluginId]); @@ -215,7 +213,7 @@ export const VisualizationButton = ({ pluginId, onClick }: { pluginId: string; o tooltip="Click to change visualization" imgSrc={pluginMeta.info.logos.small} // isOpen={isVizPickerOpen} - onClick={onClick} + onClick={onOpen} data-testid={selectors.components.PanelEditor.toggleVizPicker} aria-label="Change Visualization" variant="canvas" @@ -223,25 +221,24 @@ export const VisualizationButton = ({ pluginId, onClick }: { pluginId: string; o > {pluginMeta.name} - {/* */} + aria-label={isOpen ? 'Close options pane' : 'Show options pane'} + />
); -}; +} function getVizButtonStyles(theme: GrafanaTheme2) { return { wrapper: css({ display: 'flex', flexDirection: 'column', - paddingRight: theme.spacing(2), }), vizButton: css({ textAlign: 'left', diff --git a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx index 5b5a18cef21..3c40e06957c 100644 --- a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx +++ b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx @@ -1,9 +1,11 @@ +import { css } from '@emotion/css'; import React from 'react'; import { DataSourceApi, DataSourceInstanceSettings, FieldConfigSource, + GrafanaTheme2, PanelModel, filterFieldConfigOverrides, isStandardFieldProp, @@ -23,6 +25,7 @@ import { SceneDataTransformer, } from '@grafana/scenes'; import { DataQuery, DataTransformerConfig } from '@grafana/schema'; +import { useStyles2 } from '@grafana/ui'; import { getPluginVersion } from 'app/features/dashboard/state/PanelModel'; import { getLastUsedDatasourceFromStorage } from 'app/features/dashboard/utils/dashboard'; import { storeLastUsedDataSourceInLocalStorage } from 'app/features/datasources/components/picker/utils'; @@ -41,12 +44,6 @@ interface VizPanelManagerState extends SceneObjectState { // VizPanelManager serves as an API to manipulate VizPanel state from the outside. It allows panel type, options and data manipulation. export class VizPanelManager extends SceneObjectBase { - public static Component = ({ model }: SceneComponentProps) => { - const { panel } = model.useState(); - - return ; - }; - private _cachedPluginOptions: Record< string, { options: DeepPartial<{}>; fieldConfig: FieldConfigSource> } | undefined @@ -278,4 +275,25 @@ export class VizPanelManager extends SceneObjectBase { get panelData(): SceneDataProvider { return this.state.panel.state.$data!; } + + public static Component = ({ model }: SceneComponentProps) => { + const { panel } = model.useState(); + const styles = useStyles2(getStyles); + + return ( +
+ +
+ ); + }; +} + +function getStyles(theme: GrafanaTheme2) { + return { + wrapper: css({ + height: '100%', + width: '100%', + paddingLeft: theme.spacing(2), + }), + }; }