feat(resources): add hard-delete action to resource list (per-row and batch)
- Add batchHardDelete adminProcedure to resource-mutations router - Per-row Delete button visible to ADMIN role only - Delete Selected button in BatchActionBar for ADMIN role only - Two-step confirmation dialogs with permanent-action warnings - Audit log written for each deleted resource Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -47,7 +47,9 @@ type ModalState =
|
||||
type ConfirmState =
|
||||
| { type: "closed" }
|
||||
| { type: "batchDeactivate"; ids: string[] }
|
||||
| { type: "deactivate"; resource: Resource };
|
||||
| { type: "deactivate"; resource: Resource }
|
||||
| { type: "delete"; resource: Resource }
|
||||
| { type: "batchDelete"; ids: string[] };
|
||||
|
||||
type ActiveFilter = "active" | "inactive" | "all";
|
||||
type BooleanFilter = "all" | "yes" | "no";
|
||||
@@ -163,7 +165,7 @@ export function ResourcesClient() {
|
||||
|
||||
const selection = useSelection();
|
||||
const utils = trpc.useUtils();
|
||||
const { canViewScores, canViewCosts } = usePermissions();
|
||||
const { canViewScores, canViewCosts, canManageUsers } = usePermissions();
|
||||
const {
|
||||
customFieldFilters,
|
||||
setCustomFieldFilter,
|
||||
@@ -323,6 +325,19 @@ export function ResourcesClient() {
|
||||
selection.clear();
|
||||
},
|
||||
});
|
||||
const hardDeleteMutation = trpc.resource.hardDelete.useMutation({
|
||||
onSuccess: () => {
|
||||
void utils.resource.directory.invalidate();
|
||||
void utils.resource.listStaff.invalidate();
|
||||
},
|
||||
});
|
||||
const batchHardDeleteMutation = trpc.resource.batchHardDelete.useMutation({
|
||||
onSuccess: () => {
|
||||
void utils.resource.directory.invalidate();
|
||||
void utils.resource.listStaff.invalidate();
|
||||
selection.clear();
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
selection.clear();
|
||||
@@ -348,6 +363,10 @@ export function ResourcesClient() {
|
||||
deactivateMutation.mutate({ id: confirm.resource.id });
|
||||
} else if (confirm.type === "batchDeactivate") {
|
||||
batchDeactivateMutation.mutate({ ids: confirm.ids });
|
||||
} else if (confirm.type === "delete") {
|
||||
hardDeleteMutation.mutate({ id: confirm.resource.id });
|
||||
} else if (confirm.type === "batchDelete") {
|
||||
batchHardDeleteMutation.mutate({ ids: confirm.ids });
|
||||
}
|
||||
setConfirm({ type: "closed" });
|
||||
}
|
||||
@@ -1384,6 +1403,21 @@ export function ResourcesClient() {
|
||||
>
|
||||
{isDeactivating ? "Deactivating…" : "Deactivate"}
|
||||
</button>
|
||||
{canManageUsers && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
setConfirm({
|
||||
type: "delete",
|
||||
resource: resource as unknown as Resource,
|
||||
})
|
||||
}
|
||||
disabled={hardDeleteMutation.isPending}
|
||||
className="ml-3 text-xs font-medium text-red-800 transition-colors hover:text-red-950 disabled:opacity-50 dark:text-red-400 dark:hover:text-red-200"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
)}
|
||||
</td>
|
||||
</DraggableTableRow>
|
||||
);
|
||||
@@ -1426,6 +1460,16 @@ export function ResourcesClient() {
|
||||
onClick: () => setConfirm({ type: "batchDeactivate", ids: selection.selectedArray }),
|
||||
disabled: batchDeactivateMutation.isPending,
|
||||
},
|
||||
...(canManageUsers
|
||||
? [
|
||||
{
|
||||
label: `Delete ${selection.count > 0 ? `(${selection.count})` : ""}`,
|
||||
variant: "danger" as const,
|
||||
onClick: () => setConfirm({ type: "batchDelete", ids: selection.selectedArray }),
|
||||
disabled: batchHardDeleteMutation.isPending,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -1469,6 +1513,26 @@ export function ResourcesClient() {
|
||||
onCancel={() => setConfirm({ type: "closed" })}
|
||||
/>
|
||||
)}
|
||||
{confirm.type === "delete" && (
|
||||
<ConfirmDialog
|
||||
title="Permanently Delete Resource"
|
||||
message={`Delete "${confirm.resource.displayName}" (${confirm.resource.eid}) permanently? This will also delete all their assignments and vacation records. This action cannot be undone.`}
|
||||
confirmLabel="Delete Permanently"
|
||||
variant="danger"
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={() => setConfirm({ type: "closed" })}
|
||||
/>
|
||||
)}
|
||||
{confirm.type === "batchDelete" && (
|
||||
<ConfirmDialog
|
||||
title="Permanently Delete Resources"
|
||||
message={`Delete ${confirm.ids.length} selected resource${confirm.ids.length !== 1 ? "s" : ""} permanently? All their assignments and vacation records will also be deleted. This action cannot be undone.`}
|
||||
confirmLabel="Delete All Permanently"
|
||||
variant="danger"
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={() => setConfirm({ type: "closed" })}
|
||||
/>
|
||||
)}
|
||||
|
||||
<SuccessToast
|
||||
show={successToast !== null}
|
||||
|
||||
Reference in New Issue
Block a user