Compare commits

..

No commits in common. "b757c1a1da84c6bd2de20b53fa83cfd179cbdb78" and "0960f885dfc063f69bf897b8f3b9a2aabe491dfa" have entirely different histories.

12 changed files with 468 additions and 667 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,19 +18,19 @@
"@uiw/react-codemirror": "^4.22.2", "@uiw/react-codemirror": "^4.22.2",
"axios": "^1.7.2", "axios": "^1.7.2",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^11.0.10", "framer-motion": "^10.18.0",
"js-file-download": "^0.4.12", "js-file-download": "^0.4.12",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13", "react-error-boundary": "^4.0.13",
"react-icons": "^5.2.1", "react-icons": "^4.12.0",
"react-intl": "^6.6.8", "react-intl": "^6.6.8",
"react-loader-spinner": "^6.1.6", "react-loader-spinner": "^5.4.5",
"react-pdf": "^9.0.0", "react-pdf": "^9.0.0",
"react-router-dom": "^6.24.0", "react-router-dom": "^6.24.0",
"react-select": "^5.8.0", "react-select": "^5.8.0",
"react-tabs": "^6.0.2", "react-tabs": "^6.0.2",
"react-toastify": "^10.0.5", "react-toastify": "^9.1.3",
"react-tooltip": "^5.27.0", "react-tooltip": "^5.27.0",
"reagraph": "^4.19.2", "reagraph": "^4.19.2",
"use-debounce": "^10.0.1" "use-debounce": "^10.0.1"
@ -41,21 +41,21 @@
"@types/node": "^20.14.9", "@types/node": "^20.14.9",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.14.1", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^7.14.1", "@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.3.1", "@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7", "eslint-plugin-react-refresh": "^0.4.7",
"eslint-plugin-simple-import-sort": "^12.1.0", "eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.3.0", "eslint-plugin-tsdoc": "^0.2.17",
"jest": "^29.7.0", "jest": "^29.7.0",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"tailwindcss": "^3.4.4", "tailwindcss": "^3.4.4",
"ts-jest": "^29.1.5", "ts-jest": "^29.1.5",
"typescript": "^5.5.2", "typescript": "^5.5.2",
"vite": "^5.3.1" "vite": "^4.5.3"
}, },
"jest": { "jest": {
"preset": "ts-jest", "preset": "ts-jest",

View File

@ -1,5 +1,2 @@
User-agent: * User-agent: *
Disallow: /library Disallow: /library
Disallow: /restore-password
Disallow: /signup
Disallow: /profile

View File

@ -3,8 +3,8 @@ import { useIntl } from 'react-intl';
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable'; import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
import SearchBar from '@/components/ui/SearchBar'; import SearchBar from '@/components/ui/SearchBar';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library'; import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
import { ILibraryFilter } from '@/models/miscellaneous'; import { ILibraryFilter } from '@/models/miscellaneous';

View File

@ -65,7 +65,7 @@ interface LibraryStateProps {
} }
export const LibraryState = ({ children }: LibraryStateProps) => { export const LibraryState = ({ children }: LibraryStateProps) => {
const { user, loading: userLoading } = useAuth(); const { user } = useAuth();
const { adminMode } = useConceptOptions(); const { adminMode } = useConceptOptions();
const [items, setItems] = useState<ILibraryItem[]>([]); const [items, setItems] = useState<ILibraryItem[]>([]);
@ -92,8 +92,8 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
if (!filter.folderMode && filter.head) { if (!filter.folderMode && filter.head) {
result = result.filter(item => item.location.startsWith(filter.head!)); result = result.filter(item => item.location.startsWith(filter.head!));
} }
if (filter.folderMode && filter.location) { if (filter.folderMode && filter.folder) {
result = result.filter(item => item.location == filter.location); result = result.filter(item => item.location == filter.folder);
} }
if (filter.type) { if (filter.type) {
result = result.filter(item => item.item_type === filter.type); result = result.filter(item => item.item_type === filter.type);
@ -175,18 +175,16 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
const reloadTemplates = useCallback(() => { const reloadTemplates = useCallback(() => {
setTemplates([]); setTemplates([]);
getTemplates({ getTemplates({
setLoading: setProcessing, setLoading: setLoading,
onError: setProcessingError, onError: setLoadingError,
showError: true, showError: true,
onSuccess: newData => setTemplates(newData) onSuccess: newData => setTemplates(newData)
}); });
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!userLoading) {
reloadItems(); reloadItems();
} }, [reloadItems]);
}, [reloadItems, userLoading]);
useEffect(() => { useEffect(() => {
reloadTemplates(); reloadTemplates();

View File

@ -4,12 +4,10 @@ import { useCallback, useEffect, useState } from 'react';
import { getOssDetails } from '@/app/backendAPI'; import { getOssDetails } from '@/app/backendAPI';
import { type ErrorData } from '@/components/info/InfoError'; import { type ErrorData } from '@/components/info/InfoError';
import { useAuth } from '@/context/AuthContext';
import { IOperationSchema, IOperationSchemaData } from '@/models/oss'; import { IOperationSchema, IOperationSchemaData } from '@/models/oss';
import { OssLoader } from '@/models/OssLoader'; import { OssLoader } from '@/models/OssLoader';
function useOssDetails({ target }: { target?: string }) { function useOssDetails({ target }: { target?: string }) {
const { loading: userLoading } = useAuth();
const [schema, setInner] = useState<IOperationSchema | undefined>(undefined); const [schema, setInner] = useState<IOperationSchema | undefined>(undefined);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<ErrorData>(undefined); const [error, setError] = useState<ErrorData>(undefined);
@ -46,10 +44,8 @@ function useOssDetails({ target }: { target?: string }) {
); );
useEffect(() => { useEffect(() => {
if (!userLoading) {
reload(); reload();
} }, [reload]);
}, [reload, userLoading]);
return { schema, setSchema, reload, error, setError, loading }; return { schema, setSchema, reload, error, setError, loading };
} }

View File

@ -4,12 +4,10 @@ import { useCallback, useEffect, useState } from 'react';
import { getRSFormDetails } from '@/app/backendAPI'; import { getRSFormDetails } from '@/app/backendAPI';
import { type ErrorData } from '@/components/info/InfoError'; import { type ErrorData } from '@/components/info/InfoError';
import { useAuth } from '@/context/AuthContext';
import { IRSForm, IRSFormData } from '@/models/rsform'; import { IRSForm, IRSFormData } from '@/models/rsform';
import { RSFormLoader } from '@/models/RSFormLoader'; import { RSFormLoader } from '@/models/RSFormLoader';
function useRSFormDetails({ target, version }: { target?: string; version?: string }) { function useRSFormDetails({ target, version }: { target?: string; version?: string }) {
const { loading: userLoading } = useAuth();
const [schema, setInnerSchema] = useState<IRSForm | undefined>(undefined); const [schema, setInnerSchema] = useState<IRSForm | undefined>(undefined);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<ErrorData>(undefined); const [error, setError] = useState<ErrorData>(undefined);
@ -46,10 +44,8 @@ function useRSFormDetails({ target, version }: { target?: string; version?: stri
); );
useEffect(() => { useEffect(() => {
if (!userLoading) {
reload(); reload();
} }, [reload]);
}, [reload, userLoading]);
return { schema, setSchema, reload, error, setError, loading }; return { schema, setSchema, reload, error, setError, loading };
} }

View File

@ -144,10 +144,11 @@ export interface ILibraryFilter {
type?: LibraryItemType; type?: LibraryItemType;
query?: string; query?: string;
folderMode?: boolean;
path?: string; path?: string;
head?: LocationHead; head?: LocationHead;
location?: string;
folderMode?: boolean;
folder?: string;
isVisible?: boolean; isVisible?: boolean;
isOwned?: boolean; isOwned?: boolean;

View File

@ -14,7 +14,7 @@ import { toggleTristateFlag } from '@/utils/utils';
import TableLibraryItems from './TableLibraryItems'; import TableLibraryItems from './TableLibraryItems';
import ToolbarSearch from './ToolbarSearch'; import ToolbarSearch from './ToolbarSearch';
import ViewSideLocation from './ViewSideLocation'; import ViewSideFolders from './ViewSideFolders';
function LibraryPage() { function LibraryPage() {
const library = useLibrary(); const library = useLibrary();
@ -26,7 +26,7 @@ function LibraryPage() {
const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined); const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined);
const [folderMode, setFolderMode] = useLocalStorage<boolean>(storage.librarySearchFolderMode, true); const [folderMode, setFolderMode] = useLocalStorage<boolean>(storage.librarySearchFolderMode, true);
const [location, setLocation] = useLocalStorage<string>(storage.librarySearchLocation, ''); const [folder, setFolder] = useLocalStorage<string>(storage.librarySearchFolder, '');
const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true); const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true);
const [isSubscribed, setIsSubscribed] = useLocalStorage<boolean | undefined>( const [isSubscribed, setIsSubscribed] = useLocalStorage<boolean | undefined>(
storage.librarySearchSubscribed, storage.librarySearchSubscribed,
@ -45,9 +45,9 @@ function LibraryPage() {
isSubscribed: user ? isSubscribed : undefined, isSubscribed: user ? isSubscribed : undefined,
isVisible: user ? isVisible : true, isVisible: user ? isVisible : true,
folderMode: folderMode, folderMode: folderMode,
location: location folder: folder
}), }),
[head, path, query, isEditor, isOwned, isSubscribed, isVisible, user, folderMode, location] [head, path, query, isEditor, isOwned, isSubscribed, isVisible, user, folderMode, folder]
); );
const hasCustomFilter = useMemo( const hasCustomFilter = useMemo(
@ -59,13 +59,13 @@ function LibraryPage() {
filter.isOwned !== undefined || filter.isOwned !== undefined ||
filter.isSubscribed !== undefined || filter.isSubscribed !== undefined ||
filter.isVisible !== true || filter.isVisible !== true ||
!!filter.location, !!filter.folder,
[filter] [filter]
); );
useLayoutEffect(() => { useLayoutEffect(() => {
setItems(library.applyFilter(filter)); setItems(library.applyFilter(filter));
}, [library, library.items.length, filter]); }, [library, filter, filter.query]);
const toggleVisible = useCallback(() => setIsVisible(prev => toggleTristateFlag(prev)), [setIsVisible]); const toggleVisible = useCallback(() => setIsVisible(prev => toggleTristateFlag(prev)), [setIsVisible]);
const toggleOwned = useCallback(() => setIsOwned(prev => toggleTristateFlag(prev)), [setIsOwned]); const toggleOwned = useCallback(() => setIsOwned(prev => toggleTristateFlag(prev)), [setIsOwned]);
@ -81,13 +81,13 @@ function LibraryPage() {
setIsSubscribed(undefined); setIsSubscribed(undefined);
setIsOwned(undefined); setIsOwned(undefined);
setIsEditor(undefined); setIsEditor(undefined);
setLocation(''); setFolder('');
}, [setHead, setIsVisible, setIsSubscribed, setIsOwned, setIsEditor, setLocation]); }, [setHead, setIsVisible, setIsSubscribed, setIsOwned, setIsEditor, setFolder]);
const viewLibrary = useMemo( const view = useMemo(
() => ( () => (
<TableLibraryItems <TableLibraryItems
resetQuery={resetFilter} resetQuery={resetFilter} // prettier: split lines
items={items} items={items}
folderMode={folderMode} folderMode={folderMode}
toggleFolderMode={toggleFolderMode} toggleFolderMode={toggleFolderMode}
@ -96,18 +96,6 @@ function LibraryPage() {
[resetFilter, items, folderMode, toggleFolderMode] [resetFilter, items, folderMode, toggleFolderMode]
); );
const viewLocations = useMemo(
() => (
<ViewSideLocation
active={location}
setActive={setLocation}
folderTree={library.folders}
toggleFolderMode={toggleFolderMode}
/>
),
[location, library.folders, setLocation, toggleFolderMode]
);
return ( return (
<DataLoader <DataLoader
id='library-page' // prettier: split lines id='library-page' // prettier: split lines
@ -139,8 +127,17 @@ function LibraryPage() {
/> />
<div className='flex'> <div className='flex'>
<AnimatePresence initial={false}>{folderMode ? viewLocations : null}</AnimatePresence> <AnimatePresence initial={false}>
{viewLibrary} {folderMode ? (
<ViewSideFolders
currentFolder={folder} // prettier: split-lines
setFolder={setFolder}
folders={library.folders}
toggleFolderMode={toggleFolderMode}
/>
) : null}
</AnimatePresence>
{view}
</div> </div>
</DataLoader> </DataLoader>
); );

View File

@ -161,7 +161,7 @@ function TableLibraryItems({ items, resetQuery, folderMode, toggleFolderMode }:
columns={columns} columns={columns}
data={items} data={items}
headPosition='0' headPosition='0'
className={clsx('text-xs sm:text-sm cc-scroll-y h-fit', { 'border-l border-b': folderMode })} className={clsx('text-xs sm:text-sm cc-scroll-y', { 'border-l border-b': folderMode })}
style={{ maxHeight: tableHeight }} style={{ maxHeight: tableHeight }}
noDataComponent={ noDataComponent={
<FlexColumn className='dense p-3 items-center min-h-[6rem]'> <FlexColumn className='dense p-3 items-center min-h-[6rem]'>

View File

@ -14,14 +14,14 @@ import { animateSideView } from '@/styling/animations';
import { PARAMETER, prefixes } from '@/utils/constants'; import { PARAMETER, prefixes } from '@/utils/constants';
import { information } from '@/utils/labels'; import { information } from '@/utils/labels';
interface ViewSideLocationProps { interface ViewSideFoldersProps {
folderTree: FolderTree; folders: FolderTree;
active: string; currentFolder: string;
setActive: React.Dispatch<React.SetStateAction<string>>; setFolder: React.Dispatch<React.SetStateAction<string>>;
toggleFolderMode: () => void; toggleFolderMode: () => void;
} }
function ViewSideLocation({ folderTree, active, setActive: setActive, toggleFolderMode }: ViewSideLocationProps) { function ViewSideFolders({ folders, currentFolder, setFolder, toggleFolderMode }: ViewSideFoldersProps) {
const handleClickFolder = useCallback( const handleClickFolder = useCallback(
(event: CProps.EventMouse, target: FolderNode) => { (event: CProps.EventMouse, target: FolderNode) => {
event.preventDefault(); event.preventDefault();
@ -32,10 +32,10 @@ function ViewSideLocation({ folderTree, active, setActive: setActive, toggleFold
.then(() => toast.success(information.pathReady)) .then(() => toast.success(information.pathReady))
.catch(console.error); .catch(console.error);
} else { } else {
setActive(target.getPath()); setFolder(target.getPath());
} }
}, },
[setActive] [setFolder]
); );
return ( return (
@ -59,8 +59,8 @@ function ViewSideLocation({ folderTree, active, setActive: setActive, toggleFold
/> />
</div> </div>
<SelectLocation <SelectLocation
value={active} value={currentFolder}
folderTree={folderTree} folderTree={folders}
prefix={prefixes.folders_list} prefix={prefixes.folders_list}
onClick={handleClickFolder} onClick={handleClickFolder}
/> />
@ -68,4 +68,4 @@ function ViewSideLocation({ folderTree, active, setActive: setActive, toggleFold
); );
} }
export default ViewSideLocation; export default ViewSideFolders;

View File

@ -95,7 +95,7 @@ export const storage = {
librarySearchHead: 'library.search.head', librarySearchHead: 'library.search.head',
librarySearchFolderMode: 'library.search.folder_mode', librarySearchFolderMode: 'library.search.folder_mode',
librarySearchLocation: 'library.search.location', librarySearchFolder: 'library.search.folder',
librarySearchVisible: 'library.search.visible', librarySearchVisible: 'library.search.visible',
librarySearchOwned: 'library.search.owned', librarySearchOwned: 'library.search.owned',
librarySearchSubscribed: 'library.search.subscribed', librarySearchSubscribed: 'library.search.subscribed',