R: Refactor dialogs using zustand store

This commit is contained in:
Ivan 2025-01-16 16:31:03 +03:00
parent 539ed87ddf
commit 6f23ec5354
39 changed files with 588 additions and 537 deletions

View File

@ -9,6 +9,7 @@ import { NavigationState } from '@/context/NavigationContext';
import { useAppLayoutStore, useMainHeight, useViewportHeight } from '@/stores/appLayout'; import { useAppLayoutStore, useMainHeight, useViewportHeight } from '@/stores/appLayout';
import { globals } from '@/utils/constants'; import { globals } from '@/utils/constants';
import { GlobalDialogs } from './GlobalDialogs';
import { GlobalTooltips } from './GlobalTooltips'; import { GlobalTooltips } from './GlobalTooltips';
function ApplicationLayout() { function ApplicationLayout() {
@ -29,6 +30,7 @@ function ApplicationLayout() {
pauseOnFocusLoss={false} pauseOnFocusLoss={false}
/> />
<GlobalDialogs />
<GlobalTooltips /> <GlobalTooltips />
<Navigation /> <Navigation />

View File

@ -0,0 +1,83 @@
'use client';
import DlgChangeInputSchema from '@/dialogs/DlgChangeInputSchema';
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import DlgCloneLibraryItem from '@/dialogs/DlgCloneLibraryItem';
import DlgCreateCst from '@/dialogs/DlgCreateCst';
import DlgCreateOperation from '@/dialogs/DlgCreateOperation';
import DlgCreateVersion from '@/dialogs/DlgCreateVersion';
import DlgCstTemplate from '@/dialogs/DlgCstTemplate';
import DlgDeleteCst from '@/dialogs/DlgDeleteCst';
import DlgDeleteOperation from '@/dialogs/DlgDeleteOperation';
import DlgEditEditors from '@/dialogs/DlgEditEditors';
import DlgEditOperation from '@/dialogs/DlgEditOperation';
import DlgEditReference from '@/dialogs/DlgEditReference';
import DlgEditVersions from '@/dialogs/DlgEditVersions';
import DlgEditWordForms from '@/dialogs/DlgEditWordForms';
import DlgGraphParams from '@/dialogs/DlgGraphParams';
import DlgInlineSynthesis from '@/dialogs/DlgInlineSynthesis';
import DlgRelocateConstituents from '@/dialogs/DlgRelocateConstituents';
import DlgRenameCst from '@/dialogs/DlgRenameCst';
import DlgShowAST from '@/dialogs/DlgShowAST';
import DlgShowQR from '@/dialogs/DlgShowQR';
import DlgShowTypeGraph from '@/dialogs/DlgShowTypeGraph';
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
import { DialogType } from '@/models/miscellaneous';
import { useDialogsStore } from '@/stores/dialogs';
export const GlobalDialogs = () => {
const active = useDialogsStore(state => state.active);
if (active === undefined) {
return null;
}
switch (active) {
case DialogType.CONSTITUENTA_TEMPLATE:
return <DlgCstTemplate />;
case DialogType.CREATE_CONSTITUENTA:
return <DlgCreateCst />;
case DialogType.CREATE_OPERATION:
return <DlgCreateOperation />;
case DialogType.DELETE_CONSTITUENTA:
return <DlgDeleteCst />;
case DialogType.EDIT_EDITORS:
return <DlgEditEditors />;
case DialogType.EDIT_OPERATION:
return <DlgEditOperation />;
case DialogType.EDIT_REFERENCE:
return <DlgEditReference />;
case DialogType.EDIT_VERSIONS:
return <DlgEditVersions />;
case DialogType.EDIT_WORD_FORMS:
return <DlgEditWordForms />;
case DialogType.INLINE_SYNTHESIS:
return <DlgInlineSynthesis />;
case DialogType.SHOW_AST:
return <DlgShowAST />;
case DialogType.SHOW_TYPE_GRAPH:
return <DlgShowTypeGraph />;
case DialogType.CHANGE_INPUT_SCHEMA:
return <DlgChangeInputSchema />;
case DialogType.CHANGE_LOCATION:
return <DlgChangeLocation />;
case DialogType.CLONE_LIBRARY_ITEM:
return <DlgCloneLibraryItem />;
case DialogType.CREATE_VERSION:
return <DlgCreateVersion />;
case DialogType.DELETE_OPERATION:
return <DlgDeleteOperation />;
case DialogType.GRAPH_PARAMETERS:
return <DlgGraphParams />;
case DialogType.RELOCATE_CONSTITUENTS:
return <DlgRelocateConstituents />;
case DialogType.RENAME_CONSTITUENTA:
return <DlgRenameCst />;
case DialogType.SHOW_QR_CODE:
return <DlgShowQR />;
case DialogType.SUBSTITUTE_CONSTITUENTS:
return <DlgSubstituteCst />;
case DialogType.UPLOAD_RSFORM:
return <DlgUploadRSForm />;
}
};

View File

@ -9,13 +9,13 @@ import { EditorView } from 'codemirror';
import { forwardRef, useRef, useState } from 'react'; import { forwardRef, useRef, useState } from 'react';
import Label from '@/components/ui/Label'; import Label from '@/components/ui/Label';
import DlgEditReference from '@/dialogs/DlgEditReference';
import { ReferenceType } from '@/models/language'; import { ReferenceType } from '@/models/language';
import { DialogType } from '@/models/miscellaneous';
import { ConstituentaID, IRSForm } from '@/models/rsform'; import { ConstituentaID, IRSForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { APP_COLORS } from '@/styling/color'; import { APP_COLORS } from '@/styling/color';
import { CodeMirrorWrapper } from '@/utils/codemirror'; import { CodeMirrorWrapper } from '@/utils/codemirror';
import { PARAMETER } from '@/utils/constants';
import { refsNavigation } from './clickNavigation'; import { refsNavigation } from './clickNavigation';
import { NaturalLanguage, ReferenceTokens } from './parse'; import { NaturalLanguage, ReferenceTokens } from './parse';
@ -96,7 +96,10 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
const [isFocused, setIsFocused] = useState(false); const [isFocused, setIsFocused] = useState(false);
const [showEditor, setShowEditor] = useState(false); const showEditReference = useDialogsStore(state => state.showEditReference);
const activeDialog = useDialogsStore(state => state.active);
const isActive = activeDialog === DialogType.EDIT_REFERENCE;
const [currentType, setCurrentType] = useState<ReferenceType>(ReferenceType.ENTITY); const [currentType, setCurrentType] = useState<ReferenceType>(ReferenceType.ENTITY);
const [refText, setRefText] = useState(''); const [refText, setRefText] = useState('');
const [hintText, setHintText] = useState(''); const [hintText, setHintText] = useState('');
@ -146,7 +149,7 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
} }
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) { function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
if (!thisRef.current?.view) { if (!thisRef.current?.view || !schema) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
return; return;
@ -174,7 +177,17 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
setMainRefs(mainNodes.map(node => wrap.getText(node.from, node.to))); setMainRefs(mainNodes.map(node => wrap.getText(node.from, node.to)));
setBasePosition(mainNodes.filter(node => node.to <= selection.from).length); setBasePosition(mainNodes.filter(node => node.to <= selection.from).length);
setShowEditor(true); showEditReference({
schema: schema,
initial: {
type: currentType,
refRaw: refText,
text: hintText,
basePosition: basePosition,
mainRefs: mainRefs
},
onSave: handleInputReference
});
} }
} }
@ -187,27 +200,8 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
wrap.replaceWith(referenceText); wrap.replaceWith(referenceText);
} }
function hideEditReference() {
setShowEditor(false);
setTimeout(() => thisRef.current?.view?.focus(), PARAMETER.refreshTimeout);
}
return ( return (
<div className={clsx('flex flex-col gap-2', cursor)}> <div className={clsx('flex flex-col gap-2', cursor)}>
{showEditor && schema ? (
<DlgEditReference
hideWindow={hideEditReference}
schema={schema}
initial={{
type: currentType,
refRaw: refText,
text: hintText,
basePosition: basePosition,
mainRefs: mainRefs
}}
onSave={handleInputReference}
/>
) : null}
<Label text={label} /> <Label text={label} />
<CodeMirror <CodeMirror
id={id} id={id}
@ -215,10 +209,10 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
basicSetup={editorSetup} basicSetup={editorSetup}
theme={customTheme} theme={customTheme}
extensions={editorExtensions} extensions={editorExtensions}
value={isFocused ? value : value !== initialValue || showEditor ? value : resolved} value={isFocused ? value : value !== initialValue || isActive ? value : resolved}
indentWithTab={false} indentWithTab={false}
onChange={handleChange} onChange={handleChange}
editable={!disabled && !showEditor} editable={!disabled && !isActive}
onKeyDown={handleInput} onKeyDown={handleInput}
onFocus={handleFocusIn} onFocus={handleFocusIn}
onBlur={handleFocusOut} onBlur={handleFocusOut}

View File

@ -4,6 +4,7 @@ import clsx from 'clsx';
import useEscapeKey from '@/hooks/useEscapeKey'; import useEscapeKey from '@/hooks/useEscapeKey';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { useDialogsStore } from '@/stores/dialogs';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
import { prepareTooltip } from '@/utils/labels'; import { prepareTooltip } from '@/utils/labels';
@ -32,9 +33,6 @@ export interface ModalProps extends CProps.Styling {
/** Indicates that the modal window should be scrollable. */ /** Indicates that the modal window should be scrollable. */
overflowVisible?: boolean; overflowVisible?: boolean;
/** Callback to be called when the modal window is closed. */
hideWindow: () => void;
/** Callback to be called before submit. */ /** Callback to be called before submit. */
beforeSubmit?: () => boolean; beforeSubmit?: () => boolean;
@ -65,7 +63,6 @@ function Modal({
canSubmit, canSubmit,
overflowVisible, overflowVisible,
hideWindow,
beforeSubmit, beforeSubmit,
onSubmit, onSubmit,
onCancel, onCancel,
@ -75,10 +72,11 @@ function Modal({
hideHelpWhen, hideHelpWhen,
...restProps ...restProps
}: React.PropsWithChildren<ModalProps>) { }: React.PropsWithChildren<ModalProps>) {
useEscapeKey(hideWindow); const hideDialog = useDialogsStore(state => state.hideDialog);
useEscapeKey(hideDialog);
const handleCancel = () => { const handleCancel = () => {
hideWindow(); hideDialog();
onCancel?.(); onCancel?.();
}; };
@ -87,7 +85,7 @@ function Modal({
return; return;
} }
onSubmit?.(); onSubmit?.();
hideWindow(); hideDialog();
}; };
return ( return (
@ -95,7 +93,7 @@ function Modal({
<div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'backdrop-blur-[3px] opacity-50')} /> <div className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'backdrop-blur-[3px] opacity-50')} />
<div <div
className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'bg-prim-0 opacity-25')} className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'bg-prim-0 opacity-25')}
onClick={hideWindow} onClick={hideDialog}
/> />
<div <div
className={clsx( className={clsx(

View File

@ -7,19 +7,21 @@ import { IconReset } from '@/components/Icons';
import PickSchema from '@/components/select/PickSchema'; import PickSchema from '@/components/select/PickSchema';
import Label from '@/components/ui/Label'; import Label from '@/components/ui/Label';
import MiniButton from '@/components/ui/MiniButton'; import MiniButton from '@/components/ui/MiniButton';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library'; import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
import { IOperation, IOperationSchema } from '@/models/oss'; import { IOperation, IOperationSchema, OperationID } from '@/models/oss';
import { sortItemsForOSS } from '@/models/ossAPI'; import { sortItemsForOSS } from '@/models/ossAPI';
import { useDialogsStore } from '@/stores/dialogs';
interface DlgChangeInputSchemaProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgChangeInputSchemaProps {
oss: IOperationSchema; oss: IOperationSchema;
target: IOperation; target: IOperation;
onSubmit: (newSchema: LibraryItemID | undefined) => void; onSubmit: (target: OperationID, newSchema: LibraryItemID | undefined) => void;
} }
function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeInputSchemaProps) { function DlgChangeInputSchema() {
const { oss, target, onSubmit } = useDialogsStore(state => state.props as 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 = sortItemsForOSS(oss, library.items); const sortedItems = sortItemsForOSS(oss, library.items);
@ -38,9 +40,8 @@ function DlgChangeInputSchema({ oss, hideWindow, target, onSubmit }: DlgChangeIn
overflowVisible overflowVisible
header='Выбор концептуальной схемы' header='Выбор концептуальной схемы'
submitText='Подтвердить выбор' submitText='Подтвердить выбор'
hideWindow={hideWindow}
canSubmit={isValid} canSubmit={isValid}
onSubmit={() => onSubmit(selected)} onSubmit={() => onSubmit(target.id, selected)}
className={clsx('w-[35rem]', 'pb-3 px-6 cc-column')} className={clsx('w-[35rem]', 'pb-3 px-6 cc-column')}
> >
<div className='flex justify-between gap-3 items-center'> <div className='flex justify-between gap-3 items-center'>

View File

@ -6,20 +6,22 @@ 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';
import Label from '@/components/ui/Label'; import Label from '@/components/ui/Label';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import { useAuth } from '@/context/AuthContext'; import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import { LocationHead } from '@/models/library'; import { LocationHead } from '@/models/library';
import { combineLocation, validateLocation } from '@/models/libraryAPI'; import { combineLocation, validateLocation } from '@/models/libraryAPI';
import { useDialogsStore } from '@/stores/dialogs';
import { limits } from '@/utils/constants'; import { limits } from '@/utils/constants';
interface DlgChangeLocationProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgChangeLocationProps {
initial: string; initial: string;
onChangeLocation: (newLocation: string) => void; onChangeLocation: (newLocation: string) => void;
} }
function DlgChangeLocation({ hideWindow, initial, onChangeLocation }: DlgChangeLocationProps) { function DlgChangeLocation() {
const { initial, onChangeLocation } = useDialogsStore(state => state.props as DlgChangeLocationProps);
const { user } = useAuth(); const { user } = useAuth();
const [head, setHead] = useState<LocationHead>(initial.substring(0, 2) as LocationHead); const [head, setHead] = useState<LocationHead>(initial.substring(0, 2) as LocationHead);
const [body, setBody] = useState<string>(initial.substring(3)); const [body, setBody] = useState<string>(initial.substring(3));
@ -40,7 +42,6 @@ function DlgChangeLocation({ hideWindow, initial, onChangeLocation }: DlgChangeL
header='Изменение расположения' header='Изменение расположения'
submitText='Переместить' submitText='Переместить'
submitInvalidTooltip={`Допустимы буквы, цифры, подчерк, пробел и "!". Сегмент пути не может начинаться и заканчиваться пробелом. Общая длина (с корнем) не должна превышать ${limits.location_len}`} submitInvalidTooltip={`Допустимы буквы, цифры, подчерк, пробел и "!". Сегмент пути не может начинаться и заканчиваться пробелом. Общая длина (с корнем) не должна превышать ${limits.location_len}`}
hideWindow={hideWindow}
canSubmit={isValid} canSubmit={isValid}
onSubmit={() => onChangeLocation(location)} onSubmit={() => onChangeLocation(location)}
className={clsx('w-[35rem]', 'pb-3 px-6 flex gap-3 h-[9rem]')} className={clsx('w-[35rem]', 'pb-3 px-6 flex gap-3 h-[9rem]')}

View File

@ -12,7 +12,7 @@ import SelectLocationHead from '@/components/select/SelectLocationHead';
import Checkbox from '@/components/ui/Checkbox'; import Checkbox from '@/components/ui/Checkbox';
import Label from '@/components/ui/Label'; import Label from '@/components/ui/Label';
import MiniButton from '@/components/ui/MiniButton'; import MiniButton from '@/components/ui/MiniButton';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import TextInput from '@/components/ui/TextInput'; import TextInput from '@/components/ui/TextInput';
import { useAuth } from '@/context/AuthContext'; import { useAuth } from '@/context/AuthContext';
@ -21,18 +21,23 @@ import { useConceptNavigation } from '@/context/NavigationContext';
import { AccessPolicy, ILibraryItem, LocationHead } from '@/models/library'; import { AccessPolicy, ILibraryItem, LocationHead } from '@/models/library';
import { cloneTitle, combineLocation, validateLocation } from '@/models/libraryAPI'; import { cloneTitle, combineLocation, validateLocation } from '@/models/libraryAPI';
import { ConstituentaID, IRSFormCloneData } from '@/models/rsform'; import { ConstituentaID, IRSFormCloneData } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { information } from '@/utils/labels'; import { information } from '@/utils/labels';
interface DlgCloneLibraryItemProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgCloneLibraryItemProps {
base: ILibraryItem; base: ILibraryItem;
initialLocation: string; initialLocation: string;
selected: ConstituentaID[]; selected: ConstituentaID[];
totalCount: number; totalCount: number;
} }
function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, totalCount }: DlgCloneLibraryItemProps) { function DlgCloneLibraryItem() {
const { base, initialLocation, selected, totalCount } = useDialogsStore(
state => state.props as DlgCloneLibraryItemProps
);
const router = useConceptNavigation(); const router = useConceptNavigation();
const { user } = useAuth(); const { user } = useAuth();
const [title, setTitle] = useState(cloneTitle(base)); const [title, setTitle] = useState(cloneTitle(base));
const [alias, setAlias] = useState(base.alias); const [alias, setAlias] = useState(base.alias);
const [comment, setComment] = useState(base.comment); const [comment, setComment] = useState(base.comment);
@ -77,7 +82,6 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
return ( return (
<Modal <Modal
header='Создание копии концептуальной схемы' header='Создание копии концептуальной схемы'
hideWindow={hideWindow}
canSubmit={canSubmit} canSubmit={canSubmit}
submitText='Создать' submitText='Создать'
onSubmit={handleSubmit} onSubmit={handleSubmit}

View File

@ -1 +0,0 @@
export { default } from './DlgConstituentaTemplate';

View File

@ -2,20 +2,22 @@
import { useState } from 'react'; import { useState } from 'react';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import usePartialUpdate from '@/hooks/usePartialUpdate'; import usePartialUpdate from '@/hooks/usePartialUpdate';
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform'; import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
import { generateAlias } from '@/models/rsformAPI'; import { generateAlias } from '@/models/rsformAPI';
import { useDialogsStore } from '@/stores/dialogs';
import FormCreateCst from './FormCreateCst'; import FormCreateCst from './FormCreateCst';
interface DlgCreateCstProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgCreateCstProps {
initial?: ICstCreateData; initial?: ICstCreateData;
schema: IRSForm; schema: IRSForm;
onCreate: (data: ICstCreateData) => void; onCreate: (data: ICstCreateData) => void;
} }
function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstProps) { function DlgCreateCst() {
const { initial, schema, onCreate } = useDialogsStore(state => state.props as DlgCreateCstProps);
const [validated, setValidated] = useState(false); const [validated, setValidated] = useState(false);
const [cstData, updateCstData] = usePartialUpdate( const [cstData, updateCstData] = usePartialUpdate(
initial || { initial || {
@ -35,7 +37,6 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
return ( return (
<Modal <Modal
header='Создание конституенты' header='Создание конституенты'
hideWindow={hideWindow}
canSubmit={validated} canSubmit={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
submitText='Создать' submitText='Создать'

View File

@ -10,13 +10,13 @@ import { useLibrary } from '@/context/LibraryContext';
import { LibraryItemID } from '@/models/library'; import { LibraryItemID } from '@/models/library';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { IOperationCreateData, IOperationSchema, OperationID, OperationType } from '@/models/oss'; import { IOperationCreateData, IOperationSchema, OperationID, OperationType } from '@/models/oss';
import { useDialogsStore } from '@/stores/dialogs';
import { describeOperationType, labelOperationType } from '@/utils/labels'; import { describeOperationType, labelOperationType } from '@/utils/labels';
import TabInputOperation from './TabInputOperation'; import TabInputOperation from './TabInputOperation';
import TabSynthesisOperation from './TabSynthesisOperation'; import TabSynthesisOperation from './TabSynthesisOperation';
interface DlgCreateOperationProps { export interface DlgCreateOperationProps {
hideWindow: () => void;
oss: IOperationSchema; oss: IOperationSchema;
onCreate: (data: IOperationCreateData) => void; onCreate: (data: IOperationCreateData) => void;
initialInputs: OperationID[]; initialInputs: OperationID[];
@ -27,7 +27,8 @@ export enum TabID {
SYNTHESIS = 1 SYNTHESIS = 1
} }
function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCreateOperationProps) { function DlgCreateOperation() {
const { oss, onCreate, initialInputs } = useDialogsStore(state => state.props as DlgCreateOperationProps);
const library = useLibrary(); const library = useLibrary();
const [activeTab, setActiveTab] = useState(initialInputs.length > 0 ? TabID.SYNTHESIS : TabID.INPUT); const [activeTab, setActiveTab] = useState(initialInputs.length > 0 ? TabID.SYNTHESIS : TabID.INPUT);
@ -98,7 +99,6 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
<Modal <Modal
header='Создание операции' header='Создание операции'
submitText='Создать' submitText='Создать'
hideWindow={hideWindow}
canSubmit={isValid} canSubmit={isValid}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'

View File

@ -4,21 +4,23 @@ import clsx from 'clsx';
import { 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 from '@/components/ui/Modal';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import TextInput from '@/components/ui/TextInput'; import TextInput from '@/components/ui/TextInput';
import { IVersionCreateData, IVersionInfo } from '@/models/library'; import { IVersionCreateData, IVersionInfo } from '@/models/library';
import { nextVersion } from '@/models/libraryAPI'; import { nextVersion } from '@/models/libraryAPI';
import { ConstituentaID } from '@/models/rsform'; import { ConstituentaID } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
interface DlgCreateVersionProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgCreateVersionProps {
versions: IVersionInfo[]; versions: IVersionInfo[];
onCreate: (data: IVersionCreateData) => void; onCreate: (data: IVersionCreateData) => void;
selected: ConstituentaID[]; selected: ConstituentaID[];
totalCount: number; totalCount: number;
} }
function DlgCreateVersion({ hideWindow, versions, selected, totalCount, onCreate }: DlgCreateVersionProps) { function DlgCreateVersion() {
const { versions, selected, totalCount, onCreate } = useDialogsStore(state => state.props as DlgCreateVersionProps);
const [version, setVersion] = useState(versions.length > 0 ? nextVersion(versions[0].version) : '1.0.0'); const [version, setVersion] = useState(versions.length > 0 ? nextVersion(versions[0].version) : '1.0.0');
const [description, setDescription] = useState(''); const [description, setDescription] = useState('');
const [onlySelected, setOnlySelected] = useState(false); const [onlySelected, setOnlySelected] = useState(false);
@ -39,7 +41,6 @@ function DlgCreateVersion({ hideWindow, versions, selected, totalCount, onCreate
return ( return (
<Modal <Modal
header='Создание версии' header='Создание версии'
hideWindow={hideWindow}
canSubmit={canSubmit} canSubmit={canSubmit}
onSubmit={handleSubmit} onSubmit={handleSubmit}
submitText='Создать' submitText='Создать'

View File

@ -4,7 +4,7 @@ import clsx from 'clsx';
import { useEffect, 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 from '@/components/ui/Modal';
import TabLabel from '@/components/ui/TabLabel'; import TabLabel from '@/components/ui/TabLabel';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import usePartialUpdate from '@/hooks/usePartialUpdate'; import usePartialUpdate from '@/hooks/usePartialUpdate';
@ -12,13 +12,14 @@ import { HelpTopic } from '@/models/miscellaneous';
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform'; import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
import { generateAlias, validateNewAlias } from '@/models/rsformAPI'; import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI'; import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI';
import { useDialogsStore } from '@/stores/dialogs';
import { prompts } from '@/utils/labels'; import { prompts } from '@/utils/labels';
import FormCreateCst from '../DlgCreateCst/FormCreateCst'; import FormCreateCst from '../DlgCreateCst/FormCreateCst';
import TabArguments, { IArgumentsState } from './TabArguments'; import TabArguments, { IArgumentsState } from './TabArguments';
import TabTemplate, { ITemplateState } from './TabTemplate'; import TabTemplate, { ITemplateState } from './TabTemplate';
interface DlgConstituentaTemplateProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgCstTemplateProps {
schema: IRSForm; schema: IRSForm;
onCreate: (data: ICstCreateData) => void; onCreate: (data: ICstCreateData) => void;
insertAfter?: number; insertAfter?: number;
@ -30,7 +31,8 @@ export enum TabID {
CONSTITUENTA = 2 CONSTITUENTA = 2
} }
function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }: DlgConstituentaTemplateProps) { function DlgCstTemplate() {
const { schema, onCreate, insertAfter } = useDialogsStore(state => state.props as DlgCstTemplateProps);
const { retrieveTemplate } = useLibrary(); const { retrieveTemplate } = useLibrary();
const [activeTab, setActiveTab] = useState(TabID.TEMPLATE); const [activeTab, setActiveTab] = useState(TabID.TEMPLATE);
@ -128,7 +130,6 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
header='Создание конституенты из шаблона' header='Создание конституенты из шаблона'
submitText='Создать' submitText='Создать'
className='w-[43rem] h-[35rem] px-6' className='w-[43rem] h-[35rem] px-6'
hideWindow={hideWindow}
canSubmit={validated} canSubmit={validated}
beforeSubmit={handlePrompt} beforeSubmit={handlePrompt}
onSubmit={handleSubmit} onSubmit={handleSubmit}
@ -164,4 +165,4 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
); );
} }
export default DlgConstituentaTemplate; export default DlgCstTemplate;

View File

@ -0,0 +1 @@
export { default } from './DlgCstTemplate';

View File

@ -4,19 +4,22 @@ import clsx from 'clsx';
import { 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 from '@/components/ui/Modal';
import { ConstituentaID, IRSForm } from '@/models/rsform'; import { ConstituentaID, IRSForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
import ListConstituents from './ListConstituents'; import ListConstituents from './ListConstituents';
interface DlgDeleteCstProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgDeleteCstProps {
schema: IRSForm; schema: IRSForm;
selected: ConstituentaID[]; selected: ConstituentaID[];
onDelete: (items: ConstituentaID[]) => void; onDelete: (items: ConstituentaID[]) => void;
} }
function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstProps) { function DlgDeleteCst() {
const { selected, schema, onDelete } = useDialogsStore(state => state.props as DlgDeleteCstProps);
const hideDialog = useDialogsStore(state => state.hideDialog);
const [expandOut, setExpandOut] = useState(false); const [expandOut, setExpandOut] = useState(false);
const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected); const expansion: ConstituentaID[] = schema.graph.expandAllOutputs(selected);
const hasInherited = selected.some( const hasInherited = selected.some(
@ -25,7 +28,7 @@ function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstPr
); );
function handleSubmit() { function handleSubmit() {
hideWindow(); hideDialog();
if (expandOut) { if (expandOut) {
onDelete(selected.concat(expansion)); onDelete(selected.concat(expansion));
} else { } else {
@ -38,7 +41,6 @@ function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstPr
canSubmit canSubmit
header='Удаление конституент' header='Удаление конституент'
submitText={expandOut ? 'Удалить с зависимыми' : 'Удалить'} submitText={expandOut ? 'Удалить с зависимыми' : 'Удалить'}
hideWindow={hideWindow}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className={clsx('cc-column', 'max-w-[60vw] min-w-[30rem]', 'px-6')} className={clsx('cc-column', 'max-w-[60vw] min-w-[30rem]', 'px-6')}
> >

View File

@ -4,22 +4,24 @@ import clsx from 'clsx';
import { 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 from '@/components/ui/Modal';
import TextInput from '@/components/ui/TextInput'; import TextInput from '@/components/ui/TextInput';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { IOperation } from '@/models/oss'; import { IOperation, OperationID } from '@/models/oss';
import { useDialogsStore } from '@/stores/dialogs';
interface DlgDeleteOperationProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgDeleteOperationProps {
target: IOperation; target: IOperation;
onSubmit: (keepConstituents: boolean, deleteSchema: boolean) => void; onSubmit: (targetID: OperationID, keepConstituents: boolean, deleteSchema: boolean) => void;
} }
function DlgDeleteOperation({ hideWindow, target, onSubmit }: DlgDeleteOperationProps) { function DlgDeleteOperation() {
const { target, onSubmit } = useDialogsStore(state => state.props as DlgDeleteOperationProps);
const [keepConstituents, setKeepConstituents] = useState(false); const [keepConstituents, setKeepConstituents] = useState(false);
const [deleteSchema, setDeleteSchema] = useState(false); const [deleteSchema, setDeleteSchema] = useState(false);
function handleSubmit() { function handleSubmit() {
onSubmit(keepConstituents, deleteSchema); onSubmit(target.id, keepConstituents, deleteSchema);
} }
return ( return (
@ -27,7 +29,6 @@ function DlgDeleteOperation({ hideWindow, target, onSubmit }: DlgDeleteOperation
overflowVisible overflowVisible
header='Удаление операции' header='Удаление операции'
submitText='Подтвердить удаление' submitText='Подтвердить удаление'
hideWindow={hideWindow}
canSubmit={true} canSubmit={true}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className={clsx('w-[35rem]', 'pb-3 px-6 cc-column', 'select-none')} className={clsx('w-[35rem]', 'pb-3 px-6 cc-column', 'select-none')}

View File

@ -10,16 +10,17 @@ import MiniButton from '@/components/ui/MiniButton';
import Modal from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import { useUsers } from '@/context/UsersContext'; import { useUsers } from '@/context/UsersContext';
import { UserID } from '@/models/user'; import { UserID } from '@/models/user';
import { useDialogsStore } from '@/stores/dialogs';
import TableUsers from './TableUsers'; import TableUsers from './TableUsers';
interface DlgEditEditorsProps { export interface DlgEditEditorsProps {
editors: UserID[]; editors: UserID[];
setEditors: (newValue: UserID[]) => void; setEditors: (newValue: UserID[]) => void;
hideWindow: () => void;
} }
function DlgEditEditors({ hideWindow, editors, setEditors }: DlgEditEditorsProps) { function DlgEditEditors() {
const { editors, setEditors } = useDialogsStore(state => state.props as DlgEditEditorsProps);
const [selected, setSelected] = useState<UserID[]>(editors); const [selected, setSelected] = useState<UserID[]>(editors);
const { users } = useUsers(); const { users } = useUsers();
const filtered = users.filter(user => !selected.includes(user.id)); const filtered = users.filter(user => !selected.includes(user.id));
@ -41,7 +42,6 @@ function DlgEditEditors({ hideWindow, editors, setEditors }: DlgEditEditorsProps
canSubmit canSubmit
header='Список редакторов' header='Список редакторов'
submitText='Сохранить список' submitText='Сохранить список'
hideWindow={hideWindow}
className='flex flex-col w-[35rem] px-6 gap-3 pb-6' className='flex flex-col w-[35rem] px-6 gap-3 pb-6'
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >

View File

@ -19,13 +19,13 @@ import {
} from '@/models/oss'; } from '@/models/oss';
import { SubstitutionValidator } from '@/models/ossAPI'; import { SubstitutionValidator } from '@/models/ossAPI';
import { ConstituentaID } from '@/models/rsform'; import { ConstituentaID } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import TabArguments from './TabArguments'; import TabArguments from './TabArguments';
import TabOperation from './TabOperation'; import TabOperation from './TabOperation';
import TabSynthesis from './TabSynthesis'; import TabSynthesis from './TabSynthesis';
interface DlgEditOperationProps { export interface DlgEditOperationProps {
hideWindow: () => void;
oss: IOperationSchema; oss: IOperationSchema;
target: IOperation; target: IOperation;
onSubmit: (data: IOperationUpdateData) => void; onSubmit: (data: IOperationUpdateData) => void;
@ -37,7 +37,8 @@ export enum TabID {
SUBSTITUTION = 2 SUBSTITUTION = 2
} }
function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperationProps) { function DlgEditOperation() {
const { oss, target, onSubmit } = useDialogsStore(state => state.props as DlgEditOperationProps);
const [activeTab, setActiveTab] = useState(TabID.CARD); const [activeTab, setActiveTab] = useState(TabID.CARD);
const [alias, setAlias] = useState(target.alias); const [alias, setAlias] = useState(target.alias);
@ -142,7 +143,6 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
<Modal <Modal
header='Редактирование операции' header='Редактирование операции'
submitText='Сохранить' submitText='Сохранить'
hideWindow={hideWindow}
canSubmit={canSubmit} canSubmit={canSubmit}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'

View File

@ -9,6 +9,7 @@ import TabLabel from '@/components/ui/TabLabel';
import { ReferenceType } from '@/models/language'; import { ReferenceType } from '@/models/language';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { IRSForm } from '@/models/rsform'; import { IRSForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { labelReferenceType } from '@/utils/labels'; import { labelReferenceType } from '@/utils/labels';
import TabEntityReference from './TabEntityReference'; import TabEntityReference from './TabEntityReference';
@ -22,8 +23,7 @@ export interface IReferenceInputState {
basePosition: number; basePosition: number;
} }
interface DlgEditReferenceProps { export interface DlgEditReferenceProps {
hideWindow: () => void;
schema: IRSForm; schema: IRSForm;
initial: IReferenceInputState; initial: IReferenceInputState;
onSave: (newRef: string) => void; onSave: (newRef: string) => void;
@ -34,7 +34,8 @@ export enum TabID {
SYNTACTIC = 1 SYNTACTIC = 1
} }
function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditReferenceProps) { function DlgEditReference() {
const { schema, initial, onSave } = useDialogsStore(state => state.props as 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);
@ -43,7 +44,6 @@ function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditRefere
<Modal <Modal
header='Редактирование ссылки' header='Редактирование ссылки'
submitText='Сохранить ссылку' submitText='Сохранить ссылку'
hideWindow={hideWindow}
canSubmit={isValid} canSubmit={isValid}
onSubmit={() => onSave(reference)} onSubmit={() => onSave(reference)}
className='w-[40rem] px-6 h-[32rem]' className='w-[40rem] px-6 h-[32rem]'

View File

@ -7,21 +7,21 @@ import MiniButton from '@/components/ui/MiniButton';
import Modal from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import TextInput from '@/components/ui/TextInput'; import TextInput from '@/components/ui/TextInput';
import { useRSForm } from '@/context/RSFormContext';
import { IVersionData, IVersionInfo, VersionID } from '@/models/library'; import { IVersionData, IVersionInfo, VersionID } from '@/models/library';
import { useDialogsStore } from '@/stores/dialogs';
import TableVersions from './TableVersions'; import TableVersions from './TableVersions';
interface DlgEditVersionsProps { export interface DlgEditVersionsProps {
hideWindow: () => void;
versions: IVersionInfo[]; versions: IVersionInfo[];
onDelete: (versionID: VersionID) => void; onDelete: (versionID: VersionID) => void;
onUpdate: (versionID: VersionID, data: IVersionData) => void; onUpdate: (versionID: VersionID, data: IVersionData) => void;
} }
function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVersionsProps) { function DlgEditVersions() {
const { processing } = useRSForm(); const { versions, onDelete, onUpdate } = useDialogsStore(state => state.props as DlgEditVersionsProps);
const [selected, setSelected] = useState<IVersionInfo | undefined>(undefined); const [selected, setSelected] = useState<IVersionInfo | undefined>(undefined);
const processing = false; // TODO: fix processing hook and versions update
const [version, setVersion] = useState(''); const [version, setVersion] = useState('');
const [description, setDescription] = useState(''); const [description, setDescription] = useState('');
@ -54,12 +54,7 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
}, [selected]); }, [selected]);
return ( return (
<Modal <Modal readonly header='Редактирование версий' className='flex flex-col w-[40rem] px-6 gap-3 pb-6'>
readonly
header='Редактирование версий'
hideWindow={hideWindow}
className='flex flex-col w-[40rem] px-6 gap-3 pb-6'
>
<TableVersions <TableVersions
processing={processing} processing={processing}
items={versions} items={versions}

View File

@ -14,18 +14,19 @@ import { Grammeme, ITextRequest, IWordForm, IWordFormPlain } from '@/models/lang
import { parseGrammemes, wordFormEquals } from '@/models/languageAPI'; import { parseGrammemes, wordFormEquals } from '@/models/languageAPI';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { IConstituenta, TermForm } from '@/models/rsform'; import { IConstituenta, TermForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { prompts } from '@/utils/labels'; import { prompts } from '@/utils/labels';
import { IGrammemeOption, SelectorGrammemes, SelectorGrammemesList } from '@/utils/selectors'; import { IGrammemeOption, SelectorGrammemes, SelectorGrammemesList } from '@/utils/selectors';
import TableWordForms from './TableWordForms'; import TableWordForms from './TableWordForms';
interface DlgEditWordFormsProps { export interface DlgEditWordFormsProps {
hideWindow: () => void;
target: IConstituenta; target: IConstituenta;
onSave: (data: TermForm[]) => void; onSave: (data: TermForm[]) => void;
} }
function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps) { function DlgEditWordForms() {
const { target, onSave } = useDialogsStore(state => state.props as DlgEditWordFormsProps);
const textProcessor = useConceptText(); const textProcessor = useConceptText();
const [term, setTerm] = useState(''); const [term, setTerm] = useState('');
@ -123,7 +124,6 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
<Modal <Modal
canSubmit canSubmit
header='Редактирование словоформ' header='Редактирование словоформ'
hideWindow={hideWindow}
submitText='Сохранить' submitText='Сохранить'
onSubmit={handleSubmit} onSubmit={handleSubmit}
className='flex flex-col w-[40rem] px-6' className='flex flex-col w-[40rem] px-6'

View File

@ -1,24 +1,25 @@
'use client'; 'use client';
import Checkbox from '@/components/ui/Checkbox'; import Checkbox from '@/components/ui/Checkbox';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import usePartialUpdate from '@/hooks/usePartialUpdate'; import usePartialUpdate from '@/hooks/usePartialUpdate';
import { GraphFilterParams } from '@/models/miscellaneous'; import { GraphFilterParams } from '@/models/miscellaneous';
import { CstType } from '@/models/rsform'; import { CstType } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { labelCstType } from '@/utils/labels'; import { labelCstType } from '@/utils/labels';
interface DlgGraphParamsProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgGraphParamsProps {
initial: GraphFilterParams; initial: GraphFilterParams;
onConfirm: (params: GraphFilterParams) => void; onConfirm: (params: GraphFilterParams) => void;
} }
function DlgGraphParams({ hideWindow, initial, onConfirm }: DlgGraphParamsProps) { function DlgGraphParams() {
const { initial, onConfirm } = useDialogsStore(state => state.props as DlgGraphParamsProps);
const [params, updateParams] = usePartialUpdate(initial); const [params, updateParams] = usePartialUpdate(initial);
return ( return (
<Modal <Modal
canSubmit canSubmit
hideWindow={hideWindow}
header='Настройки графа термов' header='Настройки графа термов'
onSubmit={() => onConfirm(params)} onSubmit={() => onConfirm(params)}
submitText='Применить' submitText='Применить'

View File

@ -4,18 +4,19 @@ import clsx from 'clsx';
import { useEffect, 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 from '@/components/ui/Modal';
import TabLabel from '@/components/ui/TabLabel'; import TabLabel from '@/components/ui/TabLabel';
import useRSFormDetails from '@/hooks/useRSFormDetails'; import useRSFormDetails from '@/hooks/useRSFormDetails';
import { LibraryItemID } from '@/models/library'; import { LibraryItemID } from '@/models/library';
import { ICstSubstitute } from '@/models/oss'; import { ICstSubstitute } from '@/models/oss';
import { ConstituentaID, IInlineSynthesisData, IRSForm } from '@/models/rsform'; import { ConstituentaID, IInlineSynthesisData, IRSForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import TabConstituents from './TabConstituents'; import TabConstituents from './TabConstituents';
import TabSchema from './TabSchema'; import TabSchema from './TabSchema';
import TabSubstitutions from './TabSubstitutions'; import TabSubstitutions from './TabSubstitutions';
interface DlgInlineSynthesisProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgInlineSynthesisProps {
receiver: IRSForm; receiver: IRSForm;
onInlineSynthesis: (data: IInlineSynthesisData) => void; onInlineSynthesis: (data: IInlineSynthesisData) => void;
} }
@ -26,7 +27,8 @@ export enum TabID {
SUBSTITUTIONS = 2 SUBSTITUTIONS = 2
} }
function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInlineSynthesisProps) { function DlgInlineSynthesis() {
const { receiver, onInlineSynthesis } = useDialogsStore(state => state.props as DlgInlineSynthesisProps);
const [activeTab, setActiveTab] = useState(TabID.SCHEMA); const [activeTab, setActiveTab] = useState(TabID.SCHEMA);
const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined); const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined);
@ -60,7 +62,6 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
header='Импорт концептуальной схем' header='Импорт концептуальной схем'
submitText='Добавить конституенты' submitText='Добавить конституенты'
className='w-[40rem] h-[33rem] px-6' className='w-[40rem] h-[33rem] px-6'
hideWindow={hideWindow}
canSubmit={validated} canSubmit={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >

View File

@ -7,7 +7,7 @@ import { RelocateUpIcon } from '@/components/DomainIcons';
import PickMultiConstituenta from '@/components/select/PickMultiConstituenta'; import PickMultiConstituenta from '@/components/select/PickMultiConstituenta';
import SelectLibraryItem from '@/components/select/SelectLibraryItem'; import SelectLibraryItem from '@/components/select/SelectLibraryItem';
import MiniButton from '@/components/ui/MiniButton'; import MiniButton from '@/components/ui/MiniButton';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import DataLoader from '@/components/wrap/DataLoader'; import DataLoader from '@/components/wrap/DataLoader';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import useRSFormDetails from '@/hooks/useRSFormDetails'; import useRSFormDetails from '@/hooks/useRSFormDetails';
@ -16,15 +16,17 @@ import { HelpTopic } from '@/models/miscellaneous';
import { ICstRelocateData, IOperation, IOperationSchema } from '@/models/oss'; import { ICstRelocateData, IOperation, IOperationSchema } from '@/models/oss';
import { getRelocateCandidates } from '@/models/ossAPI'; import { getRelocateCandidates } from '@/models/ossAPI';
import { ConstituentaID } from '@/models/rsform'; import { ConstituentaID } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
interface DlgRelocateConstituentsProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgRelocateConstituentsProps {
oss: IOperationSchema; oss: IOperationSchema;
initialTarget?: IOperation; initialTarget?: IOperation;
onSubmit: (data: ICstRelocateData) => void; onSubmit: (data: ICstRelocateData) => void;
} }
function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: DlgRelocateConstituentsProps) { function DlgRelocateConstituents() {
const { oss, initialTarget, onSubmit } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
const library = useLibrary(); const library = useLibrary();
const [directionUp, setDirectionUp] = useState(true); const [directionUp, setDirectionUp] = useState(true);
@ -88,7 +90,6 @@ function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: D
<Modal <Modal
header='Перенос конституент' header='Перенос конституент'
submitText='Переместить' submitText='Переместить'
hideWindow={hideWindow}
canSubmit={isValid} canSubmit={isValid}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')} className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}

View File

@ -3,25 +3,26 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import SelectSingle from '@/components/ui/SelectSingle'; import SelectSingle from '@/components/ui/SelectSingle';
import TextInput from '@/components/ui/TextInput'; import TextInput from '@/components/ui/TextInput';
import { useRSForm } from '@/context/RSFormContext';
import usePartialUpdate from '@/hooks/usePartialUpdate'; import usePartialUpdate from '@/hooks/usePartialUpdate';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { CstType, ICstRenameData } from '@/models/rsform'; import { CstType, ICstRenameData, IRSForm } from '@/models/rsform';
import { generateAlias, validateNewAlias } from '@/models/rsformAPI'; import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
import { useDialogsStore } from '@/stores/dialogs';
import { labelCstType } from '@/utils/labels'; import { labelCstType } from '@/utils/labels';
import { SelectorCstType } from '@/utils/selectors'; import { SelectorCstType } from '@/utils/selectors';
interface DlgRenameCstProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgRenameCstProps {
schema: IRSForm;
initial: ICstRenameData; initial: ICstRenameData;
allowChangeType: boolean; allowChangeType: boolean;
onRename: (data: ICstRenameData) => void; onRename: (data: ICstRenameData) => void;
} }
function DlgRenameCst({ hideWindow, initial, allowChangeType, onRename }: DlgRenameCstProps) { function DlgRenameCst() {
const { schema } = useRSForm(); const { schema, initial, allowChangeType, onRename } = useDialogsStore(state => state.props as DlgRenameCstProps);
const [validated, setValidated] = useState(false); const [validated, setValidated] = useState(false);
const [cstData, updateData] = usePartialUpdate(initial); const [cstData, updateData] = usePartialUpdate(initial);
@ -42,7 +43,6 @@ function DlgRenameCst({ hideWindow, initial, allowChangeType, onRename }: DlgRen
header='Переименование конституенты' header='Переименование конституенты'
submitText='Переименовать' submitText='Переименовать'
submitInvalidTooltip='Введите незанятое имя, соответствующее типу' submitInvalidTooltip='Введите незанятое имя, соответствующее типу'
hideWindow={hideWindow}
canSubmit={validated} canSubmit={validated}
onSubmit={() => onRename(cstData)} onSubmit={() => onRename(cstData)}
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex gap-3 justify-center items-center ')} className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex gap-3 justify-center items-center ')}

View File

@ -3,19 +3,21 @@
import { useState } from 'react'; import { useState } from 'react';
import { ReactFlowProvider } from 'reactflow'; import { ReactFlowProvider } from 'reactflow';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { SyntaxTree } from '@/models/rslang'; import { SyntaxTree } from '@/models/rslang';
import { useDialogsStore } from '@/stores/dialogs';
import ASTFlow from './ASTFlow'; import ASTFlow from './ASTFlow';
interface DlgShowASTProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgShowASTProps {
syntaxTree: SyntaxTree; syntaxTree: SyntaxTree;
expression: string; expression: string;
} }
function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) { function DlgShowAST() {
const { syntaxTree, expression } = useDialogsStore(state => state.props as DlgShowASTProps);
const [hoverID, setHoverID] = useState<number | undefined>(undefined); const [hoverID, setHoverID] = useState<number | undefined>(undefined);
const hoverNode = syntaxTree.find(node => node.uid === hoverID); const hoverNode = syntaxTree.find(node => node.uid === hoverID);
@ -24,7 +26,6 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
return ( return (
<Modal <Modal
readonly readonly
hideWindow={hideWindow}
className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]' className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]'
helpTopic={HelpTopic.UI_FORMULA_TREE} helpTopic={HelpTopic.UI_FORMULA_TREE}
> >

View File

@ -3,19 +3,17 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import { useDialogsStore } from '@/stores/dialogs';
interface DlgShowQRProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgShowQRProps {
target: string; target: string;
} }
function DlgShowQR({ hideWindow, target }: DlgShowQRProps) { function DlgShowQR() {
const { target } = useDialogsStore(state => state.props as DlgShowQRProps);
return ( return (
<Modal <Modal readonly className={clsx('w-[30rem]', 'py-12 pr-3 pl-6 flex gap-3 justify-center items-center')}>
readonly
hideWindow={hideWindow}
className={clsx('w-[30rem]', 'py-12 pr-3 pl-6 flex gap-3 justify-center items-center')}
>
<div className='bg-[#ffffff] p-4 border'> <div className='bg-[#ffffff] p-4 border'>
<QRCodeSVG value={target} size={256} /> <QRCodeSVG value={target} size={256} />
</div> </div>

View File

@ -3,19 +3,22 @@
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { ReactFlowProvider } from 'reactflow'; import { ReactFlowProvider } from 'reactflow';
import Modal, { ModalProps } from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { ITypeInfo } from '@/models/rslang'; import { ITypeInfo } from '@/models/rslang';
import { TMGraph } from '@/models/TMGraph'; import { TMGraph } from '@/models/TMGraph';
import { useDialogsStore } from '@/stores/dialogs';
import { errors } from '@/utils/labels'; import { errors } from '@/utils/labels';
import MGraphFlow from './MGraphFlow'; import MGraphFlow from './MGraphFlow';
interface DlgShowTypeGraphProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgShowTypeGraphProps {
items: ITypeInfo[]; items: ITypeInfo[];
} }
function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) { function DlgShowTypeGraph() {
const { items } = useDialogsStore(state => state.props as DlgShowTypeGraphProps);
const hideDialog = useDialogsStore(state => state.hideDialog);
const graph = (() => { 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));
@ -24,7 +27,7 @@ function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) {
if (graph.nodes.length === 0) { if (graph.nodes.length === 0) {
toast.error(errors.typeStructureFailed); toast.error(errors.typeStructureFailed);
hideWindow(); hideDialog();
return null; return null;
} }
@ -32,7 +35,6 @@ function DlgShowTypeGraph({ hideWindow, items }: DlgShowTypeGraphProps) {
<Modal <Modal
header='Граф ступеней' header='Граф ступеней'
readonly readonly
hideWindow={hideWindow}
className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]' className='flex flex-col justify-stretch w-[calc(100dvw-3rem)] h-[calc(100dvh-6rem)]'
helpTopic={HelpTopic.UI_TYPE_GRAPH} helpTopic={HelpTopic.UI_TYPE_GRAPH}
> >

View File

@ -4,18 +4,20 @@ import clsx from 'clsx';
import { 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 from '@/components/ui/Modal';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { ICstSubstitute, ICstSubstituteData } from '@/models/oss'; import { ICstSubstitute, ICstSubstituteData } from '@/models/oss';
import { IRSForm } from '@/models/rsform'; import { IRSForm } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { prefixes } from '@/utils/constants'; import { prefixes } from '@/utils/constants';
interface DlgSubstituteCstProps extends Pick<ModalProps, 'hideWindow'> { export interface DlgSubstituteCstProps {
schema: IRSForm; schema: IRSForm;
onSubstitute: (data: ICstSubstituteData) => void; onSubstitute: (data: ICstSubstituteData) => void;
} }
function DlgSubstituteCst({ hideWindow, onSubstitute, schema }: DlgSubstituteCstProps) { function DlgSubstituteCst() {
const { onSubstitute, schema } = useDialogsStore(state => state.props as DlgSubstituteCstProps);
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]); const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]);
const canSubmit = substitutions.length > 0; const canSubmit = substitutions.length > 0;
@ -31,7 +33,6 @@ function DlgSubstituteCst({ hideWindow, onSubstitute, schema }: DlgSubstituteCst
header='Отождествление' header='Отождествление'
submitText='Отождествить' submitText='Отождествить'
submitInvalidTooltip='Выберите две различные конституенты' submitInvalidTooltip='Выберите две различные конституенты'
hideWindow={hideWindow}
canSubmit={canSubmit} canSubmit={canSubmit}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className={clsx('w-[40rem]', 'px-6 pb-3')} className={clsx('w-[40rem]', 'px-6 pb-3')}

View File

@ -6,16 +6,16 @@ import { toast } from 'react-toastify';
import Checkbox from '@/components/ui/Checkbox'; import Checkbox from '@/components/ui/Checkbox';
import FileInput from '@/components/ui/FileInput'; import FileInput from '@/components/ui/FileInput';
import Modal from '@/components/ui/Modal'; import Modal from '@/components/ui/Modal';
import { useRSForm } from '@/context/RSFormContext';
import { IRSFormUploadData } from '@/models/rsform'; import { IRSFormUploadData } from '@/models/rsform';
import { useDialogsStore } from '@/stores/dialogs';
import { EXTEOR_TRS_FILE } from '@/utils/constants'; import { EXTEOR_TRS_FILE } from '@/utils/constants';
interface DlgUploadRSFormProps { export interface DlgUploadRSFormProps {
hideWindow: () => void; upload: (data: IRSFormUploadData, callback: () => void) => void;
} }
function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) { function DlgUploadRSForm() {
const { upload } = useRSForm(); const { upload } = useDialogsStore(state => state.props as DlgUploadRSFormProps);
const [loadMetadata, setLoadMetadata] = useState(false); const [loadMetadata, setLoadMetadata] = useState(false);
const [file, setFile] = useState<File | undefined>(); const [file, setFile] = useState<File | undefined>();
@ -42,7 +42,6 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
return ( return (
<Modal <Modal
header='Импорт схемы из Экстеора' header='Импорт схемы из Экстеора'
hideWindow={hideWindow}
canSubmit={!!file} canSubmit={!!file}
onSubmit={handleSubmit} onSubmit={handleSubmit}
submitText='Загрузить' submitText='Загрузить'

View File

@ -224,3 +224,32 @@ export interface Position2D {
x: number; x: number;
y: number; y: number;
} }
/**
* Represents global dialog.
*/
export enum DialogType {
CONSTITUENTA_TEMPLATE = 1,
CREATE_CONSTITUENTA,
CREATE_OPERATION,
DELETE_CONSTITUENTA,
EDIT_EDITORS,
EDIT_OPERATION,
EDIT_REFERENCE,
EDIT_VERSIONS,
EDIT_WORD_FORMS,
INLINE_SYNTHESIS,
SHOW_AST,
SHOW_TYPE_GRAPH,
CHANGE_INPUT_SCHEMA,
CHANGE_LOCATION,
CLONE_LIBRARY_ITEM,
CREATE_VERSION,
DELETE_OPERATION,
GRAPH_PARAMETERS,
RELOCATE_CONSTITUENTS,
RENAME_CONSTITUENTA,
SHOW_QR_CODE,
SUBSTITUTE_CONSTITUENTS,
UPLOAD_RSFORM
}

View File

@ -1,7 +1,6 @@
'use client'; 'use client';
import fileDownload from 'js-file-download'; import fileDownload from 'js-file-download';
import { useCallback, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { IconCSV } from '@/components/Icons'; import { IconCSV } from '@/components/Icons';
@ -9,9 +8,9 @@ import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import DataLoader from '@/components/wrap/DataLoader'; import DataLoader from '@/components/wrap/DataLoader';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import { IRenameLocationData } from '@/models/library'; import { IRenameLocationData } from '@/models/library';
import { useAppLayoutStore } from '@/stores/appLayout'; import { useAppLayoutStore } from '@/stores/appLayout';
import { useDialogsStore } from '@/stores/dialogs';
import { useLibraryFilter, useLibrarySearchStore } from '@/stores/librarySearch'; import { useLibraryFilter, useLibrarySearchStore } from '@/stores/librarySearch';
import { information } from '@/utils/labels'; import { information } from '@/utils/labels';
import { convertToCSV } from '@/utils/utils'; import { convertToCSV } from '@/utils/utils';
@ -31,23 +30,20 @@ function LibraryPage() {
const filter = useLibraryFilter(); const filter = useLibraryFilter();
const items = library.applyFilter(filter); const items = library.applyFilter(filter);
const [showRenameLocation, setShowRenameLocation] = useState(false); const showChangeLocation = useDialogsStore(state => state.showChangeLocation);
const handleRenameLocation = useCallback( function handleRenameLocation(newLocation: string) {
(newLocation: string) => { const data: IRenameLocationData = {
const data: IRenameLocationData = { target: location,
target: location, new_location: newLocation
new_location: newLocation };
}; library.renameLocation(data, () => {
library.renameLocation(data, () => { setLocation(newLocation);
setLocation(newLocation); toast.success(information.locationRenamed);
toast.success(information.locationRenamed); });
}); }
},
[location, setLocation, library]
);
const handleDownloadCSV = useCallback(() => { function handleDownloadCSV() {
if (items.length === 0) { if (items.length === 0) {
toast.error(information.noDataToExport); toast.error(information.noDataToExport);
return; return;
@ -58,17 +54,10 @@ function LibraryPage() {
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
}, [items]); }
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 ? (
<DlgChangeLocation
initial={location}
onChangeLocation={handleRenameLocation}
hideWindow={() => setShowRenameLocation(false)}
/>
) : null}
<Overlay <Overlay
position={noNavigation ? 'top-[0.25rem] right-[3rem]' : 'top-[0.25rem] right-0'} position={noNavigation ? 'top-[0.25rem] right-[3rem]' : 'top-[0.25rem] right-0'}
layer='z-tooltip' layer='z-tooltip'
@ -86,7 +75,7 @@ function LibraryPage() {
<ViewSideLocation <ViewSideLocation
isVisible={folderMode} isVisible={folderMode}
folderTree={library.folders} folderTree={library.folders}
onRenameLocation={() => setShowRenameLocation(true)} onRenameLocation={() => showChangeLocation({ initial: location, onChangeLocation: handleRenameLocation })}
/> />
<TableLibraryItems items={items} /> <TableLibraryItems items={items} />

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import { urls } from '@/app/urls'; import { urls } from '@/app/urls';
@ -8,13 +8,6 @@ import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext'; import { useLibrary } from '@/context/LibraryContext';
import { useConceptNavigation } from '@/context/NavigationContext'; import { useConceptNavigation } from '@/context/NavigationContext';
import { useOSS } from '@/context/OssContext'; import { useOSS } from '@/context/OssContext';
import DlgChangeInputSchema from '@/dialogs/DlgChangeInputSchema';
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import DlgCreateOperation from '@/dialogs/DlgCreateOperation';
import DlgDeleteOperation from '@/dialogs/DlgDeleteOperation';
import DlgEditEditors from '@/dialogs/DlgEditEditors';
import DlgEditOperation from '@/dialogs/DlgEditOperation';
import DlgRelocateConstituents from '@/dialogs/DlgRelocateConstituents';
import { AccessPolicy, ILibraryItemEditor, LibraryItemID } from '@/models/library'; import { AccessPolicy, ILibraryItemEditor, LibraryItemID } from '@/models/library';
import { Position2D } from '@/models/miscellaneous'; import { Position2D } from '@/models/miscellaneous';
import { calculateInsertPosition } from '@/models/miscellaneousAPI'; import { calculateInsertPosition } from '@/models/miscellaneousAPI';
@ -30,6 +23,7 @@ import {
OperationType OperationType
} from '@/models/oss'; } from '@/models/oss';
import { UserID, UserRole } from '@/models/user'; import { UserID, UserRole } from '@/models/user';
import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { useRoleStore } from '@/stores/role'; import { useRoleStore } from '@/stores/role';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
@ -106,24 +100,18 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
const [showTooltip, setShowTooltip] = useState(true); const [showTooltip, setShowTooltip] = useState(true);
const [showEditEditors, setShowEditEditors] = useState(false);
const [showEditLocation, setShowEditLocation] = useState(false);
const [showEditInput, setShowEditInput] = useState(false);
const [showEditOperation, setShowEditOperation] = useState(false);
const [showDeleteOperation, setShowDeleteOperation] = useState(false);
const [showRelocateConstituents, setShowRelocateConstituents] = useState(false);
const [showCreateOperation, setShowCreateOperation] = useState(false);
const [insertPosition, setInsertPosition] = useState<Position2D>({ x: 0, y: 0 }); const [insertPosition, setInsertPosition] = useState<Position2D>({ x: 0, y: 0 });
const [initialInputs, setInitialInputs] = useState<OperationID[]>([]);
const [createCallback, setCreateCallback] = useState<((newID: OperationID) => void) | undefined>(undefined); const [createCallback, setCreateCallback] = useState<((newID: OperationID) => void) | undefined>(undefined);
const showEditEditors = useDialogsStore(state => state.showEditEditors);
const showEditLocation = useDialogsStore(state => state.showChangeLocation);
const showEditInput = useDialogsStore(state => state.showChangeInputSchema);
const showEditOperation = useDialogsStore(state => state.showEditOperation);
const showDeleteOperation = useDialogsStore(state => state.showDeleteOperation);
const showRelocateConstituents = useDialogsStore(state => state.showRelocateConstituents);
const showCreateOperation = useDialogsStore(state => state.showCreateOperation);
const [positions, setPositions] = useState<IOperationPosition[]>([]); const [positions, setPositions] = useState<IOperationPosition[]>([]);
const [targetOperationID, setTargetOperationID] = useState<OperationID | undefined>(undefined);
const targetOperation = useMemo(
() => (targetOperationID ? model.schema?.operationByID.get(targetOperationID) : undefined),
[model, targetOperationID]
);
useEffect( useEffect(
() => () =>
@ -146,14 +134,6 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const promptEditors = useCallback(() => {
setShowEditEditors(true);
}, []);
const promptLocation = useCallback(() => {
setShowEditLocation(true);
}, []);
const share = useCallback(() => { const share = useCallback(() => {
const currentRef = window.location.href; const currentRef = window.location.href;
const url = currentRef.includes('?') ? currentRef + '&share' : currentRef + '?share'; const url = currentRef.includes('?') ? currentRef + '&share' : currentRef + '?share';
@ -177,7 +157,7 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const setEditors = useCallback( const handleSetEditors = useCallback(
(newEditors: UserID[]) => { (newEditors: UserID[]) => {
model.setEditors(newEditors, () => toast.success(information.changesSaved)); model.setEditors(newEditors, () => toast.success(information.changesSaved));
}, },
@ -212,17 +192,6 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const promptCreateOperation = useCallback(
({ defaultX, defaultY, inputs, positions, callback }: ICreateOperationPrompt) => {
setInsertPosition({ x: defaultX, y: defaultY });
setInitialInputs(inputs);
setPositions(positions);
setCreateCallback(() => callback);
setShowCreateOperation(true);
},
[]
);
const handleCreateOperation = useCallback( const handleCreateOperation = useCallback(
(data: IOperationCreateData) => { (data: IOperationCreateData) => {
const target = calculateInsertPosition( const target = calculateInsertPosition(
@ -245,12 +214,6 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model, positions, insertPosition, createCallback] [model, positions, insertPosition, createCallback]
); );
const promptEditOperation = useCallback((target: OperationID, positions: IOperationPosition[]) => {
setPositions(positions);
setTargetOperationID(target);
setShowEditOperation(true);
}, []);
const handleEditOperation = useCallback( const handleEditOperation = useCallback(
(data: IOperationUpdateData) => { (data: IOperationUpdateData) => {
data.positions = positions; data.positions = positions;
@ -276,26 +239,17 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model] [model]
); );
const promptDeleteOperation = useCallback((target: OperationID, positions: IOperationPosition[]) => { const handleDeleteOperation = useCallback(
setPositions(positions); (targetID: OperationID, keepConstituents: boolean, deleteSchema: boolean) => {
setTargetOperationID(target);
setShowDeleteOperation(true);
}, []);
const deleteOperation = useCallback(
(keepConstituents: boolean, deleteSchema: boolean) => {
if (!targetOperationID) {
return;
}
const data: IOperationDeleteData = { const data: IOperationDeleteData = {
target: targetOperationID, target: targetID,
positions: positions, positions: positions,
keep_constituents: keepConstituents, keep_constituents: keepConstituents,
delete_schema: deleteSchema delete_schema: deleteSchema
}; };
model.deleteOperation(data, () => toast.success(information.operationDestroyed)); model.deleteOperation(data, () => toast.success(information.operationDestroyed));
}, },
[model, targetOperationID, positions] [model, positions]
); );
const createInput = useCallback( const createInput = useCallback(
@ -316,44 +270,18 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model, library.items, router] [model, library.items, router]
); );
const promptEditInput = useCallback((target: OperationID, positions: IOperationPosition[]) => {
setPositions(positions);
setTargetOperationID(target);
setShowEditInput(true);
}, []);
const setTargetInput = useCallback( const setTargetInput = useCallback(
(newInput: LibraryItemID | undefined) => { (target: OperationID, newInput: LibraryItemID | undefined) => {
if (!targetOperationID) {
return;
}
const data: IOperationSetInputData = { const data: IOperationSetInputData = {
target: targetOperationID, target: target,
positions: positions, positions: positions,
input: newInput ?? null input: newInput ?? null
}; };
model.setInput(data, () => toast.success(information.changesSaved)); model.setInput(data, () => toast.success(information.changesSaved));
}, },
[model, targetOperationID, positions] [model, positions]
); );
const executeOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
const data = {
target: target,
positions: positions
};
model.executeOperation(data, () => toast.success(information.operationExecuted));
},
[model]
);
const promptRelocateConstituents = useCallback((target: OperationID | undefined, positions: IOperationPosition[]) => {
setPositions(positions);
setTargetOperationID(target);
setShowRelocateConstituents(true);
}, []);
const handleRelocateConstituents = useCallback( const handleRelocateConstituents = useCallback(
(data: ICstRelocateData) => { (data: ICstRelocateData) => {
if ( if (
@ -372,6 +300,92 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
[model, positions] [model, positions]
); );
const executeOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
const data = {
target: target,
positions: positions
};
model.executeOperation(data, () => toast.success(information.operationExecuted));
},
[model]
);
const promptEditors = useCallback(() => {
if (!model.schema) {
return;
}
showEditEditors({ editors: model.schema.editors, setEditors: handleSetEditors });
}, [model.schema, showEditEditors, handleSetEditors]);
const promptLocation = useCallback(() => {
if (!model.schema) {
return;
}
showEditLocation({ initial: model.schema.location, onChangeLocation: handleSetLocation });
}, [model.schema, showEditLocation, handleSetLocation]);
const promptCreateOperation = useCallback(
({ defaultX, defaultY, inputs, positions, callback }: ICreateOperationPrompt) => {
if (!model.schema) {
return;
}
setInsertPosition({ x: defaultX, y: defaultY });
setPositions(positions);
setCreateCallback(() => callback);
showCreateOperation({ oss: model.schema, onCreate: handleCreateOperation, initialInputs: inputs });
},
[model.schema, showCreateOperation, handleCreateOperation]
);
const promptEditOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
const operation = model.schema?.operationByID.get(target);
if (!model.schema || !operation) {
return;
}
setPositions(positions);
showEditOperation({ oss: model.schema, target: operation, onSubmit: handleEditOperation });
},
[model.schema, showEditOperation, handleEditOperation]
);
const promptDeleteOperation = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
const operation = model.schema?.operationByID.get(target);
if (!model.schema || !operation) {
return;
}
setPositions(positions);
showDeleteOperation({ target: operation, onSubmit: handleDeleteOperation });
},
[model.schema, showDeleteOperation, handleDeleteOperation]
);
const promptEditInput = useCallback(
(target: OperationID, positions: IOperationPosition[]) => {
const operation = model.schema?.operationByID.get(target);
if (!model.schema || !operation) {
return;
}
setPositions(positions);
showEditInput({ oss: model.schema, target: operation, onSubmit: setTargetInput });
},
[model.schema, showEditInput, setTargetInput]
);
const promptRelocateConstituents = useCallback(
(target: OperationID | undefined, positions: IOperationPosition[]) => {
if (!model.schema) {
return;
}
const operation = target ? model.schema?.operationByID.get(target) : undefined;
setPositions(positions);
showRelocateConstituents({ oss: model.schema, initialTarget: operation, onSubmit: handleRelocateConstituents });
},
[model.schema, showRelocateConstituents, handleRelocateConstituents]
);
return ( return (
<OssEditContext <OssEditContext
value={{ value={{
@ -405,64 +419,6 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
promptRelocateConstituents promptRelocateConstituents
}} }}
> >
{model.schema ? (
<>
{showEditEditors ? (
<DlgEditEditors
hideWindow={() => setShowEditEditors(false)}
editors={model.schema.editors}
setEditors={setEditors}
/>
) : null}
{showEditLocation ? (
<DlgChangeLocation
hideWindow={() => setShowEditLocation(false)}
initial={model.schema.location}
onChangeLocation={handleSetLocation}
/>
) : null}
{showCreateOperation ? (
<DlgCreateOperation
hideWindow={() => setShowCreateOperation(false)}
oss={model.schema}
onCreate={handleCreateOperation}
initialInputs={initialInputs}
/>
) : null}
{showEditInput ? (
<DlgChangeInputSchema
hideWindow={() => setShowEditInput(false)}
oss={model.schema}
target={targetOperation!}
onSubmit={setTargetInput}
/>
) : null}
{showEditOperation ? (
<DlgEditOperation
hideWindow={() => setShowEditOperation(false)}
oss={model.schema}
target={targetOperation!}
onSubmit={handleEditOperation}
/>
) : null}
{showDeleteOperation ? (
<DlgDeleteOperation
hideWindow={() => setShowDeleteOperation(false)}
target={targetOperation!}
onSubmit={deleteOperation}
/>
) : null}
{showRelocateConstituents ? (
<DlgRelocateConstituents
hideWindow={() => setShowRelocateConstituents(false)}
initialTarget={targetOperation}
oss={model.schema}
onSubmit={handleRelocateConstituents}
/>
) : null}
</>
) : null}
{children} {children}
</OssEditContext> </OssEditContext>
); );

View File

@ -12,10 +12,10 @@ import Overlay from '@/components/ui/Overlay';
import SubmitButton from '@/components/ui/SubmitButton'; import SubmitButton from '@/components/ui/SubmitButton';
import TextArea from '@/components/ui/TextArea'; import TextArea from '@/components/ui/TextArea';
import { useRSForm } from '@/context/RSFormContext'; import { useRSForm } from '@/context/RSFormContext';
import DlgShowTypeGraph from '@/dialogs/DlgShowTypeGraph';
import { ConstituentaID, CstType, IConstituenta, ICstUpdateData } from '@/models/rsform'; import { ConstituentaID, CstType, IConstituenta, ICstUpdateData } from '@/models/rsform';
import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI'; import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI';
import { IExpressionParse, ParsingStatus } from '@/models/rslang'; import { IExpressionParse, ParsingStatus } from '@/models/rslang';
import { useDialogsStore } from '@/stores/dialogs';
import { errors, information, labelCstTypification } from '@/utils/labels'; import { errors, information, labelCstTypification } from '@/utils/labels';
import EditorRSExpression from '../EditorRSExpression'; import EditorRSExpression from '../EditorRSExpression';
@ -56,7 +56,6 @@ function FormConstituenta({
const [expression, setExpression] = useState(state?.definition_formal ?? ''); const [expression, setExpression] = useState(state?.definition_formal ?? '');
const [convention, setConvention] = useState(state?.convention ?? ''); const [convention, setConvention] = useState(state?.convention ?? '');
const [typification, setTypification] = useState('N/A'); const [typification, setTypification] = useState('N/A');
const [showTypification, setShowTypification] = useState(false);
const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined); const [localParse, setLocalParse] = useState<IExpressionParse | undefined>(undefined);
const typeInfo = state const typeInfo = state
? { ? {
@ -72,6 +71,8 @@ function FormConstituenta({
const isElementary = !!state && isBaseSet(state.cst_type); const isElementary = !!state && isBaseSet(state.cst_type);
const showConvention = !state || !!state.convention || forceComment || isBasic; const showConvention = !state || !!state.convention || forceComment || isBasic;
const showTypification = useDialogsStore(state => state.showShowTypeGraph);
useEffect(() => { useEffect(() => {
if (state) { if (state) {
setConvention(state.convention); setConvention(state.convention);
@ -142,14 +143,11 @@ function FormConstituenta({
} }
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
setShowTypification(true); showTypification({ items: typeInfo ? [typeInfo] : [] });
} }
return ( return (
<div className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'> <div className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'>
{showTypification && state ? (
<DlgShowTypeGraph items={typeInfo ? [typeInfo] : []} hideWindow={() => setShowTypification(false)} />
) : null}
{state ? ( {state ? (
<ControlsOverlay <ControlsOverlay
disabled={disabled} disabled={disabled}

View File

@ -11,13 +11,13 @@ import { parser as rslangParser } from '@/components/RSInput/rslang/parserAST';
import { RSTextWrapper } from '@/components/RSInput/textEditing'; import { RSTextWrapper } from '@/components/RSInput/textEditing';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import { useRSForm } from '@/context/RSFormContext'; import { useRSForm } from '@/context/RSFormContext';
import DlgShowAST from '@/dialogs/DlgShowAST';
import useCheckConstituenta from '@/hooks/useCheckConstituenta'; import useCheckConstituenta from '@/hooks/useCheckConstituenta';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import { ConstituentaID, IConstituenta } from '@/models/rsform'; import { ConstituentaID, IConstituenta } from '@/models/rsform';
import { getDefinitionPrefix } from '@/models/rsformAPI'; import { getDefinitionPrefix } from '@/models/rsformAPI';
import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '@/models/rslang'; import { IExpressionParse, IRSErrorDescription } from '@/models/rslang';
import { TokenID } from '@/models/rslang'; import { TokenID } from '@/models/rslang';
import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { transformAST } from '@/utils/codemirror'; import { transformAST } from '@/utils/codemirror';
import { errors, labelTypification } from '@/utils/labels'; import { errors, labelTypification } from '@/utils/labels';
@ -64,9 +64,7 @@ function EditorRSExpression({
const rsInput = useRef<ReactCodeMirrorRef>(null); const rsInput = useRef<ReactCodeMirrorRef>(null);
const showControls = usePreferencesStore(state => state.showExpressionControls); const showControls = usePreferencesStore(state => state.showExpressionControls);
const [syntaxTree, setSyntaxTree] = useState<SyntaxTree>([]); const showAST = useDialogsStore(state => state.showShowAST);
const [expression, setExpression] = useState('');
const [showAST, setShowAST] = useState(false);
useEffect(() => { useEffect(() => {
setIsModified(false); setIsModified(false);
@ -131,17 +129,13 @@ function EditorRSExpression({
if (event.ctrlKey) { if (event.ctrlKey) {
const tree = rslangParser.parse(value); const tree = rslangParser.parse(value);
const ast = transformAST(tree); const ast = transformAST(tree);
setSyntaxTree(ast); showAST({ syntaxTree: ast, expression: value });
setExpression(value);
setShowAST(true);
} else { } else {
handleCheckExpression(parse => { handleCheckExpression(parse => {
if (!parse.astText) { if (!parse.astText) {
toast.error(errors.astFailed); toast.error(errors.astFailed);
} else { } else {
setSyntaxTree(parse.ast); showAST({ syntaxTree: parse.ast, expression: getDefinitionPrefix(activeCst) + value });
setExpression(getDefinitionPrefix(activeCst) + value);
setShowAST(true);
} }
}); });
} }
@ -149,10 +143,6 @@ function EditorRSExpression({
return ( return (
<div className='cc-fade-in'> <div className='cc-fade-in'>
{showAST ? (
<DlgShowAST expression={expression} syntaxTree={syntaxTree} hideWindow={() => setShowAST(false)} />
) : null}
<ToolbarRSExpression disabled={disabled} showAST={handleShowAST} showTypeGraph={onShowTypeGraph} /> <ToolbarRSExpression disabled={disabled} showAST={handleShowAST} showTypeGraph={onShowTypeGraph} />
<Overlay <Overlay

View File

@ -24,10 +24,10 @@ import SelectedCounter from '@/components/info/SelectedCounter';
import { CProps } from '@/components/props'; import { CProps } from '@/components/props';
import ToolbarGraphSelection from '@/components/select/ToolbarGraphSelection'; import ToolbarGraphSelection from '@/components/select/ToolbarGraphSelection';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import DlgGraphParams from '@/dialogs/DlgGraphParams';
import { ConstituentaID, CstType, IConstituenta } from '@/models/rsform'; import { ConstituentaID, CstType, IConstituenta } from '@/models/rsform';
import { isBasicConcept } from '@/models/rsformAPI'; import { isBasicConcept } from '@/models/rsformAPI';
import { useMainHeight } from '@/stores/appLayout'; import { useMainHeight } from '@/stores/appLayout';
import { useDialogsStore } from '@/stores/dialogs';
import { useTermGraphStore } from '@/stores/termGraph'; import { useTermGraphStore } from '@/stores/termGraph';
import { APP_COLORS, colorBgGraphNode } from '@/styling/color'; import { APP_COLORS, colorBgGraphNode } from '@/styling/color';
import { PARAMETER } from '@/utils/constants'; import { PARAMETER } from '@/utils/constants';
@ -60,7 +60,7 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
const store = useStoreApi(); const store = useStoreApi();
const { addSelectedNodes } = store.getState(); const { addSelectedNodes } = store.getState();
const [showParamsDialog, setShowParamsDialog] = useState(false); const showParams = useDialogsStore(state => state.showGraphParams);
const filter = useTermGraphStore(state => state.filter); const filter = useTermGraphStore(state => state.filter);
const setFilter = useTermGraphStore(state => state.setFilter); const setFilter = useTermGraphStore(state => state.setFilter);
@ -295,15 +295,11 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
return ( return (
<> <>
{showParamsDialog ? (
<DlgGraphParams hideWindow={() => setShowParamsDialog(false)} initial={filter} onConfirm={setFilter} />
) : null}
<Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'> <Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'>
<ToolbarTermGraph <ToolbarTermGraph
noText={filter.noText} noText={filter.noText}
foldDerived={filter.foldDerived} foldDerived={filter.foldDerived}
showParamsDialog={() => setShowParamsDialog(true)} showParamsDialog={() => showParams({ initial: filter, onConfirm: setFilter })}
onCreate={handleCreateCst} onCreate={handleCreateCst}
onDelete={handleDeleteCst} onDelete={handleDeleteCst}
onFitView={() => setToggleResetView(prev => !prev)} onFitView={() => setToggleResetView(prev => !prev)}

View File

@ -8,21 +8,6 @@ import { urls } from '@/app/urls';
import { useAuth } from '@/context/AuthContext'; import { useAuth } from '@/context/AuthContext';
import { useConceptNavigation } from '@/context/NavigationContext'; import { useConceptNavigation } from '@/context/NavigationContext';
import { useRSForm } from '@/context/RSFormContext'; import { useRSForm } from '@/context/RSFormContext';
import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import DlgCloneLibraryItem from '@/dialogs/DlgCloneLibraryItem';
import DlgConstituentaTemplate from '@/dialogs/DlgConstituentaTemplate';
import DlgCreateCst from '@/dialogs/DlgCreateCst';
import DlgCreateVersion from '@/dialogs/DlgCreateVersion';
import DlgDeleteCst from '@/dialogs/DlgDeleteCst';
import DlgEditEditors from '@/dialogs/DlgEditEditors';
import DlgEditVersions from '@/dialogs/DlgEditVersions';
import DlgEditWordForms from '@/dialogs/DlgEditWordForms';
import DlgInlineSynthesis from '@/dialogs/DlgInlineSynthesis';
import DlgRenameCst from '@/dialogs/DlgRenameCst';
import DlgShowQR from '@/dialogs/DlgShowQR';
import DlgShowTypeGraph from '@/dialogs/DlgShowTypeGraph';
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
import { import {
AccessPolicy, AccessPolicy,
ILibraryItemEditor, ILibraryItemEditor,
@ -49,6 +34,7 @@ import {
} from '@/models/rsform'; } from '@/models/rsform';
import { generateAlias } from '@/models/rsformAPI'; import { generateAlias } from '@/models/rsformAPI';
import { UserID, UserRole } from '@/models/user'; import { UserID, UserRole } from '@/models/user';
import { useDialogsStore } from '@/stores/dialogs';
import { usePreferencesStore } from '@/stores/preferences'; import { usePreferencesStore } from '@/stores/preferences';
import { useRoleStore } from '@/stores/role'; import { useRoleStore } from '@/stores/role';
import { EXTEOR_TRS_FILE } from '@/utils/constants'; import { EXTEOR_TRS_FILE } from '@/utils/constants';
@ -161,27 +147,26 @@ export const RSEditState = ({
[model.schema] [model.schema]
); );
const [showUpload, setShowUpload] = useState(false);
const [showClone, setShowClone] = useState(false);
const [showDeleteCst, setShowDeleteCst] = useState(false);
const [showEditEditors, setShowEditEditors] = useState(false);
const [showEditLocation, setShowEditLocation] = useState(false);
const [showEditTerm, setShowEditTerm] = useState(false);
const [showSubstitute, setShowSubstitute] = useState(false);
const [showCreateVersion, setShowCreateVersion] = useState(false);
const [showEditVersions, setShowEditVersions] = useState(false);
const [showInlineSynthesis, setShowInlineSynthesis] = useState(false);
const [showTypeGraph, setShowTypeGraph] = useState(false);
const [showQR, setShowQR] = useState(false);
const [createInitialData, setCreateInitialData] = useState<ICstCreateData>();
const [showCreateCst, setShowCreateCst] = useState(false);
const [renameInitialData, setRenameInitialData] = useState<ICstRenameData>(); const [renameInitialData, setRenameInitialData] = useState<ICstRenameData>();
const [showRenameCst, setShowRenameCst] = useState(false);
const [insertCstID, setInsertCstID] = useState<ConstituentaID | undefined>(undefined); const showClone = useDialogsStore(state => state.showCloneLibraryItem);
const [showTemplates, setShowTemplates] = useState(false); const showCreateVersion = useDialogsStore(state => state.showCreateVersion);
const showEditVersions = useDialogsStore(state => state.showEditVersions);
const showEditEditors = useDialogsStore(state => state.showEditEditors);
const showEditLocation = useDialogsStore(state => state.showChangeLocation);
const showCreateCst = useDialogsStore(state => state.showCreateCst);
const showDeleteCst = useDialogsStore(state => state.showDeleteCst);
const showRenameCst = useDialogsStore(state => state.showRenameCst);
const showEditTerm = useDialogsStore(state => state.showEditWordForms);
const showSubstituteCst = useDialogsStore(state => state.showSubstituteCst);
const showCstTemplate = useDialogsStore(state => state.showCstTemplate);
const showInlineSynthesis = useDialogsStore(state => state.showInlineSynthesis);
const showTypeGraph = useDialogsStore(state => state.showShowTypeGraph);
const showUpload = useDialogsStore(state => state.showUploadRSForm);
const showQR = useDialogsStore(state => state.showQR);
const typeInfo = useMemo( const typeInfo = useMemo(
() => () =>
@ -235,13 +220,6 @@ export const RSEditState = ({
[router] [router]
); );
const createVersion = useCallback(() => {
if (isModified && !promptUnsaved()) {
return;
}
setShowCreateVersion(true);
}, [isModified]);
const restoreVersion = useCallback(() => { const restoreVersion = useCallback(() => {
if (!model.versionID || !window.confirm(prompts.restoreArchive)) { if (!model.versionID || !window.confirm(prompts.restoreArchive)) {
return; return;
@ -252,7 +230,7 @@ export const RSEditState = ({
}); });
}, [model, viewVersion]); }, [model, viewVersion]);
function calculateCloneLocation(): string { const calculateCloneLocation = useCallback(() => {
if (!model.schema) { if (!model.schema) {
return LocationHead.USER; return LocationHead.USER;
} }
@ -265,7 +243,7 @@ export const RSEditState = ({
return location; return location;
} }
return head === LocationHead.USER ? LocationHead.USER : location; return head === LocationHead.USER ? LocationHead.USER : location;
} }, [model.schema, user]);
const handleCreateCst = useCallback( const handleCreateCst = useCallback(
(data: ICstCreateData) => { (data: ICstCreateData) => {
@ -397,6 +375,29 @@ export const RSEditState = ({
[model, setSelected] [model, setSelected]
); );
const createVersion = useCallback(() => {
if (!model.schema || (isModified && !promptUnsaved())) {
return;
}
showCreateVersion({
versions: model.schema.versions,
onCreate: handleCreateVersion,
selected: selected,
totalCount: model.schema.items.length
});
}, [isModified, model.schema, selected, handleCreateVersion, showCreateVersion]);
const promptEditVersions = useCallback(() => {
if (!model.schema) {
return;
}
showEditVersions({
versions: model.schema.versions,
onDelete: handleDeleteVersion,
onUpdate: handleUpdateVersion
});
}, [model.schema, handleDeleteVersion, handleUpdateVersion, showEditVersions]);
const moveUp = useCallback(() => { const moveUp = useCallback(() => {
if (!model.schema?.items || selected.length === 0) { if (!model.schema?.items || selected.length === 0) {
return; return;
@ -460,11 +461,10 @@ export const RSEditState = ({
if (skipDialog) { if (skipDialog) {
handleCreateCst(data); handleCreateCst(data);
} else { } else {
setCreateInitialData(data); showCreateCst({ schema: model.schema, onCreate: handleCreateCst, initial: data });
setShowCreateCst(true);
} }
}, },
[activeCst, handleCreateCst, model.schema] [activeCst, handleCreateCst, model.schema, showCreateCst]
); );
const cloneCst = useCallback(() => { const cloneCst = useCallback(() => {
@ -485,7 +485,7 @@ export const RSEditState = ({
}, [activeCst, handleCreateCst, model.schema]); }, [activeCst, handleCreateCst, model.schema]);
const renameCst = useCallback(() => { const renameCst = useCallback(() => {
if (!activeCst) { if (!activeCst || !model.schema) {
return; return;
} }
const data: ICstRenameData = { const data: ICstRenameData = {
@ -494,22 +494,34 @@ export const RSEditState = ({
cst_type: activeCst.cst_type cst_type: activeCst.cst_type
}; };
setRenameInitialData(data); setRenameInitialData(data);
setShowRenameCst(true); showRenameCst({
}, [activeCst]); schema: model.schema,
initial: data,
allowChangeType: !activeCst.is_inherited,
onRename: handleRenameCst
});
}, [activeCst, model.schema, handleRenameCst, showRenameCst]);
const substitute = useCallback(() => { const substitute = useCallback(() => {
if (isModified && !promptUnsaved()) { if (!model.schema || (isModified && !promptUnsaved())) {
return; return;
} }
setShowSubstitute(true); showSubstituteCst({ schema: model.schema, onSubstitute: handleSubstituteCst });
}, [isModified]); }, [isModified, model.schema, handleSubstituteCst, showSubstituteCst]);
const inlineSynthesis = useCallback(() => { const inlineSynthesis = useCallback(() => {
if (isModified && !promptUnsaved()) { if (!model.schema || (isModified && !promptUnsaved())) {
return; return;
} }
setShowInlineSynthesis(true); showInlineSynthesis({ receiver: model.schema, onInlineSynthesis: handleInlineSynthesis });
}, [isModified]); }, [isModified, model.schema, handleInlineSynthesis, showInlineSynthesis]);
const promptDeleteCst = useCallback(() => {
if (!model.schema) {
return;
}
showDeleteCst({ schema: model.schema, selected: selected, onDelete: handleDeleteCst });
}, [model.schema, selected, handleDeleteCst, showDeleteCst]);
const editTermForms = useCallback(() => { const editTermForms = useCallback(() => {
if (!activeCst) { if (!activeCst) {
@ -518,8 +530,8 @@ export const RSEditState = ({
if (isModified && !promptUnsaved()) { if (isModified && !promptUnsaved()) {
return; return;
} }
setShowEditTerm(true); showEditTerm({ target: activeCst, onSave: handleSaveWordforms });
}, [isModified, activeCst]); }, [isModified, activeCst, handleSaveWordforms, showEditTerm]);
const reindex = useCallback(() => model.resetAliases(() => toast.success(information.reindexComplete)), [model]); const reindex = useCallback(() => model.resetAliases(() => toast.success(information.reindexComplete)), [model]);
const reorder = useCallback(() => model.restoreOrder(() => toast.success(information.reorderComplete)), [model]); const reorder = useCallback(() => model.restoreOrder(() => toast.success(information.reorderComplete)), [model]);
@ -551,28 +563,45 @@ export const RSEditState = ({
}); });
}, [activeCst, setSelected, model, isModified]); }, [activeCst, setSelected, model, isModified]);
const setEditors = useCallback(
(newEditors: UserID[]) => {
model.setEditors(newEditors, () => toast.success(information.changesSaved));
},
[model]
);
const promptTemplate = useCallback(() => { const promptTemplate = useCallback(() => {
if (isModified && !promptUnsaved()) { if ((isModified && !promptUnsaved()) || !model.schema) {
return; return;
} }
setInsertCstID(activeCst?.id); showCstTemplate({ schema: model.schema, onCreate: handleCreateCst, insertAfter: activeCst?.id });
setShowTemplates(true); }, [activeCst, isModified, handleCreateCst, model.schema, showCstTemplate]);
}, [activeCst, isModified]);
const promptClone = useCallback(() => { const promptClone = useCallback(() => {
if (isModified && !promptUnsaved()) { if (!model.schema || (isModified && !promptUnsaved())) {
return; return;
} }
setShowClone(true); showClone({
}, [isModified]); base: model.schema,
initialLocation: calculateCloneLocation(),
selected: selected,
totalCount: model.schema.items.length
});
}, [isModified, model.schema, selected, showClone, calculateCloneLocation]);
const promptEditors = useCallback(() => { const promptEditors = useCallback(() => {
setShowEditEditors(true); if (!model.schema) {
}, []); return;
}
showEditEditors({ editors: model.schema.editors, setEditors: setEditors });
}, [model.schema, showEditEditors, setEditors]);
const promptLocation = useCallback(() => { const promptLocation = useCallback(() => {
setShowEditLocation(true); if (!model.schema) {
}, []); return;
}
showEditLocation({ initial: model.schema.location, onChangeLocation: handleSetLocation });
}, [model.schema, showEditLocation, handleSetLocation]);
const download = useCallback(() => { const download = useCallback(() => {
if (isModified && !promptUnsaved()) { if (isModified && !promptUnsaved()) {
@ -611,13 +640,6 @@ export const RSEditState = ({
[model] [model]
); );
const setEditors = useCallback(
(newEditors: UserID[]) => {
model.setEditors(newEditors, () => toast.success(information.changesSaved));
},
[model]
);
function generateQR(): string { function generateQR(): string {
const currentRef = window.location.href; const currentRef = window.location.href;
return currentRef.includes('?') ? currentRef + '&qr' : currentRef + '?qr'; return currentRef.includes('?') ? currentRef + '&qr' : currentRef + '?qr';
@ -653,19 +675,19 @@ export const RSEditState = ({
viewPredecessor, viewPredecessor,
createVersion, createVersion,
restoreVersion, restoreVersion,
promptEditVersions: () => setShowEditVersions(true), promptEditVersions,
moveUp, moveUp,
moveDown, moveDown,
createCst, createCst,
cloneCst, cloneCst,
renameCst, renameCst,
promptDeleteCst: () => setShowDeleteCst(true), promptDeleteCst,
editTermForms, editTermForms,
promptTemplate, promptTemplate,
promptClone, promptClone,
promptUpload: () => setShowUpload(true), promptUpload: () => showUpload({ upload: model.upload }),
download, download,
share, share,
@ -675,113 +697,10 @@ export const RSEditState = ({
produceStructure, produceStructure,
substitute, substitute,
showTypeGraph: () => setShowTypeGraph(true), showTypeGraph: () => showTypeGraph({ items: typeInfo }),
showQR: () => setShowQR(true) showQR: () => showQR({ target: generateQR() })
}} }}
> >
{model.schema ? (
<>
{showQR ? <DlgShowQR hideWindow={() => setShowQR(false)} target={generateQR()} /> : null}
{showUpload ? <DlgUploadRSForm hideWindow={() => setShowUpload(false)} /> : null}
{showClone ? (
<DlgCloneLibraryItem
base={model.schema}
initialLocation={calculateCloneLocation()}
hideWindow={() => setShowClone(false)}
selected={selected}
totalCount={model.schema.items.length}
/>
) : null}
{showCreateCst ? (
<DlgCreateCst
hideWindow={() => setShowCreateCst(false)}
onCreate={handleCreateCst}
schema={model.schema}
initial={createInitialData}
/>
) : null}
{activeCst && showRenameCst && renameInitialData ? (
<DlgRenameCst
hideWindow={() => setShowRenameCst(false)}
onRename={handleRenameCst}
allowChangeType={!activeCst.is_inherited}
initial={renameInitialData}
/>
) : null}
{showSubstitute ? (
<DlgSubstituteCst
schema={model.schema}
hideWindow={() => setShowSubstitute(false)} // prettier: split lines
onSubstitute={handleSubstituteCst}
/>
) : null}
{showDeleteCst ? (
<DlgDeleteCst
schema={model.schema}
hideWindow={() => setShowDeleteCst(false)}
onDelete={handleDeleteCst}
selected={selected}
/>
) : null}
{showEditTerm && activeCst ? (
<DlgEditWordForms
hideWindow={() => setShowEditTerm(false)}
onSave={handleSaveWordforms}
target={activeCst}
/>
) : null}
{showTemplates ? (
<DlgConstituentaTemplate
schema={model.schema}
hideWindow={() => setShowTemplates(false)}
insertAfter={insertCstID}
onCreate={handleCreateCst}
/>
) : null}
{showCreateVersion ? (
<DlgCreateVersion
versions={model.schema.versions}
hideWindow={() => setShowCreateVersion(false)}
onCreate={handleCreateVersion}
selected={selected}
totalCount={model.schema.items.length}
/>
) : null}
{showEditVersions ? (
<DlgEditVersions
versions={model.schema.versions}
hideWindow={() => setShowEditVersions(false)}
onDelete={handleDeleteVersion}
onUpdate={handleUpdateVersion}
/>
) : null}
{showEditEditors ? (
<DlgEditEditors
hideWindow={() => setShowEditEditors(false)}
editors={model.schema.editors}
setEditors={setEditors}
/>
) : null}
{showEditLocation ? (
<DlgChangeLocation
hideWindow={() => setShowEditLocation(false)}
initial={model.schema.location}
onChangeLocation={handleSetLocation}
/>
) : null}
{showInlineSynthesis ? (
<DlgInlineSynthesis
receiver={model.schema}
hideWindow={() => setShowInlineSynthesis(false)}
onInlineSynthesis={handleInlineSynthesis}
/>
) : null}
{showTypeGraph ? <DlgShowTypeGraph items={typeInfo} hideWindow={() => setShowTypeGraph(false)} /> : null}
</>
) : null}
{children} {children}
</RSEditContext> </RSEditContext>
); );

View File

@ -0,0 +1,86 @@
import { create } from 'zustand';
import { DlgChangeInputSchemaProps } from '@/dialogs/DlgChangeInputSchema';
import { DlgChangeLocationProps } from '@/dialogs/DlgChangeLocation';
import { DlgCloneLibraryItemProps } from '@/dialogs/DlgCloneLibraryItem';
import { DlgCreateCstProps } from '@/dialogs/DlgCreateCst/DlgCreateCst';
import { DlgCreateOperationProps } from '@/dialogs/DlgCreateOperation/DlgCreateOperation';
import { DlgCreateVersionProps } from '@/dialogs/DlgCreateVersion';
import { DlgCstTemplateProps } from '@/dialogs/DlgCstTemplate/DlgCstTemplate';
import { DlgDeleteCstProps } from '@/dialogs/DlgDeleteCst/DlgDeleteCst';
import { DlgDeleteOperationProps } from '@/dialogs/DlgDeleteOperation';
import { DlgEditEditorsProps } from '@/dialogs/DlgEditEditors/DlgEditEditors';
import { DlgEditOperationProps } from '@/dialogs/DlgEditOperation/DlgEditOperation';
import { DlgEditReferenceProps } from '@/dialogs/DlgEditReference/DlgEditReference';
import { DlgEditVersionsProps } from '@/dialogs/DlgEditVersions/DlgEditVersions';
import { DlgEditWordFormsProps } from '@/dialogs/DlgEditWordForms/DlgEditWordForms';
import { DlgGraphParamsProps } from '@/dialogs/DlgGraphParams';
import { DlgInlineSynthesisProps } from '@/dialogs/DlgInlineSynthesis/DlgInlineSynthesis';
import { DlgRelocateConstituentsProps } from '@/dialogs/DlgRelocateConstituents';
import { DlgRenameCstProps } from '@/dialogs/DlgRenameCst';
import { DlgShowASTProps } from '@/dialogs/DlgShowAST/DlgShowAST';
import { DlgShowQRProps } from '@/dialogs/DlgShowQR';
import { DlgShowTypeGraphProps } from '@/dialogs/DlgShowTypeGraph/DlgShowTypeGraph';
import { DlgSubstituteCstProps } from '@/dialogs/DlgSubstituteCst';
import { DlgUploadRSFormProps } from '@/dialogs/DlgUploadRSForm';
import { DialogType } from '@/models/miscellaneous';
interface DialogsStore {
active: DialogType | undefined;
props: unknown;
hideDialog: () => void;
showCstTemplate: (props: DlgCstTemplateProps) => void;
showCreateCst: (props: DlgCreateCstProps) => void;
showCreateOperation: (props: DlgCreateOperationProps) => void;
showDeleteCst: (props: DlgDeleteCstProps) => void;
showEditEditors: (props: DlgEditEditorsProps) => void;
showEditOperation: (props: DlgEditOperationProps) => void;
showEditReference: (props: DlgEditReferenceProps) => void;
showEditVersions: (props: DlgEditVersionsProps) => void;
showEditWordForms: (props: DlgEditWordFormsProps) => void;
showInlineSynthesis: (props: DlgInlineSynthesisProps) => void;
showShowAST: (props: DlgShowASTProps) => void;
showShowTypeGraph: (props: DlgShowTypeGraphProps) => void;
showChangeInputSchema: (props: DlgChangeInputSchemaProps) => void;
showChangeLocation: (props: DlgChangeLocationProps) => void;
showCloneLibraryItem: (props: DlgCloneLibraryItemProps) => void;
showCreateVersion: (props: DlgCreateVersionProps) => void;
showDeleteOperation: (props: DlgDeleteOperationProps) => void;
showGraphParams: (props: DlgGraphParamsProps) => void;
showRelocateConstituents: (props: DlgRelocateConstituentsProps) => void;
showRenameCst: (props: DlgRenameCstProps) => void;
showQR: (props: DlgShowQRProps) => void;
showSubstituteCst: (props: DlgSubstituteCstProps) => void;
showUploadRSForm: (props: DlgUploadRSFormProps) => void;
}
export const useDialogsStore = create<DialogsStore>()(set => ({
active: undefined,
props: undefined,
hideDialog: () => set({ active: undefined, props: undefined }),
showCstTemplate: props => set({ active: DialogType.CONSTITUENTA_TEMPLATE, props: props }),
showCreateCst: props => set({ active: DialogType.CREATE_CONSTITUENTA, props: props }),
showCreateOperation: props => set({ active: DialogType.CREATE_OPERATION, props: props }),
showDeleteCst: props => set({ active: DialogType.DELETE_CONSTITUENTA, props: props }),
showEditEditors: props => set({ active: DialogType.EDIT_EDITORS, props: props }),
showEditOperation: props => set({ active: DialogType.EDIT_OPERATION, props: props }),
showEditReference: props => set({ active: DialogType.EDIT_REFERENCE, props: props }),
showEditVersions: props => set({ active: DialogType.EDIT_VERSIONS, props: props }),
showEditWordForms: props => set({ active: DialogType.EDIT_WORD_FORMS, props: props }),
showInlineSynthesis: props => set({ active: DialogType.INLINE_SYNTHESIS, props: props }),
showShowAST: props => set({ active: DialogType.SHOW_AST, props: props }),
showShowTypeGraph: props => set({ active: DialogType.SHOW_TYPE_GRAPH, props: props }),
showChangeInputSchema: props => set({ active: DialogType.CHANGE_INPUT_SCHEMA, props: props }),
showChangeLocation: props => set({ active: DialogType.CHANGE_LOCATION, props: props }),
showCloneLibraryItem: props => set({ active: DialogType.CLONE_LIBRARY_ITEM, props: props }),
showCreateVersion: props => set({ active: DialogType.CREATE_VERSION, props: props }),
showDeleteOperation: props => set({ active: DialogType.DELETE_OPERATION, props: props }),
showGraphParams: props => set({ active: DialogType.GRAPH_PARAMETERS, props: props }),
showRelocateConstituents: props => set({ active: DialogType.RELOCATE_CONSTITUENTS, props: props }),
showRenameCst: props => set({ active: DialogType.RENAME_CONSTITUENTA, props: props }),
showQR: props => set({ active: DialogType.SHOW_QR_CODE, props: props }),
showSubstituteCst: props => set({ active: DialogType.SUBSTITUTE_CONSTITUENTS, props: props }),
showUploadRSForm: props => set({ active: DialogType.UPLOAD_RSFORM, props: props })
}));