refactor: Introduce dedicated Document and Asset types and migrate codebase from DocumentLike.
This commit is contained in:
@@ -6,11 +6,7 @@ import type { FolderId, Identifier } from '../../types/identifiers';
|
||||
type FolderIdentifier = FolderId | 'root';
|
||||
type FolderInput = FolderIdentifier | number;
|
||||
|
||||
interface DocumentLike {
|
||||
id?: Identifier | null;
|
||||
title?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
import type { Document } from '../../types/documents';
|
||||
|
||||
type ApplySelectionFn = (
|
||||
keys: string[],
|
||||
@@ -28,7 +24,7 @@ interface UseDocumentDragHandlersOptions {
|
||||
selectedFolderIds: FolderInput[];
|
||||
applySelection: ApplySelectionFn;
|
||||
handleEntrySelection: HandleEntrySelectionFn;
|
||||
documentLookup: Map<Identifier, DocumentLike>;
|
||||
documentLookup: Map<Identifier, Document>;
|
||||
setDraggedDocumentIds: (ids: Identifier[] | []) => void;
|
||||
setDraggedFolderId: (id: FolderIdentifier | null) => void;
|
||||
documentsViewMode: string;
|
||||
@@ -62,7 +58,7 @@ const useDocumentDragHandlers = ({
|
||||
useEffect(() => destroyDragPreview, [destroyDragPreview]);
|
||||
|
||||
const createDragPreview = useCallback(
|
||||
({ documents = [], folders = [] }: { documents?: DocumentLike[]; folders?: FolderIdentifier[] } = {}) => {
|
||||
({ documents = [], folders = [] }: { documents?: Document[]; folders?: FolderIdentifier[] } = {}) => {
|
||||
destroyDragPreview();
|
||||
|
||||
const docEntries = (documents || []).filter(Boolean);
|
||||
@@ -202,9 +198,9 @@ const useDocumentDragHandlers = ({
|
||||
);
|
||||
|
||||
const handleDocumentDragStart = useCallback(
|
||||
(event: DragEvent<HTMLElement>, documentOrId: DocumentLike | Identifier | null) => {
|
||||
(event: DragEvent<HTMLElement>, documentOrId: Document | Identifier | null) => {
|
||||
const documentId: Identifier | null = Object(documentOrId) === documentOrId
|
||||
? (documentOrId as DocumentLike)?.id ?? null
|
||||
? (documentOrId as Document)?.id ?? null
|
||||
: (documentOrId as Identifier | null);
|
||||
if (!documentId) {
|
||||
return;
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
updateDocument,
|
||||
} from '../../lib/apiClient';
|
||||
import type { DocumentId, FolderId as FolderIdentifier } from '../../types/identifiers';
|
||||
import type { Document } from '../../types/documents';
|
||||
|
||||
type FolderId = FolderIdentifier | 'root';
|
||||
type NullableFolderId = FolderId | null;
|
||||
@@ -21,8 +22,8 @@ type NullableFolderId = FolderId | null;
|
||||
type StatusLevel = 'success' | 'error' | 'info' | string;
|
||||
|
||||
type DocumentCacheMapper = (
|
||||
doc: DocumentLike | null,
|
||||
) => DocumentLike | null;
|
||||
doc: Document | null,
|
||||
) => Document | null;
|
||||
|
||||
type MapDocumentCaches = (mapper: DocumentCacheMapper) => void;
|
||||
|
||||
@@ -53,19 +54,8 @@ interface Tag {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface DocumentLike {
|
||||
id?: DocumentId;
|
||||
folder_id?: NullableFolderId;
|
||||
folder_path?: string | null;
|
||||
folder_name?: string | null;
|
||||
issued_at?: number | null;
|
||||
title?: string;
|
||||
tags?: Tag[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface FolderContents {
|
||||
documents?: DocumentLike[];
|
||||
documents?: Document[];
|
||||
subfolders?: Array<{ id?: FolderId;[key: string]: unknown }>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
@@ -109,12 +99,12 @@ interface FolderDeleteOptions {
|
||||
|
||||
interface UseDocumentMutationsArgs {
|
||||
token?: string | null;
|
||||
documentLookup: Map<DocumentId, DocumentLike>;
|
||||
documentLookup: Map<DocumentId, Document>;
|
||||
folderLabelMap: Map<FolderId, string>;
|
||||
ensureFolderData: EnsureFolderData;
|
||||
selectedFolder: FolderId;
|
||||
setSelectedFolder: Dispatch<SetStateAction<FolderId>>;
|
||||
setDocuments: Dispatch<SetStateAction<DocumentLike[]>>;
|
||||
setDocuments: Dispatch<SetStateAction<Document[]>>;
|
||||
setFolderContents: Dispatch<SetStateAction<Map<FolderId, FolderContents>>>;
|
||||
setSearchResultIds: Dispatch<SetStateAction<DocumentId[] | null>>;
|
||||
setSelectedEntries: Dispatch<SetStateAction<string[]>>;
|
||||
@@ -140,13 +130,13 @@ interface UseDocumentMutationsArgs {
|
||||
tags: Tag[];
|
||||
refreshTags: () => Promise<void>;
|
||||
tagManager: TagManager;
|
||||
extractDocumentFromResponse?: (payload: unknown) => DocumentLike | null;
|
||||
ingestDocuments?: (docs: unknown[]) => { canonical: DocumentLike[]; changed: boolean };
|
||||
extractDocumentFromResponse?: (payload: unknown) => Document | null;
|
||||
ingestDocuments?: (docs: unknown[]) => { canonical: Document[]; changed: boolean };
|
||||
}
|
||||
|
||||
interface UseDocumentMutationsResult {
|
||||
moveDocumentsToFolder: (
|
||||
documentIds: Array<DocumentId | DocumentLike>,
|
||||
documentIds: Array<DocumentId | Document>,
|
||||
targetFolderId?: NullableFolderId,
|
||||
) => Promise<void>;
|
||||
handleThumbnailRegeneration: (documentId: DocumentId) => Promise<void>;
|
||||
@@ -155,7 +145,7 @@ interface UseDocumentMutationsResult {
|
||||
options?: DeleteOptions,
|
||||
) => Promise<boolean>;
|
||||
handleDocumentTagAdd: (
|
||||
document: DocumentLike,
|
||||
document: Document,
|
||||
label: string,
|
||||
extras?: DocumentTagExtras | null,
|
||||
) => Promise<void>;
|
||||
@@ -218,7 +208,7 @@ const useDocumentMutations = ({
|
||||
ingestDocuments,
|
||||
}: UseDocumentMutationsArgs): UseDocumentMutationsResult => {
|
||||
const moveDocumentsToFolder = useCallback(
|
||||
async (documentIds: Array<DocumentId | DocumentLike>, targetFolderId?: NullableFolderId) => {
|
||||
async (documentIds: Array<DocumentId | Document>, targetFolderId?: NullableFolderId) => {
|
||||
const uniqueIds = Array.from(
|
||||
new Set((documentIds || []).map((value) => normalizeDocumentId(value)).filter(Boolean) as DocumentId[]),
|
||||
);
|
||||
@@ -241,9 +231,9 @@ const useDocumentMutations = ({
|
||||
document: doc,
|
||||
};
|
||||
})
|
||||
.filter(Boolean) as Array<{ id: DocumentId; sourceFolderId: NullableFolderId; document: DocumentLike }>;
|
||||
.filter(Boolean) as Array<{ id: DocumentId; sourceFolderId: NullableFolderId; document: Document }>;
|
||||
|
||||
const updatedDocsMap = new Map<DocumentId, DocumentLike>();
|
||||
const updatedDocsMap = new Map<DocumentId, Document>();
|
||||
const resolveTargetName = () => {
|
||||
if (!targetLabel) {
|
||||
return null;
|
||||
@@ -257,7 +247,7 @@ const useDocumentMutations = ({
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
const updated: DocumentLike = {
|
||||
const updated: Document = {
|
||||
...document,
|
||||
folder_id: target,
|
||||
};
|
||||
@@ -572,7 +562,7 @@ const useDocumentMutations = ({
|
||||
);
|
||||
|
||||
const handleDocumentTagAdd = useCallback(
|
||||
async (document: DocumentLike, label: string, extras: DocumentTagExtras | null = null) => {
|
||||
async (document: Document, label: string, extras: DocumentTagExtras | null = null) => {
|
||||
const normalizedLabel = tagManager.normalizeLabel(label);
|
||||
const optionCandidate = extras?.option ?? null;
|
||||
const input = extras?.input ?? null;
|
||||
|
||||
@@ -8,20 +8,16 @@ import {
|
||||
} from 'react';
|
||||
import DocumentsManager from '../../documents/DocumentsManager';
|
||||
import type { DocumentId } from '../../types/identifiers';
|
||||
|
||||
interface DocumentLike {
|
||||
id?: DocumentId;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
import type { Document } from '../../types/documents';
|
||||
|
||||
interface FolderContentsEntry {
|
||||
documents?: DocumentLike[];
|
||||
documents?: Document[];
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface UseDocumentsOptions {
|
||||
setFolderContents: Dispatch<SetStateAction<Map<string, FolderContentsEntry>>>;
|
||||
fetchDocumentById?: (id: DocumentId) => Promise<DocumentLike | null>;
|
||||
fetchDocumentById?: (id: DocumentId) => Promise<Document | null>;
|
||||
}
|
||||
|
||||
const useDocuments = ({
|
||||
@@ -29,16 +25,16 @@ const useDocuments = ({
|
||||
fetchDocumentById,
|
||||
}: UseDocumentsOptions) => {
|
||||
const managerRef = useRef(
|
||||
new DocumentsManager<DocumentLike>(fetchDocumentById),
|
||||
new DocumentsManager<Document>(fetchDocumentById),
|
||||
);
|
||||
const [documents, setDocumentsState] = useState<DocumentLike[]>([]);
|
||||
const [documents, setDocumentsState] = useState<Document[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
managerRef.current.setFetcher(fetchDocumentById);
|
||||
}, [fetchDocumentById]);
|
||||
|
||||
const setDocuments = useCallback(
|
||||
(value: DocumentLike[] | ((prev: DocumentLike[]) => DocumentLike[])) => {
|
||||
(value: Document[] | ((prev: Document[]) => Document[])) => {
|
||||
setDocumentsState((prev) => {
|
||||
const resolved = typeof value === 'function' ? value(prev) : value;
|
||||
if (!Array.isArray(resolved)) {
|
||||
@@ -52,7 +48,7 @@ const useDocuments = ({
|
||||
);
|
||||
|
||||
const mapDocumentCaches = useCallback(
|
||||
(mapper: (doc: DocumentLike) => DocumentLike | undefined) => {
|
||||
(mapper: (doc: Document) => Document | undefined) => {
|
||||
managerRef.current.map(mapper);
|
||||
const lookupSnapshot = managerRef.current.getSnapshot();
|
||||
|
||||
@@ -64,7 +60,7 @@ const useDocuments = ({
|
||||
const next = prev.map((doc) => {
|
||||
const id = doc?.id;
|
||||
if (id != null && lookupSnapshot.has(id as DocumentId)) {
|
||||
const canonical = lookupSnapshot.get(id as DocumentId) as DocumentLike;
|
||||
const canonical = lookupSnapshot.get(id as DocumentId) as Document;
|
||||
if (canonical !== doc) {
|
||||
changed = true;
|
||||
}
|
||||
@@ -95,7 +91,7 @@ const useDocuments = ({
|
||||
const updatedDocs = docs.map((doc) => {
|
||||
const id = doc?.id;
|
||||
if (id != null && lookupSnapshot.has(id as DocumentId)) {
|
||||
const canonical = lookupSnapshot.get(id as DocumentId) as DocumentLike;
|
||||
const canonical = lookupSnapshot.get(id as DocumentId) as Document;
|
||||
if (canonical !== doc) {
|
||||
docsChanged = true;
|
||||
}
|
||||
|
||||
@@ -62,15 +62,11 @@ const noop = () => { };
|
||||
|
||||
type FolderId = FolderIdentifier | 'root';
|
||||
|
||||
interface DocumentLike {
|
||||
id?: DocumentId | null;
|
||||
title?: string | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
import type { Document } from '../../types/documents';
|
||||
|
||||
interface FolderContentsEntry {
|
||||
folder?: { id?: FolderId; name?: string | null } | null;
|
||||
documents?: DocumentLike[];
|
||||
documents?: Document[];
|
||||
subfolders?: Array<{ id?: FolderId; name?: string | null;[key: string]: unknown }>;
|
||||
__includesDocuments?: boolean;
|
||||
__sortField?: string | null;
|
||||
@@ -397,7 +393,7 @@ const useDocumentsWorkspace = ({
|
||||
() =>
|
||||
visibleDocumentIds
|
||||
.map((id) => documentLookup.get(id) || null)
|
||||
.filter((doc): doc is DocumentLike => Boolean(doc)),
|
||||
.filter((doc): doc is Document => Boolean(doc)),
|
||||
[visibleDocumentIds, documentLookup],
|
||||
);
|
||||
|
||||
|
||||
@@ -9,14 +9,10 @@ import {
|
||||
createFolderEntryKey,
|
||||
} from '../../app/entryKey';
|
||||
import type { FolderId as FolderIdentifier, Identifier } from '../../types/identifiers';
|
||||
import type { Document } from '../../types/documents';
|
||||
|
||||
type FolderId = FolderIdentifier | 'root';
|
||||
|
||||
interface DocumentLike {
|
||||
id?: Identifier | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface FolderSummary {
|
||||
id?: FolderId;
|
||||
name?: string;
|
||||
@@ -31,7 +27,7 @@ interface FolderSummary {
|
||||
|
||||
interface FolderContentsEntry {
|
||||
folder?: FolderSummary | null;
|
||||
documents?: DocumentLike[];
|
||||
documents?: Document[];
|
||||
subfolders?: FolderSummary[];
|
||||
__includesDocuments?: boolean;
|
||||
__sortField?: string | null;
|
||||
@@ -67,7 +63,7 @@ interface UseFolderTreeOptions {
|
||||
documentsSortFieldRef: MutableRefObject<string>;
|
||||
documentsSortDirectionRef: MutableRefObject<string>;
|
||||
selectionHelpers: SelectionHelpers;
|
||||
setDocuments: Dispatch<SetStateAction<DocumentLike[]>>;
|
||||
setDocuments: Dispatch<SetStateAction<Document[]>>;
|
||||
setFolderContents: Dispatch<SetStateAction<Map<FolderId, FolderContentsEntry>>>;
|
||||
folderContentsRef: MutableRefObject<Map<FolderId, FolderContentsEntry>>;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { resolveAssetUrl } from '../asset_manager';
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
|
||||
type DocumentLike = {
|
||||
id?: Identifier;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
import type { Document } from '../types/documents';
|
||||
|
||||
type AssetObject = {
|
||||
url?: string | null;
|
||||
@@ -29,7 +26,7 @@ type EnsureAssetUrl = (
|
||||
options?: { force?: boolean;[key: string]: unknown },
|
||||
) => Promise<unknown>;
|
||||
|
||||
type GetAsset = (document: DocumentLike, assetType: string) => AssetLike | null;
|
||||
type GetAsset = (document: Document, assetType: string) => AssetLike | null;
|
||||
|
||||
type AssetViewLike = {
|
||||
url: string | null;
|
||||
@@ -37,14 +34,14 @@ type AssetViewLike = {
|
||||
};
|
||||
|
||||
interface UseAssetNavigatorOptions {
|
||||
document?: DocumentLike | null;
|
||||
document?: Document | null;
|
||||
assetType: string;
|
||||
ensureAssetUrl?: EnsureAssetUrl | null;
|
||||
getAsset?: GetAsset;
|
||||
}
|
||||
|
||||
interface AssetNavigatorReturn {
|
||||
document: DocumentLike | null;
|
||||
document: Document | null;
|
||||
documentId: Identifier | null;
|
||||
asset: AssetLike | null;
|
||||
assetType: string;
|
||||
|
||||
Reference in New Issue
Block a user