Skip to content

Commit

Permalink
Showing 19 changed files with 815 additions and 103 deletions.
35 changes: 35 additions & 0 deletions src/boot/app/app-loader-functions.ts
Original file line number Diff line number Diff line change
@@ -58,6 +58,24 @@ import {
useUpdateCurrentBoard
} from '../../shell/boards/board-hooks';
import { getSoapFetch, getXmlSoapFetch } from '../../network/fetch';
import {
getFolder,
getFolders,
useFolder,
useFolders,
useRoot,
getRoot,
useRoots,
getRoots,
useSearch,
useSearches,
getSearch,
getSearches,
useFoldersAccordionByView,
useFoldersByView,
useRootByUser,
getRootByUser
} from '../../store/folder';
import { getTags, useTags } from '../../store/tags';
import { useNotify, useRefresh } from '../../store/network';
import { changeTagColor, createTag, deleteTag, renameTag } from '../../network/tags';
@@ -103,6 +121,23 @@ export const getAppFunctions = (pkg: CarbonioModule): Record<string, Function> =
getTags,
useNotify,
useRefresh,
// FOLDERS
useFoldersAccordionByView,
useFoldersByView,
useFolder,
getFolder,
useFolders,
getFolders,
useRoot,
getRoot,
useRoots,
getRoots,
useSearch,
useSearches,
getSearch,
getSearches,
useRootByUser,
getRootByUser,
// BOARDS
useAddBoardCallback: getUseAddBoardCallback(pkg.name),
useUpdateCurrentBoard,
2 changes: 2 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -79,3 +79,5 @@ export const BASENAME = `/carbonio/`;
export const EMAIL_VALIDATION_REGEX =
// eslint-disable-next-line @typescript-eslint/no-unused-vars, max-len, no-control-regex
/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;

