Skip to content

Commit

Permalink
#276 Improve File Tree Tab
Browse files Browse the repository at this point in the history
- add simple file search
  • Loading branch information
MaximilianZenz committed Feb 7, 2025
1 parent 2960b24 commit 956097a
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 64 deletions.
7 changes: 6 additions & 1 deletion binocular-frontend-new/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import TabControllerButtonThemeSwitch from './components/tabMenu/tabControllerBu
import { useEffect, useState } from 'react';
import DatabaseLoaders from './utils/databaseLoaders.ts';
import OverlayController from './components/overlayController/overlayController.tsx';
import FileSearch from './components/tabs/fileTree/fileSearch/fileSearch.tsx';

function App() {
// #v-ifdef PRE_CONFIGURE_DB=='pouchdb'
Expand All @@ -56,6 +57,7 @@ function App() {
filesDataPluginId !== undefined
? avaliableDataPlugins.find((dP: DatabaseSettingsDataPluginType) => dP.id === filesDataPluginId)
: undefined;
const [fileSearch, setFileSearch] = useState('');

const storedTheme = localStorage.getItem('theme');
const [theme, setTheme] = useState(storedTheme || 'binocularLight');
Expand Down Expand Up @@ -152,8 +154,11 @@ function App() {
}
}}></DataPluginQuickSelect>
</TabSection>
<TabSection name={'File Search'}>
<FileSearch setFileSearch={setFileSearch}></FileSearch>
</TabSection>
<TabSection name={'File Tree'}>
<FileList></FileList>
<FileList search={fileSearch}></FileList>
</TabSection>
</Tab>
<Tab displayName={'Help'} alignment={'right'}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ 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 { generateFileTree } from './fileListUtilities/fileTreeUtilities.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';

