refactor: Consolidate workspace utilities into new workspaceUtils.ts with typed entry keys, replacing appLayoutUtils.ts, and update related components.
This commit is contained in:
@@ -22,7 +22,6 @@ type EnsureAssetUrl = (
|
|||||||
|
|
||||||
type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
|
type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
|
||||||
type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
|
type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
|
||||||
type ResolveApiPath = (path: string) => string;
|
|
||||||
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
||||||
|
|
||||||
interface DocumentsTableProps {
|
interface DocumentsTableProps {
|
||||||
@@ -43,7 +42,6 @@ interface DocumentsRouteAppShell {
|
|||||||
previewDocumentId?: Identifier | null;
|
previewDocumentId?: Identifier | null;
|
||||||
closeDocumentPreview?: () => void;
|
closeDocumentPreview?: () => void;
|
||||||
ensurePreviewData?: EnsurePreviewData;
|
ensurePreviewData?: EnsurePreviewData;
|
||||||
resolveApiPath?: ResolveApiPath;
|
|
||||||
ensureAssetUrl?: EnsureAssetUrl;
|
ensureAssetUrl?: EnsureAssetUrl;
|
||||||
getDocumentAsset?: GetDocumentAsset;
|
getDocumentAsset?: GetDocumentAsset;
|
||||||
notifyApiError?: NotifyApiError;
|
notifyApiError?: NotifyApiError;
|
||||||
@@ -63,7 +61,6 @@ const DocumentsRouteContent: React.FC = () => {
|
|||||||
previewDocumentId,
|
previewDocumentId,
|
||||||
closeDocumentPreview,
|
closeDocumentPreview,
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
resolveApiPath,
|
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
@@ -118,7 +115,6 @@ const DocumentsRouteContent: React.FC = () => {
|
|||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
resolveApiPath,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
closeDocumentPreview,
|
closeDocumentPreview,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
import { resolveAssetExpiresAt, resolveAssetUrl } from '../asset_manager';
|
|
||||||
|
|
||||||
export const ASSET_PRESIGN_TTL_MS = 240 * 1000; // backend issues 5 min tokens; refresh slightly early
|
|
||||||
export const DEFAULT_FOLDER_NAME = 'Documents';
|
|
||||||
export const DEFAULT_SORT_FIELD = 'title';
|
|
||||||
export const DEFAULT_SORT_DIRECTION = 'asc';
|
|
||||||
export const SORT_FIELD_VALUES = ['title', 'issued_at', 'created_at', 'updated_at'];
|
|
||||||
export const TAG_FILTER_UNTAGGED = '__UNTAGGED__';
|
|
||||||
|
|
||||||
const ROW_KEY_SEPARATOR = ':';
|
|
||||||
const DOCUMENT_ROW_PREFIX = 'document';
|
|
||||||
const FOLDER_ROW_PREFIX = 'folder';
|
|
||||||
|
|
||||||
export const resolveApiPath = (path = '') => path;
|
|
||||||
|
|
||||||
const makeRowKey = (type, id) =>
|
|
||||||
id ? `${type}${ROW_KEY_SEPARATOR}${id}` : `${type}${ROW_KEY_SEPARATOR}`;
|
|
||||||
|
|
||||||
const normalizeRowKey = (key: string | number | null) => String(key ?? '');
|
|
||||||
|
|
||||||
const getRowType = (key) => normalizeRowKey(key).split(ROW_KEY_SEPARATOR, 1)[0] ?? '';
|
|
||||||
|
|
||||||
export const getRowId = (key) => {
|
|
||||||
const normalized = normalizeRowKey(key);
|
|
||||||
const separatorIndex = normalized.indexOf(ROW_KEY_SEPARATOR);
|
|
||||||
if (separatorIndex === -1) return normalized;
|
|
||||||
return normalized.slice(separatorIndex + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isDocumentRowKey = (key) => getRowType(key) === DOCUMENT_ROW_PREFIX;
|
|
||||||
export const isFolderRowKey = (key) => getRowType(key) === FOLDER_ROW_PREFIX;
|
|
||||||
|
|
||||||
export const resolveDocumentRowKey = (documentId) =>
|
|
||||||
documentId ? makeRowKey(DOCUMENT_ROW_PREFIX, documentId) : null;
|
|
||||||
|
|
||||||
export const resolveFolderRowKey = (folderId) =>
|
|
||||||
folderId ? makeRowKey(FOLDER_ROW_PREFIX, folderId) : null;
|
|
||||||
|
|
||||||
export const hasFiles = (event) =>
|
|
||||||
Array.from(event.dataTransfer?.types || []).includes('Files');
|
|
||||||
|
|
||||||
const isAssetEquivalent = (lhs, rhs) => {
|
|
||||||
if (!lhs || !rhs) return false;
|
|
||||||
const lhsPrimaryMetadata = lhs?.metadata;
|
|
||||||
const rhsPrimaryMetadata = rhs?.metadata;
|
|
||||||
const lhsExpiresAt = resolveAssetExpiresAt(lhs);
|
|
||||||
const rhsExpiresAt = resolveAssetExpiresAt(rhs);
|
|
||||||
return (
|
|
||||||
lhs.id === rhs.id
|
|
||||||
&& resolveAssetUrl(lhs) === resolveAssetUrl(rhs)
|
|
||||||
&& lhsExpiresAt === rhsExpiresAt
|
|
||||||
&& lhsPrimaryMetadata?.width === rhsPrimaryMetadata?.width
|
|
||||||
&& lhsPrimaryMetadata?.height === rhsPrimaryMetadata?.height
|
|
||||||
&& lhs.mime_type === rhs.mime_type
|
|
||||||
&& lhs.asset_type === rhs.asset_type
|
|
||||||
&& lhs.updated_at === rhs.updated_at
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const mergeAssetIntoGroup = (group, assetData) => {
|
|
||||||
if (!assetData || !assetData.asset_type) {
|
|
||||||
if (Array.isArray(group)) {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
return group || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(group) || !group) {
|
|
||||||
const list = Array.isArray(group) ? group : [];
|
|
||||||
const index = list.findIndex((item) => item?.id === assetData.id);
|
|
||||||
if (index >= 0) {
|
|
||||||
const existing = list[index];
|
|
||||||
if (isAssetEquivalent(existing, assetData)) {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
const next = list.slice();
|
|
||||||
next[index] = { ...existing, ...assetData };
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
return list.concat({ ...assetData });
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = assetData.asset_type;
|
|
||||||
const previous = group?.[key];
|
|
||||||
if (previous && isAssetEquivalent(previous, assetData)) {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
const next = { ...(group || {}) };
|
|
||||||
next[key] = { ...(previous || {}), ...assetData };
|
|
||||||
return next;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mergeAssetIntoDocument = (doc, assetData) => {
|
|
||||||
if (!doc) return doc;
|
|
||||||
const existingGroup = doc.current_version?.assets || null;
|
|
||||||
const nextGroup = mergeAssetIntoGroup(existingGroup, assetData);
|
|
||||||
if (nextGroup === existingGroup) {
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
const updatedCurrentVersion = doc.current_version
|
|
||||||
? { ...doc.current_version, assets: nextGroup }
|
|
||||||
: { assets: nextGroup };
|
|
||||||
return { ...doc, current_version: updatedCurrentVersion };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createRootNode = () => ({
|
|
||||||
id: 'root',
|
|
||||||
name: DEFAULT_FOLDER_NAME,
|
|
||||||
parentId: null,
|
|
||||||
children: [],
|
|
||||||
expanded: true,
|
|
||||||
loaded: false,
|
|
||||||
hasChildren: false,
|
|
||||||
});
|
|
||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
DEFAULT_SORT_DIRECTION,
|
DEFAULT_SORT_DIRECTION,
|
||||||
DEFAULT_SORT_FIELD,
|
DEFAULT_SORT_FIELD,
|
||||||
SORT_FIELD_VALUES,
|
SORT_FIELD_VALUES,
|
||||||
} from './appLayoutUtils';
|
} from './workspaceUtils';
|
||||||
|
|
||||||
const VIEW_MODE_STORAGE_KEY = 'papercrate_view_mode';
|
const VIEW_MODE_STORAGE_KEY = 'papercrate_view_mode';
|
||||||
const SORT_FIELD_STORAGE_KEY = 'papercrate_sort_field';
|
const SORT_FIELD_STORAGE_KEY = 'papercrate_sort_field';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
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 './workspaceUtils';
|
||||||
import { listDocuments } from '../lib/apiClient';
|
import { listDocuments } from '../lib/apiClient';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type Identifier = string | number;
|
|||||||
type EnsureAssetUrl = (docId: Identifier, asset: unknown, options?: Record<string, unknown>) => Promise<unknown> | void;
|
type EnsureAssetUrl = (docId: Identifier, asset: unknown, options?: Record<string, unknown>) => Promise<unknown> | void;
|
||||||
type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
|
type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
|
||||||
type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
|
type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
|
||||||
type ResolveApiPath = (path: string) => string;
|
|
||||||
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
||||||
|
|
||||||
type WorkspaceSurface = { content: ReactNode; detail?: ReactNode | null } | null;
|
type WorkspaceSurface = { content: ReactNode; detail?: ReactNode | null } | null;
|
||||||
@@ -28,7 +27,6 @@ interface UseWorkspaceSurfaceArgs {
|
|||||||
ensureAssetUrl?: EnsureAssetUrl;
|
ensureAssetUrl?: EnsureAssetUrl;
|
||||||
ensurePreviewData?: EnsurePreviewData;
|
ensurePreviewData?: EnsurePreviewData;
|
||||||
getDocumentAsset?: GetDocumentAsset;
|
getDocumentAsset?: GetDocumentAsset;
|
||||||
resolveApiPath?: ResolveApiPath;
|
|
||||||
notifyApiError?: NotifyApiError;
|
notifyApiError?: NotifyApiError;
|
||||||
closeDocumentPreview?: () => void;
|
closeDocumentPreview?: () => void;
|
||||||
}
|
}
|
||||||
@@ -49,7 +47,6 @@ export const useWorkspaceSurface = ({
|
|||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
resolveApiPath,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
closeDocumentPreview,
|
closeDocumentPreview,
|
||||||
}: UseWorkspaceSurfaceArgs): UseWorkspaceSurfaceResult => {
|
}: UseWorkspaceSurfaceArgs): UseWorkspaceSurfaceResult => {
|
||||||
@@ -179,7 +176,6 @@ export const useWorkspaceSurface = ({
|
|||||||
ensureAssetUrl={ensureAssetUrl}
|
ensureAssetUrl={ensureAssetUrl}
|
||||||
getDocumentAsset={getDocumentAsset}
|
getDocumentAsset={getDocumentAsset}
|
||||||
ensurePreviewData={ensurePreviewData}
|
ensurePreviewData={ensurePreviewData}
|
||||||
resolveApiPath={resolveApiPath}
|
|
||||||
notifyApiError={notifyApiError}
|
notifyApiError={notifyApiError}
|
||||||
sidebarToggle={sidebarToggle}
|
sidebarToggle={sidebarToggle}
|
||||||
onClosePanel={closeDocumentPreview}
|
onClosePanel={closeDocumentPreview}
|
||||||
@@ -203,7 +199,6 @@ export const useWorkspaceSurface = ({
|
|||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
resolveApiPath,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
renderSidebarToggle,
|
renderSidebarToggle,
|
||||||
closeDocumentPreview,
|
closeDocumentPreview,
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
export const DEFAULT_FOLDER_NAME = 'Documents';
|
||||||
|
export const DEFAULT_SORT_FIELD = 'title';
|
||||||
|
export const DEFAULT_SORT_DIRECTION = 'asc';
|
||||||
|
export const SORT_FIELD_VALUES = ['title', 'issued_at', 'created_at', 'updated_at'];
|
||||||
|
export const TAG_FILTER_UNTAGGED = '__UNTAGGED__';
|
||||||
|
|
||||||
|
const ROW_KEY_SEPARATOR = ':';
|
||||||
|
const DOCUMENT_ROW_PREFIX = 'document';
|
||||||
|
const FOLDER_ROW_PREFIX = 'folder';
|
||||||
|
|
||||||
|
const makeRowKey = (type, id) =>
|
||||||
|
id ? `${type}${ROW_KEY_SEPARATOR}${id}` : `${type}${ROW_KEY_SEPARATOR}`;
|
||||||
|
|
||||||
|
const getRowType = (key: string | null) => (key ?? '').split(ROW_KEY_SEPARATOR, 1)[0] ?? '';
|
||||||
|
|
||||||
|
export const getRowId = (key: string) => {
|
||||||
|
const parts = key.split(ROW_KEY_SEPARATOR);
|
||||||
|
return parts.slice(1).join(ROW_KEY_SEPARATOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isDocumentRowKey = (key) => getRowType(key) === DOCUMENT_ROW_PREFIX;
|
||||||
|
export const isFolderRowKey = (key) => getRowType(key) === FOLDER_ROW_PREFIX;
|
||||||
|
|
||||||
|
export const resolveDocumentRowKey = (documentId) =>
|
||||||
|
documentId ? makeRowKey(DOCUMENT_ROW_PREFIX, documentId) : null;
|
||||||
|
|
||||||
|
export const resolveFolderRowKey = (folderId) =>
|
||||||
|
folderId ? makeRowKey(FOLDER_ROW_PREFIX, folderId) : null;
|
||||||
|
|
||||||
|
export const hasFiles = (event) =>
|
||||||
|
Array.from(event.dataTransfer?.types || []).includes('Files');
|
||||||
|
|
||||||
|
const mergeAssetIntoGroup = (group, assetData) => {
|
||||||
|
if (!assetData || !assetData.asset_type) {
|
||||||
|
return group || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = Array.isArray(group) ? group : [];
|
||||||
|
const index = list.findIndex((item) => item?.asset_type === assetData.asset_type);
|
||||||
|
if (index >= 0) {
|
||||||
|
const next = list.slice();
|
||||||
|
next[index] = assetData;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
return list.concat(assetData);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mergeAssetIntoDocument = (doc, assetData) => {
|
||||||
|
if (!doc) return doc;
|
||||||
|
const nextGroup = mergeAssetIntoGroup(doc.current_version?.assets, assetData);
|
||||||
|
return {
|
||||||
|
...doc,
|
||||||
|
current_version: { ...(doc.current_version || {}), assets: nextGroup },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createRootNode = () => ({
|
||||||
|
id: 'root',
|
||||||
|
name: DEFAULT_FOLDER_NAME,
|
||||||
|
parentId: null,
|
||||||
|
children: [],
|
||||||
|
expanded: true,
|
||||||
|
loaded: false,
|
||||||
|
hasChildren: false,
|
||||||
|
});
|
||||||
@@ -202,13 +202,12 @@ export const resolveDocumentAssetUrl = (
|
|||||||
|
|
||||||
class AssetManager {
|
class AssetManager {
|
||||||
fetchAsset: ((id: Identifier) => Promise<AssetLike | null>) | null;
|
fetchAsset: ((id: Identifier) => Promise<AssetLike | null>) | null;
|
||||||
assetPresignTtlMs: number;
|
|
||||||
assetCache: Map<Identifier, AssetLike>;
|
assetCache: Map<Identifier, AssetLike>;
|
||||||
assetInflight: Map<string, Promise<AssetLike | null>>;
|
assetInflight: Map<string, Promise<AssetLike | null>>;
|
||||||
|
|
||||||
constructor({ fetchAsset, assetPresignTtlMs }: { fetchAsset: ((id: Identifier) => Promise<AssetLike | null>) | null; assetPresignTtlMs: number }) {
|
constructor({ fetchAsset }: { fetchAsset: ((id: Identifier) => Promise<AssetLike | null>) | null }) {
|
||||||
this.fetchAsset = fetchAsset;
|
this.fetchAsset = fetchAsset;
|
||||||
this.assetPresignTtlMs = assetPresignTtlMs;
|
|
||||||
this.assetCache = new Map();
|
this.assetCache = new Map();
|
||||||
this.assetInflight = new Map();
|
this.assetInflight = new Map();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
DEFAULT_FOLDER_NAME,
|
DEFAULT_FOLDER_NAME,
|
||||||
getRowId,
|
getRowId,
|
||||||
isDocumentRowKey,
|
isDocumentRowKey,
|
||||||
} from '../app/appLayoutUtils';
|
} from '../app/workspaceUtils';
|
||||||
import type { DocumentInfoPanelProps } from '../documents/DocumentInfoPanel';
|
import type { DocumentInfoPanelProps } from '../documents/DocumentInfoPanel';
|
||||||
import type { EnsureAssetUrl, GetDocumentAsset } from '../utils/ocr';
|
import type { EnsureAssetUrl, GetDocumentAsset } from '../utils/ocr';
|
||||||
|
|
||||||
@@ -46,7 +46,6 @@ interface UseDetailWorkspaceArgs {
|
|||||||
correspondents?: unknown[];
|
correspondents?: unknown[];
|
||||||
handleCorrespondentAdd?: (...args: unknown[]) => void;
|
handleCorrespondentAdd?: (...args: unknown[]) => void;
|
||||||
handleCorrespondentRemove?: (...args: unknown[]) => void;
|
handleCorrespondentRemove?: (...args: unknown[]) => void;
|
||||||
resolveApiPath?: (path: string) => string;
|
|
||||||
selectFolder?: (folderId?: Identifier | 'root') => void;
|
selectFolder?: (folderId?: Identifier | 'root') => void;
|
||||||
tags?: unknown[];
|
tags?: unknown[];
|
||||||
tagLookupById?: Map<Identifier, unknown> | null;
|
tagLookupById?: Map<Identifier, unknown> | null;
|
||||||
@@ -86,7 +85,6 @@ const useDetailWorkspace = ({
|
|||||||
correspondents,
|
correspondents,
|
||||||
handleCorrespondentAdd,
|
handleCorrespondentAdd,
|
||||||
handleCorrespondentRemove,
|
handleCorrespondentRemove,
|
||||||
resolveApiPath,
|
|
||||||
selectFolder,
|
selectFolder,
|
||||||
tags,
|
tags,
|
||||||
tagLookupById,
|
tagLookupById,
|
||||||
@@ -281,7 +279,6 @@ const useDetailWorkspace = ({
|
|||||||
correspondents,
|
correspondents,
|
||||||
onCorrespondentAdd: handleCorrespondentAdd,
|
onCorrespondentAdd: handleCorrespondentAdd,
|
||||||
onCorrespondentRemove: handleCorrespondentRemove,
|
onCorrespondentRemove: handleCorrespondentRemove,
|
||||||
resolveApiPath,
|
|
||||||
onFolderNavigate: selectFolder,
|
onFolderNavigate: selectFolder,
|
||||||
onClose: handleDetailPanelClose,
|
onClose: handleDetailPanelClose,
|
||||||
resolveFolderPath,
|
resolveFolderPath,
|
||||||
@@ -304,7 +301,6 @@ const useDetailWorkspace = ({
|
|||||||
folderNodes,
|
folderNodes,
|
||||||
ensureFolderData,
|
ensureFolderData,
|
||||||
openDocumentPreview,
|
openDocumentPreview,
|
||||||
resolveApiPath,
|
|
||||||
resolveFolderPath,
|
resolveFolderPath,
|
||||||
selectFolder,
|
selectFolder,
|
||||||
tags,
|
tags,
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ import type {
|
|||||||
DocumentLike as OcrDocumentLike,
|
DocumentLike as OcrDocumentLike,
|
||||||
} from '../utils/ocr';
|
} from '../utils/ocr';
|
||||||
|
|
||||||
type ResolveApiPath = (path: string) => string;
|
|
||||||
|
|
||||||
export type DocumentLike = OcrDocumentLike;
|
export type DocumentLike = OcrDocumentLike;
|
||||||
|
|
||||||
const asyncFalse = async () => false;
|
const asyncFalse = async () => false;
|
||||||
|
|
||||||
const resolveDocumentDownloadHref = (document?: DocumentLike | null, resolveApiPath?: ResolveApiPath | null): string | null => {
|
const resolveDocumentDownloadHref = (document?: DocumentLike | null): string | null => {
|
||||||
if (!document) {
|
if (!document) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -20,7 +18,7 @@ const resolveDocumentDownloadHref = (document?: DocumentLike | null, resolveApiP
|
|||||||
if (!downloadUrl) {
|
if (!downloadUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return resolveApiPath ? resolveApiPath(downloadUrl) : downloadUrl;
|
return downloadUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasDocumentOcrAsset = (document?: DocumentLike | null, getDocumentAsset?: GetDocumentAsset | null): boolean => {
|
const hasDocumentOcrAsset = (document?: DocumentLike | null, getDocumentAsset?: GetDocumentAsset | null): boolean => {
|
||||||
@@ -32,7 +30,6 @@ const hasDocumentOcrAsset = (document?: DocumentLike | null, getDocumentAsset?:
|
|||||||
|
|
||||||
interface CreateDocumentActionStateArgs {
|
interface CreateDocumentActionStateArgs {
|
||||||
document: DocumentLike | null;
|
document: DocumentLike | null;
|
||||||
resolveApiPath?: ResolveApiPath | null;
|
|
||||||
ensurePreviewData: EnsurePreviewData;
|
ensurePreviewData: EnsurePreviewData;
|
||||||
ensureAssetUrl: EnsureAssetUrl;
|
ensureAssetUrl: EnsureAssetUrl;
|
||||||
getDocumentAsset?: GetDocumentAsset | null;
|
getDocumentAsset?: GetDocumentAsset | null;
|
||||||
@@ -42,7 +39,6 @@ interface CreateDocumentActionStateArgs {
|
|||||||
|
|
||||||
export const createDocumentActionState = ({
|
export const createDocumentActionState = ({
|
||||||
document,
|
document,
|
||||||
resolveApiPath,
|
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
@@ -57,7 +53,7 @@ export const createDocumentActionState = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadHref = resolveDocumentDownloadHref(document, resolveApiPath);
|
const downloadHref = resolveDocumentDownloadHref(document);
|
||||||
const hasOcr = hasDocumentOcrAsset(document, getDocumentAsset);
|
const hasOcr = hasDocumentOcrAsset(document, getDocumentAsset);
|
||||||
|
|
||||||
const openOcr = hasOcr
|
const openOcr = hasOcr
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { formatFileSize } from '../utils/format';
|
import { formatFileSize } from '../utils/format';
|
||||||
import { formatDateTime as defaultFormatDateTime } from '../utils/date';
|
import { formatDateTime as defaultFormatDateTime } from '../utils/date';
|
||||||
import { DEFAULT_FOLDER_NAME } from '../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME } from '../app/workspaceUtils';
|
||||||
|
|
||||||
interface DocumentPageMetadata {
|
interface DocumentPageMetadata {
|
||||||
page_count?: number | string | null;
|
page_count?: number | string | null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { createContext, useContext, useMemo, type ReactNode } from 'react';
|
import React, { createContext, useContext, useMemo, type ReactNode } from 'react';
|
||||||
import { DEFAULT_FOLDER_NAME } from '../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME } from '../app/workspaceUtils';
|
||||||
|
|
||||||
type FolderId = string | null;
|
type FolderId = string | null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||||
import { DEFAULT_FOLDER_NAME, getRowId, isDocumentRowKey } from '../../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME, getRowId, isDocumentRowKey } from '../../app/workspaceUtils';
|
||||||
import {
|
import {
|
||||||
addDocumentTags,
|
addDocumentTags,
|
||||||
createTag,
|
createTag,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useRef, useState } from 'react';
|
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/workspaceUtils';
|
||||||
import { fetchDocument } from '../../lib/apiClient';
|
import { fetchDocument } from '../../lib/apiClient';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import useDocumentsPanelProps from '../../documents/hooks/useDocumentsPanelProps
|
|||||||
import useDocumentPreview from '../../app/useDocumentPreview';
|
import useDocumentPreview from '../../app/useDocumentPreview';
|
||||||
import useSidebarProps from '../../sidebar/useSidebarProps';
|
import useSidebarProps from '../../sidebar/useSidebarProps';
|
||||||
import {
|
import {
|
||||||
ASSET_PRESIGN_TTL_MS,
|
|
||||||
DEFAULT_SORT_DIRECTION,
|
DEFAULT_SORT_DIRECTION,
|
||||||
DEFAULT_SORT_FIELD,
|
DEFAULT_SORT_FIELD,
|
||||||
createRootNode,
|
createRootNode,
|
||||||
@@ -37,10 +37,9 @@ import {
|
|||||||
isDocumentRowKey,
|
isDocumentRowKey,
|
||||||
isFolderRowKey,
|
isFolderRowKey,
|
||||||
mergeAssetIntoDocument,
|
mergeAssetIntoDocument,
|
||||||
resolveApiPath,
|
|
||||||
resolveDocumentRowKey,
|
resolveDocumentRowKey,
|
||||||
resolveFolderRowKey,
|
resolveFolderRowKey,
|
||||||
} from '../../app/appLayoutUtils';
|
} from '../../app/workspaceUtils';
|
||||||
import useDocumentsSearch from '../../app/useDocumentsSearch';
|
import useDocumentsSearch from '../../app/useDocumentsSearch';
|
||||||
import useDocumentsStore from './store/useDocumentsStore';
|
import useDocumentsStore from './store/useDocumentsStore';
|
||||||
import useAuthManager from './useAuthManager';
|
import useAuthManager from './useAuthManager';
|
||||||
@@ -222,7 +221,7 @@ const useDocumentsWorkspace = ({
|
|||||||
const asset = await fetchAsset(id);
|
const asset = await fetchAsset(id);
|
||||||
return (asset as unknown) as any;
|
return (asset as unknown) as any;
|
||||||
};
|
};
|
||||||
assetManagerRef.current = new AssetManager({ fetchAsset: fetcher, assetPresignTtlMs: ASSET_PRESIGN_TTL_MS });
|
assetManagerRef.current = new AssetManager({ fetchAsset: fetcher });
|
||||||
}
|
}
|
||||||
const assetManager = assetManagerRef.current;
|
const assetManager = assetManagerRef.current;
|
||||||
|
|
||||||
@@ -960,12 +959,6 @@ const useDocumentsWorkspace = ({
|
|||||||
[assetManager, updateDocumentCaches, notifyApiError],
|
[assetManager, updateDocumentCaches, notifyApiError],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleDocumentTagDrop = useCallback(
|
const handleDocumentTagDrop = useCallback(
|
||||||
async (documentId, tag) => {
|
async (documentId, tag) => {
|
||||||
if (!documentId || !tag?.id) {
|
if (!documentId || !tag?.id) {
|
||||||
@@ -1176,7 +1169,6 @@ const useDocumentsWorkspace = ({
|
|||||||
correspondents,
|
correspondents,
|
||||||
handleCorrespondentAdd,
|
handleCorrespondentAdd,
|
||||||
handleCorrespondentRemove,
|
handleCorrespondentRemove,
|
||||||
resolveApiPath,
|
|
||||||
selectFolder,
|
selectFolder,
|
||||||
tags,
|
tags,
|
||||||
tagLookupById,
|
tagLookupById,
|
||||||
@@ -1462,5 +1454,4 @@ const useDocumentsWorkspace = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default useDocumentsWorkspace;
|
export default useDocumentsWorkspace;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
isFolderRowKey,
|
isFolderRowKey,
|
||||||
resolveDocumentRowKey,
|
resolveDocumentRowKey,
|
||||||
resolveFolderRowKey,
|
resolveFolderRowKey,
|
||||||
} from '../../app/appLayoutUtils';
|
} from '../../app/workspaceUtils';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
type FolderId = Identifier | 'root';
|
type FolderId = Identifier | 'root';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import type { DragEvent } from 'react';
|
import type { DragEvent } from 'react';
|
||||||
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME, hasFiles } from '../../app/workspaceUtils';
|
||||||
import {
|
import {
|
||||||
createFolder,
|
createFolder,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo } from 'react';
|
||||||
import { DEFAULT_FOLDER_NAME } from '../../app/appLayoutUtils';
|
import { DEFAULT_FOLDER_NAME } from '../../app/workspaceUtils';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
type FolderId = Identifier | 'root';
|
type FolderId = Identifier | 'root';
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
|
|||||||
ensureAssetUrl?: (docId: string | number, asset: AssetLike, options?: { force?: boolean }) => Promise<unknown>;
|
ensureAssetUrl?: (docId: string | number, asset: AssetLike, options?: { force?: boolean }) => Promise<unknown>;
|
||||||
getDocumentAsset?: (doc: DocumentLike | null, type: string) => AssetLike | null;
|
getDocumentAsset?: (doc: DocumentLike | null, type: string) => AssetLike | null;
|
||||||
ensurePreviewData?: (docId: string | number, options?: { signal?: AbortSignal }) => Promise<DocumentLike | null>;
|
ensurePreviewData?: (docId: string | number, options?: { signal?: AbortSignal }) => Promise<DocumentLike | null>;
|
||||||
resolveApiPath?: (path: string) => string;
|
|
||||||
notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
|
notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
|
||||||
sidebarToggle?: ReactNode;
|
sidebarToggle?: ReactNode;
|
||||||
onClosePanel?: () => void;
|
onClosePanel?: () => void;
|
||||||
@@ -131,7 +130,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
resolveApiPath,
|
|
||||||
notifyApiError,
|
notifyApiError,
|
||||||
sidebarToggle = null,
|
sidebarToggle = null,
|
||||||
onClosePanel,
|
onClosePanel,
|
||||||
@@ -264,7 +262,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const downloadUrl = document.current_version?.download?.url;
|
const downloadUrl = document.current_version?.download?.url;
|
||||||
const href = resolveApiPath ? resolveApiPath(downloadUrl) : downloadUrl;
|
const href = downloadUrl;
|
||||||
if (!href) {
|
if (!href) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -275,7 +273,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
mimeType,
|
mimeType,
|
||||||
filename,
|
filename,
|
||||||
};
|
};
|
||||||
}, [document, resolveApiPath]);
|
}, [document]);
|
||||||
|
|
||||||
const handleZoomOpen = useCallback(() => {
|
const handleZoomOpen = useCallback(() => {
|
||||||
if (!resolvedDocumentLink?.url) {
|
if (!resolvedDocumentLink?.url) {
|
||||||
@@ -312,7 +310,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
document
|
document
|
||||||
? createDocumentActionState({
|
? createDocumentActionState({
|
||||||
document,
|
document,
|
||||||
resolveApiPath,
|
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
@@ -322,7 +319,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
|||||||
: null,
|
: null,
|
||||||
[
|
[
|
||||||
document,
|
document,
|
||||||
resolveApiPath,
|
|
||||||
ensurePreviewData,
|
ensurePreviewData,
|
||||||
ensureAssetUrl,
|
ensureAssetUrl,
|
||||||
getDocumentAsset,
|
getDocumentAsset,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { DragEvent } from 'react';
|
import type { DragEvent } from 'react';
|
||||||
import { TAG_FILTER_UNTAGGED } from '../app/appLayoutUtils';
|
import { TAG_FILTER_UNTAGGED } from '../app/workspaceUtils';
|
||||||
import type { StatusMessage } from '../hooks/documents/store/useDocumentsStore';
|
import type { StatusMessage } from '../hooks/documents/store/useDocumentsStore';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|||||||
Reference in New Issue
Block a user