feat: implement HTTP method filtering, parallelize initialization requests, and replace native alerts with toast notifications for audit log exports

This commit is contained in:
SibarchanNayak 2026-07-29 17:18:13 +05:30
parent 2a2798cd0f
commit fd8fd3a4e8
3 changed files with 68 additions and 13 deletions

3
package-lock.json generated
View File

@ -58,6 +58,9 @@
"typescript": "~5.9.3",
"typescript-eslint": "^8.46.4",
"vite": "^7.2.4"
},
"engines": {
"node": ">=22.0.0"
}
},
"node_modules/@babel/code-frame": {

View File

@ -21,6 +21,7 @@ import { tenantService } from "@/services/tenant-service";
import type { AuditLog } from "@/types/audit-log";
import type { Tenant } from "@/types/tenant";
import { useAppTheme } from "@/hooks/useAppTheme";
import { showToast } from "@/utils/toast";
// Helper function to format date
const formatDate = (dateString: string): string => {
@ -137,7 +138,7 @@ const AuditLogs = (): ReactElement => {
null,
);
// Fetch tenants on mount for the selector
// FE-1: Run all three independent fetches in parallel instead of sequentially
useEffect(() => {
const fetchTenants = async () => {
try {
@ -176,9 +177,11 @@ const AuditLogs = (): ReactElement => {
}
};
fetchTenants();
fetchResourceTypes();
fetchModules();
Promise.all([
fetchTenants(),
fetchResourceTypes(),
fetchModules(),
]);
}, []);
@ -254,6 +257,15 @@ const AuditLogs = (): ReactElement => {
tenantId: tenantFilter || undefined,
});
if (response.success) {
// FE-3 (BE-8 truncation warning): Notify when results were silently limited
if (response.data.truncated) {
showToast.warning(
"Export Truncated",
response.data.warning ||
`Only ${(response.data.exported ?? 10000).toLocaleString()} of ${response.data.total.toLocaleString()} records were exported. Use date filters to narrow the range.`
);
}
const blob = new Blob(
[JSON.stringify(response.data.records, null, 2)],
{ type: "application/json" },
@ -267,7 +279,11 @@ const AuditLogs = (): ReactElement => {
document.body.removeChild(link);
}
} catch (err: any) {
alert("Export failed: " + err.message);
// FE-3: Use app toast system instead of native alert()
showToast.error(
"Export Failed",
err?.response?.data?.error?.message || err.message || "An unexpected error occurred"
);
}
};

View File

@ -20,6 +20,7 @@ import type { AuditLog } from "@/types/audit-log";
import { useAppTheme } from "@/hooks/useAppTheme";
import { PrimaryButton } from "@/components/shared";
import { useAppSelector } from "@/hooks/redux-hooks";
import { showToast } from "@/utils/toast";
export interface AuditLogsProps {
customTenantId?: string;
@ -123,7 +124,8 @@ const AuditLogs = ({
});
// Filter state
const methodFilter = null;
// FE-2: methodFilter converted from a hardcoded null constant to real controllable state
const [methodFilter, setMethodFilter] = useState<string | null>(null);
const [actionFilter, setActionFilter] = useState<string | null>(null);
const [resourceTypeFilter, setResourceTypeFilter] = useState<string | null>(
null,
@ -226,10 +228,12 @@ const AuditLogs = ({
}
};
// Fetch resource types and modules on mount
// FE-1: Fetch resource types and modules in parallel (were sequential before)
useEffect(() => {
fetchResourceTypes();
fetchModules();
Promise.all([
fetchResourceTypes(),
fetchModules(),
]);
}, [tenantId]);
// Debouncing for Search
@ -275,9 +279,15 @@ const AuditLogs = ({
});
if (response.success) {
// In a real app, we'd trigger a file download here.
// For now, we'll just log and show a message since the response is JSON.
console.log("Export data:", response.data.records);
// FE-3 (export truncation warning from BE-8): Inform the user if results were truncated
if (response.data.truncated) {
showToast.warning(
"Export Truncated",
response.data.warning ||
`Only ${(response.data.exported ?? 10000).toLocaleString()} of ${response.data.total.toLocaleString()} records were exported. Use date filters to narrow the range.`
);
}
const blob = new Blob(
[JSON.stringify(response.data.records, null, 2)],
{ type: "application/json" },
@ -291,7 +301,11 @@ const AuditLogs = ({
document.body.removeChild(link);
}
} catch (err: any) {
alert("Failed to export audit logs: " + (err.message || "Unknown error"));
// FE-3: Use app toast system instead of native alert()
showToast.error(
"Export Failed",
err?.response?.data?.error?.message || err.message || "An unexpected error occurred"
);
}
};
@ -564,6 +578,26 @@ const AuditLogs = ({
/>
)}
{/* FE-2: HTTP Method filter — methodFilter is now real state */}
{isTenantAdmin && (
<FilterDropdown
label="Method"
options={[
{ value: "GET", label: "GET" },
{ value: "POST", label: "POST" },
{ value: "PUT", label: "PUT" },
{ value: "PATCH", label: "PATCH" },
{ value: "DELETE", label: "DELETE" },
]}
value={methodFilter}
onChange={(value) => {
setMethodFilter(value as string | null);
setCurrentPage(1);
}}
placeholder="All Methods"
/>
)}
{/* Module Filter */}
<FilterDropdown
label="Module"
@ -659,6 +693,7 @@ const AuditLogs = ({
{(startDate ||
endDate ||
actionFilter ||
methodFilter ||
resourceTypeFilter ||
moduleIdFilter ||
search ||
@ -668,6 +703,7 @@ const AuditLogs = ({
setStartDate("");
setEndDate("");
setActionFilter(null);
setMethodFilter(null);
setResourceTypeFilter(null);
setModuleIdFilter(null);
setOrderBy(null);