export const ROOT_NAME = 'USER_ROOT';
6 changes: 5 additions & 1 deletion src/network/fetch.ts
Original file line number Diff line number Diff line change
@@ -116,8 +116,12 @@ const handleResponse = <R>(api: string, res: SoapResponse<R>): R => {
useAccountStore.setState({
usedQuota: responseUsedQuota ?? usedQuota
});
const nextPollingInterval = (res?.Body as { waitDisallowed?: number })?.waitDisallowed
? 10000
: pollingInterval;
useNetworkStore.setState({
noOpTimeout: setTimeout(() => noOp(), pollingInterval),
noOpTimeout: setTimeout(() => noOp(), nextPollingInterval),
pollingInterval: nextPollingInterval,
seq,
..._context
});
84 changes: 84 additions & 0 deletions src/store/folder/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* SPDX-FileCopyrightText: 2021 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { ComponentType, useMemo } from 'react';
import {
Folders,
Searches,
SearchFolder,
Folder,
AccordionFolder,
FolderView
} from '../../../types';
import { useFolderStore } from './store';
import { filterNodes, folderViewFilter, mapNodes, sortFolders } from './utils';

// FOLDERS
export const useFolder = (id: string): Folder | undefined => useFolderStore((s) => s.folders?.[id]);
export const getFolder = (id: string): Folder | undefined =>
useFolderStore.getState()?.folders?.[id];
export const useFolders = (): Folders => useFolderStore((s) => s.folders);
export const getFolders = (): Folders => useFolderStore.getState().folders;

// ROOTS
export const useRoot = (id: string): Folder | undefined => useFolderStore((s) => s.roots?.[id]);
export const getRoot = (id: string): Folder | undefined => useFolderStore.getState().roots?.[id];
export const useRoots = (): Folders => useFolderStore((s) => s.roots);
export const getRoots = (): Folders => useFolderStore.getState().roots;

// ROOTS BY VIEW
export const useRootByUser = (userId: string): Folder | SearchFolder | Record<string, never> =>
useFolderStore((s) => (s.roots ? s.roots[userId] : {}));
export const getRootByUser = (userId: string): Folder | SearchFolder | Record<string, never> => {
const folders = useFolderStore.getState();
return folders.roots ? folders.roots[userId] : {};
};

// SEARCHES

export const useSearch = (id: string): SearchFolder | undefined =>
useFolderStore((s) => s.searches?.[id]);
export const getSearch = (id: string): SearchFolder | undefined =>
useFolderStore.getState().searches[id];
export const useSearches = (): Searches => useFolderStore((s) => s.searches);
export const getSearches = (): Searches => useFolderStore.getState().searches;

// Accordion-ize

export const useFoldersByView = (view: FolderView): Array<Folder> => {
const roots = useRoots();
const filtered = useMemo(
() => (roots ? filterNodes<Folder>(Object.values(roots), folderViewFilter(view)) : []),
[roots, view]
);
return filtered;
};

export const useFoldersAccordionByView = (
view: FolderView,
customComponent: ComponentType<{ folder: Folder }>
): Array<AccordionFolder> => {
const roots = useRoots();
const mapped = useMemo(
() =>
roots
? mapNodes<Folder, AccordionFolder>(Object.values(roots), {
mapFunction: (f) => ({
id: f.id,
label: f.name,
customComponent,
items: [],
folder: f
}),
filterFunction: folderViewFilter(view),
recursionKey: 'items',
sortFunction: sortFolders
})
: [],
[customComponent, roots, view]
);
return mapped;
};
8 changes: 8 additions & 0 deletions src/store/folder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/

export * from './store';
export * from './hooks';
19 changes: 19 additions & 0 deletions src/store/folder/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2022 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/

import create, { StoreApi, UseBoundStore } from 'zustand';
import { FolderState } from '../../../types';
import { folderWorker } from '../../workers';

export const useFolderStore = create<FolderState>(() => ({
folders: {},
roots: {},
searches: {}
})) as UseBoundStore<FolderState, StoreApi<FolderState>>;

folderWorker.onmessage = ({ data }): void => {
useFolderStore.setState(data);
};
70 changes: 70 additions & 0 deletions src/store/folder/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2022 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { sortBy } from 'lodash';
import { Folder, FolderView, LinkFolder, TreeNode } from '../../../types';
import { FOLDERS, ROOT_NAME } from '../../constants';

const hasId = (f: Folder, id: string): boolean => f.id.split(':').includes(id);
const getOriginalId = (f: Folder): string => {
const parts = f.id.split(':');
return parts[1] ?? parts[0];
};
export const sortFolders = (f: Folder): string => {
const id = getOriginalId(f);
if (id === FOLDERS.TRASH) {
return '~';
}
// should work fine
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return id < 17 ? id : f.name.toLowerCase();
};

export const isTrash = (f: Folder): boolean => hasId(f, FOLDERS.TRASH);

export const isRoot = (f: Folder): boolean =>
f.id === FOLDERS.USER_ROOT || (f as LinkFolder).oname === ROOT_NAME;

export const folderViewFilter =
(v: FolderView) =>
(f: Folder, r?: boolean): boolean =>
f.view === v || isTrash(f) || (isRoot(f) && !r);

export const filterNodes = <T>(
children: TreeNode<T>[],
f: (i: TreeNode<T>) => boolean
): TreeNode<T>[] =>
children.filter(f).map((i) => ({ ...i, children: filterNodes<TreeNode<T>>(i.children, f) }));

type MapNodesOptions<T, U> = {
mapFunction: (i: TreeNode<T>) => U;
filterFunction: (i: TreeNode<T>, inRecursion?: boolean) => boolean;
recursionKey: keyof U;
sortFunction: (i: TreeNode<T>) => number | string;
};
export const mapNodes = <T, U>(
children: TreeNode<T>[],
{ mapFunction, filterFunction, recursionKey, sortFunction }: MapNodesOptions<T, U>,
inRecursion?: boolean
): U[] =>
sortBy(children, sortFunction).reduce((acc, folder) => {
if (filterFunction(folder, inRecursion)) {
acc.push({
...mapFunction(folder),
[recursionKey]: mapNodes<TreeNode<T>, U>(
folder.children,
{
mapFunction,
filterFunction,
recursionKey,
sortFunction
},
true
)
});
}
return acc;
}, [] as U[]);
12 changes: 11 additions & 1 deletion src/store/network/utils.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@ import { SoapContext } from '../../../types';
// import { getSoapFetch } from '../../network/fetch';
// import { useNetworkStore } from './store';

import { tagWorker } from '../../workers';
import { folderWorker, tagWorker } from '../../workers';
import { useFolderStore } from '../folder';
import { useTagStore } from '../tags';
import { useNetworkStore } from './store';

@@ -24,6 +25,10 @@ export const handleSync = ({ refresh, notify }: SoapContext): Promise<void> =>
op: 'refresh',
tags: refresh.tags?.tag ?? []
});
folderWorker.postMessage({
op: 'refresh',
folder: refresh.folder ?? []
});
}
if (notify?.length) {
forEach(notify, (item) => {
@@ -33,6 +38,11 @@ export const handleSync = ({ refresh, notify }: SoapContext): Promise<void> =>
notify: item,
state: useTagStore.getState().tags
});
folderWorker.postMessage({
op: 'notify',
notify: item,
state: useFolderStore.getState().folders
});
}
});
}
Loading

0 comments on commit 3e135ca

Please sign in to comment.