diff --git a/frontend/packages/web/src/hooks/useApprovalResourceAction.ts b/frontend/packages/web/src/hooks/useApprovalResourceAction.ts index b87aff38e4..895d24dd96 100644 --- a/frontend/packages/web/src/hooks/useApprovalResourceAction.ts +++ b/frontend/packages/web/src/hooks/useApprovalResourceAction.ts @@ -12,21 +12,31 @@ interface ApprovalResourceActionHandlers { interface UseApprovalResourceActionOptions { formKey: FormDesignKeyEnum; + preventDuplicateByResourceId?: boolean; } export default function useApprovalResourceAction(options: UseApprovalResourceActionOptions) { const { t } = useI18n(); const Message = useMessage(); + const enableDuplicateGuard = options.preventDuplicateByResourceId ?? true; + const reviewLoading = ref(false); const revokeLoading = ref(false); + const reviewPendingResourceIds = new Set(); + const revokePendingResourceIds = new Set(); async function submitReview(resourceId: string, callback?: ApprovalResourceActionHandlers) { if (!resourceId) { return; } + if (enableDuplicateGuard && reviewPendingResourceIds.has(resourceId)) { + return; + } + try { + reviewPendingResourceIds.add(resourceId); reviewLoading.value = true; await reviewResource({ resourceId, @@ -39,6 +49,7 @@ export default function useApprovalResourceAction(options: UseApprovalResourceAc // eslint-disable-next-line no-console console.error(error); } finally { + reviewPendingResourceIds.delete(resourceId); reviewLoading.value = false; } } @@ -48,7 +59,12 @@ export default function useApprovalResourceAction(options: UseApprovalResourceAc return; } + if (enableDuplicateGuard && revokePendingResourceIds.has(resourceId)) { + return; + } + try { + revokePendingResourceIds.add(resourceId); revokeLoading.value = true; await revokeResource({ resourceId, @@ -61,6 +77,7 @@ export default function useApprovalResourceAction(options: UseApprovalResourceAc // eslint-disable-next-line no-console console.error(error); } finally { + revokePendingResourceIds.delete(resourceId); revokeLoading.value = false; } }