282 lines
7.7 KiB
TypeScript
282 lines
7.7 KiB
TypeScript
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<string, any>;
|
|
search?: string;
|
|
groupId?: string;
|
|
saveGroupTree?: any[];
|
|
}
|
|
|
|
export interface PaginatedResponse<T> {
|
|
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<any>) => Promise<any>;
|
|
|
|
// ============================================================================
|
|
// API REQUEST FUNCTIONS
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Fetch file attributes from backend
|
|
* Endpoint: GET /api/attributes/FileItem
|
|
*/
|
|
export async function fetchFileAttributes(request: ApiRequestFunction): Promise<AttributeDefinition[]> {
|
|
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<PaginatedResponse<FileInfo> | 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<FileInfo | null> {
|
|
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<FileInfo>
|
|
): Promise<FileInfo> {
|
|
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<void> {
|
|
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<Array<{ success: boolean; fileId: string; error?: any }>> {
|
|
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<any> {
|
|
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<any> {
|
|
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<void> {
|
|
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<any> {
|
|
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
|
|
|