diff --git a/packages/grafana-ui/src/themes/GlobalStyles/dashboardGrid.ts b/packages/grafana-ui/src/themes/GlobalStyles/dashboardGrid.ts index aa243c17c68..80c55673bcd 100644 --- a/packages/grafana-ui/src/themes/GlobalStyles/dashboardGrid.ts +++ b/packages/grafana-ui/src/themes/GlobalStyles/dashboardGrid.ts @@ -92,6 +92,7 @@ export function getDashboardGridStyles(theme: GrafanaTheme2) { '.dashboard-canvas-add-button': { opacity: 0, + transition: theme.transitions.create('opacity'), '&:hover': { opacity: 1, diff --git a/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutManager.tsx index 0885e481c69..85d295e19d6 100644 --- a/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutManager.tsx @@ -57,7 +57,7 @@ export class ResponsiveGridLayoutManager vizPanel.clearParent(); this.state.layout.setState({ - children: [new ResponsiveGridItem({ body: vizPanel }), ...this.state.layout.state.children], + children: [...this.state.layout.state.children, new ResponsiveGridItem({ body: vizPanel })], }); this.publishEvent(new NewObjectAddedToCanvasEvent(vizPanel), true); diff --git a/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutRenderer.tsx index a3976fec4dc..12db3889148 100644 --- a/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-responsive-grid/ResponsiveGridLayoutRenderer.tsx @@ -2,21 +2,23 @@ import { css, cx } from '@emotion/css'; import { useEffect } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; -import { LazyLoader, SceneComponentProps } from '@grafana/scenes'; -import { useStyles2 } from '@grafana/ui'; +import { LazyLoader, SceneComponentProps, sceneGraph } from '@grafana/scenes'; +import { Button, useStyles2 } from '@grafana/ui'; -import { getDashboardSceneFor } from '../../utils/utils'; +import { getDefaultVizPanel, useDashboardState } from '../../utils/utils'; import { ResponsiveGridLayout, ResponsiveGridLayoutState } from './ResponsiveGridLayout'; +import { ResponsiveGridLayoutManager } from './ResponsiveGridLayoutManager'; export function ResponsiveGridLayoutRenderer({ model }: SceneComponentProps) { const { children, isHidden, isLazy } = model.useState(); const styles = useStyles2(getStyles, model.state); - const { layoutOrchestrator } = getDashboardSceneFor(model).state; + const { layoutOrchestrator, isEditing } = useDashboardState(model); const { activeLayoutItemRef } = layoutOrchestrator.useState(); const activeLayoutItem = activeLayoutItemRef?.resolve(); const currentLayoutIsActive = children.some((c) => c === activeLayoutItem); + const layoutManager = sceneGraph.getAncestor(model, ResponsiveGridLayoutManager); useEffect(() => { if (model.containerRef.current) { @@ -38,7 +40,7 @@ export function ResponsiveGridLayoutRenderer({ model }: SceneComponentProps +
); })} + {isEditing && ( +
+ +
+ )}
); } @@ -89,7 +103,6 @@ const getStyles = (theme: GrafanaTheme2, state: ResponsiveGridLayoutState) => ({ alignItems: state.alignItems || 'unset', justifyContent: state.justifyContent || 'unset', flexGrow: 1, - [theme.breakpoints.down('md')]: state.md ? { gridTemplateRows: state.md.templateRows, @@ -101,6 +114,16 @@ const getStyles = (theme: GrafanaTheme2, state: ResponsiveGridLayoutState) => ({ justifyContent: state.md.justifyContent, } : undefined, + // Show add action when hovering over the grid + '&:hover': { + '.dashboard-canvas-add-button': { + opacity: 1, + }, + }, + }), + containerEditing: css({ + paddingBottom: theme.spacing(5), + position: 'relative', }), wrapper: css({ display: 'grid', @@ -108,6 +131,18 @@ const getStyles = (theme: GrafanaTheme2, state: ResponsiveGridLayoutState) => ({ width: '100%', height: '100%', }), + addAction: css({ + position: 'absolute', + padding: theme.spacing(1, 0), + height: theme.spacing(5), + bottom: 0, + left: 0, + right: 0, + opacity: 0, + [theme.transitions.handleMotion('no-preference', 'reduce')]: { + transition: theme.transitions.create('opacity'), + }, + }), dragging: css({ position: 'fixed', top: 0, diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx index 4e6eb2df022..94835c1dd2b 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx @@ -91,7 +91,7 @@ export function RowItemRenderer({ model }: SceneComponentProps) { )} - {!isClone && isEditing && } + {/* {!isClone && isEditing && } */}
)} {!isCollapsed && } diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx index 390d7a824a5..108438ee400 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx @@ -2,12 +2,15 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; import { SceneComponentProps } from '@grafana/scenes'; -import { useStyles2 } from '@grafana/ui'; +import { Button, useStyles2 } from '@grafana/ui'; + +import { useDashboardState } from '../../utils/utils'; import { RowsLayoutManager } from './RowsLayoutManager'; export function RowLayoutManagerRenderer({ model }: SceneComponentProps) { const { rows } = model.useState(); + const { isEditing } = useDashboardState(model); const styles = useStyles2(getStyles); return ( @@ -15,6 +18,20 @@ export function RowLayoutManagerRenderer({ model }: SceneComponentProps ( ))} + {isEditing && ( +
+ +
+ )} ); } diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx index 6bef7c0bf8d..ff9473de2a1 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItem.tsx @@ -95,6 +95,10 @@ export class TabItem this._getParentLayout().addTabAfter(this); } + public onAddTab() { + this._getParentLayout().addNewTab(); + } + public onMoveLeft() { this._getParentLayout().moveTabLeft(this); } diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemMenu.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemMenu.tsx index aee83633b9a..eb3c0c3b51c 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemMenu.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemMenu.tsx @@ -1,8 +1,5 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; -import { Button, Dropdown, Menu, ToolbarButtonRow, useStyles2 } from '@grafana/ui'; -import { t, Trans } from 'app/core/internationalization'; +import { Button } from '@grafana/ui'; +import { t } from 'app/core/internationalization'; import { TabItem } from './TabItem'; @@ -11,80 +8,19 @@ interface Props { } export function TabItemMenu({ model }: Props) { - const styles = useStyles2(getStyles); - return ( - - ( - - model.onAddPanel()} - /> - - model.onAddTabBefore()} - /> - model.onAddTabAfter()} - /> - - )} - > - - - ( - - model.onMoveLeft()} - /> - - model.onMoveRight()} - /> - - )} +
+ +
); } - -function getStyles(theme: GrafanaTheme2) { - return { - container: css({ - gap: theme.spacing(1), - flexShrink: 0, - }), - }; -} diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx index 624b772db37..edf3f2eb94f 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx @@ -47,11 +47,16 @@ const getStyles = (theme: GrafanaTheme2) => ({ }), tabsBar: css({ overflow: 'hidden', + // ':hover': { + // '.dashboard-canvas-add-button': { + // opacity: 1, + // }, + // }, }), tabsRow: css({ - justifyContent: 'space-between', display: 'flex', width: '100%', + alignItems: 'center', }), tabsContainer: css({ display: 'flex',