{
- if (evt.shiftKey) {
- return;
- }
+ const sidebarContext = useSidebar({
+ hasOpenPane: Boolean(openPane),
+ contentMargin: 1,
+ position: 'right',
+ });
- editPane.clearSelection();
- }}
- >
-
-
{controls}
-
-
- {body}
-
+ /**
+ * Sync docked state to editPane state
+ */
+ useEffect(() => {
+ editPane.setState({ isDocked: sidebarContext.isDocked });
+ }, [sidebarContext.isDocked, editPane]);
+
+ const onClearSelection: React.PointerEventHandler
= (evt) => {
+ if (evt.shiftKey) {
+ return;
+ }
+
+ editPane.clearSelection();
+ };
+
+ return (
+
+
+
+ {hasUid && canStar && }
+ {hasUid && canStar && }
+ {renderDynamicNavActions()}
+ >
+ }
+ />
+
+ {controls}
+
+
- {isEditing && (
- <>
-
-
- 0}
- />
-
- >
- )}
);
}
+function renderDynamicNavActions() {
+ const dashboard = getDashboardSrv().getCurrent()!;
+ const showProps = { dashboard };
+
+ return dynamicDashNavActions.left.map((action, index) => {
+ if (action.show(showProps)) {
+ const ActionComponent = action.component;
+ return ;
+ }
+ return null;
+ });
+}
+
function getStyles(theme: GrafanaTheme2, headerHeight: number) {
return {
canvasWrappperOld: css({
@@ -138,22 +140,33 @@ function getStyles(theme: GrafanaTheme2, headerHeight: number) {
flexDirection: 'column',
flexGrow: 1,
}),
- canvasWithSplitter: css({
- overflow: 'unset',
- display: 'flex',
- flexDirection: 'column',
- flexGrow: 1,
- }),
- canvasWithSplitterEditing: css({
- overflow: 'unset',
- }),
- bodyWrapper: css({
- label: 'body-wrapper',
+ container: css({
+ label: 'container',
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
position: 'relative',
}),
+ bodyWrapper: css({
+ label: 'body-wrapper',
+ display: 'flex',
+ flexDirection: 'row',
+ flexGrow: 1,
+ position: 'relative',
+ flex: '1 1 0',
+ overflow: 'hidden',
+ }),
+ bodyWithToolbar: css({
+ display: 'flex',
+ flexDirection: 'column',
+ flexGrow: 1,
+ minHeight: 0,
+ overflow: 'auto',
+ scrollbarWidth: 'thin',
+ scrollbarGutter: 'stable',
+ // without top padding the fixed controls headers is rendered over the selection outline.
+ padding: theme.spacing(0.125, 1, 2, 2),
+ }),
body: css({
label: 'body',
display: 'flex',
@@ -181,11 +194,6 @@ function getStyles(theme: GrafanaTheme2, headerHeight: number) {
// borderLeft: `1px solid ${theme.colors.border.weak}`,
// background: theme.colors.background.primary,
}),
- splitter: css({
- '&:after': {
- display: 'none',
- },
- }),
controlsWrapperSticky: css({
[theme.breakpoints.up('md')]: {
position: 'sticky',
diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx
index 8c81d88b345..c68696e439d 100644
--- a/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx
+++ b/public/app/features/dashboard-scene/edit-pane/DashboardEditableElement.tsx
@@ -8,10 +8,9 @@ import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/Pan
import { DashboardScene } from '../scene/DashboardScene';
import { useLayoutCategory } from '../scene/layouts-shared/DashboardLayoutSelector';
-import { EditSchemaV2Button } from '../scene/new-toolbar/actions/EditSchemaV2Button';
import { EditableDashboardElement, EditableDashboardElementInfo } from '../scene/types/EditableDashboardElement';
-import { dashboardEditActions, undoRedoWasClicked } from './shared';
+import { dashboardEditActions } from './shared';
function useEditPaneOptions(
this: DashboardEditableElement,
@@ -69,19 +68,16 @@ export class DashboardEditableElement implements EditableDashboardElement {
public renderActions(): ReactNode {
return (
- <>
-
-
- >
+
);
}
}
@@ -104,7 +100,7 @@ export function DashboardTitleInput({ dashboard, id }: { dashboard: DashboardSce
}}
onBlur={(e) => {
const titleUnchanged = valueBeforeEdit.current === e.currentTarget.value;
- const shouldSkip = titleUnchanged || undoRedoWasClicked(e);
+ const shouldSkip = titleUnchanged;
if (shouldSkip) {
return;
}
@@ -135,7 +131,7 @@ export function DashboardDescriptionInput({ dashboard, id }: { dashboard: Dashbo
}}
onBlur={(e) => {
const descriptionUnchanged = valueBeforeEdit.current === e.currentTarget.value;
- const shouldSkip = descriptionUnchanged || undoRedoWasClicked(e);
+ const shouldSkip = descriptionUnchanged;
if (shouldSkip) {
return;
}
diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardExportButton.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardExportButton.tsx
new file mode 100644
index 00000000000..35d8afbdb4d
--- /dev/null
+++ b/public/app/features/dashboard-scene/edit-pane/DashboardExportButton.tsx
@@ -0,0 +1,57 @@
+import { selectors } from '@grafana/e2e-selectors';
+import { t } from '@grafana/i18n';
+import { locationService } from '@grafana/runtime';
+import { Dropdown, Sidebar } from '@grafana/ui';
+import { appEvents } from 'app/core/app_events';
+import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
+import { ShowConfirmModalEvent } from 'app/types/events';
+
+import { DashboardScene } from '../scene/DashboardScene';
+import ExportMenu from '../sharing/ExportButton/ExportMenu';
+import { DashboardInteractions } from '../utils/interactions';
+
+interface Props {
+ dashboard: DashboardScene;
+}
+
+const newExportButtonSelector = selectors.pages.Dashboard.DashNav.NewExportButton;
+
+export function ShareExportDashboardButton({ dashboard }: Props) {
+ return (
+ } placement="left-end">
+ {
+ if (dashboard.state.isEditing && dashboard.state.isDirty) {
+ evt.preventDefault();
+ evt.stopPropagation();
+
+ appEvents.publish(
+ new ShowConfirmModalEvent({
+ title: t('dashboard.sidebar.export.unsaved-modal.title', 'Save changes to dashboard?'),
+ text: t(
+ 'dashboard.sidebar.export.unsaved-modal.text',
+ 'You have unsaved changes to this dashboard. You need to save them before you can share it.'
+ ),
+ icon: 'exclamation-triangle',
+ noText: t('common.discard', 'Discard'),
+ yesText: t('common.save', 'Save'),
+ yesButtonVariant: 'primary',
+ onConfirm: () => dashboard.openSaveDrawer({}),
+ })
+ );
+ } else {
+ locationService.partial({ shareView: shareDashboardType.export });
+
+ DashboardInteractions.sharingCategoryClicked({
+ item: shareDashboardType.export,
+ shareResource: getTrackingSource(),
+ });
+ }
+ }}
+ />
+
+ );
+}
diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardOutline.test.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.test.tsx
index 81d56cab57d..7b461551773 100644
--- a/public/app/features/dashboard-scene/edit-pane/DashboardOutline.test.tsx
+++ b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.test.tsx
@@ -101,7 +101,7 @@ describe('DashboardOutline', () => {
render(
-
+
);
// select Row lvl 1
diff --git a/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx
index 48a9c738856..4ce6536ac5c 100644
--- a/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx
+++ b/public/app/features/dashboard-scene/edit-pane/DashboardOutline.tsx
@@ -5,7 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '@grafana/i18n';
import { SceneObject } from '@grafana/scenes';
-import { Box, Icon, Stack, Text, useElementSelection, useStyles2 } from '@grafana/ui';
+import { Box, Icon, Sidebar, Stack, Text, useElementSelection, useStyles2 } from '@grafana/ui';
import { isRepeatCloneOrChildOf } from '../utils/clone';
import { DashboardInteractions } from '../utils/interactions';
@@ -17,28 +17,36 @@ import { useOutlineRename } from './useOutlineRename';
export interface Props {
editPane: DashboardEditPane;
+ isEditing: boolean | undefined;
}
-export function DashboardOutline({ editPane }: Props) {
+export function DashboardOutline({ editPane, isEditing }: Props) {
const dashboard = getDashboardSceneFor(editPane);
return (
-
-
-
+ <>
+ editPane.closePane()}
+ />
+
+
+
+ >
);
}
interface DashboardOutlineNodeProps {
sceneObject: SceneObject;
editPane: DashboardEditPane;
+ isEditing: boolean | undefined;
depth: number;
index: number;
}
-function DashboardOutlineNode({ sceneObject, editPane, depth, index }: DashboardOutlineNodeProps) {
+function DashboardOutlineNode({ sceneObject, editPane, isEditing, depth, index }: DashboardOutlineNodeProps) {
const styles = useStyles2(getStyles);
- const { key } = sceneObject.useState();
+ const key = sceneObject.state.key;
const [isCollapsed, setIsCollapsed] = useState(depth > 0);
const { isSelected, onSelect } = useElementSelection(key);
const isCloned = useMemo(() => isRepeatCloneOrChildOf(sceneObject), [sceneObject]);
@@ -49,7 +57,7 @@ function DashboardOutlineNode({ sceneObject, editPane, depth, index }: Dashboard
const children = editableElement.getOutlineChildren?.() ?? [];
const elementInfo = editableElement.getEditableElementInfo();
const instanceName = elementInfo.instanceName === '' ? noTitleText : elementInfo.instanceName;
- const outlineRename = useOutlineRename(editableElement);
+ const outlineRename = useOutlineRename(editableElement, isEditing);
const isContainer = editableElement.getOutlineChildren ? true : false;
const onNodeClicked = (e: React.MouseEvent) => {
@@ -131,6 +139,7 @@ function DashboardOutlineNode({ sceneObject, editPane, depth, index }: Dashboard
sceneObject={child}
editPane={editPane}
depth={depth + 1}
+ isEditing={isEditing}
index={i}
/>
))
diff --git a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx
index b2a7a149715..ea14464fc64 100644
--- a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx
+++ b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx
@@ -1,9 +1,6 @@
-import { css } from '@emotion/css';
-
-import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '@grafana/i18n';
-import { Button, Menu, Stack, Text, useStyles2, Dropdown, Icon, IconButton } from '@grafana/ui';
+import { Button, Menu, Stack, Dropdown, Icon, Sidebar } from '@grafana/ui';
import { trackDeleteDashboardElement } from 'app/features/dashboard-scene/utils/tracking';
import { EditableDashboardElement } from '../scene/types/EditableDashboardElement';
@@ -17,15 +14,11 @@ interface EditPaneHeaderProps {
export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) {
const elementInfo = element.getEditableElementInfo();
- const styles = useStyles2(getStyles);
const onCopy = element.onCopy?.bind(element);
const onDuplicate = element.onDuplicate?.bind(element);
const onDelete = element.onDelete?.bind(element);
const onConfirmDelete = element.onConfirmDelete?.bind(element);
- // temporary simple solution, should select parent element
- const onGoBack = () => editPane.clearSelection();
- const canGoBack = editPane.state.selection;
const onDeleteElement = () => {
if (onConfirmDelete) {
@@ -37,20 +30,7 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) {
};
return (
-
-
- {canGoBack && (
-
- )}
- {elementInfo.typeName}
-
+ editPane.closePane()}>
{element.renderActions && element.renderActions()}
{(onCopy || onDuplicate) && (
@@ -95,18 +75,6 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) {
/>
)}
-
+
);
}
-
-function getStyles(theme: GrafanaTheme2) {
- return {
- wrapper: css({
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'space-between',
- padding: theme.spacing(1, 2),
- borderBottom: `1px solid ${theme.colors.border.weak}`,
- }),
- };
-}
diff --git a/public/app/features/dashboard-scene/edit-pane/shared.ts b/public/app/features/dashboard-scene/edit-pane/shared.ts
index 6d9a2279563..39fd5fec9a7 100644
--- a/public/app/features/dashboard-scene/edit-pane/shared.ts
+++ b/public/app/features/dashboard-scene/edit-pane/shared.ts
@@ -14,7 +14,6 @@ import {
import { DashboardScene } from '../scene/DashboardScene';
import { SceneGridRowEditableElement } from '../scene/layout-default/SceneGridRowEditableElement';
-import { redoButtonId, undoButtonID } from '../scene/new-toolbar/RightActions';
import { EditableDashboardElement, isEditableDashboardElement } from '../scene/types/EditableDashboardElement';
import { LocalVariableEditableElement } from '../settings/variables/LocalVariableEditableElement';
import { VariableAdd, VariableAddEditableElement } from '../settings/variables/VariableAddEditableElement';
@@ -299,7 +298,3 @@ function makeEditAction {
- if (!selection) {
- const dashboard = getDashboardSceneFor(editPane);
- return new ElementSelection([[dashboard.state.uid!, dashboard.getRef()]]).createSelectionElement();
- }
-
- return selection.createSelectionElement();
- }, [selection, editPane]);
-}
diff --git a/public/app/features/dashboard-scene/edit-pane/useOutlineRename.tsx b/public/app/features/dashboard-scene/edit-pane/useOutlineRename.tsx
index 81f3a4556f0..d87d83994eb 100644
--- a/public/app/features/dashboard-scene/edit-pane/useOutlineRename.tsx
+++ b/public/app/features/dashboard-scene/edit-pane/useOutlineRename.tsx
@@ -8,10 +8,14 @@ export interface OutlineRenameState {
error?: string;
}
-export function useOutlineRename(editableElement: EditableDashboardElement) {
+export function useOutlineRename(editableElement: EditableDashboardElement, isEditing: boolean | undefined) {
const [state, setState] = useState({});
const onNameDoubleClicked = (evt: React.MouseEvent) => {
+ if (!isEditing) {
+ return;
+ }
+
if (!editableElement.onChangeName) {
return;
}
diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
index 5268ea4d865..da18ca17dd4 100644
--- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
@@ -2,6 +2,8 @@ import { css, cx } from '@emotion/css';
import { GrafanaTheme2, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
+import { Trans } from '@grafana/i18n';
+import { config } from '@grafana/runtime';
import {
SceneObjectState,
SceneObjectBase,
@@ -15,7 +17,8 @@ import {
SceneObjectUrlValues,
CancelActivationHandler,
} from '@grafana/scenes';
-import { Box, useStyles2 } from '@grafana/ui';
+import { Box, Button, useStyles2 } from '@grafana/ui';
+import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
import { PanelEditControls } from '../panel-edit/PanelEditControls';
import { getDashboardSceneFor } from '../utils/utils';
@@ -25,6 +28,9 @@ import { DashboardDataLayerControls } from './DashboardDataLayerControls';
import { DashboardLinksControls } from './DashboardLinksControls';
import { DashboardScene } from './DashboardScene';
import { VariableControls } from './VariableControls';
+import { EditDashboardSwitch } from './new-toolbar/actions/EditDashboardSwitch';
+import { SaveDashboard } from './new-toolbar/actions/SaveDashboard';
+import { ShareDashboardButton } from './new-toolbar/actions/ShareDashboardButton';
export interface DashboardControlsState extends SceneObjectState {
timePicker: SceneTimePicker;
@@ -32,7 +38,7 @@ export interface DashboardControlsState extends SceneObjectState {
hideTimeControls?: boolean;
hideVariableControls?: boolean;
hideLinksControls?: boolean;
- // Hides the dashbaord-controls dropdown menu
+ // Hides the dashboard-controls dropdown menu
hideDashboardControls?: boolean;
}
@@ -171,6 +177,7 @@ function DashboardControlsRenderer({ model }: SceneComponentProps
)}
{!hideDashboardControls && model.hasDashboardControls() && }
+ {config.featureToggles.dashboardNewLayouts && }
{!hideVariableControls && (
<>
@@ -185,6 +192,37 @@ function DashboardControlsRenderer({ model }: SceneComponentProps
+ {showShareButton && }
+ {isEditing && }
+ {!isPlaying && canEditDashboard && }
+ {isPlaying && (
+
+ )}
+ >
+ );
+}
+
function renderHiddenVariables(dashboard: DashboardScene) {
const { variables } = sceneGraph.getVariables(dashboard).useState();
const renderAsHiddenVariables = variables.filter((v) => v.UNSAFE_renderAsHidden);
diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
index 1c75360a7b5..a542dd92826 100644
--- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
@@ -275,7 +275,7 @@ export class DashboardScene extends SceneObjectBase impleme
this._initialUrlState = locationService.getLocation();
// Switch to edit mode
- this.setState({ isEditing: true });
+ this.setState({ isEditing: true, editable: true });
// Propagate change edit mode change to children
this.state.body.editModeChanged?.(true);
@@ -692,16 +692,16 @@ export class DashboardScene extends SceneObjectBase impleme
canEditDashboard() {
const { meta } = this.state;
- return Boolean(meta.canEdit || meta.canMakeEditable || config.viewersCanEdit);
+ return !meta.isSnapshot && Boolean(meta.canEdit || meta.canMakeEditable || config.viewersCanEdit);
}
public getInitialSaveModel() {
return this.serializer.initialSaveModel;
}
- public getSnapshotUrl = () => {
- return this.serializer.getSnapshotUrl();
- };
+ public getSnapshotUrl() {
+ return this.serializer.getSnapshotUrl() ?? '';
+ }
/** Hacky temp function until we refactor transformSaveModelToScene a bit */
setInitialSaveModel(model?: Dashboard, meta?: DashboardMeta, apiVersion?: string): void;
diff --git a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
index 2efcad5a256..80c8487f1c5 100644
--- a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
+++ b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
@@ -20,7 +20,7 @@ export function GoToSnapshotOriginButton(props: { originalURL: string }) {
);
}
-const onOpenSnapshotOriginalDashboard = (originalUrl: string) => {
+export const onOpenSnapshotOriginalDashboard = (originalUrl: string) => {
const relativeURL = originalUrl ?? '';
const sanitizedRelativeURL = textUtil.sanitizeUrl(relativeURL);
try {
diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
index 68ccadaba13..959913c8f8f 100644
--- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
+++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
@@ -153,9 +153,7 @@ export function ToolbarActions({ dashboard }: Props) {
toolbarActions.push({
group: 'icon-actions',
condition: meta.isSnapshot && !isEditing,
- render: () => (
-
- ),
+ render: () => ,
});
if (!isEditingPanel && !isEditing) {
diff --git a/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx b/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx
index 59dfc714669..2e2f979d51d 100644
--- a/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx
+++ b/public/app/features/dashboard-scene/scene/new-toolbar/RightActions.tsx
@@ -1,8 +1,7 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
-import { config } from '@grafana/runtime';
-import { ToolbarButton, ToolbarButtonRow, useStyles2 } from '@grafana/ui';
+import { ToolbarButtonRow, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { playlistSrv } from 'app/features/playlist/PlaylistSrv';
@@ -11,45 +10,35 @@ import { isLibraryPanel } from '../../utils/utils';
import { DashboardScene } from '../DashboardScene';
import { BackToDashboardButton } from './actions/BackToDashboardButton';
-import { DashboardSettingsButton } from './actions/DashboardSettingsButton';
import { DiscardLibraryPanelButton } from './actions/DiscardLibraryPanelButton';
import { DiscardPanelButton } from './actions/DiscardPanelButton';
-import { EditDashboardSwitch } from './actions/EditDashboardSwitch';
-import { ExportDashboardButton } from './actions/ExportDashboardButton';
import { MakeDashboardEditableButton } from './actions/MakeDashboardEditableButton';
import { PlayListNextButton } from './actions/PlayListNextButton';
import { PlayListPreviousButton } from './actions/PlayListPreviousButton';
import { PlayListStopButton } from './actions/PlayListStopButton';
import { SaveDashboard } from './actions/SaveDashboard';
import { SaveLibraryPanelButton } from './actions/SaveLibraryPanelButton';
-import { ShareDashboardButton } from './actions/ShareDashboardButton';
import { UnlinkLibraryPanelButton } from './actions/UnlinkLibraryPanelButton';
-import { ToolbarActionProps } from './types';
import { getDynamicActions, renderActionElements } from './utils';
export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => {
- const { editPanel, editable, editview, isEditing, uid, meta, viewPanel } = dashboard.useState();
+ const { editPanel, editable, editview, isEditing, meta, viewPanel } = dashboard.useState();
const { isPlaying } = playlistSrv.useState();
const styles = useStyles2(getStyles);
const isEditable = Boolean(editable);
const canSave = Boolean(meta.canSave);
- const hasUid = Boolean(uid);
const isEditingDashboard = Boolean(isEditing);
const hasEditView = Boolean(editview);
const isEditingPanel = Boolean(editPanel);
const isViewingPanel = Boolean(viewPanel);
const isEditingLibraryPanel = isEditingPanel && isLibraryPanel(editPanel!.state.panelRef.resolve());
const isShowingDashboard = !hasEditView && !isViewingPanel && !isEditingPanel;
- const isEditingAndShowingDashboard = isEditingDashboard && isShowingDashboard;
- const isSnapshot = Boolean(meta.isSnapshot);
const canSaveInFolder = contextSrv.hasEditPermissionInFolders;
const canEditDashboard = dashboard.canEditDashboard();
const showPanelButtons = isEditingPanel && !hasEditView && !isViewingPanel;
const showPlayButtons = isPlaying && isShowingDashboard && !isEditingDashboard;
- const showShareButton = hasUid && !isSnapshot && !isPlaying && !isEditingPanel;
- const showUndoRedoButtons = isEditingAndShowingDashboard && !!config.featureToggles.dashboardUndoRedo;
return (
@@ -106,28 +95,10 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => {
group: 'panel',
condition: showPanelButtons && isEditingLibraryPanel,
},
- {
- key: 'dashboard-undo',
- component: UndoButton,
- group: 'dashboard',
- condition: showUndoRedoButtons,
- },
- {
- key: 'dashboard-redo',
- component: RedoButton,
- group: 'dashboard',
- condition: showUndoRedoButtons,
- },
- {
- key: 'dashboard-settings',
- component: DashboardSettingsButton,
- group: 'dashboard',
- condition: isEditingAndShowingDashboard && canEditDashboard,
- },
{
key: 'save-dashboard',
component: SaveDashboard,
- group: 'save-edit',
+ group: 'panel',
condition: isEditingDashboard && !isEditingLibraryPanel && (canSave || canSaveInFolder),
},
{
@@ -136,31 +107,6 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => {
group: 'save-edit',
condition: !isEditing && canEditDashboard && !isViewingPanel && !isEditable && !isPlaying,
},
- {
- key: 'edit-dashboard-switch',
- component: EditDashboardSwitch,
- group: 'save-edit',
- condition:
- canEditDashboard &&
- !isEditingPanel &&
- !isEditingLibraryPanel &&
- !isViewingPanel &&
- isEditable &&
- !isPlaying &&
- !isEditingPanel,
- },
- {
- key: 'new-export-dashboard-button',
- component: ExportDashboardButton,
- group: 'export-share',
- condition: showShareButton,
- },
- {
- key: 'new-share-dashboard-button',
- component: ShareDashboardButton,
- group: 'export-share',
- condition: showShareButton,
- },
],
dashboard
)}
@@ -168,42 +114,6 @@ export const RightActions = ({ dashboard }: { dashboard: DashboardScene }) => {
);
};
-export const undoButtonID = 'undo-button';
-function UndoButton({ dashboard }: ToolbarActionProps) {
- const editPane = dashboard.state.editPane;
- const { undoStack } = editPane.useState();
- const undoAction = undoStack[undoStack.length - 1];
- const tooltip = `Undo${undoAction?.description ? ` '${undoAction.description}'` : ''}`;
-
- return (
- editPane.undoAction()}
- tooltip={tooltip}
- />
- );
-}
-
-export const redoButtonId = 'redo-button';
-function RedoButton({ dashboard }: ToolbarActionProps) {
- const editPane = dashboard.state.editPane;
- const { redoStack } = editPane.useState();
- const redoAction = redoStack[redoStack.length - 1];
- const tooltip = `Redo${redoAction?.description ? ` '${redoAction.description}'` : ''}`;
-
- return (
- editPane.redoAction()}
- />
- );
-}
-
const getStyles = (theme: GrafanaTheme2) => ({
container: css({ paddingLeft: theme.spacing(0.5) }),
});
diff --git a/public/app/features/dashboard-scene/scene/new-toolbar/actions/ExportDashboardButton.tsx b/public/app/features/dashboard-scene/scene/new-toolbar/actions/ExportDashboardButton.tsx
deleted file mode 100644
index d8004d00b13..00000000000
--- a/public/app/features/dashboard-scene/scene/new-toolbar/actions/ExportDashboardButton.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
-import { t } from '@grafana/i18n';
-import { config, locationService } from '@grafana/runtime';
-import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
-
-import ExportMenu from '../../../sharing/ExportButton/ExportMenu';
-import { DashboardInteractions } from '../../../utils/interactions';
-import { ToolbarActionProps } from '../types';
-
-import { ShareExportDashboardButton } from './ShareExportDashboardButton';
-
-const newExportButtonSelector = e2eSelectors.pages.Dashboard.DashNav.NewExportButton;
-
-export const ExportDashboardButton = ({ dashboard }: ToolbarActionProps) => {
- const buttonTooltip = config.featureToggles.kubernetesDashboards
- ? t('dashboard.toolbar.new.export.tooltip.as-code', 'Export as code')
- : t('dashboard.toolbar.new.export.tooltip.json', 'Export as JSON');
-
- return (
- }
- groupTestId={newExportButtonSelector.container}
- buttonLabel={t('dashboard.toolbar.new.export.title', 'Export')}
- buttonTooltip={buttonTooltip}
- buttonTestId={newExportButtonSelector.container}
- onButtonClick={() => {
- locationService.partial({ shareView: shareDashboardType.export });
-
- DashboardInteractions.sharingCategoryClicked({
- item: shareDashboardType.export,
- shareResource: getTrackingSource(),
- });
- }}
- arrowLabel={t('dashboard.toolbar.new.export.arrow', 'Export')}
- arrowTestId={newExportButtonSelector.arrowMenu}
- dashboard={dashboard}
- />
- );
-};
diff --git a/public/app/features/dashboard-scene/scene/new-toolbar/actions/OpenSnapshotOriginButton.tsx b/public/app/features/dashboard-scene/scene/new-toolbar/actions/OpenSnapshotOriginButton.tsx
index c59d06a74ae..51d04d2272a 100644
--- a/public/app/features/dashboard-scene/scene/new-toolbar/actions/OpenSnapshotOriginButton.tsx
+++ b/public/app/features/dashboard-scene/scene/new-toolbar/actions/OpenSnapshotOriginButton.tsx
@@ -2,5 +2,5 @@ import { GoToSnapshotOriginButton } from '../../GoToSnapshotOriginButton';
import { ToolbarActionProps } from '../types';
export const OpenSnapshotOriginButton = ({ dashboard }: ToolbarActionProps) => (
-
+
);
diff --git a/public/app/features/dashboard-scene/scene/new-toolbar/actions/SaveDashboard.tsx b/public/app/features/dashboard-scene/scene/new-toolbar/actions/SaveDashboard.tsx
index 0c33cf19b68..f2819e44c1c 100644
--- a/public/app/features/dashboard-scene/scene/new-toolbar/actions/SaveDashboard.tsx
+++ b/public/app/features/dashboard-scene/scene/new-toolbar/actions/SaveDashboard.tsx
@@ -6,10 +6,12 @@ import { contextSrv } from 'app/core/services/context_srv';
import { ToolbarActionProps } from '../types';
export const SaveDashboard = ({ dashboard }: ToolbarActionProps) => {
- const { meta, isDirty, uid } = dashboard.state;
+ const { meta, isDirty, uid, editview, editPanel } = dashboard.state;
const isNew = !Boolean(uid || dashboard.isManaged());
const isManaged = dashboard.isManaged();
+ // In dashboard settings we still use the nav toolbar for a short while
+ const buttonSize = Boolean(editview) || editPanel ? 'sm' : 'md';
// if we only can save
if (isNew) {
@@ -17,7 +19,7 @@ export const SaveDashboard = ({ dashboard }: ToolbarActionProps) => {