Skip to content

Commit

Permalink
feat: pod search (#542)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomicvladan committed Oct 12, 2023
1 parent 266d134 commit 0c04bc2
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 36 deletions.
13 changes: 13 additions & 0 deletions src/@types/fdp-storage.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type {
DirectoryItem as FdpDirectoryItem,
FileItem as FdpFileItem,
} from '@fairdatasociety/fdp-storage';

declare module '@fairdatasociety/fdp-storage' {
interface DirectoryItem extends FdpDirectoryItem {
path?: string;
}
interface FileItem extends FdpFileItem {
path?: string;
}
}
39 changes: 28 additions & 11 deletions src/components/Inputs/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,59 @@ import CloseDarkIcon from '@media/UI/close-light.svg';

import classes from './SearchBar.module.scss';
import { useLocales } from '@context/LocalesContext';
import { useForm } from 'react-hook-form';
import PodContext from '@context/PodContext';

interface SearchBarProps {}

const SearchBar: FC<SearchBarProps> = () => {
const { theme } = useContext(ThemeContext);
const { search, updateSearch } = useContext(SearchContext);
const { updateSearch, searchDisabled } = useContext(SearchContext);
const { activePod, loading } = useContext(PodContext);
const { intl } = useLocales();
const { register, handleSubmit, reset } = useForm<{ search: '' }>();

const onSubmitInternal = ({ search }) => updateSearch(search);

return (
<div className="flex justify-center items-center w-80 md:w-98 h-10 py-2 px-4 bg-color-shade-dark-4-day dark:bg-color-shade-dark-4-night border border-color-shade-black-day dark:border-color-shade-dark-1-night effect-style-small-button-drop-shadow rounded">
{theme === 'light' ? (
<SearchLightIcon className="inline-block mr-1" />
) : (
<SearchDarkIcon className="inline-block mr-1" />
)}
<form
className="flex justify-center items-center w-80 md:w-98 h-10 py-2 px-4 bg-color-shade-dark-4-day dark:bg-color-shade-dark-4-night border border-color-shade-black-day dark:border-color-shade-dark-1-night effect-style-small-button-drop-shadow rounded"
onSubmit={handleSubmit(onSubmitInternal)}
>
<span className="cursor-pointer" onClick={handleSubmit(onSubmitInternal)}>
{theme === 'light' ? (
<SearchLightIcon className="inline-block mr-1" />
) : (
<SearchDarkIcon className="inline-block mr-1" />
)}
</span>

<input
type="text"
id="search"
name="search"
disabled={!activePod || loading || searchDisabled}
placeholder={intl.get('SEARCH')}
className={`${classes.searchBar} ${
theme === 'light' ? classes.searchBarLight : classes.searchBarDark
}`}
value={search}
onChange={(e) => updateSearch(e.target.value)}
{...register('search', { required: true })}
/>

<div className="cursor-pointer" onClick={() => updateSearch('')}>
<div
className="cursor-pointer"
onClick={() => {
reset();
updateSearch('');
}}
>
{theme === 'light' ? (
<CloseLightIcon className="inline-block mr-1" />
) : (
<CloseDarkIcon className="inline-block mr-1" />
)}
</div>
</div>
</form>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ const PreviewFileModal: FC<PreviewModalProps> = ({
setLoading(true);
downloadFile(fdpClientRef.current, {
filename: previewFile?.name,
directory: directoryName,
directory: previewFile.path || directoryName,
podName: activePod,
})
.then(async (response) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ const MainNavigationBar: FC<Record<string, never>> = () => {
</div>

<div className="flex justify-between items-center">
{/* TODO: Search functionality should be implemented */}
{/* <div className="hidden sm:block mr-16">
<div className="hidden sm:block mr-16">
<SearchBar />
</div> */}
</div>
<div className="flex flex-nowrap space-x-5">
<UserDropdownToggle
address={wallet?.address || 'Blossom'}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Views/DriveGridView/DriveGridView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UpdateDriveProps } from '@interfaces/handlers';
interface DriveGridViewProps extends UpdateDriveProps {
directories: DirectoryItem[];
files: FileItem[];
directoryOnClick: (directoryName: string) => void;
directoryOnClick: (directory: DirectoryItem) => void;
fileOnClick: (data: FileItem) => void;
}

Expand All @@ -28,7 +28,7 @@ const DriveGridView: FC<DriveGridViewProps> = ({
size: directory.size,
creationTime: (directory.raw as any)?.meta?.creationTime,
}}
onClick={() => directoryOnClick(directory.name)}
onClick={() => directoryOnClick(directory)}
updateDrive={updateDrive}
/>
))}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Views/DriveListView/DriveListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { UpdateDriveProps } from '@interfaces/handlers';
interface DriveListViewProps extends UpdateDriveProps {
directories: DirectoryItem[];
files: FileItem[];
directoryOnClick: (directoryName: string) => void;
directoryOnClick: (directory: DirectoryItem) => void;
fileOnClick: (data: FileItem) => void;
}

Expand Down Expand Up @@ -56,7 +56,7 @@ const DriveListView: FC<DriveListViewProps> = ({
size: directory.size,
creationTime: (directory.raw as any)?.meta?.creationTime,
}}
onClick={() => directoryOnClick(directory.name)}
onClick={() => directoryOnClick(directory)}
updateDrive={updateDrive}
/>
))}
Expand Down
8 changes: 8 additions & 0 deletions src/context/SearchContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { FC, ReactNode, createContext, useState } from 'react';

