Add functionality to download role permission audit history as a CSV file

Introduce a new admin-only API endpoint for exporting role permission audit data to CSV, including resolved permission names and UTF-8 BOM for Excel compatibility. Frontend button and backend logic implemented to support this feature.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 0cb48020-8f0c-42bb-8fe8-d638905f7fce
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/g7BgHDL
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
riyadhafraa
2026-05-01 16:11:43 +00:00
parent de7973f35b
commit 49bf44f0a2
9 changed files with 701 additions and 16 deletions
@@ -1254,6 +1254,24 @@ export type GetRolePermissionAuditParams = {
to?: string;
};
export type ExportRolePermissionAuditCsvParams = {
/**
* Restrict results to entries authored by the given user. Use
`0` or omit to return entries from any actor.
* @minimum 0
*/
actorUserId?: number;
/**
* Start date (inclusive, YYYY-MM-DD UTC).
*/
from?: string;
/**
* End date (inclusive, YYYY-MM-DD UTC).
*/
to?: string;
};
export type ListGroupsParams = {
q?: string;
};
+123
View File
@@ -49,6 +49,7 @@ import type {
DeleteUserParams,
ErrorResponse,
ExportAuditLogsCsvParams,
ExportRolePermissionAuditCsvParams,
ForgotPasswordBody,
ForgotPasswordResponse,
GetAdminAppDependentGroupsParams,
@@ -5742,6 +5743,128 @@ export function useGetRolePermissionAudit<
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Returns the same audit rows as `GET /roles/{id}/audit` but as a
downloadable CSV file with permission IDs resolved to names.
Honors the optional `actorUserId`, `from`, and `to` filters
identically. Pagination parameters are NOT accepted: the file
contains all matching rows up to a server-side cap (currently
10,000 — narrow the date range for a longer history).
* @summary Download permission-change audit entries for a role as CSV (admin)
*/
export const getExportRolePermissionAuditCsvUrl = (
id: number,
params?: ExportRolePermissionAuditCsvParams,
) => {
const normalizedParams = new URLSearchParams();
Object.entries(params || {}).forEach(([key, value]) => {
if (value !== undefined) {
normalizedParams.append(key, value === null ? "null" : value.toString());
}
});
const stringifiedParams = normalizedParams.toString();
return stringifiedParams.length > 0
? `/api/roles/${id}/audit.csv?${stringifiedParams}`
: `/api/roles/${id}/audit.csv`;
};
export const exportRolePermissionAuditCsv = async (
id: number,
params?: ExportRolePermissionAuditCsvParams,
options?: RequestInit,
): Promise<Blob> => {
return customFetch<Blob>(getExportRolePermissionAuditCsvUrl(id, params), {
...options,
method: "GET",
});
};
export const getExportRolePermissionAuditCsvQueryKey = (
id: number,
params?: ExportRolePermissionAuditCsvParams,
) => {
return [`/api/roles/${id}/audit.csv`, ...(params ? [params] : [])] as const;
};
export const getExportRolePermissionAuditCsvQueryOptions = <
TData = Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>,
TError = ErrorType<ErrorResponse>,
>(
id: number,
params?: ExportRolePermissionAuditCsvParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>,
TError,
TData
>;
request?: SecondParameter<typeof customFetch>;
},
) => {
const { query: queryOptions, request: requestOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ??
getExportRolePermissionAuditCsvQueryKey(id, params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>
> = ({ signal }) =>
exportRolePermissionAuditCsv(id, params, { signal, ...requestOptions });
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ExportRolePermissionAuditCsvQueryResult = NonNullable<
Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>
>;
export type ExportRolePermissionAuditCsvQueryError = ErrorType<ErrorResponse>;
/**
* @summary Download permission-change audit entries for a role as CSV (admin)
*/
export function useExportRolePermissionAuditCsv<
TData = Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>,
TError = ErrorType<ErrorResponse>,
>(
id: number,
params?: ExportRolePermissionAuditCsvParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof exportRolePermissionAuditCsv>>,
TError,
TData
>;
request?: SecondParameter<typeof customFetch>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getExportRolePermissionAuditCsvQueryOptions(
id,
params,
options,
);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return { ...query, queryKey: queryOptions.queryKey };
}
/**
* Given a candidate set of permission IDs for the role, returns the list of
permissions that would be removed and, for each one, how many users would