R: Add eslint-plugin-react-hooks and fix issues

This commit is contained in:
Ivan 2024-10-23 16:20:29 +03:00
parent 3b036f2c9d
commit 731ca12308
26 changed files with 413 additions and 480 deletions

View File

@ -59,6 +59,7 @@ This readme file is used mostly to document project dependencies and conventions
- postcss - postcss
- autoprefixer - autoprefixer
- eslint-plugin-simple-import-sort - eslint-plugin-simple-import-sort
- eslint-plugin-react-hooks
- eslint-plugin-tsdoc - eslint-plugin-tsdoc
- vite - vite
- jest - jest

View File

@ -2,8 +2,7 @@ import globals from 'globals';
import typescriptPlugin from 'typescript-eslint'; import typescriptPlugin from 'typescript-eslint';
import typescriptParser from '@typescript-eslint/parser'; import typescriptParser from '@typescript-eslint/parser';
import reactPlugin from 'eslint-plugin-react'; import reactPlugin from 'eslint-plugin-react';
// import { fixupPluginRules } from '@eslint/compat'; import reactHooksPlugin from 'eslint-plugin-react-hooks';
// import reactHooksPlugin from 'eslint-plugin-react-hooks';
import simpleImportSort from 'eslint-plugin-simple-import-sort'; import simpleImportSort from 'eslint-plugin-simple-import-sort';
@ -35,7 +34,7 @@ export default [
{ {
plugins: { plugins: {
'react': reactPlugin, 'react': reactPlugin,
// 'react-hooks': fixupPluginRules(reactHooksPlugin), 'react-hooks': reactHooksPlugin,
'simple-import-sort': simpleImportSort 'simple-import-sort': simpleImportSort
}, },
settings: { react: { version: 'detect' } }, settings: { react: { version: 'detect' } },
@ -56,7 +55,9 @@ export default [
'react-refresh/only-export-components': ['off', { allowConstantExport: true }], 'react-refresh/only-export-components': ['off', { allowConstantExport: true }],
'simple-import-sort/imports': 'warn', 'simple-import-sort/imports': 'warn',
'simple-import-sort/exports': 'error' 'simple-import-sort/exports': 'error',
...reactHooksPlugin.configs.recommended.rules
} }
}, },
{ {

File diff suppressed because it is too large Load Diff

View File

@ -18,14 +18,15 @@
"@uiw/react-codemirror": "^4.23.5", "@uiw/react-codemirror": "^4.23.5",
"axios": "^1.7.7", "axios": "^1.7.7",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^11.5.6", "eslint-plugin-react-hooks": "^5.0.0",
"framer-motion": "^11.11.9",
"html-to-image": "^1.11.11", "html-to-image": "^1.11.11",
"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.1.1", "react-error-boundary": "^4.1.2",
"react-icons": "^5.3.0", "react-icons": "^5.3.0",
"react-intl": "^6.8.0", "react-intl": "^6.8.1",
"react-loader-spinner": "^6.1.6", "react-loader-spinner": "^6.1.6",
"react-router-dom": "^6.27.0", "react-router-dom": "^6.27.0",
"react-select": "^5.8.1", "react-select": "^5.8.1",
@ -39,16 +40,16 @@
}, },
"devDependencies": { "devDependencies": {
"@lezer/generator": "^1.7.1", "@lezer/generator": "^1.7.1",
"@types/jest": "^29.5.13", "@types/jest": "^29.5.14",
"@types/node": "^22.7.6", "@types/node": "^22.7.9",
"@types/react": "^18.3.11", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@typescript-eslint/eslint-plugin": "^8.0.1", "@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1", "@typescript-eslint/parser": "^8.0.1",
"@vitejs/plugin-react": "^4.3.2", "@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^9.12.0", "eslint": "^9.13.0",
"eslint-plugin-react": "^7.37.1", "eslint-plugin-react": "^7.37.2",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"globals": "^15.11.0", "globals": "^15.11.0",
"jest": "^29.7.0", "jest": "^29.7.0",
@ -56,8 +57,8 @@
"tailwindcss": "^3.4.14", "tailwindcss": "^3.4.14",
"ts-jest": "^29.2.5", "ts-jest": "^29.2.5",
"typescript": "^5.6.3", "typescript": "^5.6.3",
"typescript-eslint": "^8.9.0", "typescript-eslint": "^8.11.0",
"vite": "^5.4.9" "vite": "^5.4.10"
}, },
"jest": { "jest": {
"preset": "ts-jest", "preset": "ts-jest",

View File

@ -61,7 +61,7 @@ function PickMultiConstituenta({
newGraph.foldNode(item.id); newGraph.foldNode(item.id);
}); });
return newGraph; return newGraph;
}, [schema.graph, data]); }, [data, schema.graph, schema.items]);
useLayoutEffect(() => { useLayoutEffect(() => {
if (filtered.length === 0) { if (filtered.length === 0) {

View File

@ -63,7 +63,7 @@ function PickSchema({
); );
} }
setFiltered(newFiltered); setFiltered(newFiltered);
}, [filterText, filterLocation]); }, [filterText, filterLocation, baseFiltered]);
const columns = useMemo( const columns = useMemo(
() => [ () => [

View File

@ -146,7 +146,7 @@ function DataTable<TData extends RowData>({
colSizes[`--col-${header.column.id}-size`] = header.column.getSize(); colSizes[`--col-${header.column.id}-size`] = header.column.getSize();
} }
return colSizes; return colSizes;
}, [tableImpl.getState().columnSizingInfo, tableImpl.getState().columnSizing]); }, [tableImpl]);
return ( return (
<div tabIndex={-1} id={id} className={className} style={{ minHeight: fixedSize, maxHeight: fixedSize, ...style }}> <div tabIndex={-1} id={id} className={className} style={{ minHeight: fixedSize, maxHeight: fixedSize, ...style }}>

View File

@ -18,7 +18,7 @@ function AnimateFade({ style, noFadeIn, noFadeOut, children, hideContent, ...res
animate={hideContent ? 'hidden' : 'active'} animate={hideContent ? 'hidden' : 'active'}
variants={animateFade.variants} variants={animateFade.variants}
exit={{ ...(!noFadeOut ? animateFade.exit : {}) }} exit={{ ...(!noFadeOut ? animateFade.exit : {}) }}
style={{ display: hideContent ? 'none' : '', ...style }} style={{ display: hideContent ? 'none' : '', willChange: 'auto', ...style }}
{...restProps} {...restProps}
> >
{children} {children}

View File

@ -238,7 +238,7 @@ export const LibraryState = ({ children }: React.PropsWithChildren) => {
}); });
} }
}, },
[reloadItems, user] [reloadItems]
); );
const destroyItem = useCallback( const destroyItem = useCallback(
@ -254,7 +254,7 @@ export const LibraryState = ({ children }: React.PropsWithChildren) => {
}) })
}); });
}, },
[reloadItems, user] [reloadItems]
); );
const cloneItem = useCallback( const cloneItem = useCallback(
@ -291,7 +291,7 @@ export const LibraryState = ({ children }: React.PropsWithChildren) => {
}) })
}); });
}, },
[reloadItems, user] [reloadItems]
); );
return ( return (

View File

@ -94,7 +94,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
useEffect(() => { useEffect(() => {
oss.setID(itemID); oss.setID(itemID);
}, [itemID, oss.setID]); }, [itemID, oss]);
const update = useCallback( const update = useCallback(
(data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => { (data: ILibraryUpdateData, callback?: DataCallback<ILibraryItem>) => {
@ -115,7 +115,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.localUpdateItem, oss.setData] [itemID, model, library, oss]
); );
const setOwner = useCallback( const setOwner = useCallback(
@ -139,7 +139,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems] [itemID, model, library]
); );
const setAccessPolicy = useCallback( const setAccessPolicy = useCallback(
@ -163,7 +163,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems] [itemID, model, library]
); );
const setLocation = useCallback( const setLocation = useCallback(
@ -187,7 +187,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems] [itemID, model, library]
); );
const setEditors = useCallback( const setEditors = useCallback(
@ -211,7 +211,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems] [itemID, model, library]
); );
const savePositions = useCallback( const savePositions = useCallback(
@ -228,7 +228,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, library.localUpdateTimestamp] [itemID, library]
); );
const createOperation = useCallback( const createOperation = useCallback(
@ -246,7 +246,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, library.localUpdateTimestamp, oss.setData] [itemID, library, oss]
); );
const deleteOperation = useCallback( const deleteOperation = useCallback(
@ -265,7 +265,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, library.reloadItems, oss.setData] [itemID, library, oss]
); );
const createInput = useCallback( const createInput = useCallback(
@ -284,7 +284,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, library.reloadItems, oss.setData] [itemID, library, oss]
); );
const setInput = useCallback( const setInput = useCallback(
@ -306,7 +306,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems, oss.setData] [itemID, model, library, oss]
); );
const updateOperation = useCallback( const updateOperation = useCallback(
@ -328,7 +328,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems, oss.setData] [itemID, model, library, oss]
); );
const executeOperation = useCallback( const executeOperation = useCallback(
@ -350,7 +350,7 @@ export const OssState = ({ itemID, children }: React.PropsWithChildren<OssStateP
} }
}); });
}, },
[itemID, model, library.reloadItems, oss.setData] [itemID, model, library, oss]
); );
return ( return (

View File

@ -151,7 +151,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, schema, library.localUpdateItem, oss.invalidateItem] [itemID, setSchema, schema, library, oss]
); );
const upload = useCallback( const upload = useCallback(
@ -172,7 +172,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, schema, library.localUpdateItem] [itemID, setSchema, schema, library]
); );
const setOwner = useCallback( const setOwner = useCallback(
@ -195,7 +195,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, schema, library.localUpdateItem] [itemID, schema, library]
); );
const setAccessPolicy = useCallback( const setAccessPolicy = useCallback(
@ -218,7 +218,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, schema, library.localUpdateItem] [itemID, schema, library]
); );
const setLocation = useCallback( const setLocation = useCallback(
@ -240,7 +240,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, schema, library.reloadItems] [itemID, schema, library]
); );
const setEditors = useCallback( const setEditors = useCallback(
@ -283,7 +283,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, schema, user, setSchema, library.localUpdateTimestamp, oss.invalidateItem] [itemID, schema, user, setSchema, library, oss]
); );
const restoreOrder = useCallback( const restoreOrder = useCallback(
@ -303,7 +303,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, schema, user, setSchema, library.localUpdateTimestamp] [itemID, schema, user, setSchema, library]
); );
const produceStructure = useCallback( const produceStructure = useCallback(
@ -322,7 +322,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[setSchema, itemID, library.localUpdateTimestamp, oss.invalidateItem] [setSchema, itemID, library, oss]
); );
const download = useCallback( const download = useCallback(
@ -354,7 +354,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, library.localUpdateTimestamp, oss.invalidateItem] [itemID, setSchema, library, oss]
); );
const cstDelete = useCallback( const cstDelete = useCallback(
@ -373,7 +373,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, library.localUpdateTimestamp, oss.invalidateItem] [itemID, setSchema, library, oss]
); );
const cstUpdate = useCallback( const cstUpdate = useCallback(
@ -392,7 +392,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
}) })
}); });
}, },
[itemID, reload, library.localUpdateTimestamp, oss.invalidateItem] [itemID, reload, library, oss]
); );
const cstRename = useCallback( const cstRename = useCallback(
@ -411,7 +411,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[setSchema, itemID, library.localUpdateTimestamp, oss.invalidateItem] [setSchema, itemID, library, oss]
); );
const cstSubstitute = useCallback( const cstSubstitute = useCallback(
@ -430,7 +430,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[setSchema, itemID, library.localUpdateTimestamp, oss.invalidateItem] [setSchema, itemID, library, oss]
); );
const cstMoveTo = useCallback( const cstMoveTo = useCallback(
@ -448,7 +448,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, library.localUpdateTimestamp] [itemID, setSchema, library]
); );
const versionCreate = useCallback( const versionCreate = useCallback(
@ -466,7 +466,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, library.localUpdateTimestamp] [itemID, setSchema, library]
); );
const findPredecessor = useCallback((data: ITargetCst, callback: (reference: IConstituentaReference) => void) => { const findPredecessor = useCallback((data: ITargetCst, callback: (reference: IConstituentaReference) => void) => {
@ -537,7 +537,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[setSchema, library.localUpdateItem] [setSchema, library]
); );
const inlineSynthesis = useCallback( const inlineSynthesis = useCallback(
@ -556,7 +556,7 @@ export const RSFormState = ({ itemID, versionID, children }: React.PropsWithChil
} }
}); });
}, },
[itemID, setSchema, library.localUpdateTimestamp, oss.invalidateItem] [setSchema, library, oss]
); );
return ( return (

View File

@ -44,7 +44,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
const handleTypeChange = useCallback( const handleTypeChange = useCallback(
(target: CstType) => partialUpdate({ cst_type: target, alias: generateAlias(target, schema) }), (target: CstType) => partialUpdate({ cst_type: target, alias: generateAlias(target, schema) }),
[partialUpdate, schema, generateAlias] [partialUpdate, schema]
); );
return ( return (

View File

@ -62,6 +62,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
const cache = useRSFormCache(); const cache = useRSFormCache();
const schemas = useMemo( const schemas = useMemo(
() => schemasIDs.map(id => cache.getSchema(id)).filter(item => item !== undefined), () => schemasIDs.map(id => cache.getSchema(id)).filter(item => item !== undefined),
// eslint-disable-next-line react-hooks/exhaustive-deps
[schemasIDs, cache.getSchema] [schemasIDs, cache.getSchema]
); );
@ -90,6 +91,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
useLayoutEffect(() => { useLayoutEffect(() => {
cache.preload(schemasIDs); cache.preload(schemasIDs);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [schemasIDs]); }, [schemasIDs]);
useLayoutEffect(() => { useLayoutEffect(() => {
@ -109,6 +111,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
return true; return true;
}) })
); );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [schemasIDs, schemas, cache.loading]); }, [schemasIDs, schemas, cache.loading]);
useLayoutEffect(() => { useLayoutEffect(() => {

View File

@ -61,7 +61,7 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
<TabSchema selected={donorID} setSelected={setDonorID} receiver={receiver} /> <TabSchema selected={donorID} setSelected={setDonorID} receiver={receiver} />
</TabPanel> </TabPanel>
), ),
[donorID] [donorID, receiver]
); );
const itemsPanel = useMemo( const itemsPanel = useMemo(
() => ( () => (

View File

@ -30,7 +30,7 @@ function DlgRelocateConstituents({ oss, hideWindow, target, onSubmit }: DlgReloc
...node.outputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null) ...node.outputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
]; ];
return ids.map(id => library.items.find(item => item.id === id)).filter(item => item !== undefined); return ids.map(id => library.items.find(item => item.id === id)).filter(item => item !== undefined);
}, [oss, library.items]); }, [oss, library.items, target.id]);
const [destination, setDestination] = useState<ILibraryItem | undefined>(undefined); const [destination, setDestination] = useState<ILibraryItem | undefined>(undefined);
const [selected, setSelected] = useState<ConstituentaID[]>([]); const [selected, setSelected] = useState<ConstituentaID[]>([]);
@ -42,7 +42,7 @@ function DlgRelocateConstituents({ oss, hideWindow, target, onSubmit }: DlgReloc
} }
const destinationOperation = oss.items.find(item => item.result === destination.id); const destinationOperation = oss.items.find(item => item.result === destination.id);
return getRelocateCandidates(target.id, destinationOperation!.id, source.schema, oss); return getRelocateCandidates(target.id, destinationOperation!.id, source.schema, oss);
}, [destination, source.schema?.items]); }, [destination, target.id, source.schema, oss]);
const isValid = useMemo(() => !!destination && selected.length > 0, [destination, selected]); const isValid = useMemo(() => !!destination && selected.length > 0, [destination, selected]);

