diff --git a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-doc.tsx b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-doc.tsx new file mode 100644 index 0000000000..b2c027e499 --- /dev/null +++ b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-doc.tsx @@ -0,0 +1,36 @@ +import HistoryFileTreeItem from './history-file-tree-item' +import iconTypeFromName from '../../../file-tree/util/icon-type-from-name' +import Icon from '../../../../shared/components/icon' +import { useSelectableEntity } from '../../context/history-file-tree-selectable' + +type HistoryFileTreeDocProps = { + name: string + id: string +} + +export default function HistoryFileTreeDoc({ + name, + id, +}: HistoryFileTreeDocProps) { + const { props: selectableEntityProps } = useSelectableEntity(id) + + return ( +
  • + + } + /> +
  • + ) +} diff --git a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder-list.tsx b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder-list.tsx new file mode 100644 index 0000000000..a7541b15c4 --- /dev/null +++ b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder-list.tsx @@ -0,0 +1,48 @@ +import classNames from 'classnames' + +import HistoryFileTreeDoc from './history-file-tree-doc' +import HistoryFileTreeFolder from './history-file-tree-folder' +import { fileCollator } from '../../../file-tree/util/file-collator' +import type { Doc } from '../../../../../../types/doc' +import type { ReactNode } from 'react' +import type { HistoryFileTree } from '../../utils/file-tree' + +type HistoryFileTreeFolderListProps = { + folders: HistoryFileTree[] + docs: Doc[] + rootClassName?: string + children?: ReactNode +} + +export default function HistoryFileTreeFolderList({ + folders, + docs, + rootClassName, + children, +}: HistoryFileTreeFolderListProps) { + return ( + + ) +} + +function compareFunction( + one: HistoryFileTree | Doc, + two: HistoryFileTree | Doc +) { + return fileCollator.compare(one.name, two.name) +} diff --git a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder.tsx b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder.tsx new file mode 100644 index 0000000000..4307521836 --- /dev/null +++ b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-folder.tsx @@ -0,0 +1,63 @@ +import { useState } from 'react' +import { useTranslation } from 'react-i18next' + +import HistoryFileTreeItem from './history-file-tree-item' +import HistoryFileTreeFolderList from './history-file-tree-folder-list' + +import Icon from '../../../../shared/components/icon' +import type { Doc } from '../../../../../../types/doc' +import type { HistoryFileTree } from '../../utils/file-tree' + +type HistoryFileTreeFolderProps = { + name: string + folders: HistoryFileTree[] + docs: Doc[] +} + +export default function HistoryFileTreeFolder({ + name, + folders, + docs, +}: HistoryFileTreeFolderProps) { + const { t } = useTranslation() + + const [expanded, setExpanded] = useState(true) + + const icons = ( + <> + + + + ) + + return ( + <> +
  • setExpanded(!expanded)} + onKeyDown={() => setExpanded(!expanded)} + > + +
  • + {expanded ? ( + + ) : null} + + ) +} diff --git a/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx new file mode 100644 index 0000000000..af5a7b94df --- /dev/null +++ b/services/web/frontend/js/features/history/components/file-tree/history-file-tree-item.tsx @@ -0,0 +1,19 @@ +import type { ReactNode } from 'react' + +type FileTreeItemProps = { + name: string + icons: ReactNode +} + +export default function FileTreeItem({ name, icons }: FileTreeItemProps) { + return ( +
    +
    + {icons} + +
    +
    + ) +} diff --git a/services/web/frontend/js/features/history/components/history-file-tree.tsx b/services/web/frontend/js/features/history/components/history-file-tree.tsx index 5aecbeb149..b8ebae1486 100644 --- a/services/web/frontend/js/features/history/components/history-file-tree.tsx +++ b/services/web/frontend/js/features/history/components/history-file-tree.tsx @@ -1,28 +1,24 @@ import _ from 'lodash' -import FileTreeContext from '../../file-tree/components/file-tree-context' -import FileTreeFolderList from '../../file-tree/components/file-tree-folder-list' +import { useCallback } from 'react' import { useHistoryContext } from '../context/history-context' +import { HistoryFileTreeSelectableProvider } from '../context/history-file-tree-selectable' import { fileTreeDiffToFileTreeData, reducePathsToTree, } from '../utils/file-tree' +import HistoryFileTreeFolderList from './file-tree/history-file-tree-folder-list' -type HistoryFileTreeProps = { - setRefProviderEnabled: any - setStartedFreeTrial: any - reindexReferences: any - onSelect: any - refProviders: any -} +export default function HistoryFileTree() { + const { fileSelection, setFileSelection } = useHistoryContext() -export default function HistoryFileTree({ - setRefProviderEnabled, - setStartedFreeTrial, - reindexReferences, - onSelect, - refProviders, -}: HistoryFileTreeProps) { - const { fileSelection } = useHistoryContext() + const handleSelectFile = useCallback( + (pathname: string) => { + if (fileSelection) { + setFileSelection({ files: fileSelection.files, pathname }) + } + }, + [fileSelection, setFileSelection] + ) if (!fileSelection) { return null @@ -33,21 +29,14 @@ export default function HistoryFileTree({ const mappedFileTree = fileTreeDiffToFileTreeData(fileTree) return ( - - +
  • - - + + ) } diff --git a/services/web/frontend/js/features/history/components/history-root.tsx b/services/web/frontend/js/features/history/components/history-root.tsx index f0ba4c5a1d..4cc81c11ac 100644 --- a/services/web/frontend/js/features/history/components/history-root.tsx +++ b/services/web/frontend/js/features/history/components/history-root.tsx @@ -19,16 +19,7 @@ function Main() { return ( <> {fileTreeContainer - ? createPortal( - {}} - refProviders={{}} - reindexReferences={() => {}} - setRefProviderEnabled={() => {}} - setStartedFreeTrial={() => {}} - />, - fileTreeContainer - ) + ? createPortal(, fileTreeContainer) : null}
    diff --git a/services/web/frontend/js/features/history/context/history-file-tree-selectable.tsx b/services/web/frontend/js/features/history/context/history-file-tree-selectable.tsx new file mode 100644 index 0000000000..a4dd5ad555 --- /dev/null +++ b/services/web/frontend/js/features/history/context/history-file-tree-selectable.tsx @@ -0,0 +1,87 @@ +import { + createContext, + type ReactNode, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react' +import classNames from 'classnames' +import _ from 'lodash' + +import usePreviousValue from '../../../shared/hooks/use-previous-value' +import { Nullable } from '../../../../../types/utils' + +type Context = { + select: (id: string) => void + selectedFile: Nullable +} + +const FileTreeSelectableContext = createContext({ + select: () => {}, + selectedFile: null, +}) + +type HistoryFileTreeSelectableProviderProps = { + onSelectFile: (id: string) => void + children: ReactNode +} + +export function HistoryFileTreeSelectableProvider({ + onSelectFile, + children, +}: HistoryFileTreeSelectableProviderProps) { + const [selectedFile, setSelectedFile] = + useState(null) + + const previousSelectedFile = usePreviousValue(selectedFile) + + useEffect(() => { + if (!selectedFile) { + return + } + + if (_.isEqual(selectedFile, previousSelectedFile)) { + return + } + + onSelectFile(selectedFile) + }, [selectedFile, previousSelectedFile, onSelectFile]) + + const select = useCallback(id => { + setSelectedFile(id) + }, []) + + const value = { + selectedFile, + select, + } + + return ( + + {children} + + ) +} + +export function useSelectableEntity(id: string) { + const { selectedFile, select } = useContext(FileTreeSelectableContext) + + const handleClick = useCallback(() => { + select(id) + }, [id, select]) + + const isSelected = selectedFile === id + + const props = useMemo( + () => ({ + className: classNames({ selected: isSelected }), + 'aria-selected': isSelected, + onClick: handleClick, + }), + [handleClick, isSelected] + ) + + return { isSelected, props } +} diff --git a/services/web/frontend/js/features/history/controllers/history-file-tree-controller.js b/services/web/frontend/js/features/history/controllers/history-file-tree-controller.js index 2775e66e8d..36c72a22f4 100644 --- a/services/web/frontend/js/features/history/controllers/history-file-tree-controller.js +++ b/services/web/frontend/js/features/history/controllers/history-file-tree-controller.js @@ -5,11 +5,5 @@ import HistoryFileTree from '../components/history-file-tree' App.component( 'historyFileTreeReact', - react2angular(rootContext.use(HistoryFileTree), [ - 'refProviders', - 'setRefProviderEnabled', - 'setStartedFreeTrial', - 'reindexReferences', - 'onSelect', - ]) + react2angular(rootContext.use(HistoryFileTree)) ) diff --git a/services/web/frontend/js/features/history/utils/file-tree.ts b/services/web/frontend/js/features/history/utils/file-tree.ts index bea2596228..ff125534df 100644 --- a/services/web/frontend/js/features/history/utils/file-tree.ts +++ b/services/web/frontend/js/features/history/utils/file-tree.ts @@ -48,14 +48,11 @@ export function reducePathsToTree( return currentFileTree } -type HistoryFileTree = { +export type HistoryFileTree = { docs?: Doc[] folders: HistoryFileTree[] name: string - // `id` and `fileRefs` are both required from react file tree. - // TODO: update react file tree to make the data optional so we can delete these keys - id: '' - fileRefs: [] + _id: string } export function fileTreeDiffToFileTreeData( @@ -68,7 +65,7 @@ export function fileTreeDiffToFileTreeData( for (const file of fileTreeDiff) { if (file.type === 'file') { docs.push({ - _id: '', + _id: file.pathname as string, name: file.name ?? '', }) } else if (file.type === 'folder') { @@ -83,8 +80,7 @@ export function fileTreeDiffToFileTreeData( docs, folders, name: currentFolderName, - id: '', - fileRefs: [], + _id: currentFolderName, } }