From b7180c17b8da8cdedc0e9ade2b6672625ac2eec6 Mon Sep 17 00:00:00 2001 From: Juan Cabanas Date: Thu, 13 Jun 2024 11:11:26 -0300 Subject: [PATCH] ShareDrawer: Add confirm action (#89001) --- .../share-externally/ShareExternally.tsx | 73 +++++++++++++------ .../ShareDrawer/ShareDrawerConfirmAction.tsx | 59 +++++++++++++++ public/locales/en-US/grafana.json | 8 +- public/locales/pseudo-LOCALE/grafana.json | 8 +- 4 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/share-externally/ShareExternally.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/share-externally/ShareExternally.tsx index 3321d5074d2..262a5ea25f2 100644 --- a/public/app/features/dashboard-scene/sharing/ShareButton/share-externally/ShareExternally.tsx +++ b/public/app/features/dashboard-scene/sharing/ShareButton/share-externally/ShareExternally.tsx @@ -23,6 +23,7 @@ import { DashboardInteractions } from 'app/features/dashboard-scene/utils/intera import { AccessControlAction } from 'app/types'; import { getDashboardSceneFor } from '../../../utils/utils'; +import { ShareDrawerConfirmAction } from '../../ShareDrawer/ShareDrawerConfirmAction'; import { useShareDrawerContext } from '../../ShareDrawer/ShareDrawerContext'; import { EmailSharing } from './EmailShare/EmailSharing'; @@ -65,22 +66,62 @@ export class ShareExternally extends SceneObjectBase { } function ShareExternallyRenderer({ model }: SceneComponentProps) { - const dashboard = getDashboardSceneFor(model); - const { data: publicDashboard, isLoading } = useGetPublicDashboardQuery(dashboard.state.uid!); + const [showRevokeAccess, setShowRevokeAccess] = useState(false); + const styles = useStyles2(getStyles); + const dashboard = getDashboardSceneFor(model); + + const { data: publicDashboard, isLoading } = useGetPublicDashboardQuery(dashboard.state.uid!); + const [deletePublicDashboard, { isLoading: isDeleteLoading }] = useDeletePublicDashboardMutation(); + + const onRevokeClick = () => { + setShowRevokeAccess(true); + }; + + const onDeleteClick = async () => { + DashboardInteractions.revokePublicDashboardClicked(); + await deletePublicDashboard({ + dashboard, + uid: publicDashboard!.uid, + dashboardUid: dashboard.state.uid!, + }).unwrap(); + setShowRevokeAccess(false); + }; if (isLoading) { return ; } + if (showRevokeAccess) { + return ( + setShowRevokeAccess(false)} + description={t( + 'public-dashboard.share-externally.revoke-access-description', + 'Are you sure you want to revoke this access? The dashboard can no longer be shared.' + )} + isActionLoading={isDeleteLoading} + /> + ); + } + return (
- +
); } -function ShareExternallyBase({ publicDashboard }: { publicDashboard?: PublicDashboard }) { +function ShareExternallyBase({ + publicDashboard, + onRevokeClick, +}: { + publicDashboard?: PublicDashboard; + onRevokeClick: () => void; +}) { const options = getShareExternallyOptions(); const getShareType = useMemo(() => { if (publicDashboard && isEmailSharingEnabled()) { @@ -105,24 +146,21 @@ function ShareExternallyBase({ publicDashboard }: { publicDashboard?: PublicDash - {Config} {publicDashboard && ( <> - + )} ); } -function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) { +function Actions({ publicDashboard, onRevokeClick }: { publicDashboard: PublicDashboard; onRevokeClick: () => void }) { const { dashboard } = useShareDrawerContext(); const [update, { isLoading: isUpdateLoading }] = usePauseOrResumePublicDashboardMutation(); - const [deletePublicDashboard, { isLoading: isDeleteLoading }] = useDeletePublicDashboardMutation(); const styles = useStyles2(getStyles); - const isLoading = isUpdateLoading || isDeleteLoading; const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite); function onCopyURL() { @@ -142,15 +180,6 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) { }); }; - const onDeleteClick = () => { - DashboardInteractions.revokePublicDashboardClicked(); - deletePublicDashboard({ - dashboard, - uid: publicDashboard!.uid, - dashboardUid: dashboard.state.uid!, - }); - }; - return (
@@ -169,8 +198,8 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) { icon="trash-alt" variant="destructive" fill="outline" - disabled={isLoading || !hasWritePermissions} - onClick={onDeleteClick} + disabled={isUpdateLoading || !hasWritePermissions} + onClick={onRevokeClick} > Revoke access @@ -187,7 +216,7 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) { : '' } onClick={onPauseOrResumeClick} - disabled={isLoading || !hasWritePermissions} + disabled={isUpdateLoading || !hasWritePermissions} > {publicDashboard.isEnabled ? ( Pause access @@ -197,7 +226,7 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) {
- {isLoading && } + {isUpdateLoading && }
); } diff --git a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx new file mode 100644 index 00000000000..91aeab1bc84 --- /dev/null +++ b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx @@ -0,0 +1,59 @@ +import { css } from '@emotion/css'; +import React from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { Spinner, Stack, Text } from '@grafana/ui'; +import { IconButton, useStyles2 } from '@grafana/ui/'; +import { ConfirmContent, ConfirmContentProps } from '@grafana/ui/src/components/ConfirmModal/ConfirmContent'; +import { t } from 'app/core/internationalization'; + +export function ShareDrawerConfirmAction({ + onConfirm, + onDismiss, + description, + confirmButtonLabel, + title, + isActionLoading, +}: { title: string; isActionLoading: boolean } & Pick< + ConfirmContentProps, + 'description' | 'onConfirm' | 'onDismiss' | 'confirmButtonLabel' +>) { + const styles = useStyles2(getStyles); + + const ConfirmBody = () => ( +
+ + + + {title} + + {isActionLoading && } + +
+ ); + + return ( + } + description={description} + confirmButtonLabel={confirmButtonLabel} + confirmButtonVariant="destructive" + dismissButtonLabel="Cancel" + dismissButtonVariant="secondary" + justifyButtons="flex-start" + onConfirm={onConfirm} + onDismiss={onDismiss} + /> + ); +} + +const getStyles = (theme: GrafanaTheme2) => ({ + bodyContainer: css({ + marginBottom: theme.spacing(2), + }), +}); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index b448f53a35b..16bfdda9b48 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1487,7 +1487,8 @@ "public-share-type-option-description": "Anyone with the link can access", "public-share-type-option-label": "Anyone with the link", "resume-access-button": "Resume access", - "revoke-access-button": "Revoke access" + "revoke-access-button": "Revoke access", + "revoke-access-description": "Are you sure you want to revoke this access? The dashboard can no longer be shared." }, "sharing": { "success-creation": "Dashboard is public!" @@ -1654,6 +1655,11 @@ "title": "You haven't created any service accounts yet" } }, + "share-drawer": { + "confirm-action": { + "back-arrow-button": "Back button" + } + }, "share-modal": { "dashboard": { "title": "Share" diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 88f6ead1fcb..474ee4c3b22 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1487,7 +1487,8 @@ "public-share-type-option-description": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ čäʼn äččęşş", "public-share-type-option-label": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ", "resume-access-button": "Ŗęşūmę äččęşş", - "revoke-access-button": "Ŗęvőĸę äččęşş" + "revoke-access-button": "Ŗęvőĸę äččęşş", + "revoke-access-description": "Åřę yőū şūřę yőū ŵäʼnŧ ŧő řęvőĸę ŧĥįş äččęşş? Ŧĥę đäşĥþőäřđ čäʼn ʼnő ľőʼnģęř þę şĥäřęđ." }, "sharing": { "success-creation": "Đäşĥþőäřđ įş pūþľįč!" @@ -1654,6 +1655,11 @@ "title": "Ÿőū ĥävęʼn'ŧ čřęäŧęđ äʼny şęřvįčę äččőūʼnŧş yęŧ" } }, + "share-drawer": { + "confirm-action": { + "back-arrow-button": "ßäčĸ þūŧŧőʼn" + } + }, "share-modal": { "dashboard": { "title": "Ŝĥäřę"