From 8061066e2755fa71bdc09edade6d52fc802dfe43 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 28 Jan 2025 19:59:20 +0530 Subject: [PATCH] feat: added detail description in ui notification --- frontend/src/hooks/api/reactQuery.tsx | 101 ++++++++++++++++++++++++++ frontend/src/hooks/api/types.ts | 14 ++++ 2 files changed, 115 insertions(+) diff --git a/frontend/src/hooks/api/reactQuery.tsx b/frontend/src/hooks/api/reactQuery.tsx index f6ae0ca76..be9dadbec 100644 --- a/frontend/src/hooks/api/reactQuery.tsx +++ b/frontend/src/hooks/api/reactQuery.tsx @@ -74,6 +74,107 @@ export const queryClient = new QueryClient({ ); return; } + if (serverResponse?.error === ApiErrorTypes.PermissionBoundaryError) { + createNotification( + { + title: "Forbidden Access", + type: "error", + text: `${serverResponse.message}.`, + callToAction: serverResponse?.details?.missingPermissions?.length ? ( + + + + + +
+ {serverResponse.details?.missingPermissions?.map((el, index) => { + const hasConditions = Boolean(Object.keys(el.conditions || {}).length); + return ( +
+
+ You are not authorized to perform the {el.action} action on the{" "} + {el.subject} resource.{" "} + {hasConditions && + "Your permission does not allow access to the following conditions:"} +
+ {hasConditions && ( +
    + {Object.keys(el.conditions || {}).flatMap((field, fieldIndex) => { + const operators = ( + el.conditions as Record< + string, + | string + | { [K in PermissionConditionOperators]: string | string[] } + > + )[field]; + + const formattedFieldName = camelCaseToSpaces(field).toLowerCase(); + if (typeof operators === "string") { + return ( +
  • + + {formattedFieldName} + {" "} + equal to{" "} + {operators} +
  • + ); + } + + return Object.keys(operators).map((operator, operatorIndex) => ( +
  • + + {formattedFieldName} + {" "} + + { + formatedConditionsOperatorNames[ + operator as PermissionConditionOperators + ] + } + {" "} + + {operators[ + operator as PermissionConditionOperators + ].toString()} + +
  • + )); + })} +
+ )} +
+ ); + })} +
+
+
+ ) : undefined, + copyActions: [ + { + value: serverResponse.reqId, + name: "Request ID", + label: `Request ID: ${serverResponse.reqId}` + } + ] + }, + { closeOnClick: false } + ); + return; + } if (serverResponse?.error === ApiErrorTypes.ForbiddenError) { createNotification( { diff --git a/frontend/src/hooks/api/types.ts b/frontend/src/hooks/api/types.ts index c03358b42..cda34ad60 100644 --- a/frontend/src/hooks/api/types.ts +++ b/frontend/src/hooks/api/types.ts @@ -44,6 +44,7 @@ export type { export enum ApiErrorTypes { ValidationError = "ValidationFailure", + PermissionBoundaryError = "PermissionBoundaryError", BadRequestError = "BadRequest", UnauthorizedError = "UnauthorizedError", ForbiddenError = "PermissionDenied" @@ -74,4 +75,17 @@ export type TApiErrors = statusCode: 400; message: string; error: ApiErrorTypes.BadRequestError; + } + | { + reqId: string; + statusCode: 403; + message: string; + error: ApiErrorTypes.PermissionBoundaryError; + details: { + missingPermissions: { + action: string; + subject: string; + conditions: Record>; + }[]; + }; };