refactor: introduce dedicated identifier types for improved clarity and type safety
This commit is contained in:
@@ -11,8 +11,7 @@ import { DocumentsHeaderBreadcrumb } from '../documents/panel/DocumentsPanelHead
|
||||
import { SidebarProvider, useSidebarContext } from '../sidebar/SidebarContext';
|
||||
import { PanelManagerProvider, usePanelManager } from './PanelManagerContext';
|
||||
import Sidebar from '../sidebar/Sidebar';
|
||||
|
||||
type Identifier = string | number;
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
|
||||
type EnsureAssetUrl = (
|
||||
docId: Identifier,
|
||||
|
||||
@@ -28,7 +28,7 @@ interface StatusMessage {
|
||||
}
|
||||
|
||||
interface TenantOption {
|
||||
id?: string | number | null;
|
||||
id?: string | null;
|
||||
name?: string | null;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ const LoginRoute: React.FC = () => {
|
||||
const payload: {
|
||||
magic_token: string;
|
||||
username?: string;
|
||||
preferred_tenant_id?: string | number;
|
||||
preferred_tenant_id?: string;
|
||||
} = {
|
||||
magic_token: magicToken,
|
||||
};
|
||||
@@ -520,14 +520,14 @@ const LoginRoute: React.FC = () => {
|
||||
onCancelSelection={handleCancelSelection}
|
||||
selectingTenantId={selectingTenantId}
|
||||
onPasskeyLogin={handlePasskeyLogin}
|
||||
passkeySupported={passkeySupported}
|
||||
passkeyLoading={passkeyLoading}
|
||||
onSignup={handleSignup}
|
||||
signupSupported={signupSupported}
|
||||
signupLoading={signupLoading}
|
||||
magicLoginPending={magicLoginPending}
|
||||
initialUsername={magicLoginParams.username || ''}
|
||||
/>
|
||||
passkeySupported={passkeySupported}
|
||||
passkeyLoading={passkeyLoading}
|
||||
onSignup={handleSignup}
|
||||
signupSupported={signupSupported}
|
||||
signupLoading={signupLoading}
|
||||
magicLoginPending={magicLoginPending}
|
||||
initialUsername={magicLoginParams.username || ''}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,12 +15,12 @@ import PanelHeader from '../ui/PanelHeader';
|
||||
type UploadStatus = 'pending' | 'uploading' | 'success' | 'duplicate' | 'error' | (string & {});
|
||||
|
||||
interface UploadQueueItem {
|
||||
id: string | number;
|
||||
id: string;
|
||||
name: string;
|
||||
status: UploadStatus;
|
||||
error?: string | null;
|
||||
document?: { id?: string | number; title?: string };
|
||||
conflictDocumentId?: string | number;
|
||||
document?: { id?: string; title?: string };
|
||||
conflictDocumentId?: string;
|
||||
}
|
||||
|
||||
interface UploadQueueOverlayProps {
|
||||
@@ -191,7 +191,7 @@ const UploadQueueOverlay = ({ queue = [], onClearQueue }: UploadQueueOverlayProp
|
||||
{item.error}
|
||||
</span>
|
||||
) : (
|
||||
<span>{meta.label}</span>
|
||||
<span>{meta.label}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { DocumentId, FolderId } from '../types/identifiers';
|
||||
|
||||
// Entry key utilities for workspace selection
|
||||
// Entry keys are strings in the format "document:id" or "folder:id"
|
||||
|
||||
const ENTRY_KEY_SEPARATOR = ':';
|
||||
|
||||
// Create entry key strings
|
||||
export const createDocumentEntryKey = (documentId: string | number): string =>
|
||||
export const createDocumentEntryKey = (documentId: DocumentId): string =>
|
||||
`document${ENTRY_KEY_SEPARATOR}${documentId}`;
|
||||
|
||||
export const createFolderEntryKey = (folderId: string | number): string =>
|
||||
export const createFolderEntryKey = (folderId: FolderId): string =>
|
||||
`folder${ENTRY_KEY_SEPARATOR}${folderId}`;
|
||||
|
||||
// Type guards for entry key strings
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
export interface DetailDocument {
|
||||
id?: string | number;
|
||||
id?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface UseDetailPanelOptions {
|
||||
documentLookup: Map<string | number, DetailDocument>;
|
||||
documentLookup: Map<string, DetailDocument>;
|
||||
orderedSelectedDocuments: DetailDocument[];
|
||||
}
|
||||
|
||||
interface OpenDetailPanelArgs {
|
||||
documentId?: string | number;
|
||||
documentId?: string;
|
||||
document?: DetailDocument | null;
|
||||
documentIds?: Array<string | number>;
|
||||
documentIds?: Array<string>;
|
||||
documents?: DetailDocument[];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export const useDetailPanel = ({
|
||||
orderedSelectedDocuments,
|
||||
}: UseDetailPanelOptions) => {
|
||||
const [detailPanelOpen, setDetailPanelOpen] = useState(false);
|
||||
const [detailPanelDocId, setDetailPanelDocId] = useState<string | number | null>(null);
|
||||
const [detailPanelDocId, setDetailPanelDocId] = useState<string | null>(null);
|
||||
const [detailPanelDocument, setDetailPanelDocument] = useState<DetailDocument | null>(null);
|
||||
const latestOrderedDocsRef = useRef<DetailDocument[]>([]);
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import type {
|
||||
SetStateAction,
|
||||
} from 'react';
|
||||
import { fetchDocument } from '../lib/apiClient';
|
||||
import type { DocumentId } from '../types/identifiers';
|
||||
|
||||
type DocumentId = string | number;
|
||||
type FolderId = DocumentId | 'root';
|
||||
|
||||
type DocumentLike = {
|
||||
@@ -102,7 +102,7 @@ const useDocumentPreview = ({
|
||||
async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise<DocumentLink | null> => {
|
||||
if (!documentId) return null;
|
||||
|
||||
const existing = documentLinks.get(documentId);
|
||||
const existing = documentLinks.get(documentId);
|
||||
const now = Date.now();
|
||||
const expiresAt = existing?.expiresAt ?? null;
|
||||
if (!force && existing && (!expiresAt || expiresAt > now)) {
|
||||
|
||||
@@ -6,8 +6,7 @@ import {
|
||||
isFolderEntry,
|
||||
getEntryId,
|
||||
} from './entryKey';
|
||||
|
||||
type DocumentId = string | number;
|
||||
import type { DocumentId } from '../types/identifiers';
|
||||
|
||||
interface SelectionEventLike {
|
||||
shiftKey?: boolean;
|
||||
@@ -21,7 +20,7 @@ interface UseDocumentSelectionOptions {
|
||||
}
|
||||
|
||||
interface ApplySelectionOptions {
|
||||
anchor?: string;
|
||||
anchor: string | null;
|
||||
interactedKeys?: string[];
|
||||
}
|
||||
|
||||
@@ -35,8 +34,8 @@ export const useDocumentSelection = ({
|
||||
const selectionOrderRef = useRef<string[]>(initialEntries);
|
||||
const selectionAnchorRef = useRef<string | null>(null);
|
||||
const selectionInitializedRef = useRef(false);
|
||||
const [focusedDocumentId, setFocusedDocumentId] = useState<DocumentId | undefined>(undefined);
|
||||
const [focusedRowKey, setFocusedRowKey] = useState<string | undefined>(undefined);
|
||||
const [focusedDocumentId, setFocusedDocumentId] = useState<DocumentId | null>(null);
|
||||
const [focusedRowKey, setFocusedRowKey] = useState<string | null>(null);
|
||||
|
||||
const visibleRowKeySetRef = useRef<Set<string>>(new Set());
|
||||
const navigableRowKeysRef = useRef<string[]>([]);
|
||||
@@ -90,7 +89,7 @@ export const useDocumentSelection = ({
|
||||
const applySelection = useCallback(
|
||||
(
|
||||
rowKeys: Array<string | null>,
|
||||
{ anchor, interactedKeys = [] }: ApplySelectionOptions = {},
|
||||
{ anchor = null, interactedKeys = [] }: ApplySelectionOptions = { anchor: null, interactedKeys: [] },
|
||||
) => {
|
||||
const visibleRowKeySet = visibleRowKeySetRef.current;
|
||||
const unique: string[] = [];
|
||||
@@ -117,7 +116,7 @@ export const useDocumentSelection = ({
|
||||
}
|
||||
});
|
||||
|
||||
let resolvedAnchor = anchor;
|
||||
let resolvedAnchor: string | null = anchor ?? null;
|
||||
if (resolvedAnchor && !unique.includes(resolvedAnchor)) {
|
||||
resolvedAnchor = null;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
import { TAG_FILTER_UNTAGGED } from './workspaceUtils';
|
||||
import { listDocuments } from '../lib/apiClient';
|
||||
|
||||
type Identifier = string | number;
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
|
||||
type DocumentLike = { id?: Identifier } & Record<string, unknown>;
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@ const TAGS_MODAL = 'tags';
|
||||
const CORRESPONDENTS_MODAL = 'correspondents';
|
||||
|
||||
interface TagRecord {
|
||||
id?: string | number;
|
||||
id?: string;
|
||||
label?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface CorrespondentRecord {
|
||||
id?: string | number;
|
||||
id?: string;
|
||||
name?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ interface SelectionEntry {
|
||||
}
|
||||
|
||||
interface WorkspaceSelectionOptions {
|
||||
onDocumentActivate?: (id: string | number) => void;
|
||||
onInspectFolder?: (id: string | number) => void;
|
||||
onDocumentActivate?: (id: string) => void;
|
||||
onInspectFolder?: (id: string) => void;
|
||||
}
|
||||
|
||||
const identity = <T,>(value: T) => value;
|
||||
@@ -71,7 +71,7 @@ export const useWorkspaceSelection = ({
|
||||
);
|
||||
|
||||
const inspectDocument = useCallback(
|
||||
(documentId?: string | number) => {
|
||||
(documentId?: string) => {
|
||||
if (!documentId) return;
|
||||
onDocumentActivate(documentId);
|
||||
},
|
||||
@@ -79,7 +79,7 @@ export const useWorkspaceSelection = ({
|
||||
);
|
||||
|
||||
const inspectFolder = useCallback(
|
||||
(folderId?: string | number) => {
|
||||
(folderId?: string) => {
|
||||
if (!folderId) return;
|
||||
onInspectFolder(folderId);
|
||||
},
|
||||
|
||||
@@ -5,8 +5,7 @@ import DocumentsPanel from '../documents/panel/DocumentsPanel';
|
||||
import DocumentViewerPanel from '../preview/DocumentViewerPanel';
|
||||
import { usePanelManager } from './PanelManagerContext';
|
||||
import { FolderManagerProvider } from '../folders/FolderManagerContext';
|
||||
|
||||
type Identifier = string | number;
|
||||
import type { Identifier } from '../types/identifiers';
|
||||
|
||||
type EnsureAssetUrl = (docId: Identifier, asset: unknown, options?: Record<string, unknown>) => Promise<unknown> | void;
|
||||
type EnsurePreviewData = (docId: Identifier, options?: Record<string, unknown>) => Promise<unknown>;
|
||||
|
||||
Reference in New Issue
Block a user