View File

@ -15,14 +15,17 @@ function useOssDetails({ target, items }: { target?: string; items: ILibraryItem
const [loading, setLoading] = useState(target != undefined); const [loading, setLoading] = useState(target != undefined);
const [error, setError] = useState<ErrorData>(undefined); const [error, setError] = useState<ErrorData>(undefined);
function setSchema(data?: IOperationSchemaData) { const setSchema = useCallback(
(data?: IOperationSchemaData) => {
if (!data) { if (!data) {
setInner(undefined); setInner(undefined);
return; return;
} }
const newSchema = new OssLoader(data, items).produceOSS(); const newSchema = new OssLoader(data, items).produceOSS();
setInner(newSchema); setInner(newSchema);
} },
[items]
);
const reload = useCallback( const reload = useCallback(
(setCustomLoading?: typeof setLoading, callback?: () => void) => { (setCustomLoading?: typeof setLoading, callback?: () => void) => {
@ -43,7 +46,7 @@ function useOssDetails({ target, items }: { target?: string; items: ILibraryItem
} }
}); });
}, },
[target] [target, setSchema]
); );
useEffect(() => { useEffect(() => {

View File

@ -76,6 +76,7 @@ function useRSFormCache() {
} }
}) })
); );
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pending]); }, [pending]);
return { preload, getSchema, getConstituenta, getSchemaByCst, loading, error, setError }; return { preload, getSchema, getConstituenta, getSchemaByCst, loading, error, setError };