interface SearchContext {
search: string;
searchDisabled: boolean;
updateSearch: (newSearch: string) => void;
setSearchDisabled: (disabled: boolean) => void;
}

interface SearchContextProps {
Expand All @@ -11,14 +13,18 @@ interface SearchContextProps {

const searchContextDefaultValues: SearchContext = {
search: '',
searchDisabled: false,
// eslint-disable-next-line @typescript-eslint/no-empty-function
updateSearch: () => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setSearchDisabled: () => {},
};

const SearchContext = createContext<SearchContext>(searchContextDefaultValues);

const SearchProvider: FC<SearchContextProps> = ({ children }) => {
const [search, setSearch] = useState('');
const [searchDisabled, setSearchDisabled] = useState<boolean>(false);

const updateSearch = (newSearch: string) => {
setSearch(newSearch.trim());
Expand All @@ -28,7 +34,9 @@ const SearchProvider: FC<SearchContextProps> = ({ children }) => {
<SearchContext.Provider
value={{
search,
searchDisabled,
updateSearch,
setSearchDisabled,
}}
>
{children}
Expand Down
121 changes: 104 additions & 17 deletions src/pages/drive/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { FC, useContext, useEffect, useState } from 'react';
import { FC, useContext, useEffect, useRef, useState } from 'react';
import { useMatomo } from '@datapunt/matomo-tracker-react';
import { useFdpStorage } from '@context/FdpStorageContext';
import ThemeContext from '@context/ThemeContext';
Expand Down Expand Up @@ -41,6 +41,7 @@ import {
} from '@utils/error';
import PodList from '@components/Views/PodList/PodList';
import FeedbackMessage from '@components/FeedbackMessage/FeedbackMessage';
import { constructPath, rootPathToRelative } from '@utils/filename';

const Drive: FC = () => {
const { trackPageView } = useMatomo();
Expand Down Expand Up @@ -69,6 +70,7 @@ const Drive: FC = () => {
const [driveSort, setDriveSort] = useState('a-z');
const { fdpClientRef, getAccountAddress } = useFdpStorage();
const [error, setError] = useState<string | null>(null);
const searchControllerRef = useRef<AbortController | null>(null);

useEffect(() => {
trackPageView({
Expand All @@ -91,6 +93,7 @@ const Drive: FC = () => {
return;
}
setError(null);
updateSearch('');

const userAddress = await getAccountAddress();
const directory = directoryName || 'root';
Expand Down Expand Up @@ -187,7 +190,7 @@ const Drive: FC = () => {
}
};

const handleDirectoryOnClick = (newDirectoryName: string) => {
const handleDirectoryOnClick = (newDirectory: DirectoryItem) => {
if (loading) {
return;
}
Expand All @@ -196,10 +199,14 @@ const Drive: FC = () => {

setLoading(true);

if (directoryName !== 'root') {
setDirectoryName(directoryName + '/' + newDirectoryName);
if (newDirectory.path) {
setDirectoryName(
rootPathToRelative(constructPath(newDirectory.path, newDirectory.name))
);
} else if (directoryName !== 'root') {
setDirectoryName(directoryName + '/' + newDirectory.name);
} else {
setDirectoryName(newDirectoryName);
setDirectoryName(newDirectory.name);
}

setLoading(false);
Expand All @@ -225,10 +232,6 @@ const Drive: FC = () => {
setShowPreviewModal(true);
};

const handleSearchFilter = (driveItem: DirectoryItem | FileItem) => {
return driveItem.name.toLowerCase().includes(search.toLocaleLowerCase());
};

const handlePodSelect = (pod: string) => {
setError(null);
setActivePod(pod);
Expand All @@ -241,6 +244,94 @@ const Drive: FC = () => {
setDirectoryName('');
};

const handleSearch = async () => {
try {
if (loading || !activePod) {
return;
}

searchControllerRef.current = new AbortController();

setLoading(true);

let matchedFiles: FileItem[] = [];
let matchedDirectories: DirectoryItem[] = [];
let folders: { path: string; depth: number }[] = [
{ path: '/', depth: 0 },
];
const maxDepth = 3;

while (folders.length > 0) {
const { path, depth } = folders.shift();

let content: DirectoryItem;
try {
content = await getFilesAndDirectories(
fdpClientRef.current,
activePod,
path === '/' ? 'root' : path
);

// eslint-disable-next-line no-empty
} catch (error) {
console.error(error);
}

if (searchControllerRef.current.signal.aborted) {
return;
}

if (Array.isArray(content?.files)) {
matchedFiles = matchedFiles
.concat(content.files.filter(({ name }) => name.includes(search)))
.map((file) => {
file.path = path;
return file;
});
}

if (Array.isArray(content?.directories)) {
matchedDirectories = matchedDirectories.concat(
content.directories
.filter(({ name }) => name.includes(search))
.map((directory) => {
directory.path = path;
return directory;
})
);

if (depth < maxDepth) {
folders = folders.concat(
content.directories.map(({ name }) => ({
path: constructPath(path, name),
depth: depth + 1,
}))
);
}
}
}

setFiles(matchedFiles);
setDirectories(matchedDirectories);
} catch (error) {
setError(errorToString(error));
} finally {
setLoading(false);
}
};

useEffect(() => {
if (searchControllerRef.current) {
searchControllerRef.current.abort();
}

if (search) {
handleSearch();
} else {
handleUpdateDrive();
}
}, [search]);

return (
<MainLayout updateDrive={handleUpdateDrive} refreshPods={handleFetchPods}>
<div className="flex flex-col">
Expand Down Expand Up @@ -298,10 +389,8 @@ const Drive: FC = () => {
<div>
{driveView === 'grid' ? (
<DriveGridView
directories={handleSort(
directories?.filter(handleSearchFilter)
)}
files={handleSort(files?.filter(handleSearchFilter))}
directories={handleSort(directories)}
files={handleSort(files)}
directoryOnClick={handleDirectoryOnClick}
fileOnClick={handleFileOnClick}
updateDrive={handleUpdateDrive}
Expand All @@ -310,10 +399,8 @@ const Drive: FC = () => {

{driveView === 'list' ? (
<DriveListView
directories={handleSort(
directories?.filter(handleSearchFilter)
)}
files={handleSort(files?.filter(handleSearchFilter))}
directories={handleSort(directories)}
files={handleSort(files)}
directoryOnClick={handleDirectoryOnClick}
fileOnClick={handleFileOnClick}
updateDrive={handleUpdateDrive}
Expand Down
8 changes: 8 additions & 0 deletions src/utils/filename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,11 @@ export function combine(...parts: string[]): string {

return getPathFromParts(parts);
}

export function constructPath(path: string, folder: string): string {
return path?.endsWith('/') ? path + folder : `${path}/${folder}`;
}

export function rootPathToRelative(path: string): string {
return path.startsWith('/') ? path.substring(1) : path;
}

0 comments on commit 0c04bc2

Please sign in to comment.