function FileList(props: { orientation?: string }) {
function FileList(props: { orientation?: string; search: string }) {
const dispatch: AppDispatch = useAppDispatch();
const currentDataPlugins = useSelector((state: RootState) => state.settings.database.dataPlugins);

const fileLists = useSelector((state: RootState) => state.files.fileLists);
const fileCounts = useSelector((state: RootState) => state.files.fileCounts);

Expand All @@ -36,6 +35,7 @@ function FileList(props: { orientation?: string }) {
children: generateFileTree(files),
checked: true,
foldedOut: true,
isRoot: true,
},
fileCount: files.length,
}),
Expand Down Expand Up @@ -80,7 +80,7 @@ function FileList(props: { orientation?: string }) {
<div>{fileCounts[filesDataPluginId]} Files indexed</div>
<div>
{fileLists[filesDataPluginId] ? (
<FileListFolder folder={fileLists[filesDataPluginId]} foldedOut={true}></FileListFolder>
<FileListFolder folder={filterFileTree(fileLists[filesDataPluginId],props.search)} foldedOut={true}></FileListFolder>
) : (
<span className="loading loading-spinner loading-xs text-accent"></span>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@
border-left: 1px solid;
@apply border-base-300;
}

.searchMark{
@apply bg-accent;
border-radius: 2px;
padding: 0 .1rem;
margin: 0 .1rem;
border: 1px solid;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FileListElementType } 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 }) {
const dispatch: AppDispatch = useAppDispatch();
Expand All @@ -17,7 +18,7 @@ function FileListFile(props: { file: FileListElementType }) {
/>
<div className={fileListElementsStyles.element}>
<img src={FileIcon} alt={`folder ${props.file.name}`} />
<span>{props.file.name}</span>
<span>{formatName(props.file.searchTerm, props.file.name)}</span>
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FolderOpenIcon from '../../../../../assets/folder_open_gray.svg';
import FileListFile from './fileListFile.tsx';
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 }) {
const dispatch: AppDispatch = useAppDispatch();
Expand All @@ -26,7 +27,7 @@ function FileListFolder(props: { folder: FileListElementType; foldedOut: boolean
className={fileListElementsStyles.element}
onClick={() => dispatch(updateFileListElement({ ...props.folder, foldedOut: false }))}>
<img src={FolderOpenIcon} alt={`folder open ${props.folder.name}`} />
<span>{props.folder.name}</span>
<span>{formatName(props.folder.searchTerm, props.folder.name)}</span>
</div>
</div>
<div className={fileListElementsStyles.inset}>
Expand Down Expand Up @@ -64,7 +65,7 @@ function FileListFolder(props: { folder: FileListElementType; foldedOut: boolean
onClick={() => dispatch(updateFileListElement({ ...props.folder, foldedOut: true }))}
className={fileListElementsStyles.element}>
<img src={FolderIcon} alt={`folder ${props.folder.name}`} />
<span>{props.folder.name}</span>
<span>{formatName(props.folder.searchTerm, props.folder.name)}</span>
</div>
</div>
)}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { FileListElementType, FileListElementTypeType } 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[] {
return convertData(files).content;
}

function convertData(files: DataPluginFile[]) {
const convertedData = { content: [] };
let id = 0;
for (const file of files) {
if (file) {
const pathParts = file.path.split('/');
id = genPathObjectString(convertedData.content, pathParts, file, id);
}
}
return convertedData;
}

function genPathObjectString(convertedData: FileListElementType[], pathParts: string[], file: DataPluginFile, id: number) {
const currElm = pathParts.shift();
id++;
if (currElm) {
if (pathParts.length === 0) {
convertedData.push({
name: currElm,
id: id,
type: FileListElementTypeType.File,
checked: true,
element: file,
foldedOut: false,
isRoot: false,
});
} else {
let elem = convertedData.find((d) => d.name === currElm);
if (elem === undefined) {
elem = {
name: currElm,
id: id,
type: FileListElementTypeType.Folder,
children: [],
checked: true,
foldedOut: false,
isRoot: false,
};
if (elem.children) {
id = genPathObjectString(elem.children, pathParts, file, id);
convertedData.push(elem);
}
} else {
if (elem.children) {
id = genPathObjectString(elem.children, pathParts, file, id);
}
}
}
}
return id;
}

export function filterFileTree(fileTree: FileListElementType, search: string): FileListElementType {
if (fileTree.children) {
return {
...fileTree,
searchTerm: search,
children: fileTree.children
?.map((child) => {
if (child.type === FileListElementTypeType.Folder) {
return filterFileTree(child, search);
} else {
return { ...child, searchTerm: search };
}
})
.filter((child) => {
if (child.type === FileListElementTypeType.Folder && child.children) {
return child.children.length > 0;
}
return child.element?.path.toLowerCase().includes(search.toLowerCase());
}),
};
} else {
return fileTree;
}
}

export function formatName(searchTerm: string | undefined, name: string): JSX.Element[] {
let formatedName = [<span key={'formatedNamePart0'}>{name}</span>];
if (searchTerm) {
const searchParts: string[] = searchTerm ? searchTerm.split('/') : [];
for (const searchPart of searchParts) {
if (name.toLowerCase().includes(searchPart.toLowerCase())) {
const nameParts = name.split(new RegExp(searchPart, 'i')).map((part, i) => <span key={`formatedNamePart${i}`}>{part}</span>);
formatedName = [
nameParts[0],
<span key={'formatedNamePartMatch'} className={fileListElementsStyles.searchMark}>
{searchPart}
</span>,
nameParts[1],
];
break;
}
}
}
return formatedName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Dispatch, SetStateAction } from 'react';

function FileSearch(props: { orientation?: string; setFileSearch: Dispatch<SetStateAction<string>> }) {
return (
<>
<label className="input input-bordered flex items-center gap-2">
<input type="text" className="grow" placeholder="Search" onChange={(event) => props.setFileSearch(event.target.value)} />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="h-4 w-4 opacity-70">
<path
fillRule="evenodd"
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
clipRule="evenodd"
/>
</svg>
</label>
</>
);
}

export default FileSearch;
2 changes: 2 additions & 0 deletions binocular-frontend-new/src/types/data/fileListType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ export interface FileListElementType {
type: FileListElementTypeType;
element?: DataPluginFile;
children?: FileListElementType[];
searchTerm?: string;
checked: boolean;
foldedOut: boolean;
isRoot: boolean;
}

export enum FileListElementTypeType {
Expand Down

0 comments on commit 956097a

Please sign in to comment.