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:
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user