ShareDrawer: Add confirm action (#89001)

This commit is contained in:
Juan Cabanas 2024-06-13 11:11:26 -03:00 committed by GitHub
parent 07ec1a303e
commit b7180c17b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 124 additions and 24 deletions

View File

@ -23,6 +23,7 @@ import { DashboardInteractions } from 'app/features/dashboard-scene/utils/intera
import { AccessControlAction } from 'app/types'; import { AccessControlAction } from 'app/types';
import { getDashboardSceneFor } from '../../../utils/utils'; import { getDashboardSceneFor } from '../../../utils/utils';
import { ShareDrawerConfirmAction } from '../../ShareDrawer/ShareDrawerConfirmAction';
import { useShareDrawerContext } from '../../ShareDrawer/ShareDrawerContext'; import { useShareDrawerContext } from '../../ShareDrawer/ShareDrawerContext';
import { EmailSharing } from './EmailShare/EmailSharing'; import { EmailSharing } from './EmailShare/EmailSharing';
@ -65,22 +66,62 @@ export class ShareExternally extends SceneObjectBase {
} }
function ShareExternallyRenderer({ model }: SceneComponentProps<ShareExternally>) { function ShareExternallyRenderer({ model }: SceneComponentProps<ShareExternally>) {
const dashboard = getDashboardSceneFor(model); const [showRevokeAccess, setShowRevokeAccess] = useState(false);
const { data: publicDashboard, isLoading } = useGetPublicDashboardQuery(dashboard.state.uid!);
const styles = useStyles2(getStyles); 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) { if (isLoading) {
return <Loader />; return <Loader />;
} }
if (showRevokeAccess) {
return (
<ShareDrawerConfirmAction
title={t('public-dashboard.share-externally.revoke-access-button', 'Revoke access')}
confirmButtonLabel={t('public-dashboard.share-externally.revoke-access-button', 'Revoke access')}
onConfirm={onDeleteClick}
onDismiss={() => 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 ( return (
<div className={styles.container}> <div className={styles.container}>
<ShareExternallyBase publicDashboard={publicDashboard} /> <ShareExternallyBase publicDashboard={publicDashboard} onRevokeClick={onRevokeClick} />
</div> </div>
); );
} }
function ShareExternallyBase({ publicDashboard }: { publicDashboard?: PublicDashboard }) { function ShareExternallyBase({
publicDashboard,
onRevokeClick,
}: {
publicDashboard?: PublicDashboard;
onRevokeClick: () => void;
}) {
const options = getShareExternallyOptions(); const options = getShareExternallyOptions();
const getShareType = useMemo(() => { const getShareType = useMemo(() => {
if (publicDashboard && isEmailSharingEnabled()) { if (publicDashboard && isEmailSharingEnabled()) {
@ -105,24 +146,21 @@ function ShareExternallyBase({ publicDashboard }: { publicDashboard?: PublicDash
<Stack direction="column" gap={2} data-testid={selectors.container}> <Stack direction="column" gap={2} data-testid={selectors.container}>
<ShareAlerts publicDashboard={publicDashboard} /> <ShareAlerts publicDashboard={publicDashboard} />
<ShareTypeSelect setShareType={setShareType} value={shareType} options={options} /> <ShareTypeSelect setShareType={setShareType} value={shareType} options={options} />
{Config} {Config}
{publicDashboard && ( {publicDashboard && (
<> <>
<Divider spacing={0} /> <Divider spacing={0} />
<Actions publicDashboard={publicDashboard} /> <Actions publicDashboard={publicDashboard} onRevokeClick={onRevokeClick} />
</> </>
)} )}
</Stack> </Stack>
); );
} }
function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) { function Actions({ publicDashboard, onRevokeClick }: { publicDashboard: PublicDashboard; onRevokeClick: () => void }) {
const { dashboard } = useShareDrawerContext(); const { dashboard } = useShareDrawerContext();
const [update, { isLoading: isUpdateLoading }] = usePauseOrResumePublicDashboardMutation(); const [update, { isLoading: isUpdateLoading }] = usePauseOrResumePublicDashboardMutation();
const [deletePublicDashboard, { isLoading: isDeleteLoading }] = useDeletePublicDashboardMutation();
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const isLoading = isUpdateLoading || isDeleteLoading;
const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite); const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite);
function onCopyURL() { 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 ( return (
<Stack alignItems="center" direction={{ xs: 'column', sm: 'row' }}> <Stack alignItems="center" direction={{ xs: 'column', sm: 'row' }}>
<div className={styles.actionsContainer}> <div className={styles.actionsContainer}>
@ -169,8 +198,8 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) {
icon="trash-alt" icon="trash-alt"
variant="destructive" variant="destructive"
fill="outline" fill="outline"
disabled={isLoading || !hasWritePermissions} disabled={isUpdateLoading || !hasWritePermissions}
onClick={onDeleteClick} onClick={onRevokeClick}
> >
<Trans i18nKey="public-dashboard.share-externally.revoke-access-button">Revoke access</Trans> <Trans i18nKey="public-dashboard.share-externally.revoke-access-button">Revoke access</Trans>
</Button> </Button>
@ -187,7 +216,7 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) {
: '' : ''
} }
onClick={onPauseOrResumeClick} onClick={onPauseOrResumeClick}
disabled={isLoading || !hasWritePermissions} disabled={isUpdateLoading || !hasWritePermissions}
> >
{publicDashboard.isEnabled ? ( {publicDashboard.isEnabled ? (
<Trans i18nKey="public-dashboard.share-externally.pause-access-button">Pause access</Trans> <Trans i18nKey="public-dashboard.share-externally.pause-access-button">Pause access</Trans>
@ -197,7 +226,7 @@ function Actions({ publicDashboard }: { publicDashboard: PublicDashboard }) {
</Button> </Button>
</Stack> </Stack>
</div> </div>
{isLoading && <Spinner />} {isUpdateLoading && <Spinner />}
</Stack> </Stack>
); );
} }

View File

@ -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 = () => (
<div className={styles.bodyContainer}>
<Stack justifyContent="space-between">
<Stack gap={1} alignItems="center">
<IconButton
size="xl"
name="angle-left"
aria-label={t('share-drawer.confirm-action.back-arrow-button', 'Back button')}
onClick={onDismiss}
/>
<Text variant="h4">{title}</Text>
</Stack>
{isActionLoading && <Spinner />}
</Stack>
</div>
);
return (
<ConfirmContent
body={<ConfirmBody />}
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),
}),
});

View File

@ -1487,7 +1487,8 @@
"public-share-type-option-description": "Anyone with the link can access", "public-share-type-option-description": "Anyone with the link can access",
"public-share-type-option-label": "Anyone with the link", "public-share-type-option-label": "Anyone with the link",
"resume-access-button": "Resume access", "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": { "sharing": {
"success-creation": "Dashboard is public!" "success-creation": "Dashboard is public!"
@ -1654,6 +1655,11 @@
"title": "You haven't created any service accounts yet" "title": "You haven't created any service accounts yet"
} }
}, },
"share-drawer": {
"confirm-action": {
"back-arrow-button": "Back button"
}
},
"share-modal": { "share-modal": {
"dashboard": { "dashboard": {
"title": "Share" "title": "Share"

View File

@ -1487,7 +1487,8 @@
"public-share-type-option-description": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ čäʼn äččęşş", "public-share-type-option-description": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ čäʼn äččęşş",
"public-share-type-option-label": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ", "public-share-type-option-label": "Åʼnyőʼnę ŵįŧĥ ŧĥę ľįʼnĸ",
"resume-access-button": "Ŗęşūmę äččęşş", "resume-access-button": "Ŗęşūmę äččęşş",
"revoke-access-button": "Ŗęvőĸę äččęşş" "revoke-access-button": "Ŗęvőĸę äččęşş",
"revoke-access-description": "Åřę yőū şūřę yőū ŵäʼnŧ ŧő řęvőĸę ŧĥįş äččęşş? Ŧĥę đäşĥþőäřđ čäʼn ʼnő ľőʼnģęř þę şĥäřęđ."
}, },
"sharing": { "sharing": {
"success-creation": "Đäşĥþőäřđ įş pūþľįč!" "success-creation": "Đäşĥþőäřđ įş pūþľįč!"
@ -1654,6 +1655,11 @@
"title": "Ÿőū ĥävęʼn'ŧ čřęäŧęđ äʼny şęřvįčę äččőūʼnŧş yęŧ" "title": "Ÿőū ĥävęʼn'ŧ čřęäŧęđ äʼny şęřvįčę äččőūʼnŧş yęŧ"
} }
}, },
"share-drawer": {
"confirm-action": {
"back-arrow-button": "ßäčĸ þūŧŧőʼn"
}
},
"share-modal": { "share-modal": {
"dashboard": { "dashboard": {
"title": "Ŝĥäřę" "title": "Ŝĥäřę"