diff --git a/.changeset/metal-donuts-suffer.md b/.changeset/metal-donuts-suffer.md new file mode 100644 index 0000000000..c4129f8083 --- /dev/null +++ b/.changeset/metal-donuts-suffer.md @@ -0,0 +1,7 @@ +--- +"@comet/admin": minor +--- + +Use `FeedbackButton` in `DeleteDialog` of `CrudContextMenu` + +This provides the user with feedback about the current status of the delete action. diff --git a/packages/admin/admin/src/common/buttons/feedback/FeedbackButton.tsx b/packages/admin/admin/src/common/buttons/feedback/FeedbackButton.tsx index 6b8bba5d48..8ca5d8a5f4 100644 --- a/packages/admin/admin/src/common/buttons/feedback/FeedbackButton.tsx +++ b/packages/admin/admin/src/common/buttons/feedback/FeedbackButton.tsx @@ -61,7 +61,6 @@ export function FeedbackButton(inProps: FeedbackButtonProps) { tooltipSuccessMessage = , tooltipErrorMessage = , slotProps, - ...restProps } = useThemeProps({ props: inProps, @@ -71,16 +70,17 @@ export function FeedbackButton(inProps: FeedbackButtonProps) { const [displayState, setDisplayState] = React.useState("idle"); const ownerState: OwnerState = { - displayState: displayState, + displayState, }; const resolveTooltipForDisplayState = (displayState: FeedbackButtonDisplayState) => { - if (displayState === "success") { - return "success"; - } else if (displayState === "error") { - return "error"; - } else { - return "neutral"; + switch (displayState) { + case "error": + return "error"; + case "success": + return "success"; + default: + return "neutral"; } }; @@ -92,8 +92,8 @@ export function FeedbackButton(inProps: FeedbackButtonProps) { if (displayState === "idle" && loading) { setDisplayState("loading"); } else if (displayState === "loading" && hasErrors) { - timeoutDuration = 500; - newDisplayState = "loading"; + timeoutDuration = 0; + newDisplayState = "error"; } else if (displayState === "loading" && !loading && !hasErrors) { timeoutDuration = 500; newDisplayState = "success"; @@ -119,23 +119,23 @@ export function FeedbackButton(inProps: FeedbackButtonProps) { const tooltip = ( - {startIcon ? startIcon : endIcon} + {startIcon || endIcon} ); return ( } startIcon={startIcon && tooltip} diff --git a/packages/admin/admin/src/dataGrid/CrudContextMenu.tsx b/packages/admin/admin/src/dataGrid/CrudContextMenu.tsx index c183e152d4..f0b435360b 100644 --- a/packages/admin/admin/src/dataGrid/CrudContextMenu.tsx +++ b/packages/admin/admin/src/dataGrid/CrudContextMenu.tsx @@ -6,6 +6,7 @@ import { FormattedMessage, useIntl } from "react-intl"; import { readClipboardText } from "../clipboard/readClipboardText"; import { writeClipboardText } from "../clipboard/writeClipboardText"; +import { FeedbackButton } from "../common/buttons/feedback/FeedbackButton"; import { useErrorDialog } from "../error/errordialog/useErrorDialog"; import { messages } from "../messages"; import { RowActionsItem } from "../rowActions/RowActionsItem"; @@ -13,12 +14,14 @@ import { RowActionsMenu } from "../rowActions/RowActionsMenu"; interface DeleteDialogProps { dialogOpen: boolean; + loading?: boolean; + hasErrors?: boolean; onDelete: () => void; onCancel: () => void; } const DeleteDialog: React.FC = (props) => { - const { dialogOpen, onDelete, onCancel } = props; + const { dialogOpen, loading, hasErrors, onDelete, onCancel } = props; return ( @@ -29,12 +32,20 @@ const DeleteDialog: React.FC = (props) => { - - + ); @@ -57,14 +68,25 @@ export function CrudContextMenu({ url, onPaste, onDelete, refetchQueri const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); const [copyLoading, setCopyLoading] = React.useState(false); const [pasting, setPasting] = React.useState(false); + const [deleteLoading, setDeleteLoading] = React.useState(false); + const [hasDeleteErrors, setHasDeleteErrors] = React.useState(false); const handleDeleteClick = async () => { if (!onDelete) return; - await onDelete({ - client, - }); - if (refetchQueries) await client.refetchQueries({ include: refetchQueries }); - setDeleteDialogOpen(false); + setHasDeleteErrors(false); + setDeleteLoading(true); + try { + await onDelete({ + client, + }); + if (refetchQueries) await client.refetchQueries({ include: refetchQueries }); + setDeleteDialogOpen(false); + } catch (_) { + setHasDeleteErrors(true); + throw new Error("Delete failed"); + } finally { + setDeleteLoading(false); + } }; const handlePasteClick = async () => { @@ -166,10 +188,10 @@ export function CrudContextMenu({ url, onPaste, onDelete, refetchQueri { - setDeleteDialogOpen(false); - }} - onCancel={handleDeleteClick} + hasErrors={hasDeleteErrors} + loading={deleteLoading} + onCancel={() => setDeleteDialogOpen(false)} + onDelete={handleDeleteClick} /> );