apiclient
This commit is contained in:
@@ -57,7 +57,7 @@ const SettingsRoute: React.FC<SettingsRouteProps> = ({ open = true, onClose }) =
|
|||||||
capabilities,
|
capabilities,
|
||||||
capabilitiesLoading,
|
capabilitiesLoading,
|
||||||
refreshCapabilities,
|
refreshCapabilities,
|
||||||
} = useCapabilities({ api, notifyApiError, token });
|
} = useCapabilities({ notifyApiError, token });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
refreshTokens();
|
refreshTokens();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type {
|
|||||||
MutableRefObject,
|
MutableRefObject,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import { fetchDocument } from '../lib/apiClient';
|
||||||
|
|
||||||
type DocumentId = string | number;
|
type DocumentId = string | number;
|
||||||
type FolderId = DocumentId | 'root';
|
type FolderId = DocumentId | 'root';
|
||||||
@@ -23,10 +24,6 @@ type DocumentLink = {
|
|||||||
expiresAt?: number;
|
expiresAt?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ApiClient {
|
|
||||||
get: <T = unknown>(path: string) => Promise<{ data: T }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type NavigateHandler = (path: string, options?: { replace?: boolean }) => void;
|
type NavigateHandler = (path: string, options?: { replace?: boolean }) => void;
|
||||||
|
|
||||||
interface UseDocumentPreviewArgs {
|
interface UseDocumentPreviewArgs {
|
||||||
@@ -39,7 +36,6 @@ interface UseDocumentPreviewArgs {
|
|||||||
ingest: (docs: unknown[]) => { canonical: DocumentLike[]; changed: boolean };
|
ingest: (docs: unknown[]) => { canonical: DocumentLike[]; changed: boolean };
|
||||||
};
|
};
|
||||||
selectedFolder?: FolderId | null;
|
selectedFolder?: FolderId | null;
|
||||||
api: ApiClient;
|
|
||||||
notifyApiError: (error: unknown, message: string) => void;
|
notifyApiError: (error: unknown, message: string) => void;
|
||||||
navigate: NavigateHandler;
|
navigate: NavigateHandler;
|
||||||
locationPathname: string;
|
locationPathname: string;
|
||||||
@@ -65,7 +61,6 @@ const useDocumentPreview = ({
|
|||||||
routeDocumentId,
|
routeDocumentId,
|
||||||
documentsManager,
|
documentsManager,
|
||||||
selectedFolder,
|
selectedFolder,
|
||||||
api,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
navigate,
|
navigate,
|
||||||
locationPathname,
|
locationPathname,
|
||||||
@@ -120,8 +115,8 @@ const useDocumentPreview = ({
|
|||||||
|
|
||||||
const request: Promise<DocumentLink | null> = (async () => {
|
const request: Promise<DocumentLink | null> = (async () => {
|
||||||
try {
|
try {
|
||||||
const docResponse = await api.get<{ document?: Record<string, any> }>(`/documents/${documentId}`);
|
const docResponse = await fetchDocument(documentId);
|
||||||
const download = docResponse.data?.document?.current_version?.download || null;
|
const download = docResponse?.current_version?.download || null;
|
||||||
const downloadUrl = download?.url;
|
const downloadUrl = download?.url;
|
||||||
if (!downloadUrl) {
|
if (!downloadUrl) {
|
||||||
throw new Error('Document missing download url');
|
throw new Error('Document missing download url');
|
||||||
@@ -129,8 +124,8 @@ const useDocumentPreview = ({
|
|||||||
|
|
||||||
const entry: DocumentLink = {
|
const entry: DocumentLink = {
|
||||||
url: downloadUrl,
|
url: downloadUrl,
|
||||||
contentType: docResponse.data?.document?.current_version?.version?.content_type || null,
|
contentType: docResponse?.content_type || null,
|
||||||
filename: docResponse.data?.document?.filename,
|
filename: docResponse?.filename,
|
||||||
expiresAt: download?.expires_at,
|
expiresAt: download?.expires_at,
|
||||||
};
|
};
|
||||||
setDocumentLinks((prev) => {
|
setDocumentLinks((prev) => {
|
||||||
@@ -150,7 +145,7 @@ const useDocumentPreview = ({
|
|||||||
previewInflightRef.current.set(documentId, request);
|
previewInflightRef.current.set(documentId, request);
|
||||||
return request;
|
return request;
|
||||||
},
|
},
|
||||||
[documentLinks, api, notifyApiError],
|
[documentLinks, notifyApiError],
|
||||||
);
|
);
|
||||||
|
|
||||||
const ensurePreviewData = useCallback(
|
const ensurePreviewData = useCallback(
|
||||||
@@ -166,8 +161,7 @@ const useDocumentPreview = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
const { data } = await api.get(`/documents/${documentId}`);
|
const fetched = await fetchDocument(documentId);
|
||||||
const fetched = (data as { document?: DocumentLike })?.document || data;
|
|
||||||
const { canonical } = documentsManager.ingest([fetched as unknown]);
|
const { canonical } = documentsManager.ingest([fetched as unknown]);
|
||||||
doc = (canonical[0] as DocumentLike | undefined) || null;
|
doc = (canonical[0] as DocumentLike | undefined) || null;
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
@@ -189,7 +183,6 @@ const useDocumentPreview = ({
|
|||||||
documentsManager,
|
documentsManager,
|
||||||
ensureDownloadUrl,
|
ensureDownloadUrl,
|
||||||
setActivePreviewId,
|
setActivePreviewId,
|
||||||
api,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import type { Dispatch, SetStateAction } from 'react';
|
import type { Dispatch, SetStateAction } from 'react';
|
||||||
import { TAG_FILTER_UNTAGGED } from './appLayoutUtils';
|
import { TAG_FILTER_UNTAGGED } from './appLayoutUtils';
|
||||||
|
import { listDocuments } from '../lib/apiClient';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|
||||||
@@ -227,7 +228,7 @@ const useDocumentsSearch = ({
|
|||||||
if (documentsSortDirection) {
|
if (documentsSortDirection) {
|
||||||
params.dir = documentsSortDirection;
|
params.dir = documentsSortDirection;
|
||||||
}
|
}
|
||||||
const { data } = await api.get<unknown[]>('/documents', { params });
|
const data = await listDocuments(params);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
|
|
||||||
const results = Array.isArray(data) ? data : [];
|
const results = Array.isArray(data) ? data : [];
|
||||||
|
|||||||
@@ -566,7 +566,6 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const docContentType = doc?.content_type ?? null;
|
const docContentType = doc?.content_type ?? null;
|
||||||
const versionContentType = (doc?.current_version as { version?: { content_type?: string | null } } | null)?.version?.content_type ?? null;
|
|
||||||
|
|
||||||
const applyEntry = (entry?: DocumentLinkLike | null) => {
|
const applyEntry = (entry?: DocumentLinkLike | null) => {
|
||||||
if (!entry?.url) {
|
if (!entry?.url) {
|
||||||
@@ -575,8 +574,8 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
|
|||||||
}
|
}
|
||||||
setOverlaySource({
|
setOverlaySource({
|
||||||
url: entry.url,
|
url: entry.url,
|
||||||
alt: doc.title as string | undefined,
|
alt: doc.title,
|
||||||
contentType: entry.contentType || docContentType || versionContentType || undefined,
|
contentType: docContentType || undefined,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { getFolderTree } from '../lib/apiClient';
|
||||||
import {
|
import {
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
AnalyzeIcon,
|
AnalyzeIcon,
|
||||||
@@ -10,7 +11,7 @@ import {
|
|||||||
} from '../ui/icons';
|
} from '../ui/icons';
|
||||||
import SelectionAssignmentMenu, { SelectionAssignmentMenuItem } from './SelectionAssignmentMenu';
|
import SelectionAssignmentMenu, { SelectionAssignmentMenuItem } from './SelectionAssignmentMenu';
|
||||||
import SelectionSummary from './SelectionSummary';
|
import SelectionSummary from './SelectionSummary';
|
||||||
import { api, useAppState } from '../app/appState';
|
import { useAppState } from '../app/appState';
|
||||||
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
|
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
|
||||||
|
|
||||||
const ROOT_FOLDER_LABEL = 'Documents';
|
const ROOT_FOLDER_LABEL = 'Documents';
|
||||||
@@ -312,7 +313,7 @@ const SelectionFloatingActions: React.FC<SelectionFloatingActionsProps> = ({
|
|||||||
const fetchPromise = (async () => {
|
const fetchPromise = (async () => {
|
||||||
setLoadingFolders(true);
|
setLoadingFolders(true);
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get('/folders/tree');
|
const data = await getFolderTree();
|
||||||
const options = buildFolderTreeOptions(data);
|
const options = buildFolderTreeOptions(data);
|
||||||
setRemoteFolderOptions(options);
|
setRemoteFolderOptions(options);
|
||||||
return options;
|
return options;
|
||||||
|
|||||||
@@ -291,7 +291,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const docContentType = previewDoc.content_type;
|
const docContentType = previewDoc.content_type;
|
||||||
const versionContentType = previewDoc.current_version?.version?.content_type;
|
const versionContentType = previewDoc.current_version?.content_type;
|
||||||
const contentFallback = docContentType || versionContentType || null;
|
const contentFallback = docContentType || versionContentType || null;
|
||||||
|
|
||||||
const applyEntry = (entry?: DocumentLinkLike | null) => {
|
const applyEntry = (entry?: DocumentLinkLike | null) => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useCallback, useRef, useState } from 'react';
|
|||||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||||
import useFileDrop from './useFileDrop';
|
import useFileDrop from './useFileDrop';
|
||||||
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../app/appLayoutUtils';
|
||||||
|
import { fetchDocument } from '../../lib/apiClient';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
type FolderId = Identifier | 'root' | null;
|
type FolderId = Identifier | 'root' | null;
|
||||||
@@ -174,8 +175,7 @@ const useDocumentUploads = ({
|
|||||||
let conflictDocument = null;
|
let conflictDocument = null;
|
||||||
if (conflictId) {
|
if (conflictId) {
|
||||||
try {
|
try {
|
||||||
const { data } = await apiClient.get(`/documents/${conflictId}`);
|
conflictDocument = await fetchDocument(conflictId);
|
||||||
conflictDocument = (data as any)?.document ?? data ?? null;
|
|
||||||
} catch (fetchError) {
|
} catch (fetchError) {
|
||||||
console.warn('[Uploads] failed to fetch conflict document', fetchError);
|
console.warn('[Uploads] failed to fetch conflict document', fetchError);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import useTags from './useTags';
|
|||||||
import useCorrespondents from './useCorrespondents';
|
import useCorrespondents from './useCorrespondents';
|
||||||
import useTenantManager from './useTenantManager';
|
import useTenantManager from './useTenantManager';
|
||||||
import useDocuments from './useDocuments';
|
import useDocuments from './useDocuments';
|
||||||
|
import { fetchDocument } from '../../lib/apiClient';
|
||||||
import useFolderTree from './useFolderTree';
|
import useFolderTree from './useFolderTree';
|
||||||
import useFolderTreeActions from './useFolderTreeActions';
|
import useFolderTreeActions from './useFolderTreeActions';
|
||||||
import useDocumentTagging from './useDocumentTagging';
|
import useDocumentTagging from './useDocumentTagging';
|
||||||
@@ -238,7 +239,7 @@ const useDocumentsWorkspace = ({
|
|||||||
if (!documentId) {
|
if (!documentId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { data } = await api.get(`/documents/${documentId}`);
|
const data = await fetchDocument(documentId);
|
||||||
return extractDocumentFromResponse(data);
|
return extractDocumentFromResponse(data);
|
||||||
},
|
},
|
||||||
[extractDocumentFromResponse],
|
[extractDocumentFromResponse],
|
||||||
@@ -449,7 +450,6 @@ const useDocumentsWorkspace = ({
|
|||||||
routeDocumentId: previewDocumentId,
|
routeDocumentId: previewDocumentId,
|
||||||
documentsManager,
|
documentsManager,
|
||||||
selectedFolder,
|
selectedFolder,
|
||||||
api,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
navigate,
|
navigate,
|
||||||
locationPathname: location.pathname,
|
locationPathname: location.pathname,
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import api from './api';
|
||||||
|
import type {
|
||||||
|
ApiTokenRecord,
|
||||||
|
AssetResponse,
|
||||||
|
CapabilityResponse,
|
||||||
|
CapabilitySetResponse,
|
||||||
|
DownloadLink,
|
||||||
|
DocumentResponse,
|
||||||
|
FolderTreeNode,
|
||||||
|
Identifier,
|
||||||
|
PasskeySummary,
|
||||||
|
} from './apiTypes';
|
||||||
|
|
||||||
|
const normalizeNumber = (value: unknown): number | undefined => {
|
||||||
|
const n = Number(value);
|
||||||
|
return Number.isFinite(n) ? n : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeDownload = (input?: DownloadLink | null): DownloadLink | null => {
|
||||||
|
if (!input?.url) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const expires_at = normalizeNumber(input.expires_at);
|
||||||
|
if (!expires_at) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { url: input.url, expires_at };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchDocument = async (id: Identifier): Promise<DocumentResponse> => {
|
||||||
|
const { data } = await api.get<{ document?: DocumentResponse }>(`/documents/${id}`);
|
||||||
|
const doc = data?.document || (data as unknown as DocumentResponse);
|
||||||
|
if (doc?.current_version?.download) {
|
||||||
|
doc.current_version.download = normalizeDownload(doc.current_version.download);
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const fetchAsset = async (id: Identifier): Promise<AssetResponse> => {
|
||||||
|
const { data } = await api.get<AssetResponse>(`/assets/${id}`);
|
||||||
|
const download = normalizeDownload(data.download);
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
download,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listDocuments = async (params: Record<string, unknown> = {}): Promise<DocumentResponse[]> => {
|
||||||
|
const { data } = await api.get<DocumentResponse[]>('/documents', { params });
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getFolderTree = async (): Promise<FolderTreeNode[]> => {
|
||||||
|
const { data } = await api.get<FolderTreeNode[]>('/folders/tree');
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listCapabilitySets = async (): Promise<CapabilitySetResponse[]> => {
|
||||||
|
const { data } = await api.get<CapabilitySetResponse[]>('/capability-sets');
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listCapabilities = async (): Promise<CapabilityResponse[]> => {
|
||||||
|
const { data } = await api.get<CapabilityResponse[]>('/capabilities');
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listApiTokens = async (): Promise<ApiTokenRecord[]> => {
|
||||||
|
const { data } = await api.get<ApiTokenRecord[]>('/profile/api-tokens');
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listPasskeys = async (): Promise<PasskeySummary[]> => {
|
||||||
|
const { data } = await api.get<PasskeySummary[]>('/profile/passkeys');
|
||||||
|
return Array.isArray(data) ? data : [];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type {
|
||||||
|
DownloadLink,
|
||||||
|
DocumentResponse,
|
||||||
|
AssetResponse,
|
||||||
|
FolderTreeNode,
|
||||||
|
CapabilitySetResponse,
|
||||||
|
CapabilityResponse,
|
||||||
|
ApiTokenRecord,
|
||||||
|
PasskeySummary,
|
||||||
|
Identifier,
|
||||||
|
} from './apiTypes';
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// Types aligned with OpenAPI schemas for common endpoints.
|
||||||
|
|
||||||
|
export type Identifier = string | number;
|
||||||
|
|
||||||
|
export interface DownloadLink {
|
||||||
|
url: string;
|
||||||
|
expires_at: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TagResponse {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
color?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CorrespondentResponse {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
metadata: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssetResponse {
|
||||||
|
id: string;
|
||||||
|
asset_type: string;
|
||||||
|
mime_type: string;
|
||||||
|
metadata: Record<string, unknown>;
|
||||||
|
download?: DownloadLink | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DocumentVersionResponse {
|
||||||
|
id: string;
|
||||||
|
version_number: number;
|
||||||
|
size_bytes: number;
|
||||||
|
checksum: string;
|
||||||
|
created_at: string;
|
||||||
|
content_type: string | null;
|
||||||
|
metadata: Record<string, unknown>;
|
||||||
|
download: DownloadLink;
|
||||||
|
assets?: AssetResponse[] | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DocumentResponse {
|
||||||
|
id: string;
|
||||||
|
filename: string;
|
||||||
|
title: string;
|
||||||
|
original_name: string;
|
||||||
|
content_type?: string | null;
|
||||||
|
folder_id?: string | null;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
issued_at?: string | null;
|
||||||
|
metadata: Record<string, unknown>;
|
||||||
|
tags: TagResponse[];
|
||||||
|
correspondents?: CorrespondentResponse[];
|
||||||
|
current_version?: DocumentVersionResponse | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FolderInfo {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
parent_id?: string | null;
|
||||||
|
created_at?: string;
|
||||||
|
updated_at?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FolderTreeNode extends FolderInfo {
|
||||||
|
children?: FolderTreeNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CapabilitySetResponse {
|
||||||
|
id: string;
|
||||||
|
slug: string;
|
||||||
|
is_system: boolean;
|
||||||
|
cap_version: number;
|
||||||
|
capabilities: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CapabilityResponse {
|
||||||
|
id?: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TenantSnippet {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiTokenRecord {
|
||||||
|
id: string;
|
||||||
|
label?: string | null;
|
||||||
|
capability_set_id: string;
|
||||||
|
created_at: string;
|
||||||
|
last_used_at?: string | null;
|
||||||
|
expires_at?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PasskeySummary {
|
||||||
|
id: string;
|
||||||
|
nickname?: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
lastUsedAt?: string | null;
|
||||||
|
transports?: string[];
|
||||||
|
revokedAt?: string | null;
|
||||||
|
revokedReason?: string | null;
|
||||||
|
}
|
||||||
@@ -268,7 +268,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
if (!href) {
|
if (!href) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const contentType = document.current_version?.version?.content_type || document.content_type || null;
|
const contentType = document.content_type || null;
|
||||||
const filename = document.current_version?.filename || document.filename || document.title || null;
|
const filename = document.current_version?.filename || document.filename || document.title || null;
|
||||||
return {
|
return {
|
||||||
url: href,
|
url: href,
|
||||||
@@ -363,15 +363,13 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
if (!resolvedDocumentLink?.url || !document) {
|
if (!resolvedDocumentLink?.url || !document) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const docContentType = document.content_type;
|
const normalizedContentType = document.content_type || null;
|
||||||
const versionContentType = document.current_version?.version?.content_type;
|
|
||||||
const normalizedContentType = resolvedDocumentLink.contentType || docContentType || versionContentType || null;
|
|
||||||
return {
|
return {
|
||||||
url: resolvedDocumentLink.url,
|
url: resolvedDocumentLink.url,
|
||||||
alt: document.title,
|
alt: document.title,
|
||||||
contentType: normalizedContentType || undefined,
|
contentType: normalizedContentType || undefined,
|
||||||
};
|
};
|
||||||
}, [resolvedDocumentLink?.url, resolvedDocumentLink?.contentType, document]);
|
}, [document, resolvedDocumentLink?.url]);
|
||||||
|
|
||||||
const headerActions = createDocumentViewerHeaderActions({
|
const headerActions = createDocumentViewerHeaderActions({
|
||||||
document,
|
document,
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { listCapabilities } from '../lib/apiClient';
|
||||||
interface CapabilitiesApi {
|
|
||||||
get: (path: string) => Promise<{ data: unknown }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UseCapabilitiesOptions {
|
interface UseCapabilitiesOptions {
|
||||||
api: CapabilitiesApi;
|
|
||||||
notifyApiError?: (error: unknown, fallbackMessage: string) => void;
|
notifyApiError?: (error: unknown, fallbackMessage: string) => void;
|
||||||
token?: string | null;
|
token?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useCapabilities = ({ api, notifyApiError, token }: UseCapabilitiesOptions) => {
|
const useCapabilities = ({ notifyApiError, token }: UseCapabilitiesOptions) => {
|
||||||
const [capabilities, setCapabilities] = useState<string[]>([]);
|
const [capabilities, setCapabilities] = useState<string[]>([]);
|
||||||
const [capabilitiesLoading, setCapabilitiesLoading] = useState(false);
|
const [capabilitiesLoading, setCapabilitiesLoading] = useState(false);
|
||||||
|
|
||||||
@@ -21,19 +17,15 @@ const useCapabilities = ({ api, notifyApiError, token }: UseCapabilitiesOptions)
|
|||||||
}
|
}
|
||||||
setCapabilitiesLoading(true);
|
setCapabilitiesLoading(true);
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get('/capabilities');
|
const data = await listCapabilities();
|
||||||
if (Array.isArray(data)) {
|
setCapabilities(Array.isArray(data) ? data.map((item) => item.name) : []);
|
||||||
setCapabilities(data as string[]);
|
|
||||||
} else {
|
|
||||||
setCapabilities([]);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifyApiError?.(error, 'Failed to load capabilities.');
|
notifyApiError?.(error, 'Failed to load capabilities.');
|
||||||
setCapabilities([]);
|
setCapabilities([]);
|
||||||
} finally {
|
} finally {
|
||||||
setCapabilitiesLoading(false);
|
setCapabilitiesLoading(false);
|
||||||
}
|
}
|
||||||
}, [api, notifyApiError, token]);
|
}, [notifyApiError, token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { listCapabilitySets } from '../lib/apiClient';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|
||||||
@@ -51,14 +52,14 @@ const useCapabilitySets = ({ api, notifyApiError, setStatusMessage, token }: Use
|
|||||||
}
|
}
|
||||||
setCapabilitySetsLoading(true);
|
setCapabilitySetsLoading(true);
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get<CapabilitySet[]>('/capability-sets');
|
const data = await listCapabilitySets();
|
||||||
applyCapabilitySets(Array.isArray(data) ? data : []);
|
applyCapabilitySets(Array.isArray(data) ? data : []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifyApiError?.(error, 'Failed to load capability sets.');
|
notifyApiError?.(error, 'Failed to load capability sets.');
|
||||||
} finally {
|
} finally {
|
||||||
setCapabilitySetsLoading(false);
|
setCapabilitySetsLoading(false);
|
||||||
}
|
}
|
||||||
}, [api, applyCapabilitySets, notifyApiError, token]);
|
}, [applyCapabilitySets, notifyApiError, token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
Reference in New Issue
Block a user