mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
UI: New share button and toolbar reorganize (#77563)
This commit is contained in:
parent
eae6adf002
commit
25ff4baa76
@ -14,7 +14,7 @@ describe('Public dashboards', () => {
|
|||||||
cy.wait('@query');
|
cy.wait('@query');
|
||||||
|
|
||||||
// Open sharing modal
|
// Open sharing modal
|
||||||
e2e.pages.ShareDashboardModal.shareButton().click();
|
e2e.pages.Dashboard.DashNav.shareButton().click();
|
||||||
|
|
||||||
// Select public dashboards tab
|
// Select public dashboards tab
|
||||||
e2e.pages.ShareDashboardModal.PublicDashboard.Tab().click();
|
e2e.pages.ShareDashboardModal.PublicDashboard.Tab().click();
|
||||||
@ -74,7 +74,7 @@ describe('Public dashboards', () => {
|
|||||||
e2e.pages.Dashboard.DashNav.publicDashboardTag().should('exist');
|
e2e.pages.Dashboard.DashNav.publicDashboardTag().should('exist');
|
||||||
|
|
||||||
// Open sharing modal
|
// Open sharing modal
|
||||||
e2e.pages.ShareDashboardModal.shareButton().click();
|
e2e.pages.Dashboard.DashNav.shareButton().click();
|
||||||
|
|
||||||
// Select public dashboards tab
|
// Select public dashboards tab
|
||||||
cy.intercept('GET', '/api/dashboards/uid/ZqZnVvFZz/public-dashboards').as('query-public-dashboard');
|
cy.intercept('GET', '/api/dashboards/uid/ZqZnVvFZz/public-dashboards').as('query-public-dashboard');
|
||||||
@ -114,7 +114,7 @@ describe('Public dashboards', () => {
|
|||||||
cy.wait('@query');
|
cy.wait('@query');
|
||||||
|
|
||||||
// Open sharing modal
|
// Open sharing modal
|
||||||
e2e.pages.ShareDashboardModal.shareButton().click();
|
e2e.pages.Dashboard.DashNav.shareButton().click();
|
||||||
|
|
||||||
// Select public dashboards tab
|
// Select public dashboards tab
|
||||||
cy.intercept('GET', '/api/dashboards/uid/ZqZnVvFZz/public-dashboards').as('query-public-dashboard');
|
cy.intercept('GET', '/api/dashboards/uid/ZqZnVvFZz/public-dashboards').as('query-public-dashboard');
|
||||||
|
@ -10,7 +10,7 @@ describe('Create a public dashboard with template variables shows a template var
|
|||||||
e2e.flows.openDashboard({ uid: 'HYaGDGIMk' });
|
e2e.flows.openDashboard({ uid: 'HYaGDGIMk' });
|
||||||
|
|
||||||
// Open sharing modal
|
// Open sharing modal
|
||||||
e2e.pages.ShareDashboardModal.shareButton().click();
|
e2e.pages.Dashboard.DashNav.shareButton().click();
|
||||||
|
|
||||||
// Select public dashboards tab
|
// Select public dashboards tab
|
||||||
e2e.pages.ShareDashboardModal.PublicDashboard.Tab().click();
|
e2e.pages.ShareDashboardModal.PublicDashboard.Tab().click();
|
||||||
|
@ -56,6 +56,7 @@ export const Pages = {
|
|||||||
nav: 'Dashboard navigation',
|
nav: 'Dashboard navigation',
|
||||||
navV2: 'data-testid Dashboard navigation',
|
navV2: 'data-testid Dashboard navigation',
|
||||||
publicDashboardTag: 'data-testid public dashboard tag',
|
publicDashboardTag: 'data-testid public dashboard tag',
|
||||||
|
shareButton: 'data-testid share-button',
|
||||||
},
|
},
|
||||||
SubMenu: {
|
SubMenu: {
|
||||||
submenu: 'Dashboard submenu',
|
submenu: 'Dashboard submenu',
|
||||||
@ -208,7 +209,6 @@ export const Pages = {
|
|||||||
linkToRenderedImage: 'Link to rendered image',
|
linkToRenderedImage: 'Link to rendered image',
|
||||||
},
|
},
|
||||||
ShareDashboardModal: {
|
ShareDashboardModal: {
|
||||||
shareButton: 'Share dashboard',
|
|
||||||
PublicDashboard: {
|
PublicDashboard: {
|
||||||
Tab: 'Tab Public dashboard',
|
Tab: 'Tab Public dashboard',
|
||||||
WillBePublicCheckbox: 'data-testid public dashboard will be public checkbox',
|
WillBePublicCheckbox: 'data-testid public dashboard will be public checkbox',
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { Dropdown, Button, useTheme2, Icon } from '@grafana/ui';
|
import { Dropdown, Button, Icon } from '@grafana/ui';
|
||||||
import { Trans } from 'app/core/internationalization';
|
import { Trans } from 'app/core/internationalization';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
|
|
||||||
@ -15,7 +13,6 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AddPanelButton = ({ dashboard, onToolbarAddMenuOpen }: Props) => {
|
const AddPanelButton = ({ dashboard, onToolbarAddMenuOpen }: Props) => {
|
||||||
const styles = getStyles(useTheme2());
|
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -32,10 +29,9 @@ const AddPanelButton = ({ dashboard, onToolbarAddMenuOpen }: Props) => {
|
|||||||
onVisibleChange={setIsMenuOpen}
|
onVisibleChange={setIsMenuOpen}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
icon="panel-add"
|
variant="secondary"
|
||||||
size="lg"
|
size="sm"
|
||||||
fill="text"
|
fill="outline"
|
||||||
className={cx(styles.button, styles.buttonIcon, styles.buttonText)}
|
|
||||||
data-testid={selectors.components.PageToolbar.itemButton('Add button')}
|
data-testid={selectors.components.PageToolbar.itemButton('Add button')}
|
||||||
>
|
>
|
||||||
<Trans i18nKey="dashboard.toolbar.add">Add</Trans>
|
<Trans i18nKey="dashboard.toolbar.add">Add</Trans>
|
||||||
@ -46,26 +42,3 @@ const AddPanelButton = ({ dashboard, onToolbarAddMenuOpen }: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default AddPanelButton;
|
export default AddPanelButton;
|
||||||
|
|
||||||
function getStyles(theme: GrafanaTheme2) {
|
|
||||||
return {
|
|
||||||
button: css({
|
|
||||||
label: 'add-panel-button',
|
|
||||||
padding: theme.spacing(0.5, 0.5, 0.5, 0.75),
|
|
||||||
height: theme.spacing((theme.components.height.sm + theme.components.height.md) / 2),
|
|
||||||
borderRadius: theme.shape.radius.default,
|
|
||||||
}),
|
|
||||||
buttonIcon: css({
|
|
||||||
svg: {
|
|
||||||
margin: 0,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
buttonText: css({
|
|
||||||
label: 'add-panel-button-text',
|
|
||||||
fontSize: theme.typography.body.fontSize,
|
|
||||||
span: {
|
|
||||||
marginLeft: theme.spacing(0.67),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -11,9 +11,9 @@ import {
|
|||||||
ModalsController,
|
ModalsController,
|
||||||
ToolbarButton,
|
ToolbarButton,
|
||||||
useForceUpdate,
|
useForceUpdate,
|
||||||
Tag,
|
|
||||||
ToolbarButtonRow,
|
ToolbarButtonRow,
|
||||||
ConfirmModal,
|
ConfirmModal,
|
||||||
|
Badge,
|
||||||
} from '@grafana/ui';
|
} from '@grafana/ui';
|
||||||
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||||
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator';
|
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbar/NavToolbarSeparator';
|
||||||
@ -163,7 +163,7 @@ export const DashNav = React.memo<Props>((props) => {
|
|||||||
|
|
||||||
const renderLeftActions = () => {
|
const renderLeftActions = () => {
|
||||||
const { dashboard, kioskMode } = props;
|
const { dashboard, kioskMode } = props;
|
||||||
const { canStar, canShare, isStarred } = dashboard.meta;
|
const { canStar, isStarred } = dashboard.meta;
|
||||||
const buttons: ReactNode[] = [];
|
const buttons: ReactNode[] = [];
|
||||||
|
|
||||||
if (kioskMode || isPlaylistRunning()) {
|
if (kioskMode || isPlaylistRunning()) {
|
||||||
@ -186,13 +186,10 @@ export const DashNav = React.memo<Props>((props) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canShare) {
|
|
||||||
buttons.push(<ShareButton key="button-share" dashboard={dashboard} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dashboard.meta.publicDashboardEnabled) {
|
if (dashboard.meta.publicDashboardEnabled) {
|
||||||
|
// TODO: This will be replaced with the new badge component. Color is required but gets override by css
|
||||||
buttons.push(
|
buttons.push(
|
||||||
<Tag key="public-dashboard" name="Public" colorIndex={5} data-testid={selectors.publicDashboardTag}></Tag>
|
<Badge color="blue" text="Public" className={publicBadgeStyle} data-testid={selectors.publicDashboardTag} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +252,7 @@ export const DashNav = React.memo<Props>((props) => {
|
|||||||
|
|
||||||
const renderRightActions = () => {
|
const renderRightActions = () => {
|
||||||
const { dashboard, onAddPanel, isFullscreen, kioskMode } = props;
|
const { dashboard, onAddPanel, isFullscreen, kioskMode } = props;
|
||||||
const { canSave, canEdit, showSettings } = dashboard.meta;
|
const { canSave, canEdit, showSettings, canShare } = dashboard.meta;
|
||||||
const { snapshot } = dashboard;
|
const { snapshot } = dashboard;
|
||||||
const snapshotUrl = snapshot && snapshot.originalUrl;
|
const snapshotUrl = snapshot && snapshot.originalUrl;
|
||||||
const buttons: ReactNode[] = [];
|
const buttons: ReactNode[] = [];
|
||||||
@ -268,6 +265,50 @@ export const DashNav = React.memo<Props>((props) => {
|
|||||||
return [renderTimeControls()];
|
return [renderTimeControls()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (snapshotUrl) {
|
||||||
|
buttons.push(
|
||||||
|
<ToolbarButton
|
||||||
|
tooltip={t('dashboard.toolbar.open-original', 'Open original dashboard')}
|
||||||
|
onClick={onOpenSnapshotOriginal}
|
||||||
|
icon="link"
|
||||||
|
key="button-snapshot"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canSave && !isFullscreen) {
|
||||||
|
buttons.push(
|
||||||
|
<ModalsController key="button-save">
|
||||||
|
{({ showModal, hideModal }) => (
|
||||||
|
<ToolbarButton
|
||||||
|
tooltip={t('dashboard.toolbar.save', 'Save dashboard')}
|
||||||
|
icon="save"
|
||||||
|
onClick={() => {
|
||||||
|
DashboardInteractions.toolbarSaveClick();
|
||||||
|
showModal(SaveDashboardDrawer, {
|
||||||
|
dashboard,
|
||||||
|
onDismiss: hideModal,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ModalsController>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addCustomContent(dynamicDashNavActions.right, buttons);
|
||||||
|
|
||||||
|
if (showSettings) {
|
||||||
|
buttons.push(
|
||||||
|
<ToolbarButton
|
||||||
|
tooltip={t('dashboard.toolbar.settings', 'Dashboard settings')}
|
||||||
|
icon="cog"
|
||||||
|
onClick={onOpenSettings}
|
||||||
|
key="button-settings"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (canEdit && !isFullscreen) {
|
if (canEdit && !isFullscreen) {
|
||||||
if (config.featureToggles.emptyDashboardPage) {
|
if (config.featureToggles.emptyDashboardPage) {
|
||||||
buttons.push(
|
buttons.push(
|
||||||
@ -290,49 +331,11 @@ export const DashNav = React.memo<Props>((props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canSave && !isFullscreen) {
|
if (canShare) {
|
||||||
buttons.push(
|
buttons.push(<ShareButton key="button-share" dashboard={dashboard} />);
|
||||||
<ModalsController key="button-save">
|
|
||||||
{({ showModal, hideModal }) => (
|
|
||||||
<ToolbarButton
|
|
||||||
tooltip={t('dashboard.toolbar.save', 'Save dashboard')}
|
|
||||||
icon="save"
|
|
||||||
onClick={() => {
|
|
||||||
DashboardInteractions.toolbarSaveClick();
|
|
||||||
showModal(SaveDashboardDrawer, {
|
|
||||||
dashboard,
|
|
||||||
onDismiss: hideModal,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ModalsController>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapshotUrl) {
|
buttons.push(<NavToolbarSeparator key="toolbar-separator" />);
|
||||||
buttons.push(
|
|
||||||
<ToolbarButton
|
|
||||||
tooltip={t('dashboard.toolbar.open-original', 'Open original dashboard')}
|
|
||||||
onClick={onOpenSnapshotOriginal}
|
|
||||||
icon="link"
|
|
||||||
key="button-snapshot"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showSettings) {
|
|
||||||
buttons.push(
|
|
||||||
<ToolbarButton
|
|
||||||
tooltip={t('dashboard.toolbar.settings', 'Dashboard settings')}
|
|
||||||
icon="cog"
|
|
||||||
onClick={onOpenSettings}
|
|
||||||
key="button-settings"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
addCustomContent(dynamicDashNavActions.right, buttons);
|
|
||||||
|
|
||||||
buttons.push(renderTimeControls());
|
buttons.push(renderTimeControls());
|
||||||
|
|
||||||
@ -360,3 +363,9 @@ const modalStyles = css({
|
|||||||
width: 'max-content',
|
width: 'max-content',
|
||||||
maxWidth: '80vw',
|
maxWidth: '80vw',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const publicBadgeStyle = css({
|
||||||
|
color: 'grey',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
border: '1px solid',
|
||||||
|
});
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import React, { useContext, useEffect } from 'react';
|
import React, { useContext, useEffect } from 'react';
|
||||||
|
|
||||||
import { ModalsContext } from '@grafana/ui';
|
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||||
|
import { ModalsContext, Button } from '@grafana/ui';
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
import { t } from 'app/core/internationalization';
|
import { Trans } from 'app/core/internationalization';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { DashboardModel } from 'app/features/dashboard/state';
|
||||||
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
|
||||||
|
|
||||||
import { ShareModal } from '../ShareModal';
|
import { ShareModal } from '../ShareModal';
|
||||||
|
|
||||||
import { DashNavButton } from './DashNavButton';
|
|
||||||
|
|
||||||
export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
|
export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
|
||||||
const [queryParams] = useQueryParams();
|
const [queryParams] = useQueryParams();
|
||||||
const { showModal, hideModal } = useContext(ModalsContext);
|
const { showModal, hideModal } = useContext(ModalsContext);
|
||||||
@ -28,10 +27,10 @@ export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
|
|||||||
}, [showModal, hideModal, dashboard, queryParams.shareView]);
|
}, [showModal, hideModal, dashboard, queryParams.shareView]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashNavButton
|
<Button
|
||||||
tooltip={t('dashboard.toolbar.share', 'Share dashboard')}
|
data-testid={e2eSelectors.pages.Dashboard.DashNav.shareButton}
|
||||||
icon="share-alt"
|
variant="primary"
|
||||||
iconSize="lg"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
DashboardInteractions.toolbarShareClick();
|
DashboardInteractions.toolbarShareClick();
|
||||||
showModal(ShareModal, {
|
showModal(ShareModal, {
|
||||||
@ -39,6 +38,8 @@ export const ShareButton = ({ dashboard }: { dashboard: DashboardModel }) => {
|
|||||||
onDismiss: hideModal,
|
onDismiss: hideModal,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<Trans i18nKey="dashboard.toolbar.share-button">Share</Trans>
|
||||||
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -311,6 +311,7 @@
|
|||||||
"save": "Dashboard speichern",
|
"save": "Dashboard speichern",
|
||||||
"settings": "Dashboard-Einstellungen",
|
"settings": "Dashboard-Einstellungen",
|
||||||
"share": "Dashboard oder Panel teilen",
|
"share": "Dashboard oder Panel teilen",
|
||||||
|
"share-button": "",
|
||||||
"unmark-favorite": "Markierung als Favorit entfernen"
|
"unmark-favorite": "Markierung als Favorit entfernen"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
@ -311,6 +311,7 @@
|
|||||||
"save": "Save dashboard",
|
"save": "Save dashboard",
|
||||||
"settings": "Dashboard settings",
|
"settings": "Dashboard settings",
|
||||||
"share": "Share dashboard",
|
"share": "Share dashboard",
|
||||||
|
"share-button": "Share",
|
||||||
"unmark-favorite": "Unmark as favorite"
|
"unmark-favorite": "Unmark as favorite"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
@ -316,6 +316,7 @@
|
|||||||
"save": "Guardar panel de control",
|
"save": "Guardar panel de control",
|
||||||
"settings": "Ajustes del panel de control",
|
"settings": "Ajustes del panel de control",
|
||||||
"share": "Compartir panel o panel de control",
|
"share": "Compartir panel o panel de control",
|
||||||
|
"share-button": "",
|
||||||
"unmark-favorite": "Deshacer marca como favorito"
|
"unmark-favorite": "Deshacer marca como favorito"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
@ -316,6 +316,7 @@
|
|||||||
"save": "Enregistrer le tableau de bord",
|
"save": "Enregistrer le tableau de bord",
|
||||||
"settings": "Paramètres du tableau de bord",
|
"settings": "Paramètres du tableau de bord",
|
||||||
"share": "Partager le tableau de bord ou le panneau",
|
"share": "Partager le tableau de bord ou le panneau",
|
||||||
|
"share-button": "",
|
||||||
"unmark-favorite": "Supprimer des favoris"
|
"unmark-favorite": "Supprimer des favoris"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
@ -311,6 +311,7 @@
|
|||||||
"save": "Ŝävę đäşĥþőäřđ",
|
"save": "Ŝävę đäşĥþőäřđ",
|
||||||
"settings": "Đäşĥþőäřđ şęŧŧįʼnģş",
|
"settings": "Đäşĥþőäřđ şęŧŧįʼnģş",
|
||||||
"share": "Ŝĥäřę đäşĥþőäřđ",
|
"share": "Ŝĥäřę đäşĥþőäřđ",
|
||||||
|
"share-button": "Ŝĥäřę",
|
||||||
"unmark-favorite": "Ůʼnmäřĸ äş ƒävőřįŧę"
|
"unmark-favorite": "Ůʼnmäřĸ äş ƒävőřįŧę"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
@ -306,6 +306,7 @@
|
|||||||
"save": "保存仪表板",
|
"save": "保存仪表板",
|
||||||
"settings": "仪表板设置",
|
"settings": "仪表板设置",
|
||||||
"share": "分享仪表板或面板",
|
"share": "分享仪表板或面板",
|
||||||
|
"share-button": "",
|
||||||
"unmark-favorite": "取消标记为收藏"
|
"unmark-favorite": "取消标记为收藏"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
Loading…
Reference in New Issue
Block a user