121 lines
3.3 KiB
TypeScript
121 lines
3.3 KiB
TypeScript
import { useState, useCallback, useEffect } from 'react';
|
|
import apiService from '../services/apiService';
|
|
|
|
export interface VersionChange {
|
|
field: string;
|
|
oldValue: any;
|
|
newValue: any;
|
|
}
|
|
|
|
export interface AuditLogEntry {
|
|
name: string;
|
|
owner: string;
|
|
creation: string;
|
|
changes: VersionChange[];
|
|
added: any[];
|
|
removed: any[];
|
|
rowChanged: any[];
|
|
}
|
|
|
|
interface UseAuditLogsOptions {
|
|
doctype: string;
|
|
docname: string | null;
|
|
limit?: number;
|
|
enabled?: boolean;
|
|
}
|
|
|
|
interface UseAuditLogsReturn {
|
|
auditLogs: AuditLogEntry[];
|
|
loading: boolean;
|
|
error: string | null;
|
|
refetch: () => void;
|
|
}
|
|
|
|
export const useAuditLogs = ({
|
|
doctype,
|
|
docname,
|
|
limit = 50,
|
|
enabled = true,
|
|
}: UseAuditLogsOptions): UseAuditLogsReturn => {
|
|
const [auditLogs, setAuditLogs] = useState<AuditLogEntry[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchAuditLogs = useCallback(async () => {
|
|
if (!enabled || !doctype || !docname) return;
|
|
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const response = await apiService.apiCall<any>(
|
|
`/api/resource/Version?filters=[["ref_doctype","=","${encodeURIComponent(doctype)}"],["docname","=","${encodeURIComponent(docname)}"]]&fields=["name","owner","creation","data"]&order_by=creation desc&limit=${limit}`
|
|
);
|
|
|
|
if (response?.data && response.data.length > 0) {
|
|
const parsedLogs: AuditLogEntry[] = response.data.map((version: any) => {
|
|
let parsedData: {
|
|
added: any[];
|
|
changed: any[];
|
|
removed: any[];
|
|
row_changed: any[];
|
|
} = { added: [], changed: [], removed: [], row_changed: [] };
|
|
try {
|
|
parsedData = JSON.parse(version.data || '{}');
|
|
} catch (e) {
|
|
console.error('Error parsing version data:', e);
|
|
}
|
|
|
|
let changes: VersionChange[] = [];
|
|
|
|
if (Array.isArray(parsedData.changed)) {
|
|
changes = parsedData.changed.map((change: any[]) => ({
|
|
field: change[0] || '',
|
|
oldValue: change[1],
|
|
newValue: change[2],
|
|
}));
|
|
} else if (parsedData.changed && typeof parsedData.changed === 'object') {
|
|
changes = Object.entries(parsedData.changed).map(([field, values]) => {
|
|
const [oldValue, newValue] = values as [any, any];
|
|
return { field, oldValue, newValue };
|
|
});
|
|
}
|
|
|
|
return {
|
|
name: version.name,
|
|
owner: version.owner,
|
|
creation: version.creation,
|
|
changes,
|
|
added: parsedData.added || [],
|
|
removed: parsedData.removed || [],
|
|
rowChanged: parsedData.row_changed || [],
|
|
};
|
|
});
|
|
|
|
setAuditLogs(parsedLogs);
|
|
} else {
|
|
setAuditLogs([]);
|
|
}
|
|
} catch (err) {
|
|
console.error(`Error fetching audit logs for ${doctype}/${docname}:`, err);
|
|
setError(err instanceof Error ? err.message : 'Failed to load activity log');
|
|
setAuditLogs([]);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [doctype, docname, limit, enabled]);
|
|
|
|
useEffect(() => {
|
|
fetchAuditLogs();
|
|
}, [fetchAuditLogs]);
|
|
|
|
return {
|
|
auditLogs,
|
|
loading,
|
|
error,
|
|
refetch: fetchAuditLogs,
|
|
};
|
|
};
|
|
|
|
export default useAuditLogs;
|