Dashboard: Edit pane tabs (#101145)

* Dashboard: Edit pane tabs

* update design

* Added translation elements

* Update

* Update

* Update

* Fix css issue

* Update
This commit is contained in:
Torkel Ödegaard
2025-02-22 14:15:26 +01:00
committed by GitHub
parent 9dac0c9eeb
commit 6d7147c38d
5 changed files with 144 additions and 82 deletions
@@ -0,0 +1,75 @@
import { selectors } from '@grafana/e2e-selectors';
import { Box, Card, Icon } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { DashboardInteractions } from '../utils/interactions';
import { getDashboardSceneFor } from '../utils/utils';
import { DashboardEditPane } from './DashboardEditPane';
export interface Props {
editPane: DashboardEditPane;
}
export function DashboardAddPane({ editPane }: Props) {
const dashboard = getDashboardSceneFor(editPane);
return (
<Box display={'flex'} direction={'column'} gap={1} padding={2}>
<Card
onClick={() => dashboard.onCreateNewPanel()}
data-testid={selectors.components.PageToolbar.itemButton('add_visualization')}
title={t('dashboard.toolbar.add-panel-description', 'A container for visualizations and other content')}
>
<Card.Heading>
<Trans i18nKey="dashboard.toolbar.add-panel">Panel</Trans>
</Card.Heading>
<Card.Figure>
<Icon name="graph-bar" size="xl" />
</Card.Figure>
</Card>
<Card
onClick={() => {
dashboard.onShowAddLibraryPanelDrawer();
DashboardInteractions.toolbarAddButtonClicked({ item: 'add_library_panel' });
}}
data-testid={selectors.pages.AddDashboard.itemButton('Add new panel from panel library menu item')}
title={t(
'dashboard.toolbar.libray-panel-description',
'Libray panels allow you share and reuse panels between dashboards'
)}
>
<Card.Heading>
<Trans i18nKey="dashboard.toolbar.add-panel-lib">Import library panel</Trans>
</Card.Heading>
<Card.Figure>
<Icon name="import" size="xl" />
</Card.Figure>
</Card>
<Card
onClick={() => dashboard.onCreateNewRow()}
data-testid={selectors.components.PageToolbar.itemButton('add_row')}
title={t('dashboard.toolbar.row-description', 'A group of panels with an optional header')}
>
<Card.Heading>
<Trans i18nKey="dashboard.toolbar.add-row">Row</Trans>
</Card.Heading>
<Card.Figure>
<Icon name="list-ul" size="xl" />
</Card.Figure>
</Card>
<Card
onClick={() => dashboard.onCreateNewTab()}
data-testid={selectors.components.PageToolbar.itemButton('add_tab')}
title={t('dashboard.toolbar.tabs-description', 'Break up your dashboard into different horizontal tabs')}
>
<Card.Heading>
<Trans i18nKey="dashboard.toolbar.add-tab">Tab</Trans>
</Card.Heading>
<Card.Figure>
<Icon name="layer-group" size="xl" />
</Card.Figure>
</Card>
</Box>
);
}
@@ -4,12 +4,20 @@ import { useEffect, useRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneObjectState, SceneObjectBase, SceneObject, sceneGraph, useSceneObjectState } from '@grafana/scenes';
import { ElementSelectionContextItem, ElementSelectionContextState, ToolbarButton, useStyles2 } from '@grafana/ui';
import {
ElementSelectionContextItem,
ElementSelectionContextState,
Tab,
TabsBar,
ToolbarButton,
useStyles2,
} from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { isInCloneChain } from '../utils/clone';
import { getDashboardSceneFor } from '../utils/utils';
import { DashboardAddPane } from './DashboardAddPane';
import { ElementEditPane } from './ElementEditPane';
import { ElementSelection } from './ElementSelection';
import { useEditableElement } from './useEditableElement';
@@ -17,8 +25,11 @@ import { useEditableElement } from './useEditableElement';
export interface DashboardEditPaneState extends SceneObjectState {
selection?: ElementSelection;
selectionContext: ElementSelectionContextState;
tab?: EditPaneTab;
}
export type EditPaneTab = 'add' | 'configure' | 'outline';
export class DashboardEditPane extends SceneObjectBase<DashboardEditPaneState> {
public constructor() {
super({
@@ -122,6 +133,10 @@ export class DashboardEditPane extends SceneObjectBase<DashboardEditPaneState> {
},
});
}
public onChangeTab = (tab: EditPaneTab) => {
this.setState({ tab });
};
}
export interface Props {
@@ -157,7 +172,7 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla
}
}, [editPane, isCollapsed]);
const { selection } = useSceneObjectState(editPane, { shouldActivateOrKeepAlive: true });
const { selection, tab = 'configure' } = useSceneObjectState(editPane, { shouldActivateOrKeepAlive: true });
const styles = useStyles2(getStyles);
const paneRef = useRef<HTMLDivElement>(null);
const editableElement = useEditableElement(selection);
@@ -191,7 +206,28 @@ export function DashboardEditPaneRenderer({ editPane, isCollapsed, onToggleColla
return (
<div className={styles.wrapper} ref={paneRef}>
<ElementEditPane element={editableElement} key={editableElement.typeName} />
<TabsBar className={styles.tabsbar}>
<Tab
active={tab === 'add'}
label={t('dashboard.editpane.add', 'Add')}
onChangeTab={() => editPane.onChangeTab('add')}
/>
<Tab
active={tab === 'configure'}
label={t('dashboard.editpane.configure', 'Configure')}
onChangeTab={() => editPane.onChangeTab('configure')}
/>
<Tab
active={tab === 'outline'}
label={t('dashboard.editpane.outline', 'Outline')}
onChangeTab={() => editPane.onChangeTab('outline')}
/>
</TabsBar>
<div className={styles.tabContent}>
{tab === 'add' && <DashboardAddPane editPane={editPane} />}
{tab === 'configure' && <ElementEditPane element={editableElement} key={editableElement.typeName} />}
{tab === 'outline' && <div />}
</div>
</div>
);
}
@@ -202,11 +238,21 @@ function getStyles(theme: GrafanaTheme2) {
display: 'flex',
flexDirection: 'column',
flex: '1 1 0',
}),
tabContent: css({
display: 'flex',
flex: '1 1 0',
flexDirection: 'column',
minHeight: 0,
overflow: 'auto',
}),
rotate180: css({
rotate: '180deg',
}),
tabsbar: css({
padding: theme.spacing(0, 1),
margin: theme.spacing(0.5, 1),
}),
expandOptionsWrapper: css({
display: 'flex',
flexDirection: 'column',
@@ -156,83 +156,6 @@ export function ToolbarActions({ dashboard }: Props) {
}
if (dashboardNewLayouts) {
leftActions.push({
group: 'add-panel',
condition: isEditingAndShowingDashboard,
render: () => (
<Button
key="add-panel-button"
variant="secondary"
size="sm"
icon="plus"
fill="text"
onClick={() => {
dashboard.onCreateNewPanel();
}}
data-testid={selectors.components.PageToolbar.itemButton('add_visualization')}
>
<Trans i18nKey="dashboard.toolbar.add-panel">Panel</Trans>
</Button>
),
});
leftActions.push({
group: 'add-panel',
condition: isEditingAndShowingDashboard,
render: () => (
<Button
key="add-panel-button"
variant="secondary"
size="sm"
icon="plus"
fill="text"
onClick={() => {
dashboard.onCreateNewRow();
}}
data-testid={selectors.components.PageToolbar.itemButton('add_row')}
>
<Trans i18nKey="dashboard.toolbar.add-row">Row</Trans>
</Button>
),
});
leftActions.push({
group: 'add-panel',
condition: isEditingAndShowingDashboard,
render: () => (
<Button
key="add-tab-button"
variant="secondary"
size="sm"
icon="plus"
fill="text"
onClick={() => {
dashboard.onCreateNewTab();
}}
data-testid={selectors.components.PageToolbar.itemButton('add_tab')}
>
<Trans i18nKey="dashboard.toolbar.add-tab">Tab</Trans>
</Button>
),
});
leftActions.push({
group: 'add-panel',
condition: isEditingAndShowingDashboard,
render: () => (
<Button
key="add-panel-lib"
variant="secondary"
size="sm"
icon="plus"
fill="text"
data-testid={selectors.pages.AddDashboard.itemButton('Add new panel from panel library menu item')}
onClick={() => {
dashboard.onShowAddLibraryPanelDrawer();
DashboardInteractions.toolbarAddButtonClicked({ item: 'add_library_panel' });
}}
>
<Trans i18nKey="dashboard.toolbar.add-panel-lib">Import</Trans>
</Button>
),
});
leftActions.push({
group: 'hidden-elements',
condition: isEditingAndShowingDashboard,
+10 -1
View File
@@ -1057,6 +1057,11 @@
}
}
},
"editpane": {
"add": "Add",
"configure": "Configure",
"outline": "Outline"
},
"empty": {
"add-library-panel-body": "Add visualizations that are shared with other dashboards.",
"add-library-panel-button": "Add library panel",
@@ -1194,7 +1199,8 @@
"toolbar": {
"add": "Add",
"add-panel": "Panel",
"add-panel-lib": "Import",
"add-panel-description": "A container for visualizations and other content",
"add-panel-lib": "Import library panel",
"add-row": "Row",
"add-tab": "Tab",
"alert-rules": "Alert rules",
@@ -1219,6 +1225,7 @@
"label": "Exit edit",
"tooltip": "Exits edit mode and discards unsaved changes"
},
"libray-panel-description": "Libray panels allow you share and reuse panels between dashboards",
"mark-favorite": "Mark as favorite",
"more-save-options": "More save options",
"open-original": "Open original dashboard",
@@ -1227,6 +1234,7 @@
"playlist-stop": "Stop playlist",
"public-dashboard": "Public",
"refresh": "Refresh dashboard",
"row-description": "A group of panels with an optional header",
"save": "Save dashboard",
"save-dashboard": {
"label": "Save dashboard",
@@ -1246,6 +1254,7 @@
"share-button": "Share",
"show-hidden-elements": "Show hidden",
"switch-old-dashboard": "Switch to old dashboard page",
"tabs-description": "Break up your dashboard into different horizontal tabs",
"unlink-library-panel": "Unlink library panel",
"unmark-favorite": "Unmark as favorite"
},
+10 -1
View File
@@ -1057,6 +1057,11 @@
}
}
},
"editpane": {
"add": "Åđđ",
"configure": "Cőʼnƒįģūřę",
"outline": "Øūŧľįʼnę"
},
"empty": {
"add-library-panel-body": "Åđđ vįşūäľįžäŧįőʼnş ŧĥäŧ äřę şĥäřęđ ŵįŧĥ őŧĥęř đäşĥþőäřđş.",
"add-library-panel-button": "Åđđ ľįþřäřy päʼnęľ",
@@ -1194,7 +1199,8 @@
"toolbar": {
"add": "Åđđ",
"add-panel": "Päʼnęľ",
"add-panel-lib": "Ĩmpőřŧ",
"add-panel-description": "Å čőʼnŧäįʼnęř ƒőř vįşūäľįžäŧįőʼnş äʼnđ őŧĥęř čőʼnŧęʼnŧ",
"add-panel-lib": "Ĩmpőřŧ ľįþřäřy päʼnęľ",
"add-row": "Ŗőŵ",
"add-tab": "Ŧäþ",
"alert-rules": "Åľęřŧ řūľęş",
@@ -1219,6 +1225,7 @@
"label": "Ēχįŧ ęđįŧ",
"tooltip": "Ēχįŧş ęđįŧ mőđę äʼnđ đįşčäřđş ūʼnşävęđ čĥäʼnģęş"
},
"libray-panel-description": "Ŀįþřäy päʼnęľş äľľőŵ yőū şĥäřę äʼnđ řęūşę päʼnęľş þęŧŵęęʼn đäşĥþőäřđş",
"mark-favorite": "Mäřĸ äş ƒävőřįŧę",
"more-save-options": "Mőřę şävę őpŧįőʼnş",
"open-original": "Øpęʼn őřįģįʼnäľ đäşĥþőäřđ",
@@ -1227,6 +1234,7 @@
"playlist-stop": "Ŝŧőp pľäyľįşŧ",
"public-dashboard": "Pūþľįč",
"refresh": "Ŗęƒřęşĥ đäşĥþőäřđ",
"row-description": "Å ģřőūp őƒ päʼnęľş ŵįŧĥ äʼn őpŧįőʼnäľ ĥęäđęř",
"save": "Ŝävę đäşĥþőäřđ",
"save-dashboard": {
"label": "Ŝävę đäşĥþőäřđ",
@@ -1246,6 +1254,7 @@
"share-button": "Ŝĥäřę",
"show-hidden-elements": "Ŝĥőŵ ĥįđđęʼn",
"switch-old-dashboard": "Ŝŵįŧčĥ ŧő őľđ đäşĥþőäřđ päģę",
"tabs-description": "ßřęäĸ ūp yőūř đäşĥþőäřđ įʼnŧő đįƒƒęřęʼnŧ ĥőřįžőʼnŧäľ ŧäþş",
"unlink-library-panel": "Ůʼnľįʼnĸ ľįþřäřy päʼnęľ",
"unmark-favorite": "Ůʼnmäřĸ äş ƒävőřįŧę"
},