View File

@ -1,19 +1,20 @@
'use client'; 'use client';
import { useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
function useWindowSize() { function useWindowSize() {
const isClient = typeof window === 'object'; const isClient = typeof window === 'object';
function getSize() { const getSize = useCallback(
return { () => ({
width: isClient ? window.innerWidth : undefined, width: isClient ? window.innerWidth : undefined,
height: isClient ? window.innerHeight : undefined, height: isClient ? window.innerHeight : undefined,
isSmall: isClient && window.innerWidth < PARAMETER.smallScreen isSmall: isClient && window.innerWidth < PARAMETER.smallScreen
}; }),
} [isClient]
);
const [windowSize, setWindowSize] = useState(getSize); const [windowSize, setWindowSize] = useState(getSize);
@ -26,7 +27,7 @@ function useWindowSize() {
} }
window.addEventListener('resize', handleResize); window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize);
}, []); }, [isClient, getSize]);
return windowSize; return windowSize;
} }

View File

@ -90,7 +90,7 @@ function LibraryPage() {
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]);
const toggleEditor = useCallback(() => setIsEditor(prev => toggleTristateFlag(prev)), [setIsEditor]); const toggleEditor = useCallback(() => setIsEditor(prev => toggleTristateFlag(prev)), [setIsEditor]);
const toggleFolderMode = useCallback(() => options.setFolderMode(prev => !prev), [options.setFolderMode]); const toggleFolderMode = useCallback(() => options.setFolderMode(prev => !prev), [options]);
const toggleSubfolders = useCallback(() => setSubfolders(prev => !prev), [setSubfolders]); const toggleSubfolders = useCallback(() => setSubfolders(prev => !prev), [setSubfolders]);
const resetFilter = useCallback(() => { const resetFilter = useCallback(() => {
@ -102,7 +102,7 @@ function LibraryPage() {
setIsEditor(undefined); setIsEditor(undefined);
setFilterUser(undefined); setFilterUser(undefined);
options.setLocation(''); options.setLocation('');
}, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options.setLocation]); }, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options]);
const promptRenameLocation = useCallback(() => { const promptRenameLocation = useCallback(() => {
setShowRenameLocation(true); setShowRenameLocation(true);
@ -119,7 +119,7 @@ function LibraryPage() {
toast.success(information.locationRenamed); toast.success(information.locationRenamed);
}); });
}, },
[location, library] [options, library]
); );
const handleDownloadCSV = useCallback(() => { const handleDownloadCSV = useCallback(() => {
@ -159,7 +159,15 @@ function LibraryPage() {
onRenameLocation={promptRenameLocation} onRenameLocation={promptRenameLocation}
/> />
), ),
[options.location, library.folders, options.setLocation, toggleFolderMode, subfolders] [
options.location,
library.folders,
options.setLocation,
toggleFolderMode,
promptRenameLocation,
toggleSubfolders,
subfolders
]
); );
return ( return (

View File

@ -19,6 +19,13 @@ function ManualsPage() {
const { mainHeight } = useConceptOptions(); const { mainHeight } = useConceptOptions();
const onSelectTopic = useCallback(
(newTopic: HelpTopic) => {
router.push(urls.help_topic(newTopic));
},
[router]
);
if (!Object.values(HelpTopic).includes(activeTopic)) { if (!Object.values(HelpTopic).includes(activeTopic)) {
setTimeout(() => { setTimeout(() => {
router.push(urls.page404); router.push(urls.page404);
@ -27,13 +34,6 @@ function ManualsPage() {
return null; return null;
} }
const onSelectTopic = useCallback(
(newTopic: HelpTopic) => {
router.push(urls.help_topic(newTopic));
},
[router]
);
return ( return (
<div className='flex mx-auto max-w-[80rem]' role='manuals' style={{ minHeight: mainHeight }}> <div className='flex mx-auto max-w-[80rem]' role='manuals' style={{ minHeight: mainHeight }}>
<TopicsList activeTopic={activeTopic} onChangeTopic={topic => onSelectTopic(topic)} /> <TopicsList activeTopic={activeTopic} onChangeTopic={topic => onSelectTopic(topic)} />

View File

@ -145,13 +145,6 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
[controller, getPositions, flow] [controller, getPositions, flow]
); );
const handleDeleteSelected = useCallback(() => {
if (controller.selected.length !== 1) {
return;
}
handleDeleteOperation(controller.selected[0]);
}, [controller, getPositions]);
const handleDeleteOperation = useCallback( const handleDeleteOperation = useCallback(
(target: OperationID) => { (target: OperationID) => {
if (!controller.canDelete(target)) { if (!controller.canDelete(target)) {
@ -162,6 +155,13 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
[controller, getPositions] [controller, getPositions]
); );
const handleDeleteSelected = useCallback(() => {
if (controller.selected.length !== 1) {
return;
}
handleDeleteOperation(controller.selected[0]);
}, [controller, handleDeleteOperation]);
const handleCreateInput = useCallback( const handleCreateInput = useCallback(
(target: OperationID) => { (target: OperationID) => {
controller.createInput(target, getPositions()); controller.createInput(target, getPositions());
@ -282,7 +282,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
handleEditOperation(Number(node.id)); handleEditOperation(Number(node.id));
} }
}, },
[handleEditOperation, controller.openOperationSchema] [handleEditOperation, controller]
); );
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) { function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {

View File

@ -288,14 +288,11 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const promptDeleteOperation = useCallback( const promptDeleteOperation = useCallback((target: OperationID, positions: IOperationPosition[]) => {
(target: OperationID, positions: IOperationPosition[]) => {
setPositions(positions); setPositions(positions);
setTargetOperationID(target); setTargetOperationID(target);
setShowDeleteOperation(true); setShowDeleteOperation(true);
}, }, []);
[model]
);
const deleteOperation = useCallback( const deleteOperation = useCallback(
(keepConstituents: boolean, deleteSchema: boolean) => { (keepConstituents: boolean, deleteSchema: boolean) => {
@ -363,22 +360,16 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const promptRelocateConstituents = useCallback( const promptRelocateConstituents = useCallback((target: OperationID) => {
(target: OperationID) => {
setTargetOperationID(target); setTargetOperationID(target);
setShowRelocateConstituents(true); setShowRelocateConstituents(true);
}, }, []);
[model]
);
const handleRelocateConstituents = useCallback( const handleRelocateConstituents = useCallback((data: ICstRelocateData) => {
(data: ICstRelocateData) => {
// TODO: implement backed call // TODO: implement backed call
console.log(data); console.log(data);
toast.success('В разработке'); toast.success('В разработке');
}, }, []);
[model]
);
return ( return (
<OssEditContext.Provider <OssEditContext.Provider

View File

@ -169,7 +169,11 @@ function FormConstituenta({
) : null} ) : null}
{state ? ( {state ? (
<AnimatePresence> <AnimatePresence>
<AnimateFade key='cst_expression_fade' hideContent={!state.definition_formal && isElementary}> <AnimateFade
key='cst_expression_fade'
hideContent={!state.definition_formal && isElementary}
style={{ willChange: 'auto' }}
>
<EditorRSExpression <EditorRSExpression
id='cst_expression' id='cst_expression'
label={ label={

View File

@ -95,8 +95,7 @@ function EditorRSExpression({
}); });
} }
const onShowError = useCallback( const onShowError = useCallback((error: IRSErrorDescription, prefixLen: number) => {
(error: IRSErrorDescription, prefixLen: number) => {
if (!rsInput.current) { if (!rsInput.current) {
return; return;
} }
@ -109,9 +108,7 @@ function EditorRSExpression({
} }
}); });
rsInput.current?.view?.focus(); rsInput.current?.view?.focus();
}, }, []);
[activeCst]
);
const handleEdit = useCallback((id: TokenID, key?: string) => { const handleEdit = useCallback((id: TokenID, key?: string) => {
if (!rsInput.current?.editor || !rsInput.current.state || !rsInput.current.view) { if (!rsInput.current?.editor || !rsInput.current.state || !rsInput.current.view) {

View File

@ -38,7 +38,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
const { accessLevel } = useAccessMode(); const { accessLevel } = useAccessMode();
const intl = useIntl(); const intl = useIntl();
const router = useConceptNavigation(); const router = useConceptNavigation();
const options = useConceptOptions(); const { setLocation, setFolderMode } = useConceptOptions();
const ownerSelector = useDropdown(); const ownerSelector = useDropdown();
const onSelectUser = useCallback( const onSelectUser = useCallback(
@ -60,11 +60,11 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
if (!item) { if (!item) {
return; return;
} }
options.setLocation(item.location); setLocation(item.location);
options.setFolderMode(true); setFolderMode(true);
router.push(urls.library, event.ctrlKey || event.metaKey); router.push(urls.library, event.ctrlKey || event.metaKey);
}, },
[options.setLocation, options.setFolderMode, item, router] [setLocation, setFolderMode, item, router]
); );
if (!item) { if (!item) {

View File

@ -341,7 +341,7 @@ export const RSEditState = ({
toast.success(information.newVersion(data.version)); toast.success(information.newVersion(data.version));
}); });
}, },
[model, viewVersion] [model]
); );
const handleDeleteVersion = useCallback( const handleDeleteVersion = useCallback(