import { ApiRequestOptions } from '../hooks/useApi'; // ============================================================================ // TYPES & INTERFACES // ============================================================================ export interface FileInfo { id: string; mandateId: string; fileName: string; mimeType: string; fileHash: string; fileSize: number; creationDate: number; [key: string]: any; // Allow additional properties } export interface AttributeDefinition { name: string; label: string; type: 'string' | 'number' | 'date' | 'boolean' | 'enum'; sortable?: boolean; filterable?: boolean; searchable?: boolean; width?: number; minWidth?: number; maxWidth?: number; filterOptions?: string[]; } export interface PaginationParams { page?: number; pageSize?: number; sort?: Array<{ field: string; direction: 'asc' | 'desc' }>; filters?: Record; search?: string; groupId?: string; saveGroupTree?: any[]; } export interface PaginatedResponse { items: T[]; pagination?: { currentPage: number; pageSize: number; totalItems: number; totalPages: number; }; } // Type for the request function passed to API functions export type ApiRequestFunction = (options: ApiRequestOptions) => Promise; // ============================================================================ // API REQUEST FUNCTIONS // ============================================================================ /** * Fetch file attributes from backend * Endpoint: GET /api/attributes/FileItem */ export async function fetchFileAttributes(request: ApiRequestFunction): Promise { const data = await request({ url: '/api/attributes/FileItem', method: 'get' }); // Handle different response formats if (Array.isArray(data)) { return data; } if (data && typeof data === 'object' && 'attributes' in data && Array.isArray(data.attributes)) { return data.attributes; } // Try to find any array property in the response if (data && typeof data === 'object') { const keys = Object.keys(data); for (const key of keys) { if (Array.isArray((data as any)[key])) { return (data as any)[key]; } } } return []; } /** * Fetch list of files with optional pagination * Endpoint: GET /api/files/list */ export async function fetchFiles( request: ApiRequestFunction, params?: PaginationParams ): Promise | FileInfo[]> { const requestParams: any = {}; // Build pagination object if provided if (params) { const paginationObj: any = {}; if (params.page !== undefined) paginationObj.page = params.page; if (params.pageSize !== undefined) paginationObj.pageSize = params.pageSize; if (params.sort) paginationObj.sort = params.sort; if (params.filters) paginationObj.filters = params.filters; if (params.search) paginationObj.search = params.search; if (params.groupId) paginationObj.groupId = params.groupId; if (params.saveGroupTree !== undefined) paginationObj.saveGroupTree = params.saveGroupTree; if (Object.keys(paginationObj).length > 0) { requestParams.pagination = JSON.stringify(paginationObj); } } const data = await request({ url: '/api/files/list', method: 'get', params: requestParams }); return data; } /** * Fetch a single file by ID * Endpoint: GET /api/files/{fileId} */ export async function fetchFileById( request: ApiRequestFunction, fileId: string ): Promise { try { const data = await request({ url: `/api/files/${fileId}`, method: 'get' }); return data || null; } catch (error: any) { console.error('Error fetching file by ID:', error); return null; } } /** * Update a file * Endpoint: PUT /api/files/{fileId} */ export async function updateFile( request: ApiRequestFunction, fileId: string, fileData: Partial ): Promise { return await request({ url: `/api/files/${fileId}`, method: 'put', data: fileData }); } /** * Delete a file * Endpoint: DELETE /api/files/{fileId} */ export async function deleteFile( request: ApiRequestFunction, fileId: string ): Promise { await request({ url: `/api/files/${fileId}`, method: 'delete' }); } /** * Delete multiple files * Endpoint: DELETE /api/files/{fileId} (called multiple times) */ export async function deleteFiles( request: ApiRequestFunction, fileIds: string[] ): Promise> { const uniqueIds = [...new Set(fileIds.filter(Boolean))]; if (uniqueIds.length === 0) return []; await request({ url: '/api/files/batch-delete', method: 'post', data: { fileIds: uniqueIds } }); return uniqueIds.map(fileId => ({ success: true, fileId })); } // ============================================================================ // GROUP BULK API FUNCTIONS // ============================================================================ /** Patch scope for all files in a group (recursive) */ export async function patchGroupScope( request: ApiRequestFunction, groupId: string, scope: string ): Promise { return await request({ url: `/api/files/groups/${groupId}/scope`, method: 'patch', data: { scope }, }); } /** Patch neutralize for all files in a group (recursive, incl. knowledge purge/reindex) */ export async function patchGroupNeutralize( request: ApiRequestFunction, groupId: string, neutralize: boolean ): Promise { return await request({ url: `/api/files/groups/${groupId}/neutralize`, method: 'patch', data: { neutralize }, }); } /** Download all files in a group as ZIP */ export async function downloadGroupZip(groupId: string): Promise { const { default: api } = await import('../api'); const response = await api.get(`/api/files/groups/${groupId}/download`, { responseType: 'blob', }); const url = window.URL.createObjectURL(response.data); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `group-${groupId}.zip`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); } /** Delete a group and optionally all its files */ export async function deleteGroup( request: ApiRequestFunction, groupId: string, deleteItems: boolean = false ): Promise { return await request({ url: `/api/files/groups/${groupId}`, method: 'delete', params: { deleteItems }, }); } /** Collect all file IDs belonging to a group recursively (client-side, from known groupTree) */ export function collectGroupItemIds( groupTree: Array<{ id: string; itemIds: string[]; subGroups: any[] }>, groupId: string ): string[] { const collect = (nodes: Array<{ id: string; itemIds: string[]; subGroups: any[] }>): string[] | null => { for (const node of nodes) { if (node.id === groupId) { const ids: string[] = [...node.itemIds]; const sub = (n: { id: string; itemIds: string[]; subGroups: any[] }) => { ids.push(...n.itemIds); n.subGroups.forEach(sub); }; node.subGroups.forEach(sub); return ids; } const found = collect(node.subGroups); if (found) return found; } return null; }; return collect(groupTree) ?? []; } // Note: The following operations require special handling (FormData, blob responses) // and should use the api instance directly from '../api' rather than the request function: // - uploadFile: Requires FormData with multipart/form-data // - downloadFile: Requires blob responseType // - previewFile: Requires flexible responseType (json or blob) // These are kept in the hooks for now due to their special requirements