diff --git a/react-openapi/src/context/useResource.tsx b/react-openapi/src/context/useResource.tsx index eea21a5..8b195d9 100644 --- a/react-openapi/src/context/useResource.tsx +++ b/react-openapi/src/context/useResource.tsx @@ -50,7 +50,7 @@ interface UseResourceReturn { resource: ResourceConfig; components: Record>; list: (params?: Record) => Promise; - get: (id: string | number) => Promise; + get: (id: string | number, params?: Record) => Promise; create: (data: any) => Promise; update: (id: string | number, data: any) => Promise; remove: (id: string | number) => Promise; @@ -366,20 +366,11 @@ export function useResource(resourceName: string): UseResourceReturn { const [state, setState] = useState({ loading: false, error: null }); - if (!resource) { - const noop = async () => { throw new Error(`Resource "${resourceName}" not found yet`); }; - return { - resource: null as unknown as ResourceConfig, - components: {}, - list: noop, - get: noop, - create: noop, - update: noop, - remove: noop, - loading: false, - error: null, - }; - } + const rPath = resource?.path; + const rPagination = resource?.pagination; + const rUpdateMethod = resource?.updateMethod; + const rStreaming = resource?.streaming; + const rFields = resource?.fields; const setLoading = useCallback((loading: boolean) => { setState((s) => ({ ...s, loading })); @@ -391,22 +382,26 @@ export function useResource(resourceName: string): UseResourceReturn { const list = useCallback( async (params?: Record): Promise => { + if (!rPath) return { items: [] }; setLoading(true); setError(null); try { const api = getApi(); - const res = await api.get(resource.path, { params }); + const res = await api.get(rPath, { params }); const data = res.data; - if (resource.pagination) { + if (rPagination) { + if (Array.isArray(data)) { + return { items: data }; + } if (!data || typeof data !== "object" || !Array.isArray(data.items)) { - throw new Error(`Expected paginated response { total, items } from ${resource.path}`); + throw new Error(`Expected paginated response { total, items } from ${rPath}`); } return { items: data.items, total: data.total ?? data.items.length }; } if (!Array.isArray(data)) { - throw new Error(`Expected array response from ${resource.path}`); + throw new Error(`Expected array response from ${rPath}`); } return { items: data }; } catch (e: any) { @@ -417,16 +412,17 @@ export function useResource(resourceName: string): UseResourceReturn { setLoading(false); } }, - [resource.path, resource.pagination, setLoading, setError] + [rPath, rPagination, setLoading, setError] ); const get = useCallback( - async (id: string | number): Promise => { + async (id: string | number, params?: Record): Promise => { + if (!rPath) throw new Error(`Resource "${resourceName}" not found yet`); setLoading(true); setError(null); try { const api = getApi(); - const res = await api.get(`${resource.path}/${id}`); + const res = await api.get(`${rPath}/${id}`, { params }); return res.data; } catch (e: any) { setError(parseError(e)); @@ -435,16 +431,17 @@ export function useResource(resourceName: string): UseResourceReturn { setLoading(false); } }, - [resource.path, setLoading, setError] + [rPath, setLoading, setError] ); const create = useCallback( async (data: any): Promise => { + if (!rPath) throw new Error(`Resource "${resourceName}" not found yet`); setLoading(true); setError(null); try { const api = getApi(); - const res = await api.post(resource.path, data); + const res = await api.post(rPath, data); return res.data; } catch (e: any) { setError(parseError(e)); @@ -453,17 +450,18 @@ export function useResource(resourceName: string): UseResourceReturn { setLoading(false); } }, - [resource.path, setLoading, setError] + [rPath, setLoading, setError] ); const update = useCallback( async (id: string | number, data: any): Promise => { + if (!rPath) throw new Error(`Resource "${resourceName}" not found yet`); setLoading(true); setError(null); try { const api = getApi(); - const method = resource.updateMethod ?? "put"; - const res = await (method === "patch" ? api.patch : api.put)(`${resource.path}/${id}`, data); + const method = rUpdateMethod ?? "put"; + const res = await (method === "patch" ? api.patch : api.put)(`${rPath}/${id}`, data); return res.data; } catch (e: any) { setError(parseError(e)); @@ -472,16 +470,17 @@ export function useResource(resourceName: string): UseResourceReturn { setLoading(false); } }, - [resource.path, resource.updateMethod, setLoading, setError] + [rPath, rUpdateMethod, setLoading, setError] ); const remove = useCallback( async (id: string | number): Promise => { + if (!rPath) throw new Error(`Resource "${resourceName}" not found yet`); setLoading(true); setError(null); try { const api = getApi(); - await api.delete(`${resource.path}/${id}`); + await api.delete(`${rPath}/${id}`); } catch (e: any) { setError(parseError(e)); throw e; @@ -489,17 +488,17 @@ export function useResource(resourceName: string): UseResourceReturn { setLoading(false); } }, - [resource.path, setLoading, setError] + [rPath, setLoading, setError] ); const stream = useCallback( (handlers: StreamHandlers): StreamSubscription => { - if (!resource.streaming) { + if (!rPath || !rStreaming) { throw new Error(`Resource "${resourceName}" does not support streaming`); } const api = getApi(); const baseUrl = (api.defaults.baseURL ?? "").replace(/\/+$/, ""); - const url = baseUrl + resource.path; + const url = baseUrl + rPath; const es = new EventSource(url); es.onopen = () => handlers.onOpen?.(); @@ -517,19 +516,35 @@ export function useResource(resourceName: string): UseResourceReturn { return { close: () => es.close() }; }, - [resource.path, resource.streaming, resourceName] + [rPath, rStreaming, resourceName] ); const components = useMemo( () => { const map: Record> = {}; - for (const field of resource.fields) { + if (!rFields) return map; + for (const field of rFields) { map[field.name] = buildFilterComponent(field, resourceName); } return map; }, - [resource.fields, resourceName] + [rFields, resourceName] ); - return { resource, components, list, get, create, update, remove, stream: resource.streaming ? stream : undefined, loading: state.loading, error: state.error }; + if (!resource) { + return { + resource: null as unknown as ResourceConfig, + components, + list, + get, + create, + update, + remove, + stream: undefined, + loading: false, + error: null, + }; + } + + return { resource, components, list, get, create, update, remove, stream: rStreaming ? stream : undefined, loading: state.loading, error: state.error }; } \ No newline at end of file diff --git a/src/features/report/useReport.ts b/src/features/report/useReport.ts index 8bb9eb8..b7b24f5 100644 --- a/src/features/report/useReport.ts +++ b/src/features/report/useReport.ts @@ -12,9 +12,11 @@ export interface ReportParams { export function useReport(params: ReportParams) { const { get } = useResource("reports"); + const { snapshot_id, ...queryParams } = params; + return useQuery({ queryKey: ["reports", "read", params], queryFn: () => - get(params.snapshot_id ? params.snapshot_id : "latest"), + get(snapshot_id ?? "latest", queryParams), }); }