mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ShareDrawer: Add confirm action (#89001)
This commit is contained in:
parent
07ec1a303e
commit
b7180c17b8
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
}),
|
||||||
|
});
|
@ -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"
|
||||||
|
@ -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": "Ŝĥäřę"
|
||||||
|
Loading…
Reference in New Issue
Block a user