refactor: Standardize document and folder identification with a new entryKey module.
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 =>
|
||||||
|
`document${ENTRY_KEY_SEPARATOR}${documentId}`;
|
||||||
|
|
||||||
|
export const createFolderEntryKey = (folderId: string | number): string =>
|
||||||
|
`folder${ENTRY_KEY_SEPARATOR}${folderId}`;
|
||||||
|
|
||||||
|
// Type guards for entry key strings
|
||||||
|
export const isDocumentEntry = (key: string): boolean =>
|
||||||
|
key.split(ENTRY_KEY_SEPARATOR, 1)[0] === 'document';
|
||||||
|
|
||||||
|
export const isFolderEntry = (key: string): boolean =>
|
||||||
|
key.split(ENTRY_KEY_SEPARATOR, 1)[0] === 'folder';
|
||||||
|
|
||||||
|
// Extract ID from entry key string
|
||||||
|
export const getEntryId = (key: string): string => {
|
||||||
|
const parts = key.split(ENTRY_KEY_SEPARATOR);
|
||||||
|
return parts.slice(1).join(ENTRY_KEY_SEPARATOR);
|
||||||
|
};
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
import { useCallback, useRef, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
|
import {
|
||||||
|
createDocumentEntryKey,
|
||||||
|
createFolderEntryKey,
|
||||||
|
isDocumentEntry,
|
||||||
|
isFolderEntry,
|
||||||
|
getEntryId,
|
||||||
|
} from './entryKey';
|
||||||
|
|
||||||
type RowKey = string;
|
|
||||||
type DocumentId = string | number;
|
type DocumentId = string | number;
|
||||||
|
|
||||||
interface SelectionEventLike {
|
interface SelectionEventLike {
|
||||||
@@ -11,46 +17,36 @@ interface SelectionEventLike {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UseDocumentSelectionOptions {
|
interface UseDocumentSelectionOptions {
|
||||||
resolveDocumentRowKey: (id: DocumentId | null) => RowKey | null;
|
initialEntries?: string[];
|
||||||
resolveFolderRowKey: (id: DocumentId | null) => RowKey | null;
|
|
||||||
isDocumentRowKey: (key?: RowKey | null) => boolean;
|
|
||||||
isFolderRowKey: (key?: RowKey | null) => boolean;
|
|
||||||
getRowId: (key?: RowKey | null) => DocumentId | null;
|
|
||||||
initialEntries?: RowKey[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ApplySelectionOptions {
|
interface ApplySelectionOptions {
|
||||||
anchor?: RowKey | null;
|
anchor?: string;
|
||||||
interactedKeys?: RowKey[];
|
interactedKeys?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_INITIAL_ENTRIES: RowKey[] = [];
|
const DEFAULT_INITIAL_ENTRIES: string[] = [];
|
||||||
|
|
||||||
export const useDocumentSelection = ({
|
export const useDocumentSelection = ({
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
isDocumentRowKey,
|
|
||||||
isFolderRowKey,
|
|
||||||
getRowId,
|
|
||||||
initialEntries = DEFAULT_INITIAL_ENTRIES,
|
initialEntries = DEFAULT_INITIAL_ENTRIES,
|
||||||
}: UseDocumentSelectionOptions) => {
|
}: UseDocumentSelectionOptions = {}) => {
|
||||||
const [selectedEntries, setSelectedEntries] = useState<RowKey[]>(initialEntries);
|
const [selectedEntries, setSelectedEntries] = useState<string[]>(initialEntries);
|
||||||
const [selectionOrder, setSelectionOrder] = useState<RowKey[]>(initialEntries);
|
const [selectionOrder, setSelectionOrder] = useState<string[]>(initialEntries);
|
||||||
const selectionOrderRef = useRef<RowKey[]>(initialEntries);
|
const selectionOrderRef = useRef<string[]>(initialEntries);
|
||||||
const selectionAnchorRef = useRef<RowKey | null>(null);
|
const selectionAnchorRef = useRef<string | null>(null);
|
||||||
const selectionInitializedRef = useRef(false);
|
const selectionInitializedRef = useRef(false);
|
||||||
const [focusedDocumentId, setFocusedDocumentId] = useState<DocumentId | null>(null);
|
const [focusedDocumentId, setFocusedDocumentId] = useState<DocumentId | undefined>(undefined);
|
||||||
const [focusedRowKey, setFocusedRowKey] = useState<RowKey | null>(null);
|
const [focusedRowKey, setFocusedRowKey] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
const visibleRowKeySetRef = useRef<Set<RowKey>>(new Set());
|
const visibleRowKeySetRef = useRef<Set<string>>(new Set());
|
||||||
const navigableRowKeysRef = useRef<RowKey[]>([]);
|
const navigableRowKeysRef = useRef<string[]>([]);
|
||||||
|
|
||||||
const configureSelectionEnvironment = useCallback(({
|
const configureSelectionEnvironment = useCallback(({
|
||||||
visibleRowKeySet,
|
visibleRowKeySet,
|
||||||
navigableRowKeys,
|
navigableRowKeys,
|
||||||
}: {
|
}: {
|
||||||
visibleRowKeySet?: Set<RowKey>;
|
visibleRowKeySet?: Set<string>;
|
||||||
navigableRowKeys?: RowKey[];
|
navigableRowKeys?: string[];
|
||||||
}) => {
|
}) => {
|
||||||
if (visibleRowKeySet) {
|
if (visibleRowKeySet) {
|
||||||
visibleRowKeySetRef.current = visibleRowKeySet;
|
visibleRowKeySetRef.current = visibleRowKeySet;
|
||||||
@@ -60,7 +56,7 @@ export const useDocumentSelection = ({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const updateSelectionOrder = useCallback((nextSelection: RowKey[], interactedKeys: RowKey[] = []) => {
|
const updateSelectionOrder = useCallback((nextSelection: string[], interactedKeys: string[] = []) => {
|
||||||
const nextSet = new Set(nextSelection);
|
const nextSet = new Set(nextSelection);
|
||||||
const previousOrder = selectionOrderRef.current.filter((id) => nextSet.has(id));
|
const previousOrder = selectionOrderRef.current.filter((id) => nextSet.has(id));
|
||||||
const interacted = (interactedKeys || []).filter((id, index, array) => array.indexOf(id) === index);
|
const interacted = (interactedKeys || []).filter((id, index, array) => array.indexOf(id) === index);
|
||||||
@@ -93,23 +89,23 @@ export const useDocumentSelection = ({
|
|||||||
|
|
||||||
const applySelection = useCallback(
|
const applySelection = useCallback(
|
||||||
(
|
(
|
||||||
rowKeys: Array<RowKey | null>,
|
rowKeys: Array<string | null>,
|
||||||
{ anchor, interactedKeys = [] }: ApplySelectionOptions = {},
|
{ anchor, interactedKeys = [] }: ApplySelectionOptions = {},
|
||||||
) => {
|
) => {
|
||||||
const visibleRowKeySet = visibleRowKeySetRef.current;
|
const visibleRowKeySet = visibleRowKeySetRef.current;
|
||||||
const unique: RowKey[] = [];
|
const unique: string[] = [];
|
||||||
|
|
||||||
(rowKeys || []).forEach((key) => {
|
(rowKeys || []).forEach((key) => {
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
let canonicalKey: RowKey | null = null;
|
let canonicalKey: string | null = null;
|
||||||
if (visibleRowKeySet.has(key)) {
|
if (visibleRowKeySet.has(key)) {
|
||||||
canonicalKey = key;
|
canonicalKey = key;
|
||||||
} else if (isDocumentRowKey(key)) {
|
} else if (isDocumentEntry(key)) {
|
||||||
const id = getRowId(key);
|
const id = getEntryId(key);
|
||||||
canonicalKey = id ? resolveDocumentRowKey(id) : null;
|
canonicalKey = id ? createDocumentEntryKey(id) : null;
|
||||||
} else if (isFolderRowKey(key)) {
|
} else if (isFolderEntry(key)) {
|
||||||
const id = getRowId(key);
|
const id = getEntryId(key);
|
||||||
canonicalKey = id ? resolveFolderRowKey(id) : null;
|
canonicalKey = id ? createFolderEntryKey(id) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canonicalKey || !visibleRowKeySet.has(canonicalKey)) {
|
if (!canonicalKey || !visibleRowKeySet.has(canonicalKey)) {
|
||||||
@@ -131,18 +127,18 @@ export const useDocumentSelection = ({
|
|||||||
|
|
||||||
const nextFocusedDocumentId: DocumentId | null = (() => {
|
const nextFocusedDocumentId: DocumentId | null = (() => {
|
||||||
if (focusedDocumentId) {
|
if (focusedDocumentId) {
|
||||||
const focusKey = resolveDocumentRowKey(focusedDocumentId);
|
const focusKey = createDocumentEntryKey(focusedDocumentId);
|
||||||
if (focusKey && unique.includes(focusKey)) {
|
if (focusKey && unique.includes(focusKey)) {
|
||||||
return focusedDocumentId;
|
return focusedDocumentId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolvedAnchor && isDocumentRowKey(resolvedAnchor)) {
|
if (resolvedAnchor && isDocumentEntry(resolvedAnchor)) {
|
||||||
return getRowId(resolvedAnchor) ?? null;
|
return getEntryId(resolvedAnchor) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastDocKey = [...unique].reverse().find((key) => isDocumentRowKey(key)) ?? null;
|
const lastDocKey = [...unique].reverse().find((key) => isDocumentEntry(key)) ?? null;
|
||||||
return lastDocKey ? getRowId(lastDocKey) ?? null : null;
|
return lastDocKey ? getEntryId(lastDocKey) ?? null : null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
setFocusedDocumentId(nextFocusedDocumentId);
|
setFocusedDocumentId(nextFocusedDocumentId);
|
||||||
@@ -159,11 +155,6 @@ export const useDocumentSelection = ({
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
focusedDocumentId,
|
focusedDocumentId,
|
||||||
getRowId,
|
|
||||||
isDocumentRowKey,
|
|
||||||
isFolderRowKey,
|
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
updateSelectionOrder,
|
updateSelectionOrder,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -174,7 +165,7 @@ export const useDocumentSelection = ({
|
|||||||
}, [applySelection]);
|
}, [applySelection]);
|
||||||
|
|
||||||
const handleEntrySelection = useCallback(
|
const handleEntrySelection = useCallback(
|
||||||
(rowKey: RowKey | null, event?: SelectionEventLike) => {
|
(rowKey: string, event?: SelectionEventLike) => {
|
||||||
const visibleRowKeySet = visibleRowKeySetRef.current;
|
const visibleRowKeySet = visibleRowKeySetRef.current;
|
||||||
const navigableRowKeys = navigableRowKeysRef.current;
|
const navigableRowKeys = navigableRowKeysRef.current;
|
||||||
if (!rowKey || !visibleRowKeySet.has(rowKey)) {
|
if (!rowKey || !visibleRowKeySet.has(rowKey)) {
|
||||||
@@ -200,8 +191,8 @@ export const useDocumentSelection = ({
|
|||||||
anchorKey = rowKey;
|
anchorKey = rowKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nextKeys: RowKey[] = [];
|
let nextKeys: string[] = [];
|
||||||
let interactedKeys: RowKey[] = [];
|
let interactedKeys: string[] = [];
|
||||||
|
|
||||||
if (shiftKey && anchorKey) {
|
if (shiftKey && anchorKey) {
|
||||||
const anchorIndex = navigableRowKeys.indexOf(anchorKey);
|
const anchorIndex = navigableRowKeys.indexOf(anchorKey);
|
||||||
@@ -245,7 +236,7 @@ export const useDocumentSelection = ({
|
|||||||
const promoteSelectionOrder = useCallback(
|
const promoteSelectionOrder = useCallback(
|
||||||
(docId?: DocumentId | null) => {
|
(docId?: DocumentId | null) => {
|
||||||
if (!docId) return;
|
if (!docId) return;
|
||||||
const rowKey = resolveDocumentRowKey(docId);
|
const rowKey = createDocumentEntryKey(docId);
|
||||||
if (!rowKey) return;
|
if (!rowKey) return;
|
||||||
|
|
||||||
if (!selectedEntries.includes(rowKey)) {
|
if (!selectedEntries.includes(rowKey)) {
|
||||||
@@ -254,7 +245,7 @@ export const useDocumentSelection = ({
|
|||||||
|
|
||||||
updateSelectionOrder(selectedEntries, [rowKey]);
|
updateSelectionOrder(selectedEntries, [rowKey]);
|
||||||
},
|
},
|
||||||
[resolveDocumentRowKey, selectedEntries, updateSelectionOrder],
|
[selectedEntries, updateSelectionOrder],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useDocumentSelection } from './useDocumentSelection';
|
import { useDocumentSelection } from './useDocumentSelection';
|
||||||
|
import { isDocumentEntry, isFolderEntry, getEntryId } from './entryKey';
|
||||||
type RowKey = string;
|
|
||||||
|
|
||||||
interface SelectionEntry {
|
interface SelectionEntry {
|
||||||
rowKey?: RowKey;
|
entryKey?: string;
|
||||||
|
// Legacy field for compatibility
|
||||||
|
rowKey?: string;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkspaceSelectionOptions {
|
interface WorkspaceSelectionOptions {
|
||||||
resolveDocumentRowKey?: (id: string | number) => RowKey | null;
|
|
||||||
resolveFolderRowKey?: (id: string | number) => RowKey | null;
|
|
||||||
isDocumentRowKey?: (key: RowKey | SelectionEntry) => boolean;
|
|
||||||
isFolderRowKey?: (key: RowKey | SelectionEntry) => boolean;
|
|
||||||
getRowId?: (key: RowKey | SelectionEntry) => string | number | null;
|
|
||||||
onDocumentActivate?: (id: string | number) => void;
|
onDocumentActivate?: (id: string | number) => void;
|
||||||
onInspectFolder?: (id: string | number) => void;
|
onInspectFolder?: (id: string | number) => void;
|
||||||
}
|
}
|
||||||
@@ -21,21 +17,10 @@ interface WorkspaceSelectionOptions {
|
|||||||
const identity = <T,>(value: T) => value;
|
const identity = <T,>(value: T) => value;
|
||||||
|
|
||||||
export const useWorkspaceSelection = ({
|
export const useWorkspaceSelection = ({
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
isDocumentRowKey = () => false,
|
|
||||||
isFolderRowKey = () => false,
|
|
||||||
getRowId = () => null,
|
|
||||||
onDocumentActivate = identity,
|
onDocumentActivate = identity,
|
||||||
onInspectFolder = identity,
|
onInspectFolder = identity,
|
||||||
}: WorkspaceSelectionOptions = {}) => {
|
}: WorkspaceSelectionOptions = {}) => {
|
||||||
const selection = useDocumentSelection({
|
const selection = useDocumentSelection();
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
isDocumentRowKey,
|
|
||||||
isFolderRowKey,
|
|
||||||
getRowId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
selectedEntries,
|
selectedEntries,
|
||||||
@@ -59,26 +44,26 @@ export const useWorkspaceSelection = ({
|
|||||||
const selectedDocumentIds = useMemo(
|
const selectedDocumentIds = useMemo(
|
||||||
() =>
|
() =>
|
||||||
selectedEntries
|
selectedEntries
|
||||||
.filter((entry) => isDocumentRowKey(entry))
|
.filter((entry) => isDocumentEntry(entry))
|
||||||
.map((entry) => getRowId(entry))
|
.map((entry) => getEntryId(entry))
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
[selectedEntries, isDocumentRowKey, getRowId],
|
[selectedEntries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedFolderIds = useMemo(
|
const selectedFolderIds = useMemo(
|
||||||
() =>
|
() =>
|
||||||
selectedEntries
|
selectedEntries
|
||||||
.filter((entry) => isFolderRowKey(entry))
|
.filter((entry) => isFolderEntry(entry))
|
||||||
.map((entry) => getRowId(entry))
|
.map((entry) => getEntryId(entry))
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
[selectedEntries, isFolderRowKey, getRowId],
|
[selectedEntries],
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectEntry = useCallback(
|
const selectEntry = useCallback(
|
||||||
(entry: SelectionEntry | string | null, event?: unknown) => {
|
(entry: SelectionEntry | string, event?: unknown) => {
|
||||||
const rowKey = entry && Object(entry) === entry
|
const rowKey = entry && Object(entry) === entry
|
||||||
? (entry as SelectionEntry).rowKey ?? null
|
? (entry as SelectionEntry).rowKey ?? undefined
|
||||||
: (entry as string | null);
|
: (entry as string);
|
||||||
if (!rowKey) return;
|
if (!rowKey) return;
|
||||||
handleEntrySelection(rowKey, event);
|
handleEntrySelection(rowKey, event);
|
||||||
},
|
},
|
||||||
@@ -86,7 +71,7 @@ export const useWorkspaceSelection = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const inspectDocument = useCallback(
|
const inspectDocument = useCallback(
|
||||||
(documentId?: string | number | null) => {
|
(documentId?: string | number) => {
|
||||||
if (!documentId) return;
|
if (!documentId) return;
|
||||||
onDocumentActivate(documentId);
|
onDocumentActivate(documentId);
|
||||||
},
|
},
|
||||||
@@ -94,7 +79,7 @@ export const useWorkspaceSelection = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const inspectFolder = useCallback(
|
const inspectFolder = useCallback(
|
||||||
(folderId?: string | number | null) => {
|
(folderId?: string | number) => {
|
||||||
if (!folderId) return;
|
if (!folderId) return;
|
||||||
onInspectFolder(folderId);
|
onInspectFolder(folderId);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,29 +4,6 @@ export const DEFAULT_SORT_DIRECTION = 'asc';
|
|||||||
export const SORT_FIELD_VALUES = ['title', 'issued_at', 'created_at', 'updated_at'];
|
export const SORT_FIELD_VALUES = ['title', 'issued_at', 'created_at', 'updated_at'];
|
||||||
export const TAG_FILTER_UNTAGGED = '__UNTAGGED__';
|
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) =>
|
export const hasFiles = (event) =>
|
||||||
Array.from(event.dataTransfer?.types || []).includes('Files');
|
Array.from(event.dataTransfer?.types || []).includes('Files');
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ import { useCallback, useEffect, useMemo } from 'react';
|
|||||||
import type { MutableRefObject } from 'react';
|
import type { MutableRefObject } from 'react';
|
||||||
import { resolveDocumentAssetUrl } from '../asset_manager';
|
import { resolveDocumentAssetUrl } from '../asset_manager';
|
||||||
import { useDetailPanel } from '../app/useDetailPanel';
|
import { useDetailPanel } from '../app/useDetailPanel';
|
||||||
import {
|
import { DEFAULT_FOLDER_NAME } from '../app/workspaceUtils';
|
||||||
DEFAULT_FOLDER_NAME,
|
import { getEntryId, isDocumentEntry } from '../app/entryKey';
|
||||||
getRowId,
|
|
||||||
isDocumentRowKey,
|
|
||||||
} 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';
|
||||||
|
|
||||||
@@ -101,10 +98,10 @@ const useDetailWorkspace = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
selectionOrder.forEach((key) => {
|
selectionOrder.forEach((key) => {
|
||||||
if (!isDocumentRowKey(key)) {
|
if (!isDocumentEntry(key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const docId = getRowId(key);
|
const docId = getEntryId(key);
|
||||||
const doc = documentLookup.get(docId) || null;
|
const doc = documentLookup.get(docId) || null;
|
||||||
pushDoc(doc);
|
pushDoc(doc);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
|
import { createDocumentEntryKey, createFolderEntryKey, isFolderEntry } from '../../app/entryKey';
|
||||||
|
|
||||||
interface FolderEntry {
|
interface FolderEntry {
|
||||||
id: string | number;
|
id: string | number;
|
||||||
@@ -17,11 +18,9 @@ interface NavigableRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UseDocumentsSelectionOptions {
|
interface UseDocumentsSelectionOptions {
|
||||||
showingSearchResults: boolean;
|
showingSearchResults?: boolean;
|
||||||
currentSubfolders: FolderEntry[];
|
currentSubfolders?: FolderEntry[];
|
||||||
visibleDocuments: DocumentEntry[];
|
visibleDocuments?: DocumentEntry[];
|
||||||
resolveFolderRowKey: (id: string | number) => string | null;
|
|
||||||
resolveDocumentRowKey: (id: string | number) => string | null;
|
|
||||||
configureSelectionEnvironment: (config: { visibleRowKeySet: Set<string>; navigableRowKeys: string[] }) => void;
|
configureSelectionEnvironment: (config: { visibleRowKeySet: Set<string>; navigableRowKeys: string[] }) => void;
|
||||||
visibleRowKeySet: Set<string>;
|
visibleRowKeySet: Set<string>;
|
||||||
selectedEntries: string[];
|
selectedEntries: string[];
|
||||||
@@ -33,15 +32,12 @@ interface UseDocumentsSelectionOptions {
|
|||||||
focusedDocumentId: string | number | null;
|
focusedDocumentId: string | number | null;
|
||||||
setFocusedRowKey: (value: string | null | ((current: string | null) => string | null)) => void;
|
setFocusedRowKey: (value: string | null | ((current: string | null) => string | null)) => void;
|
||||||
focusedRowKey: string | null;
|
focusedRowKey: string | null;
|
||||||
isFolderRowKey: (key: string | null) => boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const useDocumentsSelection = ({
|
const useDocumentsSelection = ({
|
||||||
showingSearchResults,
|
showingSearchResults,
|
||||||
currentSubfolders,
|
currentSubfolders,
|
||||||
visibleDocuments,
|
visibleDocuments,
|
||||||
resolveFolderRowKey,
|
|
||||||
resolveDocumentRowKey,
|
|
||||||
configureSelectionEnvironment,
|
configureSelectionEnvironment,
|
||||||
visibleRowKeySet,
|
visibleRowKeySet,
|
||||||
selectedEntries,
|
selectedEntries,
|
||||||
@@ -53,26 +49,25 @@ const useDocumentsSelection = ({
|
|||||||
focusedDocumentId,
|
focusedDocumentId,
|
||||||
setFocusedRowKey,
|
setFocusedRowKey,
|
||||||
focusedRowKey,
|
focusedRowKey,
|
||||||
isFolderRowKey,
|
|
||||||
}: UseDocumentsSelectionOptions) => {
|
}: UseDocumentsSelectionOptions) => {
|
||||||
const navigableRows = useMemo<NavigableRow[]>(() => {
|
const navigableRows = useMemo<NavigableRow[]>(() => {
|
||||||
const entries: NavigableRow[] = [];
|
const entries: NavigableRow[] = [];
|
||||||
if (!showingSearchResults) {
|
if (!showingSearchResults) {
|
||||||
currentSubfolders.forEach((folder) => {
|
currentSubfolders.forEach((folder) => {
|
||||||
const key = resolveFolderRowKey(folder.id);
|
const key = createFolderEntryKey(folder.id);
|
||||||
if (key) {
|
if (key) {
|
||||||
entries.push({ key, type: 'folder', id: folder.id });
|
entries.push({ key, type: 'folder', id: folder.id });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
visibleDocuments.forEach((doc) => {
|
visibleDocuments.forEach((doc) => {
|
||||||
const key = resolveDocumentRowKey(doc.id);
|
const key = createDocumentEntryKey(doc.id);
|
||||||
if (key) {
|
if (key) {
|
||||||
entries.push({ key, type: 'document', id: doc.id });
|
entries.push({ key, type: 'document', id: doc.id });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return entries;
|
return entries;
|
||||||
}, [showingSearchResults, currentSubfolders, visibleDocuments, resolveFolderRowKey, resolveDocumentRowKey]);
|
}, [showingSearchResults, currentSubfolders, visibleDocuments]);
|
||||||
|
|
||||||
const navigableRowKeys = useMemo(
|
const navigableRowKeys = useMemo(
|
||||||
() => navigableRows.map((entry) => entry.key),
|
() => navigableRows.map((entry) => entry.key),
|
||||||
@@ -90,14 +85,14 @@ const useDocumentsSelection = ({
|
|||||||
(docId: string | number | null) => {
|
(docId: string | number | null) => {
|
||||||
if (!docId) return;
|
if (!docId) return;
|
||||||
promoteSelectionOrderRaw(docId);
|
promoteSelectionOrderRaw(docId);
|
||||||
const rowKey = resolveDocumentRowKey(docId);
|
const rowKey = createDocumentEntryKey(docId);
|
||||||
if (rowKey) {
|
if (rowKey) {
|
||||||
selectionAnchorRef.current = rowKey;
|
selectionAnchorRef.current = rowKey;
|
||||||
}
|
}
|
||||||
setFocusedDocumentId(docId);
|
setFocusedDocumentId(docId);
|
||||||
setActivePreviewId(docId);
|
setActivePreviewId(docId);
|
||||||
},
|
},
|
||||||
[promoteSelectionOrderRaw, resolveDocumentRowKey, selectionAnchorRef, setFocusedDocumentId, setActivePreviewId],
|
[promoteSelectionOrderRaw, selectionAnchorRef, setFocusedDocumentId, setActivePreviewId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const clearDocumentSelection = useCallback(() => {
|
const clearDocumentSelection = useCallback(() => {
|
||||||
@@ -112,11 +107,11 @@ const useDocumentsSelection = ({
|
|||||||
}
|
}
|
||||||
prevFocusedDocIdRef.current = focusedDocumentId;
|
prevFocusedDocIdRef.current = focusedDocumentId;
|
||||||
if (focusedDocumentId) {
|
if (focusedDocumentId) {
|
||||||
setFocusedRowKey(resolveDocumentRowKey(focusedDocumentId));
|
setFocusedRowKey(createDocumentEntryKey(focusedDocumentId));
|
||||||
} else {
|
} else {
|
||||||
setFocusedRowKey((current) => (isFolderRowKey(current) ? current : null));
|
setFocusedRowKey((current) => (isFolderEntry(current) ? current : null));
|
||||||
}
|
}
|
||||||
}, [focusedDocumentId, resolveDocumentRowKey, setFocusedRowKey, isFolderRowKey]);
|
}, [focusedDocumentId, setFocusedRowKey]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!navigableRowKeys.length) {
|
if (!navigableRowKeys.length) {
|
||||||
@@ -130,7 +125,7 @@ const useDocumentsSelection = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const docKey = focusedDocumentId ? resolveDocumentRowKey(focusedDocumentId) : null;
|
const docKey = focusedDocumentId ? createDocumentEntryKey(focusedDocumentId) : null;
|
||||||
if (docKey && navigableRowKeys.includes(docKey)) {
|
if (docKey && navigableRowKeys.includes(docKey)) {
|
||||||
setFocusedRowKey(docKey);
|
setFocusedRowKey(docKey);
|
||||||
return;
|
return;
|
||||||
@@ -145,7 +140,7 @@ const useDocumentsSelection = ({
|
|||||||
if (focusedRowKey) {
|
if (focusedRowKey) {
|
||||||
setFocusedRowKey(null);
|
setFocusedRowKey(null);
|
||||||
}
|
}
|
||||||
}, [focusedRowKey, focusedDocumentId, navigableRowKeys, selectedEntries, setFocusedRowKey, resolveDocumentRowKey]);
|
}, [focusedRowKey, focusedDocumentId, navigableRowKeys, selectedEntries, setFocusedRowKey]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
navigableRows,
|
navigableRows,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { createDocumentEntryKey, createFolderEntryKey } from '../app/entryKey';
|
||||||
|
|
||||||
export type PointerEventLike = MouseEvent | PointerEvent;
|
export type PointerEventLike = MouseEvent | PointerEvent;
|
||||||
|
|
||||||
@@ -26,8 +27,6 @@ export interface WorkspaceEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UseEntryPointerOptions {
|
interface UseEntryPointerOptions {
|
||||||
resolveDocumentRowKey?: (id: string | number) => string | null;
|
|
||||||
resolveFolderRowKey?: (id: string | number) => string | null;
|
|
||||||
onSelectEntry?: (entry: WorkspaceEntry, event?: PointerEventLike | null, metadata?: EntryPointerMetadata) => void;
|
onSelectEntry?: (entry: WorkspaceEntry, event?: PointerEventLike | null, metadata?: EntryPointerMetadata) => void;
|
||||||
onDocumentActivate?: (id: string | number, metadata?: EntryPointerMetadata) => void;
|
onDocumentActivate?: (id: string | number, metadata?: EntryPointerMetadata) => void;
|
||||||
}
|
}
|
||||||
@@ -41,8 +40,6 @@ export interface EntryPointerMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useEntryPointer = ({
|
export const useEntryPointer = ({
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
onSelectEntry,
|
onSelectEntry,
|
||||||
onDocumentActivate,
|
onDocumentActivate,
|
||||||
}: UseEntryPointerOptions) =>
|
}: UseEntryPointerOptions) =>
|
||||||
@@ -58,7 +55,7 @@ export const useEntryPointer = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rowKey = entry.key
|
const rowKey = entry.key
|
||||||
|| (type === 'document' ? resolveDocumentRowKey?.(id) : resolveFolderRowKey?.(id));
|
|| (type === 'document' ? createDocumentEntryKey(id) : createFolderEntryKey(id));
|
||||||
if (!rowKey) {
|
if (!rowKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -73,7 +70,7 @@ export const useEntryPointer = ({
|
|||||||
onDocumentActivate?.(id, metadata);
|
onDocumentActivate?.(id, metadata);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[resolveDocumentRowKey, resolveFolderRowKey, onSelectEntry, onDocumentActivate],
|
[onSelectEntry, onDocumentActivate],
|
||||||
);
|
);
|
||||||
|
|
||||||
export default useEntryPointer;
|
export default useEntryPointer;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||||
import type { DragEvent } from 'react';
|
import type { DragEvent } from 'react';
|
||||||
|
import { createDocumentEntryKey, createFolderEntryKey } from '../../app/entryKey';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
type FolderIdentifier = string | 'root';
|
type FolderIdentifier = string | 'root';
|
||||||
@@ -30,8 +31,6 @@ interface UseDocumentDragHandlersOptions {
|
|||||||
documentLookup: Map<Identifier, DocumentLike>;
|
documentLookup: Map<Identifier, DocumentLike>;
|
||||||
setDraggedDocumentIds: (ids: Identifier[] | []) => void;
|
setDraggedDocumentIds: (ids: Identifier[] | []) => void;
|
||||||
setDraggedFolderId: (id: FolderIdentifier | null) => void;
|
setDraggedFolderId: (id: FolderIdentifier | null) => void;
|
||||||
resolveDocumentRowKey: (id: Identifier) => string | null;
|
|
||||||
resolveFolderRowKey: (id: FolderIdentifier) => string | null;
|
|
||||||
documentsViewMode: string;
|
documentsViewMode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +43,6 @@ const useDocumentDragHandlers = ({
|
|||||||
documentLookup,
|
documentLookup,
|
||||||
setDraggedDocumentIds,
|
setDraggedDocumentIds,
|
||||||
setDraggedFolderId,
|
setDraggedFolderId,
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
documentsViewMode,
|
documentsViewMode,
|
||||||
}: UseDocumentDragHandlersOptions) => {
|
}: UseDocumentDragHandlersOptions) => {
|
||||||
const dragPreviewRef = useRef<HTMLDivElement | null>(null);
|
const dragPreviewRef = useRef<HTMLDivElement | null>(null);
|
||||||
@@ -213,7 +210,7 @@ const useDocumentDragHandlers = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const documentKey = resolveDocumentRowKey(documentId);
|
const documentKey = createDocumentEntryKey(documentId);
|
||||||
if (!documentKey) {
|
if (!documentKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -279,7 +276,6 @@ const useDocumentDragHandlers = ({
|
|||||||
setDraggedFolderId,
|
setDraggedFolderId,
|
||||||
setDraggedDocumentIds,
|
setDraggedDocumentIds,
|
||||||
documentsViewMode,
|
documentsViewMode,
|
||||||
resolveDocumentRowKey,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -300,7 +296,7 @@ const useDocumentDragHandlers = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const folderKey = resolveFolderRowKey(normalizedFolderId);
|
const folderKey = createFolderEntryKey(normalizedFolderId);
|
||||||
const isAlreadySelected = folderKey ? selectedEntries.includes(folderKey) : false;
|
const isAlreadySelected = folderKey ? selectedEntries.includes(folderKey) : false;
|
||||||
|
|
||||||
let effectiveFolderSelection: FolderIdentifier[] = normalizedFolderIds;
|
let effectiveFolderSelection: FolderIdentifier[] = normalizedFolderIds;
|
||||||
@@ -309,7 +305,7 @@ const useDocumentDragHandlers = ({
|
|||||||
if (!isAlreadySelected && folderKey) {
|
if (!isAlreadySelected && folderKey) {
|
||||||
effectiveFolderSelection = [normalizedFolderId];
|
effectiveFolderSelection = [normalizedFolderId];
|
||||||
effectiveDocumentSelection = [];
|
effectiveDocumentSelection = [];
|
||||||
handleEntrySelection(folderKey, { preventDefault: () => {} });
|
handleEntrySelection(folderKey, { preventDefault: () => { } });
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniqueFolders = effectiveFolderSelection.length
|
const uniqueFolders = effectiveFolderSelection.length
|
||||||
@@ -363,7 +359,6 @@ const useDocumentDragHandlers = ({
|
|||||||
setDraggedDocumentIds,
|
setDraggedDocumentIds,
|
||||||
documentLookup,
|
documentLookup,
|
||||||
createDragPreview,
|
createDragPreview,
|
||||||
resolveFolderRowKey,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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/workspaceUtils';
|
import { DEFAULT_FOLDER_NAME } from '../../app/workspaceUtils';
|
||||||
|
import { getEntryId, isDocumentEntry } from '../../app/entryKey';
|
||||||
import {
|
import {
|
||||||
addDocumentTags,
|
addDocumentTags,
|
||||||
createTag,
|
createTag,
|
||||||
@@ -275,10 +275,10 @@ const useDocumentMutations = ({
|
|||||||
|
|
||||||
const pruneRow = (collection: string[]): string[] =>
|
const pruneRow = (collection: string[]): string[] =>
|
||||||
collection.filter((key) => {
|
collection.filter((key) => {
|
||||||
if (!isDocumentRowKey(key)) {
|
if (!isDocumentEntry(key)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const id = getRowId(key);
|
const id = getEntryId(key);
|
||||||
return id ? !uniqueIdSet.has(id as DocumentId) : true;
|
return id ? !uniqueIdSet.has(id as DocumentId) : true;
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
@@ -348,8 +348,8 @@ const useDocumentMutations = ({
|
|||||||
selectionOrderRef.current = nextSelectionOrder;
|
selectionOrderRef.current = nextSelectionOrder;
|
||||||
if (
|
if (
|
||||||
selectionAnchorRef.current &&
|
selectionAnchorRef.current &&
|
||||||
isDocumentRowKey(selectionAnchorRef.current) &&
|
isDocumentEntry(selectionAnchorRef.current) &&
|
||||||
uniqueIdSet.has(getRowId(selectionAnchorRef.current) as DocumentId)
|
uniqueIdSet.has(getEntryId(selectionAnchorRef.current) as DocumentId)
|
||||||
) {
|
) {
|
||||||
selectionAnchorRef.current = null;
|
selectionAnchorRef.current = null;
|
||||||
}
|
}
|
||||||
@@ -358,8 +358,8 @@ const useDocumentMutations = ({
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
focusedRowKey &&
|
focusedRowKey &&
|
||||||
isDocumentRowKey(focusedRowKey) &&
|
isDocumentEntry(focusedRowKey) &&
|
||||||
uniqueIdSet.has(getRowId(focusedRowKey) as DocumentId)
|
uniqueIdSet.has(getEntryId(focusedRowKey) as DocumentId)
|
||||||
) {
|
) {
|
||||||
setFocusedRowKey(null);
|
setFocusedRowKey(null);
|
||||||
}
|
}
|
||||||
@@ -617,7 +617,7 @@ const useDocumentMutations = ({
|
|||||||
if (!source || source.id == null) {
|
if (!source || source.id == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const labelText = `${source.label ?? ''}`.trim();
|
const labelText = `${source.label ?? ''} `.trim();
|
||||||
if (!labelText) {
|
if (!labelText) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,17 +29,12 @@ 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 {
|
||||||
|
|
||||||
DEFAULT_SORT_DIRECTION,
|
DEFAULT_SORT_DIRECTION,
|
||||||
DEFAULT_SORT_FIELD,
|
DEFAULT_SORT_FIELD,
|
||||||
createRootNode,
|
createRootNode,
|
||||||
getRowId,
|
|
||||||
isDocumentRowKey,
|
|
||||||
isFolderRowKey,
|
|
||||||
mergeAssetIntoDocument,
|
mergeAssetIntoDocument,
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
} from '../../app/workspaceUtils';
|
} from '../../app/workspaceUtils';
|
||||||
|
import { createDocumentEntryKey, createFolderEntryKey } from '../../app/entryKey';
|
||||||
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';
|
||||||
@@ -252,13 +247,7 @@ const useDocumentsWorkspace = ({
|
|||||||
}
|
}
|
||||||
const tagManager = tagManagerRef.current;
|
const tagManager = tagManagerRef.current;
|
||||||
|
|
||||||
const selection = useWorkspaceSelection({
|
const selection = useWorkspaceSelection();
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
isDocumentRowKey,
|
|
||||||
isFolderRowKey,
|
|
||||||
getRowId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
selectedEntries,
|
selectedEntries,
|
||||||
@@ -415,7 +404,7 @@ const useDocumentsWorkspace = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const visibleDocumentKeys = useMemo(
|
const visibleDocumentKeys = useMemo(
|
||||||
() => visibleDocumentIds.map((id) => resolveDocumentRowKey(id)).filter(Boolean),
|
() => visibleDocumentIds.map((id) => createDocumentEntryKey(id)).filter(Boolean),
|
||||||
[visibleDocumentIds],
|
[visibleDocumentIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -424,7 +413,7 @@ const useDocumentsWorkspace = ({
|
|||||||
showingSearchResults
|
showingSearchResults
|
||||||
? []
|
? []
|
||||||
: currentSubfolders
|
: currentSubfolders
|
||||||
.map((folder) => resolveFolderRowKey(folder.id))
|
.map((folder) => createFolderEntryKey(folder.id))
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
[showingSearchResults, currentSubfolders],
|
[showingSearchResults, currentSubfolders],
|
||||||
);
|
);
|
||||||
@@ -599,8 +588,6 @@ const useDocumentsWorkspace = ({
|
|||||||
documentLookup,
|
documentLookup,
|
||||||
setDraggedDocumentIds,
|
setDraggedDocumentIds,
|
||||||
setDraggedFolderId,
|
setDraggedFolderId,
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
documentsViewMode,
|
documentsViewMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -827,8 +814,6 @@ const useDocumentsWorkspace = ({
|
|||||||
showingSearchResults,
|
showingSearchResults,
|
||||||
currentSubfolders,
|
currentSubfolders,
|
||||||
visibleDocuments: viewDocuments,
|
visibleDocuments: viewDocuments,
|
||||||
resolveFolderRowKey,
|
|
||||||
resolveDocumentRowKey,
|
|
||||||
configureSelectionEnvironment,
|
configureSelectionEnvironment,
|
||||||
visibleRowKeySet,
|
visibleRowKeySet,
|
||||||
selectedEntries,
|
selectedEntries,
|
||||||
@@ -840,7 +825,6 @@ const useDocumentsWorkspace = ({
|
|||||||
focusedDocumentId,
|
focusedDocumentId,
|
||||||
setFocusedRowKey,
|
setFocusedRowKey,
|
||||||
focusedRowKey,
|
focusedRowKey,
|
||||||
isFolderRowKey,
|
|
||||||
});
|
});
|
||||||
const initializeAfterLogin = useCallback(async () => {
|
const initializeAfterLogin = useCallback(async () => {
|
||||||
await Promise.all([refreshTags(), refreshCorrespondents()]);
|
await Promise.all([refreshTags(), refreshCorrespondents()]);
|
||||||
@@ -1191,12 +1175,10 @@ const useDocumentsWorkspace = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleEntryPointerCore = useEntryPointerCore({
|
const handleEntryPointerCore = useEntryPointerCore({
|
||||||
resolveDocumentRowKey,
|
|
||||||
resolveFolderRowKey,
|
|
||||||
onSelectEntry: (entry, event, { rowKey, modifierClick, primaryClick }) => {
|
onSelectEntry: (entry, event, { rowKey, modifierClick, primaryClick }) => {
|
||||||
const { type, id } = entry;
|
const { type, id } = entry;
|
||||||
const key = rowKey
|
const key = rowKey
|
||||||
|| (type === EntryType.document ? resolveDocumentRowKey(id) : resolveFolderRowKey(id));
|
|| (type === EntryType.document ? createDocumentEntryKey(id) : createFolderEntryKey(id));
|
||||||
if (key) {
|
if (key) {
|
||||||
handleEntrySelection(key, event);
|
handleEntrySelection(key, event);
|
||||||
}
|
}
|
||||||
@@ -1238,7 +1220,6 @@ const useDocumentsWorkspace = ({
|
|||||||
selectedEntries,
|
selectedEntries,
|
||||||
selectionAnchorRef,
|
selectionAnchorRef,
|
||||||
applySelection,
|
applySelection,
|
||||||
resolveDocumentRowKey,
|
|
||||||
showingSearchResults,
|
showingSearchResults,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
activeTagFilters,
|
activeTagFilters,
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
import type { Dispatch, MutableRefObject, SetStateAction } from 'react';
|
||||||
|
import { createRootNode, DEFAULT_FOLDER_NAME } from '../../app/workspaceUtils';
|
||||||
import {
|
import {
|
||||||
DEFAULT_FOLDER_NAME,
|
getEntryId,
|
||||||
createRootNode,
|
isDocumentEntry,
|
||||||
getRowId,
|
isFolderEntry,
|
||||||
isDocumentRowKey,
|
createDocumentEntryKey,
|
||||||
isFolderRowKey,
|
createFolderEntryKey,
|
||||||
resolveDocumentRowKey,
|
} from '../../app/entryKey';
|
||||||
resolveFolderRowKey,
|
|
||||||
} from '../../app/workspaceUtils';
|
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
type FolderId = Identifier | 'root';
|
type FolderId = Identifier | 'root';
|
||||||
@@ -118,12 +117,12 @@ const useFolderTree = ({
|
|||||||
setCurrentFolder(folderInfo);
|
setCurrentFolder(folderInfo);
|
||||||
|
|
||||||
const availableDocKeys = docs
|
const availableDocKeys = docs
|
||||||
.map((doc) => resolveDocumentRowKey(doc?.id as Identifier))
|
.map((doc) => createDocumentEntryKey(doc?.id as Identifier))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const availableDocKeySet = new Set(availableDocKeys);
|
const availableDocKeySet = new Set(availableDocKeys);
|
||||||
const availableFolderKeys = new Set(
|
const availableFolderKeys = new Set(
|
||||||
subfolders
|
subfolders
|
||||||
.map((folder) => resolveFolderRowKey(folder?.id as Identifier))
|
.map((folder) => createFolderEntryKey(folder?.id as Identifier))
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -132,22 +131,22 @@ const useFolderTree = ({
|
|||||||
|
|
||||||
setSelectedEntries((previous) => {
|
setSelectedEntries((previous) => {
|
||||||
const previousFolderKeys = previous
|
const previousFolderKeys = previous
|
||||||
.filter(isFolderRowKey)
|
.filter(isFolderEntry)
|
||||||
.filter((key) => availableFolderKeys.has(key));
|
.filter((key) => availableFolderKeys.has(key));
|
||||||
const previousDocKeys = previous.filter(isDocumentRowKey);
|
const previousDocKeys = previous.filter(isDocumentEntry);
|
||||||
nextDocKeys = previousDocKeys.filter((key) => availableDocKeySet.has(key));
|
nextDocKeys = previousDocKeys.filter((key) => availableDocKeySet.has(key));
|
||||||
mergedSelection = [...previousFolderKeys, ...nextDocKeys];
|
mergedSelection = [...previousFolderKeys, ...nextDocKeys];
|
||||||
return mergedSelection;
|
return mergedSelection;
|
||||||
});
|
});
|
||||||
|
|
||||||
const nextFocus = (() => {
|
const nextFocus = (() => {
|
||||||
const currentFocusedKey = resolveDocumentRowKey(focusedDocumentId);
|
const currentFocusedKey = createDocumentEntryKey(focusedDocumentId);
|
||||||
if (currentFocusedKey && availableDocKeySet.has(currentFocusedKey)) {
|
if (currentFocusedKey && availableDocKeySet.has(currentFocusedKey)) {
|
||||||
return focusedDocumentId;
|
return focusedDocumentId;
|
||||||
}
|
}
|
||||||
if (nextDocKeys.length) {
|
if (nextDocKeys.length) {
|
||||||
const lastDocKey = nextDocKeys[nextDocKeys.length - 1];
|
const lastDocKey = nextDocKeys[nextDocKeys.length - 1];
|
||||||
return getRowId(lastDocKey) || null;
|
return getEntryId(lastDocKey) || null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import type { MutableRefObject } from 'react';
|
import type { MutableRefObject } from 'react';
|
||||||
|
import { createDocumentEntryKey } from '../../app/entryKey';
|
||||||
|
|
||||||
type Identifier = string | number;
|
type Identifier = string | number;
|
||||||
|
|
||||||
|
interface ApplySelectionFn {
|
||||||
|
(keys: string[], options?: { anchor?: string | null; interactedKeys?: string[] }): unknown;
|
||||||
|
}
|
||||||
|
|
||||||
interface UseWorkspaceDeskPropsArgs {
|
interface UseWorkspaceDeskPropsArgs {
|
||||||
viewDocuments: any[];
|
viewDocuments: unknown[];
|
||||||
inspectDocumentForDesk: (doc: any) => void;
|
inspectDocumentForDesk?: (id: Identifier | null) => void;
|
||||||
handleEntryPointer: (params: { rowKey?: string | null; id?: Identifier | null; type?: string; event?: any }) => void;
|
handleEntryPointer: (params: { rowKey?: string | null; id?: Identifier | null; type?: string; event?: any }) => void;
|
||||||
selectedEntries: Array<string | number>;
|
selectedEntries: string[];
|
||||||
selectionAnchorRef: MutableRefObject<Identifier | string | null>;
|
selectionAnchorRef: MutableRefObject<Identifier | string | null>;
|
||||||
applySelection: (rowKeys: Array<string | number>, options?: { anchor?: Identifier | string | null; interactedKeys?: Array<string | number> }) => void;
|
applySelection: ApplySelectionFn;
|
||||||
resolveDocumentRowKey: (id?: Identifier | null) => string | null;
|
|
||||||
showingSearchResults: boolean;
|
showingSearchResults: boolean;
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
activeTagFilters: Array<string | number>;
|
activeTagFilters: Array<string | number>;
|
||||||
@@ -32,7 +36,6 @@ const useWorkspaceDeskProps = ({
|
|||||||
selectedEntries,
|
selectedEntries,
|
||||||
selectionAnchorRef,
|
selectionAnchorRef,
|
||||||
applySelection,
|
applySelection,
|
||||||
resolveDocumentRowKey,
|
|
||||||
showingSearchResults,
|
showingSearchResults,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
activeTagFilters,
|
activeTagFilters,
|
||||||
@@ -53,7 +56,7 @@ const useWorkspaceDeskProps = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rowKeys = docIds
|
const rowKeys = docIds
|
||||||
.map((id) => resolveDocumentRowKey(id as Identifier))
|
.map((id) => createDocumentEntryKey(id as Identifier))
|
||||||
.filter((value): value is string => typeof value === 'string');
|
.filter((value): value is string => typeof value === 'string');
|
||||||
|
|
||||||
if (!rowKeys.length) {
|
if (!rowKeys.length) {
|
||||||
@@ -69,14 +72,14 @@ const useWorkspaceDeskProps = ({
|
|||||||
|
|
||||||
const anchor = (rowKeys[0]
|
const anchor = (rowKeys[0]
|
||||||
|| selectionAnchorRef.current
|
|| selectionAnchorRef.current
|
||||||
|| nextKeys[nextKeys.length - 1]) as Identifier | string | null;
|
|| nextKeys[nextKeys.length - 1]) as string | null;
|
||||||
|
|
||||||
applySelection(nextKeys, {
|
applySelection(nextKeys, {
|
||||||
anchor,
|
anchor,
|
||||||
interactedKeys: rowKeys,
|
interactedKeys: rowKeys,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[applySelection, resolveDocumentRowKey, selectedEntries, selectionAnchorRef],
|
[applySelection, selectedEntries, selectionAnchorRef],
|
||||||
);
|
);
|
||||||
|
|
||||||
const deskViewId = useMemo(() => {
|
const deskViewId = useMemo(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user