R: Remove unused useMemo and useCallback
This commit is contained in:
parent
dc7a0025c9
commit
6f922df227
|
@ -6,7 +6,7 @@ import { createTheme } from '@uiw/codemirror-themes';
|
||||||
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import { forwardRef, useCallback, useMemo, useRef } from 'react';
|
import { forwardRef, useRef } from 'react';
|
||||||
|
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -66,12 +66,10 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
const { darkMode, colors } = useConceptOptions();
|
const { darkMode, colors } = useConceptOptions();
|
||||||
|
|
||||||
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
||||||
const thisRef = useMemo(() => (!ref || typeof ref === 'function' ? internalRef : ref), [internalRef, ref]);
|
const thisRef = !ref || typeof ref === 'function' ? internalRef : ref;
|
||||||
|
|
||||||
const cursor = useMemo(() => (!disabled ? 'cursor-text' : 'cursor-default'), [disabled]);
|
const cursor = !disabled ? 'cursor-text' : 'cursor-default';
|
||||||
const customTheme: Extension = useMemo(
|
const customTheme: Extension = createTheme({
|
||||||
() =>
|
|
||||||
createTheme({
|
|
||||||
theme: darkMode ? 'dark' : 'light',
|
theme: darkMode ? 'dark' : 'light',
|
||||||
settings: {
|
settings: {
|
||||||
fontFamily: 'inherit',
|
fontFamily: 'inherit',
|
||||||
|
@ -90,23 +88,17 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
{ tag: tags.unit, fontSize: '0.75rem' }, // indices
|
{ tag: tags.unit, fontSize: '0.75rem' }, // indices
|
||||||
{ tag: tags.brace, color: colors.fgPurple, fontWeight: '600' } // braces (curly brackets)
|
{ tag: tags.brace, color: colors.fgPurple, fontWeight: '600' } // braces (curly brackets)
|
||||||
]
|
]
|
||||||
}),
|
});
|
||||||
[disabled, colors, darkMode, schema, cursor]
|
|
||||||
);
|
|
||||||
|
|
||||||
const editorExtensions = useMemo(
|
const editorExtensions = [
|
||||||
() => [
|
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
RSLanguage,
|
RSLanguage,
|
||||||
ccBracketMatching(darkMode),
|
ccBracketMatching(darkMode),
|
||||||
...(!schema || !onOpenEdit ? [] : [rsNavigation(schema, onOpenEdit)]),
|
...(!schema || !onOpenEdit ? [] : [rsNavigation(schema, onOpenEdit)]),
|
||||||
...(noTooltip || !schema ? [] : [rsHoverTooltip(schema, onOpenEdit !== undefined)])
|
...(noTooltip || !schema ? [] : [rsHoverTooltip(schema, onOpenEdit !== undefined)])
|
||||||
],
|
];
|
||||||
[darkMode, schema, noTooltip, onOpenEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleInput = useCallback(
|
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
||||||
if (!thisRef.current) {
|
if (!thisRef.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -159,9 +151,7 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[thisRef, onAnalyze, schema]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col gap-2', className, cursor)} style={style}>
|
<div className={clsx('flex flex-col gap-2', className, cursor)} style={style}>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { createTheme } from '@uiw/codemirror-themes';
|
||||||
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import { forwardRef, useCallback, useMemo, useRef, useState } from 'react';
|
import { forwardRef, useRef, useState } from 'react';
|
||||||
|
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -103,12 +103,10 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
const [mainRefs, setMainRefs] = useState<string[]>([]);
|
const [mainRefs, setMainRefs] = useState<string[]>([]);
|
||||||
|
|
||||||
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
||||||
const thisRef = useMemo(() => (!ref || typeof ref === 'function' ? internalRef : ref), [internalRef, ref]);
|
const thisRef = !ref || typeof ref === 'function' ? internalRef : ref;
|
||||||
|
|
||||||
const cursor = useMemo(() => (!disabled ? 'cursor-text' : 'cursor-default'), [disabled]);
|
const cursor = !disabled ? 'cursor-text' : 'cursor-default';
|
||||||
const customTheme: Extension = useMemo(
|
const customTheme: Extension = createTheme({
|
||||||
() =>
|
|
||||||
createTheme({
|
|
||||||
theme: darkMode ? 'dark' : 'light',
|
theme: darkMode ? 'dark' : 'light',
|
||||||
settings: {
|
settings: {
|
||||||
fontFamily: 'inherit',
|
fontFamily: 'inherit',
|
||||||
|
@ -122,20 +120,15 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
{ tag: tags.literal, color: colors.fgTeal, cursor: 'default' }, // SyntacticReference
|
{ tag: tags.literal, color: colors.fgTeal, cursor: 'default' }, // SyntacticReference
|
||||||
{ tag: tags.comment, color: colors.fgRed } // Error
|
{ tag: tags.comment, color: colors.fgRed } // Error
|
||||||
]
|
]
|
||||||
}),
|
});
|
||||||
[disabled, colors, darkMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const editorExtensions = useMemo(
|
const editorExtensions = [
|
||||||
() => [
|
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
EditorView.contentAttributes.of({ spellcheck: 'true' }),
|
EditorView.contentAttributes.of({ spellcheck: 'true' }),
|
||||||
NaturalLanguage,
|
NaturalLanguage,
|
||||||
...(!schema || !onOpenEdit ? [] : [refsNavigation(schema, onOpenEdit)]),
|
...(!schema || !onOpenEdit ? [] : [refsNavigation(schema, onOpenEdit)]),
|
||||||
...(schema ? [refsHoverTooltip(schema, colors, onOpenEdit !== undefined)] : [])
|
...(schema ? [refsHoverTooltip(schema, colors, onOpenEdit !== undefined)] : [])
|
||||||
],
|
];
|
||||||
[schema, colors, onOpenEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
function handleChange(newValue: string) {
|
function handleChange(newValue: string) {
|
||||||
if (onChange) onChange(newValue);
|
if (onChange) onChange(newValue);
|
||||||
|
@ -151,8 +144,7 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
if (onBlur) onBlur(event);
|
if (onBlur) onBlur(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleInput = useCallback(
|
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
||||||
if (!thisRef.current?.view) {
|
if (!thisRef.current?.view) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
@ -183,26 +175,21 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
|
|
||||||
setShowEditor(true);
|
setShowEditor(true);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[thisRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleInputReference = useCallback(
|
function handleInputReference(referenceText: string) {
|
||||||
(referenceText: string) => {
|
|
||||||
if (!thisRef.current?.view) {
|
if (!thisRef.current?.view) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
thisRef.current.view.focus();
|
thisRef.current.view.focus();
|
||||||
const wrap = new CodeMirrorWrapper(thisRef.current as Required<ReactCodeMirrorRef>);
|
const wrap = new CodeMirrorWrapper(thisRef.current as Required<ReactCodeMirrorRef>);
|
||||||
wrap.replaceWith(referenceText);
|
wrap.replaceWith(referenceText);
|
||||||
},
|
}
|
||||||
[thisRef]
|
|
||||||
);
|
|
||||||
|
|
||||||
const hideEditReference = useCallback(() => {
|
function hideEditReference() {
|
||||||
setShowEditor(false);
|
setShowEditor(false);
|
||||||
setTimeout(() => thisRef.current?.view?.focus(), PARAMETER.refreshTimeout);
|
setTimeout(() => thisRef.current?.view?.focus(), PARAMETER.refreshTimeout);
|
||||||
}, [thisRef]);
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col gap-2', cursor)}>
|
<div className={clsx('flex flex-col gap-2', cursor)}>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { createColumnHelper } from '@tanstack/react-table';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import Tooltip from '@/components/ui/Tooltip';
|
import Tooltip from '@/components/ui/Tooltip';
|
||||||
import { OssNodeInternal } from '@/models/miscellaneous';
|
import { OssNodeInternal } from '@/models/miscellaneous';
|
||||||
|
@ -19,8 +18,7 @@ interface TooltipOperationProps {
|
||||||
const columnHelper = createColumnHelper<ICstSubstituteEx>();
|
const columnHelper = createColumnHelper<ICstSubstituteEx>();
|
||||||
|
|
||||||
function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('substitution_term', {
|
columnHelper.accessor('substitution_term', {
|
||||||
id: 'substitution_term',
|
id: 'substitution_term',
|
||||||
size: 200
|
size: 200
|
||||||
|
@ -43,23 +41,7 @@ function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
||||||
id: 'original_term',
|
id: 'original_term',
|
||||||
size: 200
|
size: 200
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const table = useMemo(
|
|
||||||
() => (
|
|
||||||
<DataTable
|
|
||||||
dense
|
|
||||||
noHeader
|
|
||||||
noFooter
|
|
||||||
className='text-sm border select-none mb-2'
|
|
||||||
data={node.data.operation.substitutions}
|
|
||||||
columns={columns}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[columns, node]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip layer='z-modalTooltip' anchorSelect={anchor} className='max-w-[35rem] max-h-[40rem] dense'>
|
<Tooltip layer='z-modalTooltip' anchorSelect={anchor} className='max-w-[35rem] max-h-[40rem] dense'>
|
||||||
|
@ -90,7 +72,14 @@ function TooltipOperation({ node, anchor }: TooltipOperationProps) {
|
||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
{node.data.operation.substitutions.length > 0 ? (
|
{node.data.operation.substitutions.length > 0 ? (
|
||||||
table
|
<DataTable
|
||||||
|
dense
|
||||||
|
noHeader
|
||||||
|
noFooter
|
||||||
|
className='text-sm border select-none mb-2'
|
||||||
|
data={node.data.operation.substitutions}
|
||||||
|
columns={columns}
|
||||||
|
/>
|
||||||
) : node.data.operation.operation_type !== OperationType.INPUT ? (
|
) : node.data.operation.operation_type !== OperationType.INPUT ? (
|
||||||
<p>
|
<p>
|
||||||
<b>Отождествления:</b> Отсутствуют
|
<b>Отождествления:</b> Отсутствуют
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
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';
|
||||||
|
@ -64,8 +64,7 @@ function PickConstituenta({
|
||||||
}
|
}
|
||||||
}, [data, filterText, matchFunc, onBeginFilter]);
|
}, [data, filterText, matchFunc, onBeginFilter]);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
size: 65,
|
size: 65,
|
||||||
|
@ -78,19 +77,14 @@ function PickConstituenta({
|
||||||
size: 1000,
|
size: 1000,
|
||||||
minSize: 1000
|
minSize: 1000
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[colors, prefixID, describeFunc]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<IConstituenta>[] = [
|
||||||
(): IConditionalStyle<IConstituenta>[] => [
|
|
||||||
{
|
{
|
||||||
when: (cst: IConstituenta) => cst.id === value?.id,
|
when: (cst: IConstituenta) => cst.id === value?.id,
|
||||||
style: { backgroundColor: colors.bgSelected }
|
style: { backgroundColor: colors.bgSelected }
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[value, colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('border divide-y', className)} {...restProps}>
|
<div className={clsx('border divide-y', className)} {...restProps}>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import DataTable, { createColumnHelper, RowSelectionState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, RowSelectionState } from '@/components/ui/DataTable';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -49,7 +49,8 @@ function PickMultiConstituenta({
|
||||||
const [filtered, setFiltered] = useState<IConstituenta[]>(data);
|
const [filtered, setFiltered] = useState<IConstituenta[]>(data);
|
||||||
const [filterText, setFilterText] = useState('');
|
const [filterText, setFilterText] = useState('');
|
||||||
|
|
||||||
const foldedGraph = useMemo(() => {
|
// TODO: extract graph fold logic to separate function
|
||||||
|
const foldedGraph = (() => {
|
||||||
if (data.length === schema.items.length) {
|
if (data.length === schema.items.length) {
|
||||||
return schema.graph;
|
return schema.graph;
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,7 @@ function PickMultiConstituenta({
|
||||||
newGraph.foldNode(item.id);
|
newGraph.foldNode(item.id);
|
||||||
});
|
});
|
||||||
return newGraph;
|
return newGraph;
|
||||||
}, [data, schema.graph, schema.items]);
|
})();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
|
@ -105,8 +106,7 @@ function PickMultiConstituenta({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: () => <span className='pl-3'>Имя</span>,
|
header: () => <span className='pl-3'>Имя</span>,
|
||||||
|
@ -118,9 +118,7 @@ function PickMultiConstituenta({
|
||||||
size: 1000,
|
size: 1000,
|
||||||
header: 'Описание'
|
header: 'Описание'
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[colors, prefixID]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(noBorder ? '' : 'border', className)} {...restProps}>
|
<div className={clsx(noBorder ? '' : 'border', className)} {...restProps}>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/Icons';
|
import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/Icons';
|
||||||
import SelectOperation from '@/components/select/SelectOperation';
|
import SelectOperation from '@/components/select/SelectOperation';
|
||||||
|
@ -23,31 +23,23 @@ interface PickMultiOperationProps extends CProps.Styling {
|
||||||
const columnHelper = createColumnHelper<IOperation>();
|
const columnHelper = createColumnHelper<IOperation>();
|
||||||
|
|
||||||
function PickMultiOperation({ rows, items, selected, setSelected, className, ...restProps }: PickMultiOperationProps) {
|
function PickMultiOperation({ rows, items, selected, setSelected, className, ...restProps }: PickMultiOperationProps) {
|
||||||
const selectedItems = useMemo(
|
const selectedItems = selected.map(itemID => items.find(item => item.id === itemID)!);
|
||||||
() => selected.map(itemID => items.find(item => item.id === itemID)!),
|
const nonSelectedItems = items.filter(item => !selected.includes(item.id));
|
||||||
[items, selected]
|
|
||||||
);
|
|
||||||
const nonSelectedItems = useMemo(() => items.filter(item => !selected.includes(item.id)), [items, selected]);
|
|
||||||
const [lastSelected, setLastSelected] = useState<IOperation | undefined>(undefined);
|
const [lastSelected, setLastSelected] = useState<IOperation | undefined>(undefined);
|
||||||
|
|
||||||
const handleDelete = useCallback(
|
function handleDelete(operation: OperationID) {
|
||||||
(operation: OperationID) => setSelected(prev => prev.filter(item => item !== operation)),
|
setSelected(prev => prev.filter(item => item !== operation));
|
||||||
[setSelected]
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const handleSelect = useCallback(
|
function handleSelect(operation?: IOperation) {
|
||||||
(operation?: IOperation) => {
|
|
||||||
if (operation) {
|
if (operation) {
|
||||||
setLastSelected(operation);
|
setLastSelected(operation);
|
||||||
setSelected(prev => [...prev, operation.id]);
|
setSelected(prev => [...prev, operation.id]);
|
||||||
setTimeout(() => setLastSelected(undefined), 1000);
|
setTimeout(() => setLastSelected(undefined), 1000);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[setSelected]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMoveUp = useCallback(
|
function handleMoveUp(operation: OperationID) {
|
||||||
(operation: OperationID) => {
|
|
||||||
const index = selected.indexOf(operation);
|
const index = selected.indexOf(operation);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
setSelected(prev => {
|
setSelected(prev => {
|
||||||
|
@ -57,12 +49,9 @@ function PickMultiOperation({ rows, items, selected, setSelected, className, ...
|
||||||
return newSelected;
|
return newSelected;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[setSelected, selected]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMoveDown = useCallback(
|
function handleMoveDown(operation: OperationID) {
|
||||||
(operation: OperationID) => {
|
|
||||||
const index = selected.indexOf(operation);
|
const index = selected.indexOf(operation);
|
||||||
if (index < selected.length - 1) {
|
if (index < selected.length - 1) {
|
||||||
setSelected(prev => {
|
setSelected(prev => {
|
||||||
|
@ -72,12 +61,9 @@ function PickMultiOperation({ rows, items, selected, setSelected, className, ...
|
||||||
return newSelected;
|
return newSelected;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[setSelected, selected]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: 'Шифр',
|
header: 'Шифр',
|
||||||
|
@ -122,9 +108,7 @@ function PickMultiOperation({ rows, items, selected, setSelected, className, ...
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[handleDelete, handleMoveUp, handleMoveDown]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
|
||||||
|
@ -51,10 +51,7 @@ function PickSchema({
|
||||||
const [filterText, setFilterText] = useState(initialFilter);
|
const [filterText, setFilterText] = useState(initialFilter);
|
||||||
const [filterLocation, setFilterLocation] = useState('');
|
const [filterLocation, setFilterLocation] = useState('');
|
||||||
const [filtered, setFiltered] = useState<ILibraryItem[]>([]);
|
const [filtered, setFiltered] = useState<ILibraryItem[]>([]);
|
||||||
const baseFiltered = useMemo(
|
const baseFiltered = items.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item)));
|
||||||
() => items.filter(item => item.item_type === itemType && (!baseFilter || baseFilter(item))),
|
|
||||||
[items, itemType, baseFilter]
|
|
||||||
);
|
|
||||||
|
|
||||||
const locationMenu = useDropdown();
|
const locationMenu = useDropdown();
|
||||||
|
|
||||||
|
@ -68,8 +65,7 @@ function PickSchema({
|
||||||
setFiltered(newFiltered);
|
setFiltered(newFiltered);
|
||||||
}, [filterText, filterLocation, baseFiltered]);
|
}, [filterText, filterLocation, baseFiltered]);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: 'Шифр',
|
header: 'Шифр',
|
||||||
|
@ -98,29 +94,21 @@ function PickSchema({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[intl]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
|
||||||
(): IConditionalStyle<ILibraryItem>[] => [
|
|
||||||
{
|
{
|
||||||
when: (item: ILibraryItem) => item.id === value,
|
when: (item: ILibraryItem) => item.id === value,
|
||||||
style: { backgroundColor: colors.bgSelected }
|
style: { backgroundColor: colors.bgSelected }
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[value, colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleLocationClick = useCallback(
|
function handleLocationClick(event: CProps.EventMouse, newValue: string) {
|
||||||
(event: CProps.EventMouse, newValue: string) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
locationMenu.hide();
|
locationMenu.hide();
|
||||||
setFilterLocation(newValue);
|
setFilterLocation(newValue);
|
||||||
},
|
}
|
||||||
[locationMenu]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('border divide-y', className)} {...restProps}>
|
<div className={clsx('border divide-y', className)} {...restProps}>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
|
@ -62,42 +62,12 @@ function PickSubstitutions({
|
||||||
const toggleDelete = () => setDeleteRight(prev => !prev);
|
const toggleDelete = () => setDeleteRight(prev => !prev);
|
||||||
|
|
||||||
const [ignores, setIgnores] = useState<ICstSubstitute[]>([]);
|
const [ignores, setIgnores] = useState<ICstSubstitute[]>([]);
|
||||||
const filteredSuggestions = useMemo(
|
const filteredSuggestions =
|
||||||
() =>
|
|
||||||
suggestions?.filter(
|
suggestions?.filter(
|
||||||
item => !ignores.find(ignore => ignore.original === item.original && ignore.substitution === item.substitution)
|
item => !ignores.find(ignore => ignore.original === item.original && ignore.substitution === item.substitution)
|
||||||
) ?? [],
|
) ?? [];
|
||||||
[ignores, suggestions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getSchemaByCst = useCallback(
|
const substitutionData: IMultiSubstitution[] = [
|
||||||
(id: ConstituentaID): IRSForm | undefined => {
|
|
||||||
for (const schema of schemas) {
|
|
||||||
const cst = schema.cstByID.get(id);
|
|
||||||
if (cst) {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
[schemas]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getConstituenta = useCallback(
|
|
||||||
(id: ConstituentaID): IConstituenta | undefined => {
|
|
||||||
for (const schema of schemas) {
|
|
||||||
const cst = schema.cstByID.get(id);
|
|
||||||
if (cst) {
|
|
||||||
return cst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
[schemas]
|
|
||||||
);
|
|
||||||
|
|
||||||
const substitutionData: IMultiSubstitution[] = useMemo(
|
|
||||||
() => [
|
|
||||||
...substitutions.map(item => ({
|
...substitutions.map(item => ({
|
||||||
original_source: getSchemaByCst(item.original)!,
|
original_source: getSchemaByCst(item.original)!,
|
||||||
original: getConstituenta(item.original)!,
|
original: getConstituenta(item.original)!,
|
||||||
|
@ -112,9 +82,27 @@ function PickSubstitutions({
|
||||||
substitution_source: getSchemaByCst(item.substitution)!,
|
substitution_source: getSchemaByCst(item.substitution)!,
|
||||||
is_suggestion: true
|
is_suggestion: true
|
||||||
}))
|
}))
|
||||||
],
|
];
|
||||||
[getConstituenta, getSchemaByCst, substitutions, filteredSuggestions]
|
|
||||||
);
|
function getSchemaByCst(id: ConstituentaID): IRSForm | undefined {
|
||||||
|
for (const schema of schemas) {
|
||||||
|
const cst = schema.cstByID.get(id);
|
||||||
|
if (cst) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getConstituenta(id: ConstituentaID): IConstituenta | undefined {
|
||||||
|
for (const schema of schemas) {
|
||||||
|
const cst = schema.cstByID.get(id);
|
||||||
|
if (cst) {
|
||||||
|
return cst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function addSubstitution() {
|
function addSubstitution() {
|
||||||
if (!leftCst || !rightCst) {
|
if (!leftCst || !rightCst) {
|
||||||
|
@ -145,22 +133,15 @@ function PickSubstitutions({
|
||||||
setRightCst(undefined);
|
setRightCst(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDeclineSuggestion = useCallback(
|
function handleDeclineSuggestion(item: IMultiSubstitution) {
|
||||||
(item: IMultiSubstitution) => {
|
|
||||||
setIgnores(prev => [...prev, { original: item.original.id, substitution: item.substitution.id }]);
|
setIgnores(prev => [...prev, { original: item.original.id, substitution: item.substitution.id }]);
|
||||||
},
|
}
|
||||||
[setIgnores]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAcceptSuggestion = useCallback(
|
function handleAcceptSuggestion(item: IMultiSubstitution) {
|
||||||
(item: IMultiSubstitution) => {
|
|
||||||
setSubstitutions(prev => [...prev, { original: item.original.id, substitution: item.substitution.id }]);
|
setSubstitutions(prev => [...prev, { original: item.original.id, substitution: item.substitution.id }]);
|
||||||
},
|
}
|
||||||
[setSubstitutions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDeleteSubstitution = useCallback(
|
function handleDeleteSubstitution(target: IMultiSubstitution) {
|
||||||
(target: IMultiSubstitution) => {
|
|
||||||
handleDeclineSuggestion(target);
|
handleDeclineSuggestion(target);
|
||||||
setSubstitutions(prev => {
|
setSubstitutions(prev => {
|
||||||
const newItems: ICstSubstitute[] = [];
|
const newItems: ICstSubstitute[] = [];
|
||||||
|
@ -171,12 +152,9 @@ function PickSubstitutions({
|
||||||
});
|
});
|
||||||
return newItems;
|
return newItems;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
[setSubstitutions, handleDeclineSuggestion]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor(item => item.substitution_source.alias, {
|
columnHelper.accessor(item => item.substitution_source.alias, {
|
||||||
id: 'left_schema',
|
id: 'left_schema',
|
||||||
size: 100,
|
size: 100,
|
||||||
|
@ -244,21 +222,16 @@ function PickSubstitutions({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[handleDeleteSubstitution, handleDeclineSuggestion, handleAcceptSuggestion, colors, prefixID]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<IMultiSubstitution>[] = [
|
||||||
(): IConditionalStyle<IMultiSubstitution>[] => [
|
|
||||||
{
|
{
|
||||||
when: (item: IMultiSubstitution) => item.is_suggestion,
|
when: (item: IMultiSubstitution) => item.is_suggestion,
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: colors.bgOrange50
|
backgroundColor: colors.bgOrange50
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col', className)} {...restProps}>
|
<div className={clsx('flex flex-col', className)} {...restProps}>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { CstMatchMode } from '@/models/miscellaneous';
|
import { CstMatchMode } from '@/models/miscellaneous';
|
||||||
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
||||||
|
@ -28,22 +27,16 @@ function SelectConstituenta({
|
||||||
placeholder = 'Выберите конституенту',
|
placeholder = 'Выберите конституенту',
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectConstituentaProps) {
|
}: SelectConstituentaProps) {
|
||||||
const options = useMemo(() => {
|
const options =
|
||||||
return (
|
|
||||||
items?.map(cst => ({
|
items?.map(cst => ({
|
||||||
value: cst.id,
|
value: cst.id,
|
||||||
label: `${cst.alias}${cst.is_inherited ? '*' : ''}: ${describeConstituenta(cst)}`
|
label: `${cst.alias}${cst.is_inherited ? '*' : ''}: ${describeConstituenta(cst)}`
|
||||||
})) ?? []
|
})) ?? [];
|
||||||
);
|
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
const filter = useCallback(
|
function filter(option: { value: ConstituentaID | undefined; label: string }, inputValue: string) {
|
||||||
(option: { value: ConstituentaID | undefined; label: string }, inputValue: string) => {
|
|
||||||
const cst = items?.find(item => item.id === option.value);
|
const cst = items?.find(item => item.id === option.value);
|
||||||
return !cst ? false : matchConstituenta(cst, inputValue, CstMatchMode.ALL);
|
return !cst ? false : matchConstituenta(cst, inputValue, CstMatchMode.ALL);
|
||||||
},
|
}
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
||||||
import { matchLibraryItem } from '@/models/libraryAPI';
|
import { matchLibraryItem } from '@/models/libraryAPI';
|
||||||
|
@ -26,22 +25,16 @@ function SelectLibraryItem({
|
||||||
placeholder = 'Выберите схему',
|
placeholder = 'Выберите схему',
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectLibraryItemProps) {
|
}: SelectLibraryItemProps) {
|
||||||
const options = useMemo(() => {
|
const options =
|
||||||
return (
|
|
||||||
items?.map(cst => ({
|
items?.map(cst => ({
|
||||||
value: cst.id,
|
value: cst.id,
|
||||||
label: `${cst.alias}: ${cst.title}`
|
label: `${cst.alias}: ${cst.title}`
|
||||||
})) ?? []
|
})) ?? [];
|
||||||
);
|
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
const filter = useCallback(
|
function filter(option: { value: LibraryItemID | undefined; label: string }, inputValue: string) {
|
||||||
(option: { value: LibraryItemID | undefined; label: string }, inputValue: string) => {
|
|
||||||
const item = items?.find(item => item.id === option.value);
|
const item = items?.find(item => item.id === option.value);
|
||||||
return !item ? false : matchLibraryItem(item, inputValue);
|
return !item ? false : matchLibraryItem(item, inputValue);
|
||||||
},
|
}
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
||||||
import { labelFolderNode } from '@/utils/labels';
|
import { labelFolderNode } from '@/utils/labels';
|
||||||
|
@ -19,17 +19,15 @@ interface SelectLocationProps extends CProps.Styling {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectLocation({ value, folderTree, dense, prefix, onClick, className, style }: SelectLocationProps) {
|
function SelectLocation({ value, folderTree, dense, prefix, onClick, className, style }: SelectLocationProps) {
|
||||||
const activeNode = useMemo(() => folderTree.at(value), [folderTree, value]);
|
const activeNode = folderTree.at(value);
|
||||||
|
const items = folderTree.getTree();
|
||||||
const items = useMemo(() => folderTree.getTree(), [folderTree]);
|
|
||||||
const [folded, setFolded] = useState<FolderNode[]>(items);
|
const [folded, setFolded] = useState<FolderNode[]>(items);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFolded(items.filter(item => item !== activeNode && !activeNode?.hasPredecessor(item)));
|
setFolded(items.filter(item => item !== activeNode && !activeNode?.hasPredecessor(item)));
|
||||||
}, [items, activeNode]);
|
}, [items, activeNode]);
|
||||||
|
|
||||||
const onFoldItem = useCallback(
|
function onFoldItem(target: FolderNode, showChildren: boolean) {
|
||||||
(target: FolderNode, showChildren: boolean) => {
|
|
||||||
setFolded(prev =>
|
setFolded(prev =>
|
||||||
items.filter(item => {
|
items.filter(item => {
|
||||||
if (item === target) {
|
if (item === target) {
|
||||||
|
@ -42,18 +40,13 @@ function SelectLocation({ value, folderTree, dense, prefix, onClick, className,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickFold = useCallback(
|
function handleClickFold(event: CProps.EventMouse, target: FolderNode, showChildren: boolean) {
|
||||||
(event: CProps.EventMouse, target: FolderNode, showChildren: boolean) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onFoldItem(target, showChildren);
|
onFoldItem(target, showChildren);
|
||||||
},
|
}
|
||||||
[onFoldItem]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('flex flex-col', 'cc-scroll-y', className)} style={style}>
|
<div className={clsx('flex flex-col', 'cc-scroll-y', className)} style={style}>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IOperation, OperationID } from '@/models/oss';
|
import { IOperation, OperationID } from '@/models/oss';
|
||||||
import { matchOperation } from '@/models/ossAPI';
|
import { matchOperation } from '@/models/ossAPI';
|
||||||
|
@ -26,22 +25,16 @@ function SelectOperation({
|
||||||
placeholder = 'Выберите операцию',
|
placeholder = 'Выберите операцию',
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectOperationProps) {
|
}: SelectOperationProps) {
|
||||||
const options = useMemo(() => {
|
const options =
|
||||||
return (
|
|
||||||
items?.map(cst => ({
|
items?.map(cst => ({
|
||||||
value: cst.id,
|
value: cst.id,
|
||||||
label: `${cst.alias}: ${cst.title}`
|
label: `${cst.alias}: ${cst.title}`
|
||||||
})) ?? []
|
})) ?? [];
|
||||||
);
|
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
const filter = useCallback(
|
function filter(option: { value: OperationID | undefined; label: string }, inputValue: string) {
|
||||||
(option: { value: OperationID | undefined; label: string }, inputValue: string) => {
|
|
||||||
const operation = items?.find(item => item.id === option.value);
|
const operation = items?.find(item => item.id === option.value);
|
||||||
return !operation ? false : matchOperation(operation, inputValue);
|
return !operation ? false : matchOperation(operation, inputValue);
|
||||||
},
|
}
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { useUsers } from '@/context/UsersContext';
|
import { useUsers } from '@/context/UsersContext';
|
||||||
import { IUserInfo, UserID } from '@/models/user';
|
import { IUserInfo, UserID } from '@/models/user';
|
||||||
|
@ -28,22 +27,16 @@ function SelectUser({
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectUserProps) {
|
}: SelectUserProps) {
|
||||||
const { getUserLabel } = useUsers();
|
const { getUserLabel } = useUsers();
|
||||||
const options = useMemo(() => {
|
const options =
|
||||||
return (
|
|
||||||
items?.map(user => ({
|
items?.map(user => ({
|
||||||
value: user.id,
|
value: user.id,
|
||||||
label: getUserLabel(user.id)
|
label: getUserLabel(user.id)
|
||||||
})) ?? []
|
})) ?? [];
|
||||||
);
|
|
||||||
}, [items, getUserLabel]);
|
|
||||||
|
|
||||||
const filter = useCallback(
|
function filter(option: { value: UserID | undefined; label: string }, inputValue: string) {
|
||||||
(option: { value: UserID | undefined; label: string }, inputValue: string) => {
|
|
||||||
const user = items?.find(item => item.id === option.value);
|
const user = items?.find(item => item.id === option.value);
|
||||||
return !user ? false : matchUser(user, inputValue);
|
return !user ? false : matchUser(user, inputValue);
|
||||||
},
|
}
|
||||||
[items]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IVersionInfo, VersionID } from '@/models/library';
|
import { IVersionInfo, VersionID } from '@/models/library';
|
||||||
import { labelVersion } from '@/utils/labels';
|
import { labelVersion } from '@/utils/labels';
|
||||||
|
@ -20,8 +19,7 @@ interface SelectVersionProps extends CProps.Styling {
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectVersion({ id, className, items, value, onSelectValue, ...restProps }: SelectVersionProps) {
|
function SelectVersion({ id, className, items, value, onSelectValue, ...restProps }: SelectVersionProps) {
|
||||||
const options = useMemo(() => {
|
const options = [
|
||||||
return [
|
|
||||||
{
|
{
|
||||||
value: undefined,
|
value: undefined,
|
||||||
label: labelVersion(undefined)
|
label: labelVersion(undefined)
|
||||||
|
@ -31,11 +29,11 @@ function SelectVersion({ id, className, items, value, onSelectValue, ...restProp
|
||||||
label: version.version
|
label: version.version
|
||||||
})) ?? [])
|
})) ?? [])
|
||||||
];
|
];
|
||||||
}, [items]);
|
|
||||||
const valueLabel = useMemo(() => {
|
const valueLabel = (() => {
|
||||||
const version = items?.find(ver => ver.id === value);
|
const version = items?.find(ver => ver.id === value);
|
||||||
return version ? version.version : labelVersion(undefined);
|
return version ? version.version : labelVersion(undefined);
|
||||||
}, [items, value]);
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { globals } from '@/utils/constants';
|
import { globals } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -34,15 +33,7 @@ function Checkbox({
|
||||||
setValue,
|
setValue,
|
||||||
...restProps
|
...restProps
|
||||||
}: CheckboxProps) {
|
}: CheckboxProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = disabled ? 'cursor-arrow' : setValue ? 'cursor-pointer' : '';
|
||||||
if (disabled) {
|
|
||||||
return 'cursor-arrow';
|
|
||||||
} else if (setValue) {
|
|
||||||
return 'cursor-pointer';
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}, [disabled, setValue]);
|
|
||||||
|
|
||||||
function handleClick(event: CProps.EventMouse): void {
|
function handleClick(event: CProps.EventMouse): void {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { globals } from '@/utils/constants';
|
import { globals } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -29,15 +28,7 @@ function CheckboxTristate({
|
||||||
setValue,
|
setValue,
|
||||||
...restProps
|
...restProps
|
||||||
}: CheckboxTristateProps) {
|
}: CheckboxTristateProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = disabled ? 'cursor-arrow' : setValue ? 'cursor-pointer' : '';
|
||||||
if (disabled) {
|
|
||||||
return 'cursor-arrow';
|
|
||||||
} else if (setValue) {
|
|
||||||
return 'cursor-pointer';
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}, [disabled, setValue]);
|
|
||||||
|
|
||||||
function handleClick(event: CProps.EventMouse): void {
|
function handleClick(event: CProps.EventMouse): void {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
|
|
||||||
|
@ -29,10 +27,8 @@ function PDFViewer({ file, offsetXpx, minWidth = MINIMUM_WIDTH }: PDFViewerProps
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const { calculateHeight } = useConceptOptions();
|
const { calculateHeight } = useConceptOptions();
|
||||||
|
|
||||||
const pageWidth = useMemo(() => {
|
const pageWidth = Math.max(minWidth, Math.min((windowSize?.width ?? 0) - (offsetXpx ?? 0) - 10, MAXIMUM_WIDTH));
|
||||||
return Math.max(minWidth, Math.min((windowSize?.width ?? 0) - (offsetXpx ?? 0) - 10, MAXIMUM_WIDTH));
|
const pageHeight = calculateHeight('1rem');
|
||||||
}, [windowSize, offsetXpx, minWidth]);
|
|
||||||
const pageHeight = useMemo(() => calculateHeight('1rem'), [calculateHeight]);
|
|
||||||
|
|
||||||
return <embed src={`${file}#toolbar=0`} className='p-3' style={{ width: pageWidth, height: pageHeight }} />;
|
return <embed src={`${file}#toolbar=0`} className='p-3' style={{ width: pageWidth, height: pageHeight }} />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import Select, {
|
import Select, {
|
||||||
ClearIndicatorProps,
|
ClearIndicatorProps,
|
||||||
components,
|
components,
|
||||||
|
@ -54,10 +53,9 @@ function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>
|
||||||
}: SelectMultiProps<Option, Group>) {
|
}: SelectMultiProps<Option, Group>) {
|
||||||
const { darkMode, colors } = useConceptOptions();
|
const { darkMode, colors } = useConceptOptions();
|
||||||
const size = useWindowSize();
|
const size = useWindowSize();
|
||||||
const themeColors = useMemo(() => (!darkMode ? selectLightT : selectDarkT), [darkMode]);
|
const themeColors = !darkMode ? selectLightT : selectDarkT;
|
||||||
|
|
||||||
const adjustedStyles: StylesConfig<Option, true, Group> = useMemo(
|
const adjustedStyles: StylesConfig<Option, true, Group> = {
|
||||||
() => ({
|
|
||||||
container: defaultStyles => ({
|
container: defaultStyles => ({
|
||||||
...defaultStyles,
|
...defaultStyles,
|
||||||
borderRadius: '0.25rem'
|
borderRadius: '0.25rem'
|
||||||
|
@ -103,9 +101,7 @@ function SelectMulti<Option, Group extends GroupBase<Option> = GroupBase<Option>
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
paddingBottom: 0
|
paddingBottom: 0
|
||||||
})
|
})
|
||||||
}),
|
};
|
||||||
[colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import Select, {
|
import Select, {
|
||||||
ClearIndicatorProps,
|
ClearIndicatorProps,
|
||||||
components,
|
components,
|
||||||
|
@ -56,10 +55,9 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
|
||||||
}: SelectSingleProps<Option, Group>) {
|
}: SelectSingleProps<Option, Group>) {
|
||||||
const { darkMode, colors } = useConceptOptions();
|
const { darkMode, colors } = useConceptOptions();
|
||||||
const size = useWindowSize();
|
const size = useWindowSize();
|
||||||
const themeColors = useMemo(() => (!darkMode ? selectLightT : selectDarkT), [darkMode]);
|
const themeColors = !darkMode ? selectLightT : selectDarkT;
|
||||||
|
|
||||||
const adjustedStyles: StylesConfig<Option, false, Group> = useMemo(
|
const adjustedStyles: StylesConfig<Option, false, Group> = {
|
||||||
() => ({
|
|
||||||
container: defaultStyles => ({
|
container: defaultStyles => ({
|
||||||
...defaultStyles,
|
...defaultStyles,
|
||||||
borderRadius: '0.25rem'
|
borderRadius: '0.25rem'
|
||||||
|
@ -102,9 +100,7 @@ function SelectSingle<Option, Group extends GroupBase<Option> = GroupBase<Option
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
paddingBottom: 0
|
paddingBottom: 0
|
||||||
})
|
})
|
||||||
}),
|
};
|
||||||
[colors, noBorder]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { globals, PARAMETER } from '@/utils/constants';
|
import { globals, PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -44,18 +44,14 @@ function SelectTree<ItemType>({
|
||||||
prefix,
|
prefix,
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectTreeProps<ItemType>) {
|
}: SelectTreeProps<ItemType>) {
|
||||||
const foldable = useMemo(
|
const foldable = new Set(items.filter(item => getParent(item) !== item).map(item => getParent(item)));
|
||||||
() => new Set(items.filter(item => getParent(item) !== item).map(item => getParent(item))),
|
|
||||||
[items, getParent]
|
|
||||||
);
|
|
||||||
const [folded, setFolded] = useState<ItemType[]>(items);
|
const [folded, setFolded] = useState<ItemType[]>(items);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFolded(items.filter(item => getParent(value) !== item && getParent(getParent(value)) !== item));
|
setFolded(items.filter(item => getParent(value) !== item && getParent(getParent(value)) !== item));
|
||||||
}, [value, getParent, items]);
|
}, [value, getParent, items]);
|
||||||
|
|
||||||
const onFoldItem = useCallback(
|
function onFoldItem(target: ItemType, showChildren: boolean) {
|
||||||
(target: ItemType, showChildren: boolean) => {
|
|
||||||
setFolded(prev =>
|
setFolded(prev =>
|
||||||
items.filter(item => {
|
items.filter(item => {
|
||||||
if (item === target) {
|
if (item === target) {
|
||||||
|
@ -68,27 +64,19 @@ function SelectTree<ItemType>({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
[items, getParent]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClickFold = useCallback(
|
function handleClickFold(event: CProps.EventMouse, target: ItemType, showChildren: boolean) {
|
||||||
(event: CProps.EventMouse, target: ItemType, showChildren: boolean) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onFoldItem(target, showChildren);
|
onFoldItem(target, showChildren);
|
||||||
},
|
}
|
||||||
[onFoldItem]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSetValue = useCallback(
|
function handleSetValue(event: CProps.EventMouse, target: ItemType) {
|
||||||
(event: CProps.EventMouse, target: ItemType) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onChangeValue(target);
|
onChangeValue(target);
|
||||||
},
|
}
|
||||||
[onChangeValue]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div {...restProps}>
|
<div {...restProps}>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { globals } from '@/utils/constants';
|
import { globals } from '@/utils/constants';
|
||||||
|
|
||||||
|
@ -50,7 +49,8 @@ function ValueIcon({
|
||||||
onClick,
|
onClick,
|
||||||
...restProps
|
...restProps
|
||||||
}: ValueIconProps) {
|
}: ValueIconProps) {
|
||||||
const isSmall = useMemo(() => !smallThreshold || String(value).length < smallThreshold, [value, smallThreshold]);
|
// TODO: use CSS instead of threshold
|
||||||
|
const isSmall = !smallThreshold || String(value).length < smallThreshold;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { IconReset } from '@/components/Icons';
|
import { IconReset } from '@/components/Icons';
|
||||||
import PickSchema from '@/components/select/PickSchema';
|
import PickSchema from '@/components/select/PickSchema';
|
||||||
|
@ -22,18 +22,16 @@ interface DlgChangeInputSchemaProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeInputSchemaProps) {
|
function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeInputSchemaProps) {
|
||||||
const [selected, setSelected] = useState<LibraryItemID | undefined>(target.result ?? undefined);
|
const [selected, setSelected] = useState<LibraryItemID | undefined>(target.result ?? undefined);
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
const sortedItems = useMemo(() => sortItemsForOSS(oss, library.items), [oss, library.items]);
|
const sortedItems = sortItemsForOSS(oss, library.items);
|
||||||
|
const isValid = target.result !== selected;
|
||||||
|
|
||||||
const baseFilter = useCallback(
|
function baseFilter(item: ILibraryItem) {
|
||||||
(item: ILibraryItem) => !oss.schemas.includes(item.id) || item.id === selected || item.id === target.result,
|
return !oss.schemas.includes(item.id) || item.id === selected || item.id === target.result;
|
||||||
[oss, selected, target]
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const isValid = useMemo(() => target.result !== selected, [target, selected]);
|
function handleSelectLocation(newValue: LibraryItemID) {
|
||||||
|
|
||||||
const handleSelectLocation = useCallback((newValue: LibraryItemID) => {
|
|
||||||
setSelected(newValue);
|
setSelected(newValue);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
import SelectLocationContext from '@/components/select/SelectLocationContext';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
|
@ -26,13 +26,13 @@ function DlgChangeLocation({ hideWindow, initial, onChangeLocation }: DlgChangeL
|
||||||
|
|
||||||
const { folders } = useLibrary();
|
const { folders } = useLibrary();
|
||||||
|
|
||||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
const location = combineLocation(head, body);
|
||||||
const isValid = useMemo(() => initial !== location && validateLocation(location), [initial, location]);
|
const isValid = initial !== location && validateLocation(location);
|
||||||
|
|
||||||
const handleSelectLocation = useCallback((newValue: string) => {
|
function handleSelectLocation(newValue: string) {
|
||||||
setHead(newValue.substring(0, 2) as LocationHead);
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -43,16 +43,16 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
|
|
||||||
const [head, setHead] = useState(initialLocation.substring(0, 2) as LocationHead);
|
const [head, setHead] = useState(initialLocation.substring(0, 2) as LocationHead);
|
||||||
const [body, setBody] = useState(initialLocation.substring(3));
|
const [body, setBody] = useState(initialLocation.substring(3));
|
||||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
const location = combineLocation(head, body);
|
||||||
|
|
||||||
const { cloneItem, folders } = useLibrary();
|
const { cloneItem, folders } = useLibrary();
|
||||||
|
|
||||||
const canSubmit = useMemo(() => title !== '' && alias !== '' && validateLocation(location), [title, alias, location]);
|
const canSubmit = title !== '' && alias !== '' && validateLocation(location);
|
||||||
|
|
||||||
const handleSelectLocation = useCallback((newValue: string) => {
|
function handleSelectLocation(newValue: string) {
|
||||||
setHead(newValue.substring(0, 2) as LocationHead);
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
const data: IRSFormCloneData = {
|
const data: IRSFormCloneData = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
@ -123,35 +123,6 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
setValidated(!!template.prototype && validateNewAlias(constituenta.alias, constituenta.cst_type, schema));
|
setValidated(!!template.prototype && validateNewAlias(constituenta.alias, constituenta.cst_type, schema));
|
||||||
}, [constituenta.alias, constituenta.cst_type, schema, template.prototype]);
|
}, [constituenta.alias, constituenta.cst_type, schema, template.prototype]);
|
||||||
|
|
||||||
const templatePanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabTemplate state={template} partialUpdate={updateTemplate} templateSchema={templateSchema} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[template, templateSchema, updateTemplate]
|
|
||||||
);
|
|
||||||
|
|
||||||
const argumentsPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabArguments schema={schema} state={substitutes} partialUpdate={updateSubstitutes} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[schema, substitutes, updateSubstitutes]
|
|
||||||
);
|
|
||||||
|
|
||||||
const editorPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<div className='cc-fade-in cc-column'>
|
|
||||||
<FormCreateCst state={constituenta} partialUpdate={updateConstituenta} schema={schema} />
|
|
||||||
</div>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[constituenta, updateConstituenta, schema]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header='Создание конституенты из шаблона'
|
header='Создание конституенты из шаблона'
|
||||||
|
@ -175,9 +146,19 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
<TabLabel label='Конституента' title='Редактирование конституенты' className='w-[8rem]' />
|
<TabLabel label='Конституента' title='Редактирование конституенты' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{templatePanel}
|
<TabPanel>
|
||||||
{argumentsPanel}
|
<TabTemplate state={template} partialUpdate={updateTemplate} templateSchema={templateSchema} />
|
||||||
{editorPanel}
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabArguments schema={schema} state={substitutes} partialUpdate={updateSubstitutes} />
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<div className='cc-fade-in cc-column'>
|
||||||
|
<FormCreateCst state={constituenta} partialUpdate={updateConstituenta} schema={schema} />
|
||||||
|
</div>
|
||||||
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { createColumnHelper } from '@tanstack/react-table';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { IconAccept, IconRemove, IconReset } from '@/components/Icons';
|
import { IconAccept, IconRemove, IconReset } from '@/components/Icons';
|
||||||
import RSInput from '@/components/RSInput';
|
import RSInput from '@/components/RSInput';
|
||||||
|
@ -33,13 +33,8 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) {
|
||||||
|
|
||||||
const [selectedCst, setSelectedCst] = useState<IConstituenta | undefined>(undefined);
|
const [selectedCst, setSelectedCst] = useState<IConstituenta | undefined>(undefined);
|
||||||
const [selectedArgument, setSelectedArgument] = useState<IArgumentValue | undefined>(undefined);
|
const [selectedArgument, setSelectedArgument] = useState<IArgumentValue | undefined>(undefined);
|
||||||
|
|
||||||
const [argumentValue, setArgumentValue] = useState('');
|
const [argumentValue, setArgumentValue] = useState('');
|
||||||
|
const isModified = selectedArgument && argumentValue !== selectedArgument.value;
|
||||||
const isModified = useMemo(
|
|
||||||
() => selectedArgument && argumentValue !== selectedArgument.value,
|
|
||||||
[selectedArgument, argumentValue]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedArgument && state.arguments.length > 0) {
|
if (!selectedArgument && state.arguments.length > 0) {
|
||||||
|
@ -47,46 +42,39 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) {
|
||||||
}
|
}
|
||||||
}, [state.arguments, selectedArgument]);
|
}, [state.arguments, selectedArgument]);
|
||||||
|
|
||||||
const handleSelectArgument = useCallback((arg: IArgumentValue) => {
|
function handleSelectArgument(arg: IArgumentValue) {
|
||||||
setSelectedArgument(arg);
|
setSelectedArgument(arg);
|
||||||
if (arg.value) {
|
if (arg.value) {
|
||||||
setArgumentValue(arg.value);
|
setArgumentValue(arg.value);
|
||||||
}
|
}
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleSelectConstituenta = useCallback((cst: IConstituenta) => {
|
function handleSelectConstituenta(cst: IConstituenta) {
|
||||||
setSelectedCst(cst);
|
setSelectedCst(cst);
|
||||||
setArgumentValue(cst.alias);
|
setArgumentValue(cst.alias);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleClearArgument = useCallback(
|
function handleClearArgument(target: IArgumentValue) {
|
||||||
(target: IArgumentValue) => {
|
|
||||||
const newArg = { ...target, value: '' };
|
const newArg = { ...target, value: '' };
|
||||||
partialUpdate({
|
partialUpdate({
|
||||||
arguments: state.arguments.map(arg => (arg.alias !== target.alias ? arg : newArg))
|
arguments: state.arguments.map(arg => (arg.alias !== target.alias ? arg : newArg))
|
||||||
});
|
});
|
||||||
setSelectedArgument(newArg);
|
setSelectedArgument(newArg);
|
||||||
},
|
}
|
||||||
[partialUpdate, state.arguments]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleReset = useCallback(() => {
|
function handleReset() {
|
||||||
setArgumentValue(selectedArgument?.value ?? '');
|
setArgumentValue(selectedArgument?.value ?? '');
|
||||||
}, [selectedArgument]);
|
}
|
||||||
|
|
||||||
const handleAssignArgument = useCallback(
|
function handleAssignArgument(target: IArgumentValue, value: string) {
|
||||||
(target: IArgumentValue, value: string) => {
|
|
||||||
const newArg = { ...target, value: value };
|
const newArg = { ...target, value: value };
|
||||||
partialUpdate({
|
partialUpdate({
|
||||||
arguments: state.arguments.map(arg => (arg.alias !== target.alias ? arg : newArg))
|
arguments: state.arguments.map(arg => (arg.alias !== target.alias ? arg : newArg))
|
||||||
});
|
});
|
||||||
setSelectedArgument(newArg);
|
setSelectedArgument(newArg);
|
||||||
},
|
}
|
||||||
[partialUpdate, state.arguments]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
argumentsHelper.accessor('alias', {
|
argumentsHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
size: 40,
|
size: 40,
|
||||||
|
@ -131,19 +119,14 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[handleClearArgument]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<IArgumentValue>[] = [
|
||||||
(): IConditionalStyle<IArgumentValue>[] => [
|
|
||||||
{
|
{
|
||||||
when: (arg: IArgumentValue) => arg.alias === selectedArgument?.alias,
|
when: (arg: IArgumentValue) => arg.alias === selectedArgument?.alias,
|
||||||
style: { backgroundColor: colors.bgSelected }
|
style: { backgroundColor: colors.bgSelected }
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[selectedArgument, colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in'>
|
<div className='cc-fade-in'>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Dispatch, useEffect, useMemo, useState } from 'react';
|
import { Dispatch, useEffect, useState } from 'react';
|
||||||
|
|
||||||
import RSInput from '@/components/RSInput';
|
import RSInput from '@/components/RSInput';
|
||||||
import PickConstituenta from '@/components/select/PickConstituenta';
|
import PickConstituenta from '@/components/select/PickConstituenta';
|
||||||
|
@ -28,36 +28,23 @@ function TabTemplate({ state, partialUpdate, templateSchema }: TabTemplateProps)
|
||||||
|
|
||||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>([]);
|
const [filteredData, setFilteredData] = useState<IConstituenta[]>([]);
|
||||||
|
|
||||||
const prototypeInfo = useMemo(() => {
|
const prototypeInfo = !state.prototype
|
||||||
if (!state.prototype) {
|
? ''
|
||||||
return '';
|
: `${state.prototype?.term_raw}${state.prototype?.definition_raw ? ` — ${state.prototype?.definition_raw}` : ''}`;
|
||||||
} else {
|
|
||||||
return `${state.prototype?.term_raw}${
|
|
||||||
state.prototype?.definition_raw ? ` — ${state.prototype?.definition_raw}` : ''
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
}, [state.prototype]);
|
|
||||||
|
|
||||||
const templateSelector = useMemo(
|
const templateSelector = templates.map(template => ({
|
||||||
() =>
|
|
||||||
templates.map(template => ({
|
|
||||||
value: template.id,
|
value: template.id,
|
||||||
label: template.title
|
label: template.title
|
||||||
})),
|
}));
|
||||||
[templates]
|
|
||||||
);
|
|
||||||
|
|
||||||
const categorySelector = useMemo((): { value: number; label: string }[] => {
|
const categorySelector: { value: number; label: string }[] = !templateSchema
|
||||||
if (!templateSchema) {
|
? []
|
||||||
return [];
|
: templateSchema.items
|
||||||
}
|
|
||||||
return templateSchema.items
|
|
||||||
.filter(cst => cst.cst_type === CATEGORY_CST_TYPE)
|
.filter(cst => cst.cst_type === CATEGORY_CST_TYPE)
|
||||||
.map(cst => ({
|
.map(cst => ({
|
||||||
value: cst.id,
|
value: cst.id,
|
||||||
label: cst.term_raw
|
label: cst.term_raw
|
||||||
}));
|
}));
|
||||||
}, [templateSchema]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (templates.length > 0 && !state.templateID) {
|
if (templates.length > 0 && !state.templateID) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
import RSInput from '@/components/RSInput';
|
import RSInput from '@/components/RSInput';
|
||||||
|
@ -26,9 +26,9 @@ interface FormCreateCstProps {
|
||||||
function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreateCstProps) {
|
function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreateCstProps) {
|
||||||
const [forceComment, setForceComment] = useState(false);
|
const [forceComment, setForceComment] = useState(false);
|
||||||
|
|
||||||
const isBasic = useMemo(() => isBasicConcept(state.cst_type), [state]);
|
const isBasic = isBasicConcept(state.cst_type);
|
||||||
const isElementary = useMemo(() => isBaseSet(state.cst_type), [state]);
|
const isElementary = isBaseSet(state.cst_type);
|
||||||
const showConvention = useMemo(() => !!state.convention || forceComment || isBasic, [state, forceComment, isBasic]);
|
const showConvention = !!state.convention || forceComment || isBasic;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setForceComment(false);
|
setForceComment(false);
|
||||||
|
@ -40,10 +40,9 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
}
|
}
|
||||||
}, [state.alias, state.cst_type, schema, setValidated]);
|
}, [state.alias, state.cst_type, schema, setValidated]);
|
||||||
|
|
||||||
const handleTypeChange = useCallback(
|
function handleTypeChange(target: CstType) {
|
||||||
(target: CstType) => partialUpdate({ cst_type: target, alias: generateAlias(target, schema) }),
|
return partialUpdate({ cst_type: target, alias: generateAlias(target, schema) });
|
||||||
[partialUpdate, schema]
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import Modal from '@/components/ui/Modal';
|
import Modal from '@/components/ui/Modal';
|
||||||
|
@ -38,7 +38,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
||||||
const [attachedID, setAttachedID] = useState<LibraryItemID | undefined>(undefined);
|
const [attachedID, setAttachedID] = useState<LibraryItemID | undefined>(undefined);
|
||||||
const [createSchema, setCreateSchema] = useState(false);
|
const [createSchema, setCreateSchema] = useState(false);
|
||||||
|
|
||||||
const isValid = useMemo(() => {
|
const isValid = (() => {
|
||||||
if (alias === '') {
|
if (alias === '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}, [alias, activeTab, inputs, attachedID, oss.items]);
|
})();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (attachedID) {
|
if (attachedID) {
|
||||||
|
@ -82,8 +82,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
||||||
onCreate(data);
|
onCreate(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectTab = useCallback(
|
function handleSelectTab(newTab: TabID, last: TabID) {
|
||||||
(newTab: TabID, last: TabID) => {
|
|
||||||
if (last === newTab) {
|
if (last === newTab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -93,49 +92,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
||||||
setInputs(initialInputs);
|
setInputs(initialInputs);
|
||||||
}
|
}
|
||||||
setActiveTab(newTab);
|
setActiveTab(newTab);
|
||||||
},
|
}
|
||||||
[setActiveTab, initialInputs]
|
|
||||||
);
|
|
||||||
|
|
||||||
const inputPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabInputOperation
|
|
||||||
oss={oss}
|
|
||||||
alias={alias}
|
|
||||||
onChangeAlias={setAlias}
|
|
||||||
comment={comment}
|
|
||||||
onChangeComment={setComment}
|
|
||||||
title={title}
|
|
||||||
onChangeTitle={setTitle}
|
|
||||||
attachedID={attachedID}
|
|
||||||
onChangeAttachedID={setAttachedID}
|
|
||||||
createSchema={createSchema}
|
|
||||||
onChangeCreateSchema={setCreateSchema}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[alias, comment, title, attachedID, oss, createSchema, setAlias]
|
|
||||||
);
|
|
||||||
|
|
||||||
const synthesisPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabSynthesisOperation
|
|
||||||
oss={oss}
|
|
||||||
alias={alias}
|
|
||||||
onChangeAlias={setAlias}
|
|
||||||
comment={comment}
|
|
||||||
onChangeComment={setComment}
|
|
||||||
title={title}
|
|
||||||
onChangeTitle={setTitle}
|
|
||||||
inputs={inputs}
|
|
||||||
setInputs={setInputs}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[oss, alias, comment, title, inputs, setAlias]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -164,8 +121,35 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
||||||
/>
|
/>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{inputPanel}
|
<TabPanel>
|
||||||
{synthesisPanel}
|
<TabInputOperation
|
||||||
|
oss={oss}
|
||||||
|
alias={alias}
|
||||||
|
onChangeAlias={setAlias}
|
||||||
|
comment={comment}
|
||||||
|
onChangeComment={setComment}
|
||||||
|
title={title}
|
||||||
|
onChangeTitle={setTitle}
|
||||||
|
attachedID={attachedID}
|
||||||
|
onChangeAttachedID={setAttachedID}
|
||||||
|
createSchema={createSchema}
|
||||||
|
onChangeCreateSchema={setCreateSchema}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabSynthesisOperation
|
||||||
|
oss={oss}
|
||||||
|
alias={alias}
|
||||||
|
onChangeAlias={setAlias}
|
||||||
|
comment={comment}
|
||||||
|
onChangeComment={setComment}
|
||||||
|
title={title}
|
||||||
|
onChangeTitle={setTitle}
|
||||||
|
inputs={inputs}
|
||||||
|
setInputs={setInputs}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { IconReset } from '@/components/Icons';
|
import { IconReset } from '@/components/Icons';
|
||||||
import PickSchema from '@/components/select/PickSchema';
|
import PickSchema from '@/components/select/PickSchema';
|
||||||
|
@ -41,9 +41,12 @@ function TabInputOperation({
|
||||||
createSchema,
|
createSchema,
|
||||||
onChangeCreateSchema
|
onChangeCreateSchema
|
||||||
}: TabInputOperationProps) {
|
}: TabInputOperationProps) {
|
||||||
const baseFilter = useCallback((item: ILibraryItem) => !oss.schemas.includes(item.id), [oss]);
|
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
const sortedItems = useMemo(() => sortItemsForOSS(oss, library.items), [oss, library.items]);
|
const sortedItems = sortItemsForOSS(oss, library.items);
|
||||||
|
|
||||||
|
function baseFilter(item: ILibraryItem) {
|
||||||
|
return !oss.schemas.includes(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (createSchema) {
|
if (createSchema) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
@ -23,9 +23,7 @@ function DlgCreateVersion({ hideWindow, versions, selected, totalCount, onCreate
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [onlySelected, setOnlySelected] = useState(false);
|
const [onlySelected, setOnlySelected] = useState(false);
|
||||||
|
|
||||||
const canSubmit = useMemo(() => {
|
const canSubmit = !versions.find(ver => ver.version === version);
|
||||||
return !versions.find(ver => ver.version === version);
|
|
||||||
}, [versions, version]);
|
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
const data: IVersionCreateData = {
|
const data: IVersionCreateData = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import Checkbox from '@/components/ui/Checkbox';
|
import Checkbox from '@/components/ui/Checkbox';
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
@ -18,12 +18,9 @@ interface DlgDeleteCstProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
|
||||||
function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstProps) {
|
function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstProps) {
|
||||||
const [expandOut, setExpandOut] = useState(false);
|
const [expandOut, setExpandOut] = useState(false);
|
||||||
const expansion: ConstituentaID[] = useMemo(
|
const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected);
|
||||||
() => schema.graph.expandAllOutputs(selected), // prettier: split-lines
|
const hasInherited = selected.some(
|
||||||
[selected, schema.graph]
|
id => schema.inheritance.find(item => item.parent === id),
|
||||||
);
|
|
||||||
const hasInherited = useMemo(
|
|
||||||
() => selected.some(id => schema.inheritance.find(item => item.parent === id), [selected, schema.inheritance]),
|
|
||||||
[selected, schema.inheritance]
|
[selected, schema.inheritance]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { IconRemove } from '@/components/Icons';
|
import { IconRemove } from '@/components/Icons';
|
||||||
import SelectUser from '@/components/select/SelectUser';
|
import SelectUser from '@/components/select/SelectUser';
|
||||||
|
@ -22,20 +22,19 @@ interface DlgEditEditorsProps {
|
||||||
function DlgEditEditors({ hideWindow, editors, setEditors }: DlgEditEditorsProps) {
|
function DlgEditEditors({ hideWindow, editors, setEditors }: DlgEditEditorsProps) {
|
||||||
const [selected, setSelected] = useState<UserID[]>(editors);
|
const [selected, setSelected] = useState<UserID[]>(editors);
|
||||||
const { users } = useUsers();
|
const { users } = useUsers();
|
||||||
const filtered = useMemo(() => users.filter(user => !selected.includes(user.id)), [users, selected]);
|
const filtered = users.filter(user => !selected.includes(user.id));
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
setEditors(selected);
|
setEditors(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDeleteEditor = useCallback((target: UserID) => setSelected(prev => prev.filter(id => id !== target)), []);
|
function onDeleteEditor(target: UserID) {
|
||||||
|
setSelected(prev => prev.filter(id => id !== target));
|
||||||
|
}
|
||||||
|
|
||||||
const onAddEditor = useCallback((target: UserID) => setSelected(prev => [...prev, target]), []);
|
function onAddEditor(target: UserID) {
|
||||||
|
setSelected(prev => [...prev, target]);
|
||||||
const usersTable = useMemo(
|
}
|
||||||
() => <TableUsers items={users.filter(user => selected.includes(user.id))} onDelete={onDeleteEditor} />,
|
|
||||||
[users, selected, onDeleteEditor]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -58,7 +57,7 @@ function DlgEditEditors({ hideWindow, editors, setEditors }: DlgEditEditorsProps
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{usersTable}
|
<TableUsers items={users.filter(user => selected.includes(user.id))} onDelete={onDeleteEditor} />
|
||||||
|
|
||||||
<div className='flex items-center gap-3'>
|
<div className='flex items-center gap-3'>
|
||||||
<Label text='Добавить' />
|
<Label text='Добавить' />
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IconRemove } from '@/components/Icons';
|
import { IconRemove } from '@/components/Icons';
|
||||||
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
@ -15,8 +13,7 @@ interface TableUsersProps {
|
||||||
const columnHelper = createColumnHelper<IUserInfo>();
|
const columnHelper = createColumnHelper<IUserInfo>();
|
||||||
|
|
||||||
function TableUsers({ items, onDelete }: TableUsersProps) {
|
function TableUsers({ items, onDelete }: TableUsersProps) {
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('last_name', {
|
columnHelper.accessor('last_name', {
|
||||||
id: 'last_name',
|
id: 'last_name',
|
||||||
size: 400,
|
size: 400,
|
||||||
|
@ -42,9 +39,7 @@ function TableUsers({ items, onDelete }: TableUsersProps) {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[onDelete]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import Modal from '@/components/ui/Modal';
|
import Modal from '@/components/ui/Modal';
|
||||||
|
@ -47,9 +47,9 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
||||||
const [isCorrect, setIsCorrect] = useState(true);
|
const [isCorrect, setIsCorrect] = useState(true);
|
||||||
const [validationText, setValidationText] = useState('');
|
const [validationText, setValidationText] = useState('');
|
||||||
|
|
||||||
const initialInputs = useMemo(() => oss.graph.expandInputs([target.id]), [oss.graph, target.id]);
|
const initialInputs = oss.graph.expandInputs([target.id]);
|
||||||
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
const [inputs, setInputs] = useState<OperationID[]>(initialInputs);
|
||||||
const inputOperations = useMemo(() => inputs.map(id => oss.operationByID.get(id)!), [inputs, oss.operationByID]);
|
const inputOperations = inputs.map(id => oss.operationByID.get(id)!);
|
||||||
|
|
||||||
const [needPreload, setNeedPreload] = useState(false);
|
const [needPreload, setNeedPreload] = useState(false);
|
||||||
const [schemasIDs, setSchemaIDs] = useState<LibraryItemID[]>([]);
|
const [schemasIDs, setSchemaIDs] = useState<LibraryItemID[]>([]);
|
||||||
|
@ -58,33 +58,16 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
||||||
const [suggestions, setSuggestions] = useState<ICstSubstitute[]>([]);
|
const [suggestions, setSuggestions] = useState<ICstSubstitute[]>([]);
|
||||||
|
|
||||||
const cache = useRSFormCache();
|
const cache = useRSFormCache();
|
||||||
const schemas = useMemo(
|
const schemas = schemasIDs.map(id => cache.data.find(item => item.id === id)).filter(item => item !== undefined);
|
||||||
() => schemasIDs.map(id => cache.data.find(item => item.id === id)).filter(item => item !== undefined),
|
|
||||||
[schemasIDs, cache.data]
|
|
||||||
);
|
|
||||||
|
|
||||||
const isModified = useMemo(
|
const isModified =
|
||||||
() =>
|
|
||||||
alias !== target.alias ||
|
alias !== target.alias ||
|
||||||
title !== target.title ||
|
title !== target.title ||
|
||||||
comment !== target.comment ||
|
comment !== target.comment ||
|
||||||
JSON.stringify(initialInputs) !== JSON.stringify(inputs) ||
|
JSON.stringify(initialInputs) !== JSON.stringify(inputs) ||
|
||||||
JSON.stringify(substitutions) !== JSON.stringify(target.substitutions),
|
JSON.stringify(substitutions) !== JSON.stringify(target.substitutions);
|
||||||
[
|
|
||||||
alias,
|
|
||||||
title,
|
|
||||||
comment,
|
|
||||||
target.alias,
|
|
||||||
target.title,
|
|
||||||
target.comment,
|
|
||||||
initialInputs,
|
|
||||||
inputs,
|
|
||||||
substitutions,
|
|
||||||
target.substitutions
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
const canSubmit = useMemo(() => isModified && alias !== '', [isModified, alias]);
|
const canSubmit = isModified && alias !== '';
|
||||||
|
|
||||||
const getSchemaByCst = useCallback(
|
const getSchemaByCst = useCallback(
|
||||||
(id: ConstituentaID) => {
|
(id: ConstituentaID) => {
|
||||||
|
@ -140,7 +123,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
||||||
setSuggestions(validator.suggestions);
|
setSuggestions(validator.suggestions);
|
||||||
}, [substitutions, cache.loading, schemas, schemasIDs.length]);
|
}, [substitutions, cache.loading, schemas, schemasIDs.length]);
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
function handleSubmit() {
|
||||||
const data: IOperationUpdateData = {
|
const data: IOperationUpdateData = {
|
||||||
target: target.id,
|
target: target.id,
|
||||||
item_data: {
|
item_data: {
|
||||||
|
@ -153,55 +136,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
||||||
substitutions: target.operation_type !== OperationType.SYNTHESIS ? undefined : substitutions
|
substitutions: target.operation_type !== OperationType.SYNTHESIS ? undefined : substitutions
|
||||||
};
|
};
|
||||||
onSubmit(data);
|
onSubmit(data);
|
||||||
}, [alias, comment, title, inputs, substitutions, target, onSubmit]);
|
}
|
||||||
|
|
||||||
const cardPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabOperation
|
|
||||||
alias={alias}
|
|
||||||
onChangeAlias={setAlias}
|
|
||||||
comment={comment}
|
|
||||||
onChangeComment={setComment}
|
|
||||||
title={title}
|
|
||||||
onChangeTitle={setTitle}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[alias, comment, title, setAlias]
|
|
||||||
);
|
|
||||||
|
|
||||||
const argumentsPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabArguments
|
|
||||||
target={target.id} // prettier: split-lines
|
|
||||||
oss={oss}
|
|
||||||
inputs={inputs}
|
|
||||||
setInputs={setInputs}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[oss, target, inputs, setInputs]
|
|
||||||
);
|
|
||||||
|
|
||||||
const synthesisPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabSynthesis
|
|
||||||
schemas={schemas}
|
|
||||||
loading={cache.loading}
|
|
||||||
error={cache.error}
|
|
||||||
validationText={validationText}
|
|
||||||
isCorrect={isCorrect}
|
|
||||||
substitutions={substitutions}
|
|
||||||
setSubstitutions={setSubstitutions}
|
|
||||||
suggestions={suggestions}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[cache.loading, cache.error, substitutions, suggestions, schemas, validationText, isCorrect]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -234,9 +169,41 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
||||||
) : null}
|
) : null}
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{cardPanel}
|
<TabPanel>
|
||||||
{target.operation_type === OperationType.SYNTHESIS ? argumentsPanel : null}
|
<TabOperation
|
||||||
{target.operation_type === OperationType.SYNTHESIS ? synthesisPanel : null}
|
alias={alias}
|
||||||
|
onChangeAlias={setAlias}
|
||||||
|
comment={comment}
|
||||||
|
onChangeComment={setComment}
|
||||||
|
title={title}
|
||||||
|
onChangeTitle={setTitle}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||||
|
<TabPanel>
|
||||||
|
<TabArguments
|
||||||
|
target={target.id} // prettier: split-lines
|
||||||
|
oss={oss}
|
||||||
|
inputs={inputs}
|
||||||
|
setInputs={setInputs}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
) : null}
|
||||||
|
{target.operation_type === OperationType.SYNTHESIS ? (
|
||||||
|
<TabPanel>
|
||||||
|
<TabSynthesis
|
||||||
|
schemas={schemas}
|
||||||
|
loading={cache.loading}
|
||||||
|
error={cache.error}
|
||||||
|
validationText={validationText}
|
||||||
|
isCorrect={isCorrect}
|
||||||
|
substitutions={substitutions}
|
||||||
|
setSubstitutions={setSubstitutions}
|
||||||
|
suggestions={suggestions}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
) : null}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import PickMultiOperation from '@/components/select/PickMultiOperation';
|
import PickMultiOperation from '@/components/select/PickMultiOperation';
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -15,11 +13,8 @@ interface TabArgumentsProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabArguments({ oss, inputs, target, setInputs }: TabArgumentsProps) {
|
function TabArguments({ oss, inputs, target, setInputs }: TabArgumentsProps) {
|
||||||
const potentialCycle = useMemo(() => [target, ...oss.graph.expandAllOutputs([target])], [target, oss.graph]);
|
const potentialCycle = [target, ...oss.graph.expandAllOutputs([target])];
|
||||||
const filtered = useMemo(
|
const filtered = oss.items.filter(item => !potentialCycle.includes(item.id));
|
||||||
() => oss.items.filter(item => !potentialCycle.includes(item.id)),
|
|
||||||
[oss.items, potentialCycle]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in cc-column'>
|
<div className='cc-fade-in cc-column'>
|
||||||
<FlexColumn>
|
<FlexColumn>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import Modal from '@/components/ui/Modal';
|
import Modal from '@/components/ui/Modal';
|
||||||
|
@ -36,42 +36,16 @@ export enum TabID {
|
||||||
|
|
||||||
function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditReferenceProps) {
|
function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditReferenceProps) {
|
||||||
const [activeTab, setActiveTab] = useState(initial.type === ReferenceType.ENTITY ? TabID.ENTITY : TabID.SYNTACTIC);
|
const [activeTab, setActiveTab] = useState(initial.type === ReferenceType.ENTITY ? TabID.ENTITY : TabID.SYNTACTIC);
|
||||||
|
|
||||||
const [reference, setReference] = useState('');
|
const [reference, setReference] = useState('');
|
||||||
const [isValid, setIsValid] = useState(false);
|
const [isValid, setIsValid] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = () => onSave(reference);
|
|
||||||
|
|
||||||
const entityPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabEntityReference
|
|
||||||
initial={initial}
|
|
||||||
schema={schema}
|
|
||||||
onChangeReference={setReference}
|
|
||||||
onChangeValid={setIsValid}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[initial, schema]
|
|
||||||
);
|
|
||||||
|
|
||||||
const syntacticPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabSyntacticReference initial={initial} onChangeReference={setReference} onChangeValid={setIsValid} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[initial]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header='Редактирование ссылки'
|
header='Редактирование ссылки'
|
||||||
submitText='Сохранить ссылку'
|
submitText='Сохранить ссылку'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={isValid}
|
canSubmit={isValid}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={() => onSave(reference)}
|
||||||
className='w-[40rem] px-6 h-[32rem]'
|
className='w-[40rem] px-6 h-[32rem]'
|
||||||
helpTopic={HelpTopic.TERM_CONTROL}
|
helpTopic={HelpTopic.TERM_CONTROL}
|
||||||
>
|
>
|
||||||
|
@ -89,8 +63,18 @@ function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditRefere
|
||||||
/>
|
/>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{entityPanel}
|
<TabPanel>
|
||||||
{syntacticPanel}
|
<TabEntityReference
|
||||||
|
initial={initial}
|
||||||
|
schema={schema}
|
||||||
|
onChangeReference={setReference}
|
||||||
|
onChangeValid={setIsValid}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabSyntacticReference initial={initial} onChangeReference={setReference} onChangeValid={setIsValid} />
|
||||||
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import TextInput from '@/components/ui/TextInput';
|
import TextInput from '@/components/ui/TextInput';
|
||||||
import { ReferenceType } from '@/models/language';
|
import { ReferenceType } from '@/models/language';
|
||||||
|
@ -18,14 +18,14 @@ function TabSyntacticReference({ initial, onChangeValid, onChangeReference }: Ta
|
||||||
const [nominal, setNominal] = useState('');
|
const [nominal, setNominal] = useState('');
|
||||||
const [offset, setOffset] = useState(1);
|
const [offset, setOffset] = useState(1);
|
||||||
|
|
||||||
const mainLink = useMemo(() => {
|
const mainLink = (() => {
|
||||||
const position = offset > 0 ? initial.basePosition + (offset - 1) : initial.basePosition + offset;
|
const position = offset > 0 ? initial.basePosition + (offset - 1) : initial.basePosition + offset;
|
||||||
if (offset === 0 || position < 0 || position >= initial.mainRefs.length) {
|
if (offset === 0 || position < 0 || position >= initial.mainRefs.length) {
|
||||||
return 'Некорректное значение смещения';
|
return 'Некорректное значение смещения';
|
||||||
} else {
|
} else {
|
||||||
return initial.mainRefs[position];
|
return initial.mainRefs[position];
|
||||||
}
|
}
|
||||||
}, [initial, offset]);
|
})();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initial.refRaw && initial.type === ReferenceType.SYNTACTIC) {
|
if (initial.refRaw && initial.type === ReferenceType.SYNTACTIC) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { IconReset, IconSave } from '@/components/Icons';
|
import { IconReset, IconSave } from '@/components/Icons';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
@ -26,19 +26,8 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
||||||
const [version, setVersion] = useState('');
|
const [version, setVersion] = useState('');
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
|
|
||||||
const isValid = useMemo(() => {
|
const isValid = selected && versions.every(ver => ver.id === selected.id || ver.version != version);
|
||||||
if (!selected) {
|
const isModified = selected && (selected.version != version || selected.description != description);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return versions.every(ver => ver.id === selected.id || ver.version != version);
|
|
||||||
}, [selected, version, versions]);
|
|
||||||
|
|
||||||
const isModified = useMemo(() => {
|
|
||||||
if (!selected) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return selected.version != version || selected.description != description;
|
|
||||||
}, [version, description, selected]);
|
|
||||||
|
|
||||||
function handleUpdate() {
|
function handleUpdate() {
|
||||||
if (!isModified || !selected || processing || !isValid) {
|
if (!isModified || !selected || processing || !isValid) {
|
||||||
|
@ -64,19 +53,6 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
||||||
setDescription(selected?.description ?? '');
|
setDescription(selected?.description ?? '');
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
const versionsTable = useMemo(
|
|
||||||
() => (
|
|
||||||
<TableVersions
|
|
||||||
processing={processing}
|
|
||||||
items={versions}
|
|
||||||
onDelete={onDelete}
|
|
||||||
onSelect={versionID => setSelected(versions.find(ver => ver.id === versionID))}
|
|
||||||
selected={selected?.id}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[processing, versions, onDelete, selected?.id]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
readonly
|
readonly
|
||||||
|
@ -84,7 +60,14 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
className='flex flex-col w-[40rem] px-6 gap-3 pb-6'
|
className='flex flex-col w-[40rem] px-6 gap-3 pb-6'
|
||||||
>
|
>
|
||||||
{versionsTable}
|
<TableVersions
|
||||||
|
processing={processing}
|
||||||
|
items={versions}
|
||||||
|
onDelete={onDelete}
|
||||||
|
onSelect={versionID => setSelected(versions.find(ver => ver.id === versionID))}
|
||||||
|
selected={selected?.id}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<TextInput
|
<TextInput
|
||||||
id='dlg_version'
|
id='dlg_version'
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { IconRemove } from '@/components/Icons';
|
import { IconRemove } from '@/components/Icons';
|
||||||
|
@ -24,8 +23,7 @@ function TableVersions({ processing, items, onDelete, selected, onSelect }: Tabl
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('version', {
|
columnHelper.accessor('version', {
|
||||||
id: 'version',
|
id: 'version',
|
||||||
header: 'Версия',
|
header: 'Версия',
|
||||||
|
@ -70,21 +68,16 @@ function TableVersions({ processing, items, onDelete, selected, onSelect }: Tabl
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[onDelete, intl, processing]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<IVersionInfo>[] = [
|
||||||
(): IConditionalStyle<IVersionInfo>[] => [
|
|
||||||
{
|
{
|
||||||
when: (version: IVersionInfo) => version.id === selected,
|
when: (version: IVersionInfo) => version.id === selected,
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: colors.bgSelected
|
backgroundColor: colors.bgSelected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[selected, colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IconRemove } from '@/components/Icons';
|
import { IconRemove } from '@/components/Icons';
|
||||||
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
||||||
|
@ -19,8 +18,7 @@ interface TableWordFormsProps {
|
||||||
const columnHelper = createColumnHelper<IWordForm>();
|
const columnHelper = createColumnHelper<IWordForm>();
|
||||||
|
|
||||||
function TableWordForms({ forms, setForms, onFormSelect }: TableWordFormsProps) {
|
function TableWordForms({ forms, setForms, onFormSelect }: TableWordFormsProps) {
|
||||||
const handleDeleteRow = useCallback(
|
function handleDeleteRow(row: number) {
|
||||||
(row: number) => {
|
|
||||||
setForms(prev => {
|
setForms(prev => {
|
||||||
const newForms: IWordForm[] = [];
|
const newForms: IWordForm[] = [];
|
||||||
prev.forEach((form, index) => {
|
prev.forEach((form, index) => {
|
||||||
|
@ -30,12 +28,9 @@ function TableWordForms({ forms, setForms, onFormSelect }: TableWordFormsProps)
|
||||||
});
|
});
|
||||||
return newForms;
|
return newForms;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
[setForms]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('text', {
|
columnHelper.accessor('text', {
|
||||||
id: 'text',
|
id: 'text',
|
||||||
size: 350,
|
size: 350,
|
||||||
|
@ -63,9 +58,7 @@ function TableWordForms({ forms, setForms, onFormSelect }: TableWordFormsProps)
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[handleDeleteRow]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
@ -35,7 +35,7 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
||||||
|
|
||||||
const source = useRSFormDetails({ target: donorID ? String(donorID) : undefined });
|
const source = useRSFormDetails({ target: donorID ? String(donorID) : undefined });
|
||||||
|
|
||||||
const validated = useMemo(() => !!source.schema && selected.length > 0, [source.schema, selected]);
|
const validated = !!source.schema && selected.length > 0;
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
if (!source.schema) {
|
if (!source.schema) {
|
||||||
|
@ -55,43 +55,6 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
||||||
setSubstitutions([]);
|
setSubstitutions([]);
|
||||||
}, [source.schema]);
|
}, [source.schema]);
|
||||||
|
|
||||||
const schemaPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabSchema selected={donorID} setSelected={setDonorID} receiver={receiver} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[donorID, receiver]
|
|
||||||
);
|
|
||||||
const itemsPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabConstituents
|
|
||||||
schema={source.schema}
|
|
||||||
loading={source.loading}
|
|
||||||
selected={selected}
|
|
||||||
setSelected={setSelected}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[source.schema, source.loading, selected]
|
|
||||||
);
|
|
||||||
const substitutesPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<TabSubstitutions
|
|
||||||
receiver={receiver}
|
|
||||||
source={source.schema}
|
|
||||||
selected={selected}
|
|
||||||
loading={source.loading}
|
|
||||||
substitutions={substitutions}
|
|
||||||
setSubstitutions={setSubstitutions}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[source.schema, source.loading, receiver, selected, substitutions]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
header='Импорт концептуальной схем'
|
header='Импорт концептуальной схем'
|
||||||
|
@ -113,9 +76,29 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
||||||
<TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
|
<TabLabel label='Отождествления' title='Таблица отождествлений' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{schemaPanel}
|
<TabPanel>
|
||||||
{itemsPanel}
|
<TabSchema selected={donorID} setSelected={setDonorID} receiver={receiver} />
|
||||||
{substitutesPanel}
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabConstituents
|
||||||
|
schema={source.schema}
|
||||||
|
loading={source.loading}
|
||||||
|
selected={selected}
|
||||||
|
setSelected={setSelected}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabSubstitutions
|
||||||
|
receiver={receiver}
|
||||||
|
source={source.schema}
|
||||||
|
selected={selected}
|
||||||
|
loading={source.loading}
|
||||||
|
substitutions={substitutions}
|
||||||
|
setSubstitutions={setSubstitutions}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import PickSchema from '@/components/select/PickSchema';
|
import PickSchema from '@/components/select/PickSchema';
|
||||||
import TextInput from '@/components/ui/TextInput';
|
import TextInput from '@/components/ui/TextInput';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
|
@ -17,8 +15,8 @@ interface TabSchemaProps {
|
||||||
|
|
||||||
function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) {
|
function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) {
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
const selectedInfo = useMemo(() => library.items.find(item => item.id === selected), [selected, library.items]);
|
const selectedInfo = library.items.find(item => item.id === selected);
|
||||||
const sortedItems = useMemo(() => sortItemsForInlineSynthesis(receiver, library.items), [receiver, library.items]);
|
const sortedItems = sortItemsForInlineSynthesis(receiver, library.items);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in flex flex-col'>
|
<div className='cc-fade-in flex flex-col'>
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { ErrorData } from '@/components/info/InfoError';
|
import { ErrorData } from '@/components/info/InfoError';
|
||||||
import PickSubstitutions from '@/components/select/PickSubstitutions';
|
import PickSubstitutions from '@/components/select/PickSubstitutions';
|
||||||
import DataLoader from '@/components/wrap/DataLoader';
|
import DataLoader from '@/components/wrap/DataLoader';
|
||||||
import { ICstSubstitute } from '@/models/oss';
|
import { ICstSubstitute } from '@/models/oss';
|
||||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
interface TabSubstitutionsProps {
|
interface TabSubstitutionsProps {
|
||||||
|
@ -32,12 +30,7 @@ function TabSubstitutions({
|
||||||
substitutions,
|
substitutions,
|
||||||
setSubstitutions
|
setSubstitutions
|
||||||
}: TabSubstitutionsProps) {
|
}: TabSubstitutionsProps) {
|
||||||
const filter = useCallback(
|
const schemas = [...(source ? [source] : []), ...(receiver ? [receiver] : [])];
|
||||||
(cst: IConstituenta) => cst.id !== source?.id || selected.includes(cst.id),
|
|
||||||
[selected, source]
|
|
||||||
);
|
|
||||||
|
|
||||||
const schemas = useMemo(() => [...(source ? [source] : []), ...(receiver ? [receiver] : [])], [source, receiver]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataLoader isLoading={loading} error={error} hasNoData={!source}>
|
<DataLoader isLoading={loading} error={error} hasNoData={!source}>
|
||||||
|
@ -47,7 +40,7 @@ function TabSubstitutions({
|
||||||
rows={10}
|
rows={10}
|
||||||
prefixID={prefixes.cst_inline_synth_substitutes}
|
prefixID={prefixes.cst_inline_synth_substitutes}
|
||||||
schemas={schemas}
|
schemas={schemas}
|
||||||
filter={filter}
|
filter={cst => cst.id !== source?.id || selected.includes(cst.id)}
|
||||||
/>
|
/>
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { RelocateUpIcon } from '@/components/DomainIcons';
|
import { RelocateUpIcon } from '@/components/DomainIcons';
|
||||||
import PickMultiConstituenta from '@/components/select/PickMultiConstituenta';
|
import PickMultiConstituenta from '@/components/select/PickMultiConstituenta';
|
||||||
|
@ -33,10 +33,11 @@ function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: D
|
||||||
const [source, setSource] = useState<ILibraryItem | undefined>(
|
const [source, setSource] = useState<ILibraryItem | undefined>(
|
||||||
library.items.find(item => item.id === initialTarget?.result)
|
library.items.find(item => item.id === initialTarget?.result)
|
||||||
);
|
);
|
||||||
|
const isValid = !!destination && selected.length > 0;
|
||||||
|
|
||||||
const operation = useMemo(() => oss.items.find(item => item.result === source?.id), [oss, source]);
|
const operation = oss.items.find(item => item.result === source?.id);
|
||||||
const sourceSchemas = useMemo(() => library.items.filter(item => oss.schemas.includes(item.id)), [library, oss]);
|
const sourceSchemas = library.items.filter(item => oss.schemas.includes(item.id));
|
||||||
const destinationSchemas = useMemo(() => {
|
const destinationSchemas = (() => {
|
||||||
if (!operation) {
|
if (!operation) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -45,35 +46,34 @@ function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: D
|
||||||
? node.inputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
|
? node.inputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
|
||||||
: 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, operation, directionUp]);
|
})();
|
||||||
|
|
||||||
const sourceData = useRSFormDetails({ target: source ? String(source.id) : undefined });
|
const sourceData = useRSFormDetails({ target: source ? String(source.id) : undefined });
|
||||||
const filteredConstituents = useMemo(() => {
|
const filteredConstituents = (() => {
|
||||||
if (!sourceData.schema || !destination || !operation) {
|
if (!sourceData.schema || !destination || !operation) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const destinationOperation = oss.items.find(item => item.result === destination.id);
|
const destinationOperation = oss.items.find(item => item.result === destination.id);
|
||||||
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
|
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
|
||||||
}, [destination, operation, sourceData.schema, oss]);
|
})();
|
||||||
|
|
||||||
const isValid = useMemo(() => !!destination && selected.length > 0, [destination, selected]);
|
function toggleDirection() {
|
||||||
const toggleDirection = useCallback(() => {
|
|
||||||
setDirectionUp(prev => !prev);
|
setDirectionUp(prev => !prev);
|
||||||
setDestination(undefined);
|
setDestination(undefined);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleSelectSource = useCallback((newValue: ILibraryItem | undefined) => {
|
function handleSelectSource(newValue: ILibraryItem | undefined) {
|
||||||
setSource(newValue);
|
setSource(newValue);
|
||||||
setDestination(undefined);
|
setDestination(undefined);
|
||||||
setSelected([]);
|
setSelected([]);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleSelectDestination = useCallback((newValue: ILibraryItem | undefined) => {
|
function handleSelectDestination(newValue: ILibraryItem | undefined) {
|
||||||
setDestination(newValue);
|
setDestination(newValue);
|
||||||
setSelected([]);
|
setSelected([]);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleSubmit = useCallback(() => {
|
function handleSubmit() {
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: D
|
||||||
items: selected
|
items: selected
|
||||||
};
|
};
|
||||||
onSubmit(data);
|
onSubmit(data);
|
||||||
}, [destination, onSubmit, selected]);
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { ReactFlowProvider } from 'reactflow';
|
import { ReactFlowProvider } from 'reactflow';
|
||||||
import { Node } from 'reactflow';
|
|
||||||
|
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
import Overlay from '@/components/ui/Overlay';
|
||||||
|
@ -20,10 +19,7 @@ interface DlgShowASTProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
|
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
|
||||||
const hoverNode = useMemo(() => syntaxTree.find(node => node.uid === hoverID), [hoverID, syntaxTree]);
|
const hoverNode = syntaxTree.find(node => node.uid === hoverID);
|
||||||
|
|
||||||
const handleHoverIn = useCallback((node: Node) => setHoverID(Number(node.id)), []);
|
|
||||||
const handleHoverOut = useCallback(() => setHoverID(undefined), []);
|
|
||||||
|
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
|
|
||||||
|
@ -51,8 +47,8 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
||||||
<ReactFlowProvider>
|
<ReactFlowProvider>
|
||||||
<ASTFlow
|
<ASTFlow
|
||||||
data={syntaxTree}
|
data={syntaxTree}
|
||||||
onNodeEnter={handleHoverIn}
|
onNodeEnter={node => setHoverID(Number(node.id))}
|
||||||
onNodeLeave={handleHoverOut}
|
onNodeLeave={() => setHoverID(undefined)}
|
||||||
onChangeDragging={setIsDragging}
|
onChangeDragging={setIsDragging}
|
||||||
/>
|
/>
|
||||||
</ReactFlowProvider>
|
</ReactFlowProvider>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -27,7 +26,7 @@ interface ASTNodeInternal {
|
||||||
|
|
||||||
function ASTNode(node: ASTNodeInternal) {
|
function ASTNode(node: ASTNodeInternal) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const label = useMemo(() => labelSyntaxTree(node.data), [node.data]);
|
const label = labelSyntaxTree(node.data);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { ReactFlowProvider } from 'reactflow';
|
import { ReactFlowProvider } from 'reactflow';
|
||||||
|
|
||||||
|
@ -17,11 +16,11 @@ interface DlgShowTypeGraphProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) {
|
function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) {
|
||||||
const graph = useMemo(() => {
|
const graph = (() => {
|
||||||
const result = new TMGraph();
|
const result = new TMGraph();
|
||||||
items.forEach(item => result.addConstituenta(item.alias, item.result, item.args));
|
items.forEach(item => result.addConstituenta(item.alias, item.result, item.args));
|
||||||
return result;
|
return result;
|
||||||
}, [items]);
|
})();
|
||||||
|
|
||||||
if (graph.nodes.length === 0) {
|
if (graph.nodes.length === 0) {
|
||||||
toast.error(errors.typeStructureFailed);
|
toast.error(errors.typeStructureFailed);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -22,12 +21,9 @@ interface MGraphNodeInternal {
|
||||||
function MGraphNode(node: MGraphNodeInternal) {
|
function MGraphNode(node: MGraphNodeInternal) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
|
|
||||||
const tooltipText = useMemo(
|
const tooltipText =
|
||||||
() =>
|
|
||||||
(node.data.annotations.length === 0 ? '' : `Конституенты: ${node.data.annotations.join(' ')}<br/>`) +
|
(node.data.annotations.length === 0 ? '' : `Конституенты: ${node.data.annotations.join(' ')}<br/>`) +
|
||||||
node.data.text,
|
node.data.text;
|
||||||
[node.data]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import PickSubstitutions from '@/components/select/PickSubstitutions';
|
import PickSubstitutions from '@/components/select/PickSubstitutions';
|
||||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
@ -17,8 +17,7 @@ interface DlgSubstituteCstProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
|
||||||
function DlgSubstituteCst({ hideWindow, onSubstitute, schema }: DlgSubstituteCstProps) {
|
function DlgSubstituteCst({ hideWindow, onSubstitute, schema }: DlgSubstituteCstProps) {
|
||||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]);
|
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]);
|
||||||
|
const canSubmit = substitutions.length > 0;
|
||||||
const canSubmit = useMemo(() => substitutions.length > 0, [substitutions]);
|
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
const data: ICstSubstituteData = {
|
const data: ICstSubstituteData = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -45,8 +45,8 @@ function FormCreateItem() {
|
||||||
const [head, setHead] = useState(LocationHead.USER);
|
const [head, setHead] = useState(LocationHead.USER);
|
||||||
const [body, setBody] = useState('');
|
const [body, setBody] = useState('');
|
||||||
|
|
||||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
const location = combineLocation(head, body);
|
||||||
const isValid = useMemo(() => validateLocation(location), [location]);
|
const isValid = validateLocation(location);
|
||||||
|
|
||||||
const [fileName, setFileName] = useState('');
|
const [fileName, setFileName] = useState('');
|
||||||
const [file, setFile] = useState<File | undefined>();
|
const [file, setFile] = useState<File | undefined>();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch';
|
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -9,7 +9,7 @@ import { resources } from '@/utils/constants';
|
||||||
function DatabaseSchemaPage() {
|
function DatabaseSchemaPage() {
|
||||||
const { calculateHeight, setNoFooter } = useConceptOptions();
|
const { calculateHeight, setNoFooter } = useConceptOptions();
|
||||||
|
|
||||||
const panelHeight = useMemo(() => calculateHeight('0px'), [calculateHeight]);
|
const panelHeight = calculateHeight('0px');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNoFooter(true);
|
setNoFooter(true);
|
||||||
|
|
|
@ -69,8 +69,7 @@ function LibraryPage() {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasCustomFilter = useMemo(
|
const hasCustomFilter =
|
||||||
() =>
|
|
||||||
!!filter.path ||
|
!!filter.path ||
|
||||||
!!filter.query ||
|
!!filter.query ||
|
||||||
filter.head !== undefined ||
|
filter.head !== undefined ||
|
||||||
|
@ -78,19 +77,13 @@ function LibraryPage() {
|
||||||
filter.isOwned !== undefined ||
|
filter.isOwned !== undefined ||
|
||||||
filter.isVisible !== true ||
|
filter.isVisible !== true ||
|
||||||
filter.filterUser !== undefined ||
|
filter.filterUser !== undefined ||
|
||||||
!!filter.location,
|
!!filter.location;
|
||||||
[filter]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setItems(library.applyFilter(filter));
|
setItems(library.applyFilter(filter));
|
||||||
}, [library, library.items.length, filter]);
|
}, [library, library.items.length, filter]);
|
||||||
|
|
||||||
const toggleVisible = useCallback(() => setIsVisible(prev => toggleTristateFlag(prev)), [setIsVisible]);
|
const toggleFolderMode = () => options.setFolderMode(prev => !prev);
|
||||||
const toggleOwned = useCallback(() => setIsOwned(prev => toggleTristateFlag(prev)), [setIsOwned]);
|
|
||||||
const toggleEditor = useCallback(() => setIsEditor(prev => toggleTristateFlag(prev)), [setIsEditor]);
|
|
||||||
const toggleFolderMode = useCallback(() => options.setFolderMode(prev => !prev), [options]);
|
|
||||||
const toggleSubfolders = useCallback(() => setSubfolders(prev => !prev), [setSubfolders]);
|
|
||||||
|
|
||||||
const resetFilter = useCallback(() => {
|
const resetFilter = useCallback(() => {
|
||||||
setQuery('');
|
setQuery('');
|
||||||
|
@ -103,10 +96,6 @@ function LibraryPage() {
|
||||||
options.setLocation('');
|
options.setLocation('');
|
||||||
}, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options]);
|
}, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options]);
|
||||||
|
|
||||||
const promptRenameLocation = useCallback(() => {
|
|
||||||
setShowRenameLocation(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleRenameLocation = useCallback(
|
const handleRenameLocation = useCallback(
|
||||||
(newLocation: string) => {
|
(newLocation: string) => {
|
||||||
const data: IRenameLocationData = {
|
const data: IRenameLocationData = {
|
||||||
|
@ -134,43 +123,6 @@ function LibraryPage() {
|
||||||
}
|
}
|
||||||
}, [items]);
|
}, [items]);
|
||||||
|
|
||||||
const viewLibrary = useMemo(
|
|
||||||
() => (
|
|
||||||
<TableLibraryItems
|
|
||||||
resetQuery={resetFilter}
|
|
||||||
items={items}
|
|
||||||
folderMode={options.folderMode}
|
|
||||||
toggleFolderMode={toggleFolderMode}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[resetFilter, items, options.folderMode, toggleFolderMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const viewLocations = useMemo(
|
|
||||||
() => (
|
|
||||||
<ViewSideLocation
|
|
||||||
isVisible={options.folderMode}
|
|
||||||
activeLocation={options.location}
|
|
||||||
onChangeActiveLocation={options.setLocation}
|
|
||||||
subfolders={subfolders}
|
|
||||||
folderTree={library.folders}
|
|
||||||
toggleFolderMode={toggleFolderMode}
|
|
||||||
toggleSubfolders={toggleSubfolders}
|
|
||||||
onRenameLocation={promptRenameLocation}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[
|
|
||||||
options.location,
|
|
||||||
library.folders,
|
|
||||||
options.setLocation,
|
|
||||||
options.folderMode,
|
|
||||||
toggleFolderMode,
|
|
||||||
promptRenameLocation,
|
|
||||||
toggleSubfolders,
|
|
||||||
subfolders
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataLoader isLoading={library.loading} error={library.loadingError} hasNoData={library.items.length === 0}>
|
<DataLoader isLoading={library.loading} error={library.loadingError} hasNoData={library.items.length === 0}>
|
||||||
{showRenameLocation ? (
|
{showRenameLocation ? (
|
||||||
|
@ -203,10 +155,10 @@ function LibraryPage() {
|
||||||
onChangeHead={setHead}
|
onChangeHead={setHead}
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
isOwned={isOwned}
|
isOwned={isOwned}
|
||||||
toggleOwned={toggleOwned}
|
toggleOwned={() => setIsOwned(prev => toggleTristateFlag(prev))}
|
||||||
toggleVisible={toggleVisible}
|
toggleVisible={() => setIsVisible(prev => toggleTristateFlag(prev))}
|
||||||
isEditor={isEditor}
|
isEditor={isEditor}
|
||||||
toggleEditor={toggleEditor}
|
toggleEditor={() => setIsEditor(prev => toggleTristateFlag(prev))}
|
||||||
filterUser={filterUser}
|
filterUser={filterUser}
|
||||||
onChangeFilterUser={setFilterUser}
|
onChangeFilterUser={setFilterUser}
|
||||||
resetFilter={resetFilter}
|
resetFilter={resetFilter}
|
||||||
|
@ -215,8 +167,23 @@ function LibraryPage() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='cc-fade-in flex'>
|
<div className='cc-fade-in flex'>
|
||||||
{viewLocations}
|
<ViewSideLocation
|
||||||
{viewLibrary}
|
isVisible={options.folderMode}
|
||||||
|
activeLocation={options.location}
|
||||||
|
onChangeActiveLocation={options.setLocation}
|
||||||
|
subfolders={subfolders}
|
||||||
|
folderTree={library.folders}
|
||||||
|
toggleFolderMode={toggleFolderMode}
|
||||||
|
toggleSubfolders={() => setSubfolders(prev => !prev)}
|
||||||
|
onRenameLocation={() => setShowRenameLocation(true)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TableLibraryItems
|
||||||
|
resetQuery={resetFilter}
|
||||||
|
items={items}
|
||||||
|
folderMode={options.folderMode}
|
||||||
|
toggleFolderMode={toggleFolderMode}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useLayoutEffect, useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -54,17 +54,13 @@ function TableLibraryItems({ items, resetQuery, folderMode, toggleFolderMode }:
|
||||||
});
|
});
|
||||||
}, [windowSize]);
|
}, [windowSize]);
|
||||||
|
|
||||||
const handleToggleFolder = useCallback(
|
function handleToggleFolder(event: CProps.EventMouse) {
|
||||||
(event: CProps.EventMouse) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
toggleFolderMode();
|
toggleFolderMode();
|
||||||
},
|
}
|
||||||
[toggleFolderMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
...(folderMode
|
...(folderMode
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
|
@ -137,23 +133,18 @@ function TableLibraryItems({ items, resetQuery, folderMode, toggleFolderMode }:
|
||||||
sortingFn: 'datetime',
|
sortingFn: 'datetime',
|
||||||
sortDescFirst: true
|
sortDescFirst: true
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[intl, getUserLabel, windowSize, handleToggleFolder, folderMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
const tableHeight = useMemo(() => calculateHeight('2.2rem'), [calculateHeight]);
|
const tableHeight = calculateHeight('2.2rem');
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<ILibraryItem>[] = [
|
||||||
(): IConditionalStyle<ILibraryItem>[] => [
|
|
||||||
{
|
{
|
||||||
when: (item: ILibraryItem) => item.item_type === LibraryItemType.OSS,
|
when: (item: ILibraryItem) => item.item_type === LibraryItemType.OSS,
|
||||||
style: {
|
style: {
|
||||||
color: colors.fgGreen
|
color: colors.fgGreen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { LocationIcon, VisibilityIcon } from '@/components/DomainIcons';
|
import { LocationIcon, VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import {
|
import {
|
||||||
|
@ -85,34 +84,25 @@ function ToolbarSearch({
|
||||||
const userMenu = useDropdown();
|
const userMenu = useDropdown();
|
||||||
const { users } = useUsers();
|
const { users } = useUsers();
|
||||||
|
|
||||||
const userActive = useMemo(
|
const userActive = isOwned !== undefined || isEditor !== undefined || filterUser !== undefined;
|
||||||
() => isOwned !== undefined || isEditor !== undefined || filterUser !== undefined,
|
|
||||||
[isOwned, isEditor, filterUser]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleChange = useCallback(
|
function handleChange(newValue: LocationHead | undefined) {
|
||||||
(newValue: LocationHead | undefined) => {
|
|
||||||
headMenu.hide();
|
headMenu.hide();
|
||||||
onChangeHead(newValue);
|
onChangeHead(newValue);
|
||||||
},
|
}
|
||||||
[headMenu, onChangeHead]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleToggleFolder = useCallback(() => {
|
function handleToggleFolder() {
|
||||||
headMenu.hide();
|
headMenu.hide();
|
||||||
toggleFolderMode();
|
toggleFolderMode();
|
||||||
}, [headMenu, toggleFolderMode]);
|
}
|
||||||
|
|
||||||
const handleFolderClick = useCallback(
|
function handleFolderClick(event: CProps.EventMouse) {
|
||||||
(event: CProps.EventMouse) => {
|
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
toggleFolderMode();
|
toggleFolderMode();
|
||||||
} else {
|
} else {
|
||||||
headMenu.toggle();
|
headMenu.toggle();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[headMenu, toggleFolderMode]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { SubfoldersIcon } from '@/components/DomainIcons';
|
import { SubfoldersIcon } from '@/components/DomainIcons';
|
||||||
|
@ -43,7 +42,7 @@ function ViewSideLocation({
|
||||||
const { calculateHeight } = useConceptOptions();
|
const { calculateHeight } = useConceptOptions();
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
const canRename = useMemo(() => {
|
const canRename = (() => {
|
||||||
if (activeLocation.length <= 3 || !user) {
|
if (activeLocation.length <= 3 || !user) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -55,12 +54,11 @@ function ViewSideLocation({
|
||||||
item => item.location == activeLocation || item.location.startsWith(`${activeLocation}/`)
|
item => item.location == activeLocation || item.location.startsWith(`${activeLocation}/`)
|
||||||
);
|
);
|
||||||
return located.length !== 0;
|
return located.length !== 0;
|
||||||
}, [activeLocation, user, items]);
|
})();
|
||||||
|
|
||||||
const maxHeight = useMemo(() => calculateHeight('4.5rem'), [calculateHeight]);
|
const maxHeight = calculateHeight('4.5rem');
|
||||||
|
|
||||||
const handleClickFolder = useCallback(
|
function handleClickFolder(event: CProps.EventMouse, target: FolderNode) {
|
||||||
(event: CProps.EventMouse, target: FolderNode) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
@ -71,9 +69,7 @@ function ViewSideLocation({
|
||||||
} else {
|
} else {
|
||||||
onChangeActiveLocation(target.getPath());
|
onChangeActiveLocation(target.getPath());
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[onChangeActiveLocation]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import EmbedYoutube from '@/components/ui/EmbedYoutube';
|
import EmbedYoutube from '@/components/ui/EmbedYoutube';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
@ -10,12 +8,12 @@ import Subtopics from '../Subtopics';
|
||||||
function HelpRSLang() {
|
function HelpRSLang() {
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
const videoHeight = useMemo(() => {
|
const videoHeight = (() => {
|
||||||
const viewH = windowSize.height ?? 0;
|
const viewH = windowSize.height ?? 0;
|
||||||
const viewW = windowSize.width ?? 0;
|
const viewW = windowSize.width ?? 0;
|
||||||
const availableWidth = viewW - (windowSize.isSmall ? 35 : 310);
|
const availableWidth = viewW - (windowSize.isSmall ? 35 : 310);
|
||||||
return Math.min(1080, Math.max(viewH - 450, 300), Math.floor((availableWidth * 9) / 16));
|
return Math.min(1080, Math.max(viewH - 450, 300), Math.floor((availableWidth * 9) / 16));
|
||||||
}, [windowSize]);
|
})();
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IconChild,
|
IconChild,
|
||||||
|
@ -51,7 +51,7 @@ function NodeContextMenu({
|
||||||
const controller = useOssEdit();
|
const controller = useOssEdit();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const readyForSynthesis = useMemo(() => {
|
const readyForSynthesis = (() => {
|
||||||
if (operation.operation_type !== OperationType.SYNTHESIS) {
|
if (operation.operation_type !== OperationType.SYNTHESIS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ function NodeContextMenu({
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, [operation, controller.schema]);
|
})();
|
||||||
|
|
||||||
const handleHide = useCallback(() => {
|
const handleHide = useCallback(() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { toPng } from 'html-to-image';
|
import { toPng } from 'html-to-image';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import {
|
import {
|
||||||
Background,
|
Background,
|
||||||
|
@ -102,36 +102,29 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
}, PARAMETER.graphRefreshDelay);
|
}, PARAMETER.graphRefreshDelay);
|
||||||
}, [model.schema, setNodes, setEdges, setIsModified, toggleReset, edgeStraight, edgeAnimate]);
|
}, [model.schema, setNodes, setEdges, setIsModified, toggleReset, edgeStraight, edgeAnimate]);
|
||||||
|
|
||||||
const getPositions = useCallback(
|
function getPositions() {
|
||||||
() =>
|
return nodes.map(node => ({
|
||||||
nodes.map(node => ({
|
|
||||||
id: Number(node.id),
|
id: Number(node.id),
|
||||||
position_x: node.position.x,
|
position_x: node.position.x,
|
||||||
position_y: node.position.y
|
position_y: node.position.y
|
||||||
})),
|
}));
|
||||||
[nodes]
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const handleNodesChange = useCallback(
|
function handleNodesChange(changes: NodeChange[]) {
|
||||||
(changes: NodeChange[]) => {
|
|
||||||
if (changes.some(change => change.type === 'position' && change.position)) {
|
if (changes.some(change => change.type === 'position' && change.position)) {
|
||||||
setIsModified(true);
|
setIsModified(true);
|
||||||
}
|
}
|
||||||
onNodesChange(changes);
|
onNodesChange(changes);
|
||||||
},
|
}
|
||||||
[onNodesChange, setIsModified]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSavePositions = useCallback(() => {
|
function handleSavePositions() {
|
||||||
controller.savePositions(getPositions(), () => setIsModified(false));
|
controller.savePositions(getPositions(), () => setIsModified(false));
|
||||||
}, [controller, getPositions, setIsModified]);
|
}
|
||||||
|
|
||||||
const handleCreateOperation = useCallback(
|
function handleCreateOperation(inputs: OperationID[]) {
|
||||||
(inputs: OperationID[]) => {
|
|
||||||
if (!controller.schema) {
|
if (!controller.schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const positions = getPositions();
|
const positions = getPositions();
|
||||||
const target = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
|
const target = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
|
||||||
controller.promptCreateOperation({
|
controller.promptCreateOperation({
|
||||||
|
@ -141,78 +134,50 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
positions: positions,
|
positions: positions,
|
||||||
callback: () => flow.fitView({ duration: PARAMETER.zoomDuration })
|
callback: () => flow.fitView({ duration: PARAMETER.zoomDuration })
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
[controller, getPositions, flow]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDeleteOperation = useCallback(
|
function handleDeleteOperation(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
if (!controller.canDelete(target)) {
|
if (!controller.canDelete(target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
controller.promptDeleteOperation(target, getPositions());
|
controller.promptDeleteOperation(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDeleteSelected = useCallback(() => {
|
function handleDeleteSelected() {
|
||||||
if (controller.selected.length !== 1) {
|
if (controller.selected.length !== 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleDeleteOperation(controller.selected[0]);
|
handleDeleteOperation(controller.selected[0]);
|
||||||
}, [controller, handleDeleteOperation]);
|
}
|
||||||
|
|
||||||
const handleCreateInput = useCallback(
|
function handleCreateInput(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
controller.createInput(target, getPositions());
|
controller.createInput(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleEditSchema = useCallback(
|
function handleEditSchema(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
controller.promptEditInput(target, getPositions());
|
controller.promptEditInput(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleEditOperation = useCallback(
|
function handleEditOperation(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
controller.promptEditOperation(target, getPositions());
|
controller.promptEditOperation(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleExecuteOperation = useCallback(
|
function handleExecuteOperation(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
controller.executeOperation(target, getPositions());
|
controller.executeOperation(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleExecuteSelected = useCallback(() => {
|
function handleExecuteSelected() {
|
||||||
if (controller.selected.length !== 1) {
|
if (controller.selected.length !== 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleExecuteOperation(controller.selected[0]);
|
handleExecuteOperation(controller.selected[0]);
|
||||||
}, [controller, handleExecuteOperation]);
|
}
|
||||||
|
|
||||||
const handleRelocateConstituents = useCallback(
|
function handleRelocateConstituents(target: OperationID) {
|
||||||
(target: OperationID) => {
|
|
||||||
controller.promptRelocateConstituents(target, getPositions());
|
controller.promptRelocateConstituents(target, getPositions());
|
||||||
},
|
}
|
||||||
[controller, getPositions]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleFitView = useCallback(() => {
|
function handleSaveImage() {
|
||||||
flow.fitView({ duration: PARAMETER.zoomDuration });
|
|
||||||
}, [flow]);
|
|
||||||
|
|
||||||
const handleResetPositions = useCallback(() => {
|
|
||||||
setToggleReset(prev => !prev);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSaveImage = useCallback(() => {
|
|
||||||
if (!model.schema) {
|
if (!model.schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -246,10 +211,9 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
toast.error(errors.imageFailed);
|
toast.error(errors.imageFailed);
|
||||||
});
|
});
|
||||||
}, [colors, nodes, model.schema]);
|
}
|
||||||
|
|
||||||
const handleContextMenu = useCallback(
|
function handleContextMenu(event: CProps.EventMouse, node: OssNode) {
|
||||||
(event: CProps.EventMouse, node: OssNode) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
@ -259,21 +223,18 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
cursorY: event.clientY
|
cursorY: event.clientY
|
||||||
});
|
});
|
||||||
controller.setShowTooltip(false);
|
controller.setShowTooltip(false);
|
||||||
},
|
}
|
||||||
[controller]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleContextMenuHide = useCallback(() => {
|
function handleContextMenuHide() {
|
||||||
controller.setShowTooltip(true);
|
controller.setShowTooltip(true);
|
||||||
setMenuProps(undefined);
|
setMenuProps(undefined);
|
||||||
}, [controller]);
|
}
|
||||||
|
|
||||||
const handleCanvasClick = useCallback(() => {
|
function handleCanvasClick() {
|
||||||
handleContextMenuHide();
|
handleContextMenuHide();
|
||||||
}, [handleContextMenuHide]);
|
}
|
||||||
|
|
||||||
const handleNodeDoubleClick = useCallback(
|
function handleNodeDoubleClick(event: CProps.EventMouse, node: OssNode) {
|
||||||
(event: CProps.EventMouse, node: OssNode) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (node.data.operation.result) {
|
if (node.data.operation.result) {
|
||||||
|
@ -281,9 +242,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
} else {
|
} else {
|
||||||
handleEditOperation(Number(node.id));
|
handleEditOperation(Number(node.id));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[handleEditOperation, controller]
|
|
||||||
);
|
|
||||||
|
|
||||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
if (controller.isProcessing) {
|
if (controller.isProcessing) {
|
||||||
|
@ -312,41 +271,6 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const graph = useMemo(
|
|
||||||
() => (
|
|
||||||
<ReactFlow
|
|
||||||
nodes={nodes}
|
|
||||||
edges={edges}
|
|
||||||
onNodesChange={handleNodesChange}
|
|
||||||
onEdgesChange={onEdgesChange}
|
|
||||||
onNodeDoubleClick={handleNodeDoubleClick}
|
|
||||||
edgesFocusable={false}
|
|
||||||
nodesFocusable={false}
|
|
||||||
fitView
|
|
||||||
nodeTypes={OssNodeTypes}
|
|
||||||
maxZoom={ZOOM_MAX}
|
|
||||||
minZoom={ZOOM_MIN}
|
|
||||||
nodesConnectable={false}
|
|
||||||
snapToGrid={true}
|
|
||||||
snapGrid={[PARAMETER.ossGridSize, PARAMETER.ossGridSize]}
|
|
||||||
onNodeContextMenu={handleContextMenu}
|
|
||||||
onClick={handleCanvasClick}
|
|
||||||
>
|
|
||||||
{showGrid ? <Background gap={PARAMETER.ossGridSize} /> : null}
|
|
||||||
</ReactFlow>
|
|
||||||
),
|
|
||||||
[
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
handleNodesChange,
|
|
||||||
handleContextMenu,
|
|
||||||
handleCanvasClick,
|
|
||||||
onEdgesChange,
|
|
||||||
handleNodeDoubleClick,
|
|
||||||
showGrid
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} onKeyDown={handleKeyDown}>
|
<div tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||||
<Overlay position='top-[1.9rem] pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
|
<Overlay position='top-[1.9rem] pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
|
||||||
|
@ -355,12 +279,12 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
showGrid={showGrid}
|
showGrid={showGrid}
|
||||||
edgeAnimate={edgeAnimate}
|
edgeAnimate={edgeAnimate}
|
||||||
edgeStraight={edgeStraight}
|
edgeStraight={edgeStraight}
|
||||||
onFitView={handleFitView}
|
onFitView={() => flow.fitView({ duration: PARAMETER.zoomDuration })}
|
||||||
onCreate={() => handleCreateOperation(controller.selected)}
|
onCreate={() => handleCreateOperation(controller.selected)}
|
||||||
onDelete={handleDeleteSelected}
|
onDelete={handleDeleteSelected}
|
||||||
onEdit={() => handleEditOperation(controller.selected[0])}
|
onEdit={() => handleEditOperation(controller.selected[0])}
|
||||||
onExecute={handleExecuteSelected}
|
onExecute={handleExecuteSelected}
|
||||||
onResetPositions={handleResetPositions}
|
onResetPositions={() => setToggleReset(prev => !prev)}
|
||||||
onSavePositions={handleSavePositions}
|
onSavePositions={handleSavePositions}
|
||||||
onSaveImage={handleSaveImage}
|
onSaveImage={handleSaveImage}
|
||||||
toggleShowGrid={() => setShowGrid(prev => !prev)}
|
toggleShowGrid={() => setShowGrid(prev => !prev)}
|
||||||
|
@ -381,7 +305,26 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<div className='cc-fade-in relative w-[100vw]' style={{ height: mainHeight, fontFamily: 'Rubik' }}>
|
<div className='cc-fade-in relative w-[100vw]' style={{ height: mainHeight, fontFamily: 'Rubik' }}>
|
||||||
{graph}
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={edges}
|
||||||
|
onNodesChange={handleNodesChange}
|
||||||
|
onEdgesChange={onEdgesChange}
|
||||||
|
onNodeDoubleClick={handleNodeDoubleClick}
|
||||||
|
edgesFocusable={false}
|
||||||
|
nodesFocusable={false}
|
||||||
|
fitView
|
||||||
|
nodeTypes={OssNodeTypes}
|
||||||
|
maxZoom={ZOOM_MAX}
|
||||||
|
minZoom={ZOOM_MIN}
|
||||||
|
nodesConnectable={false}
|
||||||
|
snapToGrid={true}
|
||||||
|
snapGrid={[PARAMETER.ossGridSize, PARAMETER.ossGridSize]}
|
||||||
|
onNodeContextMenu={handleContextMenu}
|
||||||
|
onClick={handleCanvasClick}
|
||||||
|
>
|
||||||
|
{showGrid ? <Background gap={PARAMETER.ossGridSize} /> : null}
|
||||||
|
</ReactFlow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IconAnimation,
|
IconAnimation,
|
||||||
|
@ -63,11 +62,8 @@ function ToolbarOssGraph({
|
||||||
toggleEdgeStraight
|
toggleEdgeStraight
|
||||||
}: ToolbarOssGraphProps) {
|
}: ToolbarOssGraphProps) {
|
||||||
const controller = useOssEdit();
|
const controller = useOssEdit();
|
||||||
const selectedOperation = useMemo(
|
const selectedOperation = controller.schema?.operationByID.get(controller.selected[0]);
|
||||||
() => controller.schema?.operationByID.get(controller.selected[0]),
|
const readyForSynthesis = (() => {
|
||||||
[controller.selected, controller.schema]
|
|
||||||
);
|
|
||||||
const readyForSynthesis = useMemo(() => {
|
|
||||||
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
|
if (!selectedOperation || selectedOperation.operation_type !== OperationType.SYNTHESIS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +82,7 @@ function ToolbarOssGraph({
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, [selectedOperation, controller.schema]);
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center'>
|
<div className='flex flex-col items-center'>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -64,8 +64,7 @@ function OssTabs() {
|
||||||
setNoFooter(activeTab === OssTabID.GRAPH);
|
setNoFooter(activeTab === OssTabID.GRAPH);
|
||||||
}, [activeTab, setNoFooter]);
|
}, [activeTab, setNoFooter]);
|
||||||
|
|
||||||
const navigateTab = useCallback(
|
function navigateTab(tab: OssTabID) {
|
||||||
(tab: OssTabID) => {
|
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -74,9 +73,7 @@ function OssTabs() {
|
||||||
tab: tab
|
tab: tab
|
||||||
});
|
});
|
||||||
router.push(url);
|
router.push(url);
|
||||||
},
|
}
|
||||||
[router, schema]
|
|
||||||
);
|
|
||||||
|
|
||||||
function onSelectTab(index: number, last: number, event: Event) {
|
function onSelectTab(index: number, last: number, event: Event) {
|
||||||
if (last === index) {
|
if (last === index) {
|
||||||
|
@ -97,7 +94,7 @@ function OssTabs() {
|
||||||
navigateTab(index);
|
navigateTab(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onDestroySchema = useCallback(() => {
|
function onDestroySchema() {
|
||||||
if (!schema || !window.confirm(prompts.deleteOSS)) {
|
if (!schema || !window.confirm(prompts.deleteOSS)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -105,29 +102,7 @@ function OssTabs() {
|
||||||
toast.success(information.itemDestroyed);
|
toast.success(information.itemDestroyed);
|
||||||
router.push(urls.library);
|
router.push(urls.library);
|
||||||
});
|
});
|
||||||
}, [schema, destroyItem, router]);
|
}
|
||||||
|
|
||||||
const cardPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorRSForm
|
|
||||||
isModified={isModified} // prettier: split lines
|
|
||||||
setIsModified={setIsModified}
|
|
||||||
onDestroy={onDestroySchema}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[isModified, onDestroySchema]
|
|
||||||
);
|
|
||||||
|
|
||||||
const graphPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorTermGraph isModified={isModified} setIsModified={setIsModified} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[isModified]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OssEditState selected={selected} setSelected={setSelected}>
|
<OssEditState selected={selected} setSelected={setSelected}>
|
||||||
|
@ -151,8 +126,17 @@ function OssTabs() {
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<div className='overflow-x-hidden'>
|
<div className='overflow-x-hidden'>
|
||||||
{cardPanel}
|
<TabPanel>
|
||||||
{graphPanel}
|
<EditorRSForm
|
||||||
|
isModified={isModified} // prettier: split lines
|
||||||
|
setIsModified={setIsModified}
|
||||||
|
onDestroy={onDestroySchema}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<EditorTermGraph isModified={isModified} setIsModified={setIsModified} />
|
||||||
|
</TabPanel>
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
|
@ -24,17 +24,10 @@ function PasswordChangePage() {
|
||||||
const [newPassword, setNewPassword] = useState('');
|
const [newPassword, setNewPassword] = useState('');
|
||||||
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
||||||
|
|
||||||
const passwordColor = useMemo(() => {
|
const passwordColor =
|
||||||
if (!!newPassword && !!newPasswordRepeat && newPassword !== newPasswordRepeat) {
|
!!newPassword && !!newPasswordRepeat && newPassword !== newPasswordRepeat ? 'clr-warning' : 'clr-input';
|
||||||
return 'clr-warning';
|
|
||||||
} else {
|
|
||||||
return 'clr-input';
|
|
||||||
}
|
|
||||||
}, [newPassword, newPasswordRepeat]);
|
|
||||||
|
|
||||||
const canSubmit = useMemo(() => {
|
const canSubmit = !!newPassword && !!newPasswordRepeat && newPassword === newPasswordRepeat;
|
||||||
return !!newPassword && !!newPasswordRepeat && newPassword === newPasswordRepeat;
|
|
||||||
}, [newPassword, newPasswordRepeat]);
|
|
||||||
|
|
||||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
|
@ -32,12 +32,8 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
|
||||||
const [showList, setShowList] = useLocalStorage(storage.rseditShowList, true);
|
const [showList, setShowList] = useLocalStorage(storage.rseditShowList, true);
|
||||||
const [toggleReset, setToggleReset] = useState(false);
|
const [toggleReset, setToggleReset] = useState(false);
|
||||||
|
|
||||||
const disabled = useMemo(
|
const disabled = !activeCst || !controller.isContentEditable || controller.isProcessing;
|
||||||
() => !activeCst || !controller.isContentEditable || controller.isProcessing,
|
const isNarrow = !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD;
|
||||||
[activeCst, controller.isContentEditable, controller.isProcessing]
|
|
||||||
);
|
|
||||||
|
|
||||||
const isNarrow = useMemo(() => !!windowSize.width && windowSize.width <= SIDELIST_LAYOUT_THRESHOLD, [windowSize]);
|
|
||||||
|
|
||||||
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { IconChild, IconPredecessor, IconSave } from '@/components/Icons';
|
import { IconChild, IconPredecessor, IconSave } from '@/components/Icons';
|
||||||
|
@ -58,26 +58,19 @@ function FormConstituenta({
|
||||||
const [typification, setTypification] = useState('N/A');
|
const [typification, setTypification] = useState('N/A');
|
||||||
const [showTypification, setShowTypification] = useState(false);
|
const [showTypification, setShowTypification] = useState(false);
|
||||||
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
|
||||||
const typeInfo = useMemo(
|
const typeInfo = state
|
||||||
() =>
|
|
||||||
state
|
|
||||||
? {
|
? {
|
||||||
alias: state.alias,
|
alias: state.alias,
|
||||||
result: localParse ? localParse.typification : state.parse.typification,
|
result: localParse ? localParse.typification : state.parse.typification,
|
||||||
args: localParse ? localParse.args : state.parse.args
|
args: localParse ? localParse.args : state.parse.args
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined;
|
||||||
[state, localParse]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [forceComment, setForceComment] = useState(false);
|
const [forceComment, setForceComment] = useState(false);
|
||||||
|
|
||||||
const isBasic = useMemo(() => !!state && isBasicConcept(state.cst_type), [state]);
|
const isBasic = !!state && isBasicConcept(state.cst_type);
|
||||||
const isElementary = useMemo(() => !!state && isBaseSet(state.cst_type), [state]);
|
const isElementary = !!state && isBaseSet(state.cst_type);
|
||||||
const showConvention = useMemo(
|
const showConvention = !state || !!state.convention || forceComment || isBasic;
|
||||||
() => !state || !!state.convention || forceComment || isBasic,
|
|
||||||
[state, forceComment, isBasic]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state) {
|
if (state) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
|
@ -99,7 +99,7 @@ function EditorRSExpression({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const onShowError = useCallback((error: IRSErrorDescription, prefixLen: number) => {
|
function onShowError(error: IRSErrorDescription, prefixLen: number) {
|
||||||
if (!rsInput.current) {
|
if (!rsInput.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -112,9 +112,9 @@ function EditorRSExpression({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
rsInput.current?.view?.focus();
|
rsInput.current?.view?.focus();
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const handleEdit = useCallback((id: TokenID, key?: string) => {
|
function handleEdit(id: TokenID, key?: string) {
|
||||||
if (!rsInput.current?.editor || !rsInput.current.state || !rsInput.current.view) {
|
if (!rsInput.current?.editor || !rsInput.current.state || !rsInput.current.view) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ function EditorRSExpression({
|
||||||
}
|
}
|
||||||
rsInput.current?.view?.focus();
|
rsInput.current?.view?.focus();
|
||||||
setIsModified(true);
|
setIsModified(true);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
function handleShowAST(event: CProps.EventMouse) {
|
function handleShowAST(event: CProps.EventMouse) {
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
|
@ -148,17 +148,6 @@ function EditorRSExpression({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const controls = useMemo(
|
|
||||||
() => (
|
|
||||||
<RSEditorControls
|
|
||||||
isOpen={showControls && (!disabled || (model.processing && !activeCst.is_inherited))}
|
|
||||||
disabled={disabled}
|
|
||||||
onEdit={handleEdit}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[showControls, disabled, model.processing, handleEdit, activeCst]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='cc-fade-in'>
|
<div className='cc-fade-in'>
|
||||||
{showAST ? (
|
{showAST ? (
|
||||||
|
@ -201,7 +190,11 @@ function EditorRSExpression({
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{controls}
|
<RSEditorControls
|
||||||
|
isOpen={showControls && (!disabled || (model.processing && !activeCst.is_inherited))}
|
||||||
|
disabled={disabled}
|
||||||
|
onEdit={handleEdit}
|
||||||
|
/>
|
||||||
|
|
||||||
<ParsingResult
|
<ParsingResult
|
||||||
isOpen={!!parser.parseData && parser.parseData.errors.length > 0}
|
isOpen={!!parser.parseData && parser.parseData.errors.length > 0}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { StatusIcon } from '@/components/DomainIcons';
|
import { StatusIcon } from '@/components/DomainIcons';
|
||||||
import Loader from '@/components/ui/Loader';
|
import Loader from '@/components/ui/Loader';
|
||||||
|
@ -24,7 +23,7 @@ interface StatusBarProps {
|
||||||
|
|
||||||
function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const status = useMemo(() => {
|
const status = (() => {
|
||||||
if (isModified) {
|
if (isModified) {
|
||||||
return ExpressionStatus.UNKNOWN;
|
return ExpressionStatus.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +32,7 @@ function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }:
|
||||||
return inferStatus(parse, parseData.valueClass);
|
return inferStatus(parse, parseData.valueClass);
|
||||||
}
|
}
|
||||||
return inferStatus(activeCst.parse.status, activeCst.parse.valueClass);
|
return inferStatus(activeCst.parse.status, activeCst.parse.valueClass);
|
||||||
}, [isModified, activeCst, parseData]);
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { VisibilityIcon } from '@/components/DomainIcons';
|
import { VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import { IconImmutable, IconMutable } from '@/components/Icons';
|
import { IconImmutable, IconMutable } from '@/components/Icons';
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
|
@ -23,10 +21,7 @@ interface ToolbarItemAccessProps {
|
||||||
|
|
||||||
function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, controller }: ToolbarItemAccessProps) {
|
function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, controller }: ToolbarItemAccessProps) {
|
||||||
const { accessLevel } = useAccessMode();
|
const { accessLevel } = useAccessMode();
|
||||||
const policy = useMemo(
|
const policy = controller.schema?.access_policy ?? AccessPolicy.PRIVATE;
|
||||||
() => controller.schema?.access_policy ?? AccessPolicy.PRIVATE,
|
|
||||||
[controller.schema?.access_policy]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay position='top-[4.5rem] right-0 w-[12rem] pr-2' className='flex' layer='z-bottom'>
|
<Overlay position='top-[4.5rem] right-0 w-[12rem] pr-2' className='flex' layer='z-bottom'>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IconDestroy, IconSave, IconShare } from '@/components/Icons';
|
import { IconDestroy, IconSave, IconShare } from '@/components/Icons';
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
import MiniSelectorOSS from '@/components/select/MiniSelectorOSS';
|
||||||
|
@ -26,9 +24,9 @@ interface ToolbarRSFormCardProps {
|
||||||
|
|
||||||
function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
|
function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: ToolbarRSFormCardProps) {
|
||||||
const { accessLevel } = useAccessMode();
|
const { accessLevel } = useAccessMode();
|
||||||
const canSave = useMemo(() => modified && !controller.isProcessing, [modified, controller.isProcessing]);
|
const canSave = modified && !controller.isProcessing;
|
||||||
|
|
||||||
const ossSelector = useMemo(() => {
|
const ossSelector = (() => {
|
||||||
if (!controller.schema || controller.schema?.item_type !== LibraryItemType.RSFORM) {
|
if (!controller.schema || controller.schema?.item_type !== LibraryItemType.RSFORM) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +40,7 @@ function ToolbarRSFormCard({ modified, controller, onSubmit, onDestroy }: Toolba
|
||||||
onSelect={(event, value) => (controller as IRSEditContext).viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
onSelect={(event, value) => (controller as IRSEditContext).viewOSS(value.id, event.ctrlKey || event.metaKey)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [controller]);
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Overlay position='cc-tab-tools' className='cc-icons'>
|
<Overlay position='cc-tab-tools' className='cc-icons'>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import fileDownload from 'js-file-download';
|
import fileDownload from 'js-file-download';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { IconCSV } from '@/components/Icons';
|
import { IconCSV } from '@/components/Icons';
|
||||||
|
@ -54,7 +54,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
||||||
}
|
}
|
||||||
}, [filterText, controller.schema?.items, controller.schema]);
|
}, [filterText, controller.schema?.items, controller.schema]);
|
||||||
|
|
||||||
const handleDownloadCSV = useCallback(() => {
|
function handleDownloadCSV() {
|
||||||
if (!controller.schema || filtered.length === 0) {
|
if (!controller.schema || filtered.length === 0) {
|
||||||
toast.error(information.noDataToExport);
|
toast.error(information.noDataToExport);
|
||||||
return;
|
return;
|
||||||
|
@ -65,7 +65,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}, [filtered, controller]);
|
}
|
||||||
|
|
||||||
function handleRowSelection(updater: React.SetStateAction<RowSelectionState>) {
|
function handleRowSelection(updater: React.SetStateAction<RowSelectionState>) {
|
||||||
if (!controller.schema) {
|
if (!controller.schema) {
|
||||||
|
@ -136,7 +136,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableHeight = useMemo(() => calculateHeight('4.05rem + 5px'), [calculateHeight]);
|
const tableHeight = calculateHeight('4.05rem + 5px');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
|
@ -59,26 +59,19 @@ function TableRSList({
|
||||||
});
|
});
|
||||||
}, [windowSize]);
|
}, [windowSize]);
|
||||||
|
|
||||||
const handleRowClicked = useCallback(
|
function handleRowClicked(cst: IConstituenta, event: CProps.EventMouse) {
|
||||||
(cst: IConstituenta, event: CProps.EventMouse) => {
|
|
||||||
if (event.altKey) {
|
if (event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onEdit(cst.id);
|
onEdit(cst.id);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[onEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleRowDoubleClicked = useCallback(
|
function handleRowDoubleClicked(cst: IConstituenta, event: CProps.EventMouse) {
|
||||||
(cst: IConstituenta, event: CProps.EventMouse) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onEdit(cst.id);
|
onEdit(cst.id);
|
||||||
},
|
}
|
||||||
[onEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = [
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: () => <span className='pl-3'>Имя</span>,
|
header: () => <span className='pl-3'>Имя</span>,
|
||||||
|
@ -132,9 +125,7 @@ function TableRSList({
|
||||||
enableHiding: true,
|
enableHiding: true,
|
||||||
cell: props => <TextContent text={props.getValue()} maxLength={COMMENT_MAX_SYMBOLS} />
|
cell: props => <TextContent text={props.getValue()} maxLength={COMMENT_MAX_SYMBOLS} />
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IconHelp } from '@/components/Icons';
|
import { IconHelp } from '@/components/Icons';
|
||||||
import Tooltip from '@/components/ui/Tooltip';
|
import Tooltip from '@/components/ui/Tooltip';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -17,7 +15,7 @@ function SchemasGuide({ schema }: SchemasGuideProps) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
|
|
||||||
const schemas = useMemo(() => {
|
const schemas = (() => {
|
||||||
const processed = new Set<LibraryItemID>();
|
const processed = new Set<LibraryItemID>();
|
||||||
const aliases: string[] = [];
|
const aliases: string[] = [];
|
||||||
const indexes: number[] = [];
|
const indexes: number[] = [];
|
||||||
|
@ -39,7 +37,7 @@ function SchemasGuide({ schema }: SchemasGuideProps) {
|
||||||
result.push(aliases[trueIndex]);
|
result.push(aliases[trueIndex]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, [schema, library.items]);
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div tabIndex={-1} id={globals.graph_schemas} className='p-1'>
|
<div tabIndex={-1} id={globals.graph_schemas} className='p-1'>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { toPng } from 'html-to-image';
|
import { toPng } from 'html-to-image';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import {
|
import {
|
||||||
Edge,
|
Edge,
|
||||||
|
@ -89,9 +89,7 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
|
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const [hoverID, setHoverID] = useState<ConstituentaID | undefined>(undefined);
|
const [hoverID, setHoverID] = useState<ConstituentaID | undefined>(undefined);
|
||||||
const hoverCst = useMemo(() => {
|
const hoverCst = hoverID && controller.schema?.cstByID.get(hoverID);
|
||||||
return hoverID && controller.schema?.cstByID.get(hoverID);
|
|
||||||
}, [controller.schema?.cstByID, hoverID]);
|
|
||||||
const [hoverCstDebounced] = useDebounce(hoverCst, PARAMETER.graphPopupDelay);
|
const [hoverCstDebounced] = useDebounce(hoverCst, PARAMETER.graphPopupDelay);
|
||||||
const [hoverLeft, setHoverLeft] = useState(true);
|
const [hoverLeft, setHoverLeft] = useState(true);
|
||||||
|
|
||||||
|
@ -223,14 +221,11 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
controller.promptDeleteCst();
|
controller.promptDeleteCst();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeParams = useCallback(
|
function handleChangeParams(params: GraphFilterParams) {
|
||||||
(params: GraphFilterParams) => {
|
|
||||||
setFilterParams(params);
|
setFilterParams(params);
|
||||||
},
|
}
|
||||||
[setFilterParams]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleSaveImage = useCallback(() => {
|
function handleSaveImage() {
|
||||||
if (!controller.schema) {
|
if (!controller.schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +259,7 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
toast.error(errors.imageFailed);
|
toast.error(errors.imageFailed);
|
||||||
});
|
});
|
||||||
}, [colors, nodes, controller.schema]);
|
}
|
||||||
|
|
||||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
if (controller.isProcessing) {
|
if (controller.isProcessing) {
|
||||||
|
@ -288,7 +283,7 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFoldDerived = useCallback(() => {
|
function handleFoldDerived() {
|
||||||
setFilterParams(prev => ({
|
setFilterParams(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
foldDerived: !prev.foldDerived
|
foldDerived: !prev.foldDerived
|
||||||
|
@ -296,99 +291,37 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setToggleResetView(prev => !prev);
|
setToggleResetView(prev => !prev);
|
||||||
}, PARAMETER.graphRefreshDelay);
|
}, PARAMETER.graphRefreshDelay);
|
||||||
}, [setFilterParams, setToggleResetView]);
|
}
|
||||||
|
|
||||||
const handleSetFocus = useCallback(
|
function handleSetFocus(cstID: ConstituentaID | undefined) {
|
||||||
(cstID: ConstituentaID | undefined) => {
|
|
||||||
const target = cstID !== undefined ? controller.schema?.cstByID.get(cstID) : cstID;
|
const target = cstID !== undefined ? controller.schema?.cstByID.get(cstID) : cstID;
|
||||||
setFocusCst(prev => (prev === target ? undefined : target));
|
setFocusCst(prev => (prev === target ? undefined : target));
|
||||||
if (target) {
|
if (target) {
|
||||||
controller.setSelected([]);
|
controller.setSelected([]);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[controller]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleNodeClick = useCallback(
|
function handleNodeClick(event: CProps.EventMouse, cstID: ConstituentaID) {
|
||||||
(event: CProps.EventMouse, cstID: ConstituentaID) => {
|
|
||||||
if (event.altKey) {
|
if (event.altKey) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
handleSetFocus(cstID);
|
handleSetFocus(cstID);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[handleSetFocus]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleNodeDoubleClick = useCallback(
|
function handleNodeDoubleClick(event: CProps.EventMouse, cstID: ConstituentaID) {
|
||||||
(event: CProps.EventMouse, cstID: ConstituentaID) => {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onOpenEdit(cstID);
|
onOpenEdit(cstID);
|
||||||
},
|
}
|
||||||
[onOpenEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleNodeEnter = useCallback(
|
function handleNodeEnter(event: CProps.EventMouse, cstID: ConstituentaID) {
|
||||||
(event: CProps.EventMouse, cstID: ConstituentaID) => {
|
|
||||||
setHoverID(cstID);
|
setHoverID(cstID);
|
||||||
setHoverLeft(
|
setHoverLeft(
|
||||||
event.clientX / window.innerWidth >= PARAMETER.graphHoverXLimit ||
|
event.clientX / window.innerWidth >= PARAMETER.graphHoverXLimit ||
|
||||||
event.clientY / window.innerHeight >= PARAMETER.graphHoverYLimit
|
event.clientY / window.innerHeight >= PARAMETER.graphHoverYLimit
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
[setHoverID, setHoverLeft]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleNodeLeave = useCallback(() => {
|
|
||||||
setHoverID(undefined);
|
|
||||||
}, [setHoverID]);
|
|
||||||
|
|
||||||
const selectors = useMemo(
|
|
||||||
() => <GraphSelectors schema={controller.schema} coloring={coloring} onChangeColoring={setColoring} />,
|
|
||||||
[coloring, controller.schema, setColoring]
|
|
||||||
);
|
|
||||||
const viewHidden = useMemo(
|
|
||||||
() => (
|
|
||||||
<ViewHidden
|
|
||||||
items={hidden}
|
|
||||||
selected={controller.selected}
|
|
||||||
schema={controller.schema}
|
|
||||||
coloringScheme={coloring}
|
|
||||||
toggleSelection={controller.toggleSelect}
|
|
||||||
setFocus={handleSetFocus}
|
|
||||||
onEdit={onOpenEdit}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[hidden, controller.selected, controller.schema, coloring, controller.toggleSelect, handleSetFocus, onOpenEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const graph = useMemo(
|
|
||||||
() => (
|
|
||||||
<div className='relative outline-none w-[100dvw]' style={{ height: mainHeight }}>
|
|
||||||
<ReactFlow
|
|
||||||
nodes={nodes}
|
|
||||||
onNodesChange={onNodesChange}
|
|
||||||
edges={edges}
|
|
||||||
fitView
|
|
||||||
edgesFocusable={false}
|
|
||||||
nodesFocusable={false}
|
|
||||||
nodesConnectable={false}
|
|
||||||
nodeTypes={TGNodeTypes}
|
|
||||||
edgeTypes={TGEdgeTypes}
|
|
||||||
maxZoom={ZOOM_MAX}
|
|
||||||
minZoom={ZOOM_MIN}
|
|
||||||
onNodeDragStart={() => setIsDragging(true)}
|
|
||||||
onNodeDragStop={() => setIsDragging(false)}
|
|
||||||
onNodeMouseEnter={(event, node) => handleNodeEnter(event, Number(node.id))}
|
|
||||||
onNodeMouseLeave={handleNodeLeave}
|
|
||||||
onNodeClick={(event, node) => handleNodeClick(event, Number(node.id))}
|
|
||||||
onNodeDoubleClick={(event, node) => handleNodeDoubleClick(event, Number(node.id))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
[nodes, edges, mainHeight, handleNodeClick, handleNodeDoubleClick, handleNodeLeave, handleNodeEnter, onNodesChange]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -480,12 +413,40 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
||||||
|
|
||||||
<Overlay position='top-[6.15rem] sm:top-[5.9rem] left-0' className='flex gap-1'>
|
<Overlay position='top-[6.15rem] sm:top-[5.9rem] left-0' className='flex gap-1'>
|
||||||
<div className='flex flex-col ml-2 w-[13.5rem]'>
|
<div className='flex flex-col ml-2 w-[13.5rem]'>
|
||||||
{selectors}
|
<GraphSelectors schema={controller.schema} coloring={coloring} onChangeColoring={setColoring} />
|
||||||
{viewHidden}
|
<ViewHidden
|
||||||
|
items={hidden}
|
||||||
|
selected={controller.selected}
|
||||||
|
schema={controller.schema}
|
||||||
|
coloringScheme={coloring}
|
||||||
|
toggleSelection={controller.toggleSelect}
|
||||||
|
setFocus={handleSetFocus}
|
||||||
|
onEdit={onOpenEdit}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
{graph}
|
<div className='relative outline-none w-[100dvw]' style={{ height: mainHeight }}>
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
onNodesChange={onNodesChange}
|
||||||
|
edges={edges}
|
||||||
|
fitView
|
||||||
|
edgesFocusable={false}
|
||||||
|
nodesFocusable={false}
|
||||||
|
nodesConnectable={false}
|
||||||
|
nodeTypes={TGNodeTypes}
|
||||||
|
edgeTypes={TGEdgeTypes}
|
||||||
|
maxZoom={ZOOM_MAX}
|
||||||
|
minZoom={ZOOM_MIN}
|
||||||
|
onNodeDragStart={() => setIsDragging(true)}
|
||||||
|
onNodeDragStop={() => setIsDragging(false)}
|
||||||
|
onNodeMouseEnter={(event, node) => handleNodeEnter(event, Number(node.id))}
|
||||||
|
onNodeMouseLeave={() => setHoverID(undefined)}
|
||||||
|
onNodeClick={(event, node) => handleNodeClick(event, Number(node.id))}
|
||||||
|
onNodeDoubleClick={(event, node) => handleNodeDoubleClick(event, Number(node.id))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { IconDropArrow, IconDropArrowUp } from '@/components/Icons';
|
import { IconDropArrow, IconDropArrowUp } from '@/components/Icons';
|
||||||
import TooltipConstituenta from '@/components/info/TooltipConstituenta';
|
import TooltipConstituenta from '@/components/info/TooltipConstituenta';
|
||||||
|
@ -30,19 +29,16 @@ interface ViewHiddenProps {
|
||||||
function ViewHidden({ items, selected, toggleSelection, setFocus, schema, coloringScheme, onEdit }: ViewHiddenProps) {
|
function ViewHidden({ items, selected, toggleSelection, setFocus, schema, coloringScheme, onEdit }: ViewHiddenProps) {
|
||||||
const { colors, calculateHeight } = useConceptOptions();
|
const { colors, calculateHeight } = useConceptOptions();
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
const localSelected = useMemo(() => items.filter(id => selected.includes(id)), [items, selected]);
|
const localSelected = items.filter(id => selected.includes(id));
|
||||||
const [isFolded, setIsFolded] = useLocalStorage(storage.rsgraphFoldHidden, false);
|
const [isFolded, setIsFolded] = useLocalStorage(storage.rsgraphFoldHidden, false);
|
||||||
|
|
||||||
const handleClick = useCallback(
|
function handleClick(cstID: ConstituentaID, event: CProps.EventMouse) {
|
||||||
(cstID: ConstituentaID, event: CProps.EventMouse) => {
|
|
||||||
if (event.ctrlKey || event.metaKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
setFocus(cstID);
|
setFocus(cstID);
|
||||||
} else {
|
} else {
|
||||||
toggleSelection(cstID);
|
toggleSelection(cstID);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[setFocus, toggleSelection]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!schema || items.length <= 0) {
|
if (!schema || items.length <= 0) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
|
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -34,10 +33,7 @@ interface TGNodeInternal {
|
||||||
|
|
||||||
function TGNode(node: TGNodeInternal) {
|
function TGNode(node: TGNodeInternal) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const description = useMemo(
|
const description = truncateToLastWord(node.data.description, MAX_DESCRIPTION_LENGTH);
|
||||||
() => truncateToLastWord(node.data.description, MAX_DESCRIPTION_LENGTH),
|
|
||||||
[node.data.description]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Graph } from '@/models/Graph';
|
import { Graph } from '@/models/Graph';
|
||||||
import { GraphFilterParams } from '@/models/miscellaneous';
|
import { GraphFilterParams } from '@/models/miscellaneous';
|
||||||
|
@ -7,7 +7,7 @@ import { ConstituentaID, CstType, IConstituenta, IRSForm } from '@/models/rsform
|
||||||
function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams, focusCst: IConstituenta | undefined) {
|
function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams, focusCst: IConstituenta | undefined) {
|
||||||
const [filtered, setFiltered] = useState<Graph>(new Graph());
|
const [filtered, setFiltered] = useState<Graph>(new Graph());
|
||||||
|
|
||||||
const allowedTypes: CstType[] = useMemo(() => {
|
const allowedTypes: CstType[] = (() => {
|
||||||
const result: CstType[] = [];
|
const result: CstType[] = [];
|
||||||
if (params.allowBase) result.push(CstType.BASE);
|
if (params.allowBase) result.push(CstType.BASE);
|
||||||
if (params.allowStruct) result.push(CstType.STRUCTURED);
|
if (params.allowStruct) result.push(CstType.STRUCTURED);
|
||||||
|
@ -18,7 +18,7 @@ function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams,
|
||||||
if (params.allowConstant) result.push(CstType.CONSTANT);
|
if (params.allowConstant) result.push(CstType.CONSTANT);
|
||||||
if (params.allowTheorem) result.push(CstType.THEOREM);
|
if (params.allowTheorem) result.push(CstType.THEOREM);
|
||||||
return result;
|
return result;
|
||||||
}, [params]);
|
})();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -54,13 +54,13 @@ function RSTabs() {
|
||||||
useBlockNavigation(isModified);
|
useBlockNavigation(isModified);
|
||||||
|
|
||||||
const [selected, setSelected] = useState<ConstituentaID[]>([]);
|
const [selected, setSelected] = useState<ConstituentaID[]>([]);
|
||||||
const activeCst: IConstituenta | undefined = useMemo(() => {
|
const activeCst: IConstituenta | undefined = (() => {
|
||||||
if (!schema || selected.length === 0) {
|
if (!schema || selected.length === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
} else {
|
} else {
|
||||||
return schema.cstByID.get(selected.at(-1)!);
|
return schema.cstByID.get(selected.at(-1)!);
|
||||||
}
|
}
|
||||||
}, [schema, selected]);
|
})();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (schema) {
|
if (schema) {
|
||||||
|
@ -86,8 +86,7 @@ function RSTabs() {
|
||||||
return () => setNoFooter(false);
|
return () => setNoFooter(false);
|
||||||
}, [activeTab, cstQuery, setSelected, schema, setNoFooter, setIsModified]);
|
}, [activeTab, cstQuery, setSelected, schema, setNoFooter, setIsModified]);
|
||||||
|
|
||||||
const navigateTab = useCallback(
|
function navigateTab(tab: RSTabID, activeID?: ConstituentaID) {
|
||||||
(tab: RSTabID, activeID?: ConstituentaID) => {
|
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -109,9 +108,7 @@ function RSTabs() {
|
||||||
} else {
|
} else {
|
||||||
router.push(url);
|
router.push(url);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[router, schema, activeTab, version]
|
|
||||||
);
|
|
||||||
|
|
||||||
function onSelectTab(index: number, last: number, event: Event) {
|
function onSelectTab(index: number, last: number, event: Event) {
|
||||||
if (last === index) {
|
if (last === index) {
|
||||||
|
@ -132,8 +129,7 @@ function RSTabs() {
|
||||||
navigateTab(index, selected.length > 0 ? selected.at(-1) : undefined);
|
navigateTab(index, selected.length > 0 ? selected.at(-1) : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onCreateCst = useCallback(
|
function onCreateCst(newCst: IConstituentaMeta) {
|
||||||
(newCst: IConstituentaMeta) => {
|
|
||||||
navigateTab(activeTab, newCst.id);
|
navigateTab(activeTab, newCst.id);
|
||||||
if (activeTab === RSTabID.CST_LIST) {
|
if (activeTab === RSTabID.CST_LIST) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -147,12 +143,9 @@ function RSTabs() {
|
||||||
}
|
}
|
||||||
}, PARAMETER.refreshTimeout);
|
}, PARAMETER.refreshTimeout);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[activeTab, navigateTab]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onDeleteCst = useCallback(
|
function onDeleteCst(newActive?: ConstituentaID) {
|
||||||
(newActive?: ConstituentaID) => {
|
|
||||||
if (!newActive) {
|
if (!newActive) {
|
||||||
navigateTab(RSTabID.CST_LIST);
|
navigateTab(RSTabID.CST_LIST);
|
||||||
} else if (activeTab === RSTabID.CST_EDIT) {
|
} else if (activeTab === RSTabID.CST_EDIT) {
|
||||||
|
@ -160,20 +153,15 @@ function RSTabs() {
|
||||||
} else {
|
} else {
|
||||||
navigateTab(activeTab);
|
navigateTab(activeTab);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[activeTab, navigateTab]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onOpenCst = useCallback(
|
function onOpenCst(cstID: ConstituentaID) {
|
||||||
(cstID: ConstituentaID) => {
|
|
||||||
if (cstID !== activeCst?.id || activeTab !== RSTabID.CST_EDIT) {
|
if (cstID !== activeCst?.id || activeTab !== RSTabID.CST_EDIT) {
|
||||||
navigateTab(RSTabID.CST_EDIT, cstID);
|
navigateTab(RSTabID.CST_EDIT, cstID);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
[navigateTab, activeCst, activeTab]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onDestroySchema = useCallback(() => {
|
function onDestroySchema() {
|
||||||
if (!schema || !window.confirm(prompts.deleteLibraryItem)) {
|
if (!schema || !window.confirm(prompts.deleteLibraryItem)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -187,52 +175,7 @@ function RSTabs() {
|
||||||
router.push(urls.library);
|
router.push(urls.library);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [schema, library, oss, router]);
|
}
|
||||||
|
|
||||||
const cardPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorRSForm
|
|
||||||
isModified={isModified} // prettier: split lines
|
|
||||||
setIsModified={setIsModified}
|
|
||||||
onDestroy={onDestroySchema}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[isModified, onDestroySchema]
|
|
||||||
);
|
|
||||||
|
|
||||||
const listPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorRSList onOpenEdit={onOpenCst} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[onOpenCst]
|
|
||||||
);
|
|
||||||
|
|
||||||
const editorPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorConstituenta
|
|
||||||
isModified={isModified}
|
|
||||||
setIsModified={setIsModified}
|
|
||||||
activeCst={activeCst}
|
|
||||||
onOpenEdit={onOpenCst}
|
|
||||||
/>
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[isModified, setIsModified, activeCst, onOpenCst]
|
|
||||||
);
|
|
||||||
|
|
||||||
const graphPanel = useMemo(
|
|
||||||
() => (
|
|
||||||
<TabPanel>
|
|
||||||
<EditorTermGraph onOpenEdit={onOpenCst} />
|
|
||||||
</TabPanel>
|
|
||||||
),
|
|
||||||
[onOpenCst]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RSEditState
|
<RSEditState
|
||||||
|
@ -270,10 +213,30 @@ function RSTabs() {
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<div className='overflow-x-hidden'>
|
<div className='overflow-x-hidden'>
|
||||||
{cardPanel}
|
<TabPanel>
|
||||||
{listPanel}
|
<EditorRSForm
|
||||||
{editorPanel}
|
isModified={isModified} // prettier: split lines
|
||||||
{graphPanel}
|
setIsModified={setIsModified}
|
||||||
|
onDestroy={onDestroySchema}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<EditorRSList onOpenEdit={onOpenCst} />
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<EditorConstituenta
|
||||||
|
isModified={isModified}
|
||||||
|
setIsModified={setIsModified}
|
||||||
|
activeCst={activeCst}
|
||||||
|
onOpenEdit={onOpenCst}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<EditorTermGraph onOpenEdit={onOpenCst} />
|
||||||
|
</TabPanel>
|
||||||
</div>
|
</div>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { IconChild } from '@/components/Icons';
|
import { IconChild } from '@/components/Icons';
|
||||||
import SelectGraphFilter from '@/components/select/SelectGraphFilter';
|
import SelectGraphFilter from '@/components/select/SelectGraphFilter';
|
||||||
|
@ -58,16 +58,6 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
||||||
showInherited
|
showInherited
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const selectGraph = useMemo(
|
|
||||||
() => <SelectGraphFilter value={filterSource} onChange={newValue => setFilterSource(newValue)} dense={dense} />,
|
|
||||||
[filterSource, setFilterSource, dense]
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectMatchMode = useMemo(
|
|
||||||
() => <SelectMatchMode value={filterMatch} onChange={newValue => setFilterMatch(newValue)} dense={dense} />,
|
|
||||||
[filterMatch, setFilterMatch, dense]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex border-b clr-input rounded-t-md'>
|
<div className='flex border-b clr-input rounded-t-md'>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
|
@ -77,8 +67,8 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
||||||
query={filterText}
|
query={filterText}
|
||||||
onChangeQuery={setFilterText}
|
onChangeQuery={setFilterText}
|
||||||
/>
|
/>
|
||||||
{selectMatchMode}
|
<SelectMatchMode value={filterMatch} onChange={newValue => setFilterMatch(newValue)} dense={dense} />
|
||||||
{selectGraph}
|
<SelectGraphFilter value={filterSource} onChange={newValue => setFilterSource(newValue)} dense={dense} />
|
||||||
{schema && schema?.stats.count_inherited > 0 ? (
|
{schema && schema?.stats.count_inherited > 0 ? (
|
||||||
<MiniButton
|
<MiniButton
|
||||||
noHover
|
noHover
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
|
||||||
|
@ -50,15 +50,7 @@ function TableSideConstituents({
|
||||||
}
|
}
|
||||||
}, [activeCst, autoScroll]);
|
}, [activeCst, autoScroll]);
|
||||||
|
|
||||||
const handleRowClicked = useCallback(
|
const columns = [
|
||||||
(cst: IConstituenta) => {
|
|
||||||
onOpenEdit(cst.id);
|
|
||||||
},
|
|
||||||
[onOpenEdit]
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns = useMemo(
|
|
||||||
() => [
|
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: () => <span className='pl-3'>Имя</span>,
|
header: () => <span className='pl-3'>Имя</span>,
|
||||||
|
@ -92,12 +84,9 @@ function TableSideConstituents({
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
],
|
];
|
||||||
[colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles: IConditionalStyle<IConstituenta>[] = [
|
||||||
(): IConditionalStyle<IConstituenta>[] => [
|
|
||||||
{
|
{
|
||||||
when: (cst: IConstituenta) => !!activeCst && cst.id === activeCst?.id,
|
when: (cst: IConstituenta) => !!activeCst && cst.id === activeCst?.id,
|
||||||
style: {
|
style: {
|
||||||
|
@ -116,9 +105,7 @@ function TableSideConstituents({
|
||||||
backgroundColor: colors.bgGreen50
|
backgroundColor: colors.bgGreen50
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
];
|
||||||
[activeCst, colors]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
|
@ -137,7 +124,7 @@ function TableSideConstituents({
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</NoData>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={handleRowClicked}
|
onRowClicked={cst => onOpenEdit(cst.id)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
import { useAccessMode } from '@/context/AccessModeContext';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
|
@ -32,23 +32,6 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit,
|
||||||
|
|
||||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
|
||||||
|
|
||||||
const table = useMemo(
|
|
||||||
() => (
|
|
||||||
<TableSideConstituents
|
|
||||||
maxHeight={
|
|
||||||
isBottom
|
|
||||||
? calculateHeight(accessLevel !== UserLevel.READER ? '42rem' : '35rem', '10rem')
|
|
||||||
: calculateHeight('8.2rem')
|
|
||||||
}
|
|
||||||
items={filteredData}
|
|
||||||
activeCst={activeCst}
|
|
||||||
onOpenEdit={onOpenEdit}
|
|
||||||
autoScroll={!isBottom}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[isBottom, filteredData, activeCst, onOpenEdit, calculateHeight, accessLevel]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -73,7 +56,17 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit,
|
||||||
activeExpression={expression}
|
activeExpression={expression}
|
||||||
setFiltered={setFilteredData}
|
setFiltered={setFilteredData}
|
||||||
/>
|
/>
|
||||||
{table}
|
<TableSideConstituents
|
||||||
|
maxHeight={
|
||||||
|
isBottom
|
||||||
|
? calculateHeight(accessLevel !== UserLevel.READER ? '42rem' : '35rem', '10rem')
|
||||||
|
: calculateHeight('8.2rem')
|
||||||
|
}
|
||||||
|
items={filteredData}
|
||||||
|
activeCst={activeCst}
|
||||||
|
onOpenEdit={onOpenEdit}
|
||||||
|
autoScroll={!isBottom}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -37,10 +37,7 @@ function FormSignup() {
|
||||||
const [acceptPrivacy, setAcceptPrivacy] = useState(false);
|
const [acceptPrivacy, setAcceptPrivacy] = useState(false);
|
||||||
const [acceptRules, setAcceptRules] = useState(false);
|
const [acceptRules, setAcceptRules] = useState(false);
|
||||||
|
|
||||||
const isValid = useMemo(
|
const isValid = acceptPrivacy && acceptRules && !!email && !!username;
|
||||||
() => acceptPrivacy && acceptRules && !!email && !!username,
|
|
||||||
[acceptPrivacy, acceptRules, email, username]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -23,17 +23,10 @@ function EditorPassword() {
|
||||||
const [newPassword, setNewPassword] = useState('');
|
const [newPassword, setNewPassword] = useState('');
|
||||||
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
const [newPasswordRepeat, setNewPasswordRepeat] = useState('');
|
||||||
|
|
||||||
const passwordColor = useMemo(() => {
|
const passwordColor =
|
||||||
if (!!newPassword && !!newPasswordRepeat && newPassword !== newPasswordRepeat) {
|
!!newPassword && !!newPasswordRepeat && newPassword !== newPasswordRepeat ? 'clr-warning' : 'clr-input';
|
||||||
return 'clr-warning';
|
|
||||||
} else {
|
|
||||||
return 'clr-input';
|
|
||||||
}
|
|
||||||
}, [newPassword, newPasswordRepeat]);
|
|
||||||
|
|
||||||
const canSubmit = useMemo(() => {
|
const canSubmit = !!oldPassword && !!newPassword && !!newPasswordRepeat && newPassword === newPasswordRepeat;
|
||||||
return !!oldPassword && !!newPassword && !!newPasswordRepeat && newPassword === newPasswordRepeat;
|
|
||||||
}, [newPassword, newPasswordRepeat, oldPassword]);
|
|
||||||
|
|
||||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
import InfoError, { ErrorData } from '@/components/info/InfoError';
|
||||||
|
@ -20,12 +20,9 @@ function EditorProfile() {
|
||||||
const [first_name, setFirstName] = useState(user?.first_name ?? '');
|
const [first_name, setFirstName] = useState(user?.first_name ?? '');
|
||||||
const [last_name, setLastName] = useState(user?.last_name ?? '');
|
const [last_name, setLastName] = useState(user?.last_name ?? '');
|
||||||
|
|
||||||
const isModified: boolean = useMemo(() => {
|
const isModified =
|
||||||
if (!user) {
|
user != undefined && (user.email !== email || user.first_name !== first_name || user.last_name !== last_name);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return user.email !== email || user.first_name !== first_name || user.last_name !== last_name;
|
|
||||||
}, [user, email, first_name, last_name]);
|
|
||||||
useBlockNavigation(isModified);
|
useBlockNavigation(isModified);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user