diff --git a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileList.tsx b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileList.tsx index 5cb95c19..514de40e 100644 --- a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileList.tsx +++ b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileList.tsx @@ -2,16 +2,18 @@ import fileListStyles from './fileList.module.scss'; import { useSelector } from 'react-redux'; import { AppDispatch, RootState, store as globalStore, useAppDispatch } from '../../../../redux'; import { useEffect } from 'react'; -import { FileListElementTypeType } from '../../../../types/data/fileListType.ts'; +import { FileTreeElementTypeType } from '../../../../types/data/fileListType.ts'; import { filterFileTree, generateFileTree } from './fileListUtilities/fileTreeUtilities.tsx'; import FileListFolder from './fileListElements/fileListFolder.tsx'; import { DatabaseSettingsDataPluginType } from '../../../../types/settings/databaseSettingsType.ts'; import DataPluginStorage from '../../../../utils/dataPluginStorage.ts'; import { setFileList, setFilesDataPluginId } from '../../../../redux/reducer/data/filesReducer.ts'; +import { DataPluginFile } from '../../../../plugins/interfaces/dataPluginInterfaces/dataPluginFiles.ts'; function FileList(props: { orientation?: string; search: string }) { const dispatch: AppDispatch = useAppDispatch(); const currentDataPlugins = useSelector((state: RootState) => state.settings.database.dataPlugins); + const fileTrees = useSelector((state: RootState) => state.files.fileTrees); const fileLists = useSelector((state: RootState) => state.files.fileLists); const fileCounts = useSelector((state: RootState) => state.files.fileCounts); @@ -29,15 +31,20 @@ function FileList(props: { orientation?: string; search: string }) { dispatch( setFileList({ dataPluginId: dP.id !== undefined ? dP.id : -1, - files: { + fileTree: { name: '/', - type: FileListElementTypeType.Folder, + type: FileTreeElementTypeType.Folder, children: generateFileTree(files), checked: true, foldedOut: true, isRoot: true, }, - fileCount: files.length, + files: files.map((f: DataPluginFile) => { + return { + element: f, + checked: true, + }; + }), }), ), ) @@ -68,6 +75,7 @@ function FileList(props: { orientation?: string; search: string }) { } }); + console.log(fileLists[filesDataPluginId]); return ( <>
{fileCounts[filesDataPluginId]} Files indexed
- {fileLists[filesDataPluginId] ? ( - + {fileTrees[filesDataPluginId] ? ( + ) : ( )} diff --git a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFile.tsx b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFile.tsx index 5d84a1e1..df87fc4e 100644 --- a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFile.tsx +++ b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFile.tsx @@ -1,11 +1,11 @@ import fileListElementsStyles from './fileListElements.module.scss'; -import { FileListElementType } from '../../../../../types/data/fileListType.ts'; +import { FileTreeElementType } from '../../../../../types/data/fileListType.ts'; import FileIcon from '../../../../../assets/file_gray.svg'; import { updateFileListElement } from '../../../../../redux/reducer/data/filesReducer.ts'; import { AppDispatch, useAppDispatch } from '../../../../../redux'; import { formatName } from '../fileListUtilities/fileTreeUtilities.tsx'; -function FileListFile(props: { file: FileListElementType }) { +function FileListFile(props: { file: FileTreeElementType }) { const dispatch: AppDispatch = useAppDispatch(); return ( <> diff --git a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFolder.tsx b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFolder.tsx index 1ab93948..c85aa782 100644 --- a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFolder.tsx +++ b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListElements/fileListFolder.tsx @@ -1,5 +1,5 @@ import fileListElementsStyles from './fileListElements.module.scss'; -import { FileListElementType, FileListElementTypeType } from '../../../../../types/data/fileListType.ts'; +import { FileTreeElementType, FileTreeElementTypeType } from '../../../../../types/data/fileListType.ts'; import FolderIcon from '../../../../../assets/folder_gray.svg'; import FolderOpenIcon from '../../../../../assets/folder_open_gray.svg'; import FileListFile from './fileListFile.tsx'; @@ -7,7 +7,7 @@ import { AppDispatch, useAppDispatch } from '../../../../../redux'; import { updateFileListElement } from '../../../../../redux/reducer/data/filesReducer.ts'; import { formatName } from '../fileListUtilities/fileTreeUtilities.tsx'; -function FileListFolder(props: { folder: FileListElementType; foldedOut: boolean }) { +function FileListFolder(props: { folder: FileTreeElementType; foldedOut: boolean }) { const dispatch: AppDispatch = useAppDispatch(); return ( @@ -43,9 +43,9 @@ function FileListFolder(props: { folder: FileListElementType; foldedOut: boolean } return 0; }) - .sort((e) => (e.type === FileListElementTypeType.Folder ? -1 : 1)) + .sort((e) => (e.type === FileTreeElementTypeType.Folder ? -1 : 1)) .map((element, i) => { - if (element.type === FileListElementTypeType.Folder && element.children) { + if (element.type === FileTreeElementTypeType.Folder && element.children) { return ; } else { return ; diff --git a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListUtilities/fileTreeUtilities.tsx b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListUtilities/fileTreeUtilities.tsx index e76e1916..f6156fff 100644 --- a/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListUtilities/fileTreeUtilities.tsx +++ b/binocular-frontend-new/src/components/tabs/fileTree/fileList/fileListUtilities/fileTreeUtilities.tsx @@ -1,8 +1,8 @@ -import { FileListElementType, FileListElementTypeType } from '../../../../../types/data/fileListType.ts'; +import { FileTreeElementType, FileTreeElementTypeType } from '../../../../../types/data/fileListType.ts'; import { DataPluginFile } from '../../../../../plugins/interfaces/dataPluginInterfaces/dataPluginFiles.ts'; import fileListElementsStyles from '../fileListElements/fileListElements.module.scss'; -export function generateFileTree(files: DataPluginFile[]): FileListElementType[] { +export function generateFileTree(files: DataPluginFile[]): FileTreeElementType[] { return convertData(files).content; } @@ -18,7 +18,7 @@ function convertData(files: DataPluginFile[]) { return convertedData; } -function genPathObjectString(convertedData: FileListElementType[], pathParts: string[], file: DataPluginFile, id: number) { +function genPathObjectString(convertedData: FileTreeElementType[], pathParts: string[], file: DataPluginFile, id: number) { const currElm = pathParts.shift(); id++; if (currElm) { @@ -26,7 +26,7 @@ function genPathObjectString(convertedData: FileListElementType[], pathParts: st convertedData.push({ name: currElm, id: id, - type: FileListElementTypeType.File, + type: FileTreeElementTypeType.File, checked: true, element: file, foldedOut: false, @@ -38,7 +38,7 @@ function genPathObjectString(convertedData: FileListElementType[], pathParts: st elem = { name: currElm, id: id, - type: FileListElementTypeType.Folder, + type: FileTreeElementTypeType.Folder, children: [], checked: true, foldedOut: false, @@ -58,21 +58,21 @@ function genPathObjectString(convertedData: FileListElementType[], pathParts: st return id; } -export function filterFileTree(fileTree: FileListElementType, search: string): FileListElementType { +export function filterFileTree(fileTree: FileTreeElementType, search: string): FileTreeElementType { if (fileTree.children) { return { ...fileTree, searchTerm: search, children: fileTree.children ?.map((child) => { - if (child.type === FileListElementTypeType.Folder) { + if (child.type === FileTreeElementTypeType.Folder) { return filterFileTree(child, search); } else { return { ...child, searchTerm: search }; } }) .filter((child) => { - if (child.type === FileListElementTypeType.Folder && child.children) { + if (child.type === FileTreeElementTypeType.Folder && child.children) { return child.children.length > 0; } return child.element?.path.toLowerCase().includes(search.toLowerCase()); diff --git a/binocular-frontend-new/src/redux/reducer/data/filesReducer.ts b/binocular-frontend-new/src/redux/reducer/data/filesReducer.ts index 76c33d4a..d43f94b1 100644 --- a/binocular-frontend-new/src/redux/reducer/data/filesReducer.ts +++ b/binocular-frontend-new/src/redux/reducer/data/filesReducer.ts @@ -1,14 +1,16 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import Config from '../../../config.ts'; -import { FileListElementType } from '../../../types/data/fileListType.ts'; +import { FileListElementType, FileTreeElementType } from '../../../types/data/fileListType.ts'; export interface FilesInitialState { - fileLists: { [id: number]: FileListElementType }; + fileTrees: { [id: number]: FileTreeElementType }; + fileLists: { [id: number]: FileListElementType[] }; fileCounts: { [id: number]: number }; dataPluginId: number | undefined; } const initialState: FilesInitialState = { + fileTrees: {}, fileLists: {}, fileCounts: {}, dataPluginId: undefined, @@ -26,11 +28,12 @@ export const filesSlice = createSlice({ } }, reducers: { - setFileList: (state, action: PayloadAction<{ dataPluginId: number; files: FileListElementType; fileCount: number }>) => { + setFileList: (state, action: PayloadAction<{ dataPluginId: number; fileTree: FileTreeElementType; files: FileListElementType[] }>) => { const fileCount: number = state.fileCounts[action.payload.dataPluginId]; - if (fileCount === undefined || fileCount !== action.payload.fileCount) { + if (fileCount === undefined || fileCount !== action.payload.files.length) { + state.fileTrees[action.payload.dataPluginId] = action.payload.fileTree; + state.fileCounts[action.payload.dataPluginId] = action.payload.files.length; state.fileLists[action.payload.dataPluginId] = action.payload.files; - state.fileCounts[action.payload.dataPluginId] = action.payload.fileCount; } localStorage.setItem(`${filesSlice.name}StateV${Config.localStorageVersion}`, JSON.stringify(state)); }, @@ -38,9 +41,14 @@ export const filesSlice = createSlice({ state.dataPluginId = action.payload; localStorage.setItem(`${filesSlice.name}StateV${Config.localStorageVersion}`, JSON.stringify(state)); }, - updateFileListElement: (state, action: PayloadAction) => { - state.fileLists[state.dataPluginId] = updateFileListElementRecursive(state.fileLists[state.dataPluginId], action.payload); - + updateFileListElement: (state, action: PayloadAction) => { + const updatedPaths: string[] = updateFileTreeRecursive(state.fileTrees[state.dataPluginId], action.payload); + state.fileLists[state.dataPluginId] = state.fileLists[state.dataPluginId].map((f: FileListElementType) => { + if (updatedPaths.includes(f.element.path)) { + f.checked = action.payload.checked; + } + return f; + }); localStorage.setItem(`${filesSlice.name}StateV${Config.localStorageVersion}`, JSON.stringify(state)); }, }, @@ -49,24 +57,27 @@ export const filesSlice = createSlice({ export const { setFilesDataPluginId, setFileList, updateFileListElement } = filesSlice.actions; export default filesSlice.reducer; -function updateFileListElementRecursive( - fileList: FileListElementType, - element: FileListElementType, - checked?: boolean, -): FileListElementType { - if (fileList.children) { - fileList.children = fileList.children.map((f: FileListElementType) => { +function updateFileTreeRecursive(fileTree: FileTreeElementType, element: FileTreeElementType, checked?: boolean): string[] { + const updatedPaths: string[] = []; + if (fileTree.children) { + fileTree.children = fileTree.children.map((f: FileTreeElementType) => { let elementChecked = checked; if (f.id === element.id) { + if (f.element?.path && !updatedPaths.includes(f.element.path)) { + updatedPaths.push(f.element.path); + } elementChecked = element.checked; f.foldedOut = element.foldedOut; } if (elementChecked !== undefined) { + if (f.element?.path && !updatedPaths.includes(f.element.path)) { + updatedPaths.push(f.element.path); + } f.checked = elementChecked; } - updateFileListElementRecursive(f, element, elementChecked); + updatedPaths.push(...updateFileTreeRecursive(f, element, elementChecked)); return f; }); } - return fileList; + return updatedPaths; } diff --git a/binocular-frontend-new/src/types/data/fileListType.ts b/binocular-frontend-new/src/types/data/fileListType.ts index 95be2e06..592ed048 100644 --- a/binocular-frontend-new/src/types/data/fileListType.ts +++ b/binocular-frontend-new/src/types/data/fileListType.ts @@ -1,18 +1,22 @@ import { DataPluginFile } from '../../plugins/interfaces/dataPluginInterfaces/dataPluginFiles.ts'; export interface FileListElementType { + element: DataPluginFile; + checked: boolean; +} +export interface FileTreeElementType { name: string; id?: number; - type: FileListElementTypeType; + type: FileTreeElementTypeType; element?: DataPluginFile; - children?: FileListElementType[]; + children?: FileTreeElementType[]; searchTerm?: string; checked: boolean; foldedOut: boolean; isRoot: boolean; } -export enum FileListElementTypeType { +export enum FileTreeElementTypeType { Folder, File, }