mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
Refactor dialogs
This commit is contained in:
parent
4f45b9978e
commit
44cc9371e4
|
@ -7,25 +7,24 @@ import SubmitButton from '../../components/Common/SubmitButton';
|
||||||
import TextArea from '../../components/Common/TextArea';
|
import TextArea from '../../components/Common/TextArea';
|
||||||
import { DumpBinIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons';
|
import { DumpBinIcon, SaveIcon, SmallPlusIcon } from '../../components/Icons';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { type CstType, EditMode, type ICstCreateData, ICstUpdateData, SyntaxTree } from '../../utils/models';
|
import { type CstType, EditMode, ICstUpdateData, SyntaxTree } from '../../utils/models';
|
||||||
import { createAliasFor, getCstTypeLabel } from '../../utils/staticUI';
|
import { getCstTypeLabel } from '../../utils/staticUI';
|
||||||
import DlgCreateCst from './DlgCreateCst';
|
|
||||||
import EditorRSExpression from './EditorRSExpression';
|
import EditorRSExpression from './EditorRSExpression';
|
||||||
import ViewSideConstituents from './elements/ViewSideConstituents';
|
import ViewSideConstituents from './elements/ViewSideConstituents';
|
||||||
import { RSTabsList } from './RSTabs';
|
import { RSTabsList } from './RSTabs';
|
||||||
|
|
||||||
interface EditorConstituentaProps {
|
interface EditorConstituentaProps {
|
||||||
onShowAST: (ast: SyntaxTree) => void
|
onShowAST: (ast: SyntaxTree) => void
|
||||||
|
onShowCreateCst: (position: number | undefined, type: CstType | undefined) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditorConstituenta({onShowAST}: EditorConstituentaProps) {
|
function EditorConstituenta({ onShowAST, onShowCreateCst }: EditorConstituentaProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const {
|
const {
|
||||||
activeCst, activeID, schema, setActiveID, processing, isEditable,
|
activeCst, activeID, schema, setActiveID, processing, isEditable,
|
||||||
cstDelete, cstUpdate, cstCreate
|
cstDelete, cstUpdate
|
||||||
} = useRSForm();
|
} = useRSForm();
|
||||||
|
|
||||||
const [showCstModal, setShowCstModal] = useState(false);
|
|
||||||
const [isModified, setIsModified] = useState(false);
|
const [isModified, setIsModified] = useState(false);
|
||||||
const [editMode, setEditMode] = useState(EditMode.TEXT);
|
const [editMode, setEditMode] = useState(EditMode.TEXT);
|
||||||
|
|
||||||
|
@ -107,24 +106,12 @@ function EditorConstituenta({onShowAST}: EditorConstituentaProps) {
|
||||||
}, [activeID, schema, cstDelete, navigate]);
|
}, [activeID, schema, cstDelete, navigate]);
|
||||||
|
|
||||||
const handleAddNew = useCallback(
|
const handleAddNew = useCallback(
|
||||||
(type?: CstType) => {
|
() => {
|
||||||
if (!activeID || !schema?.items) {
|
if (!activeID || !schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!type) {
|
onShowCreateCst(activeID, activeCst?.cstType);
|
||||||
setShowCstModal(true);
|
}, [activeID, activeCst?.cstType, schema, onShowCreateCst]);
|
||||||
} else {
|
|
||||||
const data: ICstCreateData = {
|
|
||||||
cst_type: type,
|
|
||||||
alias: createAliasFor(type, schema),
|
|
||||||
insert_after: activeID
|
|
||||||
}
|
|
||||||
cstCreate(data, newCst => {
|
|
||||||
navigate(`/rsforms/${schema.id}?tab=${RSTabsList.CST_EDIT}&active=${newCst.id}`);
|
|
||||||
toast.success(`Конституента добавлена: ${newCst.alias}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [activeID, schema, cstCreate, navigate]);
|
|
||||||
|
|
||||||
const handleRename = useCallback(() => {
|
const handleRename = useCallback(() => {
|
||||||
toast.info('Переименование в разработке');
|
toast.info('Переименование в разработке');
|
||||||
|
@ -136,11 +123,6 @@ function EditorConstituenta({onShowAST}: EditorConstituentaProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-start w-full gap-2'>
|
<div className='flex items-start w-full gap-2'>
|
||||||
{showCstModal && <DlgCreateCst
|
|
||||||
hideWindow={() => { setShowCstModal(false); }}
|
|
||||||
onCreate={handleAddNew}
|
|
||||||
defaultType={activeCst?.cstType as CstType}
|
|
||||||
/>}
|
|
||||||
<form onSubmit={handleSubmit} className='flex-grow min-w-[50rem] max-w-min px-4 py-2 border'>
|
<form onSubmit={handleSubmit} className='flex-grow min-w-[50rem] max-w-min px-4 py-2 border'>
|
||||||
<div className='flex items-start justify-between'>
|
<div className='flex items-start justify-between'>
|
||||||
<button type='submit'
|
<button type='submit'
|
||||||
|
@ -176,7 +158,7 @@ function EditorConstituenta({onShowAST}: EditorConstituentaProps) {
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Создать конституенты после данной'
|
tooltip='Создать конституенты после данной'
|
||||||
disabled={!isEnabled}
|
disabled={!isEnabled}
|
||||||
onClick={() => { handleAddNew(); }}
|
onClick={handleAddNew}
|
||||||
icon={<SmallPlusIcon size={5} color={isEnabled ? 'text-green' : ''} />}
|
icon={<SmallPlusIcon size={5} color={isEnabled ? 'text-green' : ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
|
|
@ -7,24 +7,23 @@ import Divider from '../../components/Common/Divider';
|
||||||
import { ArrowDownIcon, ArrowsRotateIcon, ArrowUpIcon, DumpBinIcon, SmallPlusIcon } from '../../components/Icons';
|
import { ArrowDownIcon, ArrowsRotateIcon, ArrowUpIcon, DumpBinIcon, SmallPlusIcon } from '../../components/Icons';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import { useConceptTheme } from '../../context/ThemeContext';
|
import { useConceptTheme } from '../../context/ThemeContext';
|
||||||
import { CstType, type IConstituenta, type ICstCreateData, ICstMovetoData,inferStatus, ParsingStatus, ValueClass } from '../../utils/models'
|
import { CstType, type IConstituenta, ICstMovetoData, inferStatus, ParsingStatus, ValueClass } from '../../utils/models'
|
||||||
import { createAliasFor, getCstTypePrefix, getCstTypeShortcut, getStatusInfo, getTypeLabel } from '../../utils/staticUI';
|
import { getCstTypePrefix, getCstTypeShortcut, getStatusInfo, getTypeLabel } from '../../utils/staticUI';
|
||||||
import DlgCreateCst from './DlgCreateCst';
|
|
||||||
|
|
||||||
interface EditorItemsProps {
|
interface EditorItemsProps {
|
||||||
onOpenEdit: (cst: IConstituenta) => void
|
onOpenEdit: (cst: IConstituenta) => void
|
||||||
|
onShowCreateCst: (position: number | undefined, type: CstType | undefined, skipDialog?: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditorItems({ onOpenEdit }: EditorItemsProps) {
|
function EditorItems({ onOpenEdit, onShowCreateCst }: EditorItemsProps) {
|
||||||
const {
|
const {
|
||||||
schema, isEditable,
|
schema, isEditable,
|
||||||
cstCreate, cstDelete, cstMoveTo, resetAliases
|
cstDelete, cstMoveTo, resetAliases
|
||||||
} = useRSForm();
|
} = useRSForm();
|
||||||
const { noNavigation } = useConceptTheme();
|
const { noNavigation } = useConceptTheme();
|
||||||
const [selected, setSelected] = useState<number[]>([]);
|
const [selected, setSelected] = useState<number[]>([]);
|
||||||
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
|
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
|
||||||
|
|
||||||
const [showCstModal, setShowCstModal] = useState(false);
|
|
||||||
const [toggledClearRows, setToggledClearRows] = useState(false);
|
const [toggledClearRows, setToggledClearRows] = useState(false);
|
||||||
|
|
||||||
const handleRowClicked = useCallback(
|
const handleRowClicked = useCallback(
|
||||||
|
@ -112,25 +111,18 @@ function EditorItems({ onOpenEdit }: EditorItemsProps) {
|
||||||
}, [resetAliases]);
|
}, [resetAliases]);
|
||||||
|
|
||||||
// Add new constituent
|
// Add new constituent
|
||||||
const handleAddNew = useCallback((type?: CstType) => {
|
const handleAddNew = useCallback(
|
||||||
|
(type?: CstType) => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!type) {
|
|
||||||
setShowCstModal(true);
|
|
||||||
} else {
|
|
||||||
const selectedPosition = selected.reduce((prev, cstID) => {
|
const selectedPosition = selected.reduce((prev, cstID) => {
|
||||||
const position = schema.items.findIndex(cst => cst.id === cstID);
|
const position = schema.items.findIndex(cst => cst.id === cstID);
|
||||||
return Math.max(position, prev);
|
return Math.max(position, prev);
|
||||||
}, -1) + 1;
|
}, -1) + 1;
|
||||||
const data: ICstCreateData = {
|
const insert_where = selectedPosition > 0 ? selectedPosition : undefined;
|
||||||
cst_type: type,
|
onShowCreateCst(insert_where, type, type !== undefined);
|
||||||
alias: createAliasFor(type, schema),
|
}, [schema, onShowCreateCst, selected]);
|
||||||
insert_after: selectedPosition > 0 ? selectedPosition : null
|
|
||||||
}
|
|
||||||
cstCreate(data, new_cst => toast.success(`Добавлена конституента ${new_cst.alias}`));
|
|
||||||
}
|
|
||||||
}, [schema, selected, cstCreate]);
|
|
||||||
|
|
||||||
// Implement hotkeys for working with constituents table
|
// Implement hotkeys for working with constituents table
|
||||||
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
|
function handleTableKey(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
|
@ -283,11 +275,7 @@ function EditorItems({ onOpenEdit }: EditorItemsProps) {
|
||||||
], []
|
], []
|
||||||
);
|
);
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
{showCstModal && <DlgCreateCst
|
|
||||||
hideWindow={() => { setShowCstModal(false); }}
|
|
||||||
onCreate={handleAddNew}
|
|
||||||
/>}
|
|
||||||
<div className='w-full'>
|
<div className='w-full'>
|
||||||
<div
|
<div
|
||||||
className={'flex justify-start w-full gap-1 px-2 py-1 border-y items-center h-[2.2rem] clr-app' +
|
className={'flex justify-start w-full gap-1 px-2 py-1 border-y items-center h-[2.2rem] clr-app' +
|
||||||
|
@ -376,7 +364,7 @@ function EditorItems({ onOpenEdit }: EditorItemsProps) {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EditorItems;
|
export default EditorItems;
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
import { useCallback, useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import BackendError from '../../components/BackendError';
|
import BackendError from '../../components/BackendError';
|
||||||
import ConceptTab from '../../components/Common/ConceptTab';
|
import ConceptTab from '../../components/Common/ConceptTab';
|
||||||
import { Loader } from '../../components/Common/Loader';
|
import { Loader } from '../../components/Common/Loader';
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import useLocalStorage from '../../hooks/useLocalStorage';
|
import useLocalStorage from '../../hooks/useLocalStorage';
|
||||||
import { type IConstituenta,SyntaxTree } from '../../utils/models';
|
import { CstType,type IConstituenta, ICstCreateData, SyntaxTree } from '../../utils/models';
|
||||||
|
import { createAliasFor } from '../../utils/staticUI';
|
||||||
import DlgCloneRSForm from './DlgCloneRSForm';
|
import DlgCloneRSForm from './DlgCloneRSForm';
|
||||||
|
import DlgCreateCst from './DlgCreateCst';
|
||||||
import DlgShowAST from './DlgShowAST';
|
import DlgShowAST from './DlgShowAST';
|
||||||
import DlgUploadRSForm from './DlgUploadRSForm';
|
import DlgUploadRSForm from './DlgUploadRSForm';
|
||||||
import EditorConstituenta from './EditorConstituenta';
|
import EditorConstituenta from './EditorConstituenta';
|
||||||
|
@ -23,28 +27,64 @@ export enum RSTabsList {
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSTabs() {
|
function RSTabs() {
|
||||||
const { setActiveID, activeID, error, schema, loading } = useRSForm();
|
const navigate = useNavigate();
|
||||||
const [tabIndex, setTabIndex] = useLocalStorage('rsform_edit_tab', RSTabsList.CARD);
|
const { setActiveID, activeID, error, schema, loading, cstCreate } = useRSForm();
|
||||||
|
const [activeTab, setActiveTab] = useLocalStorage('rsform_edit_tab', RSTabsList.CARD);
|
||||||
const [init, setInit] = useState(false);
|
const [init, setInit] = useState(false);
|
||||||
|
|
||||||
const [showUpload, setShowUpload] = useState(false);
|
const [showUpload, setShowUpload] = useState(false);
|
||||||
|
|
||||||
const [showClone, setShowClone] = useState(false);
|
const [showClone, setShowClone] = useState(false);
|
||||||
|
|
||||||
const [syntaxTree, setSyntaxTree] = useState<SyntaxTree>([]);
|
const [syntaxTree, setSyntaxTree] = useState<SyntaxTree>([]);
|
||||||
const [showAST, setShowAST] = useState(false);
|
const [showAST, setShowAST] = useState(false);
|
||||||
|
|
||||||
|
const [defaultType, setDefaultType] = useState<CstType | undefined>(undefined);
|
||||||
|
const [insertPosition, setInsertPosition] = useState<number | undefined>(undefined);
|
||||||
|
const [showCreateCst, setShowCreateCst] = useState(false);
|
||||||
|
|
||||||
|
const handleAddNew = useCallback(
|
||||||
|
(type: CstType) => {
|
||||||
|
if (!schema?.items) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data: ICstCreateData = {
|
||||||
|
cst_type: type,
|
||||||
|
alias: createAliasFor(type, schema),
|
||||||
|
insert_after: insertPosition ?? null
|
||||||
|
}
|
||||||
|
cstCreate(data, newCst => {
|
||||||
|
toast.success(`Конституента добавлена: ${newCst.alias}`);
|
||||||
|
if (activeTab === RSTabsList.CST_EDIT) {
|
||||||
|
navigate(`/rsforms/${schema.id}?tab=${RSTabsList.CST_EDIT}&active=${newCst.id}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [schema, cstCreate, insertPosition, navigate, activeTab]);
|
||||||
|
|
||||||
|
const onShowCreateCst = useCallback(
|
||||||
|
(position: number | undefined, type: CstType | undefined, skipDialog?: boolean) => {
|
||||||
|
if (skipDialog && type) {
|
||||||
|
handleAddNew(type);
|
||||||
|
} else {
|
||||||
|
setDefaultType(type);
|
||||||
|
setInsertPosition(position);
|
||||||
|
setShowCreateCst(true);
|
||||||
|
}
|
||||||
|
}, [handleAddNew]);
|
||||||
|
|
||||||
const onShowAST = useCallback(
|
const onShowAST = useCallback(
|
||||||
(ast: SyntaxTree) => {
|
(ast: SyntaxTree) => {
|
||||||
setSyntaxTree(ast);
|
setSyntaxTree(ast);
|
||||||
setShowAST(true);
|
setShowAST(true);
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const onEditCst = (cst: IConstituenta) => {
|
const onEditCst = (cst: IConstituenta) => {
|
||||||
setActiveID(cst.id);
|
setActiveID(cst.id);
|
||||||
setTabIndex(RSTabsList.CST_EDIT)
|
setActiveTab(RSTabsList.CST_EDIT)
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelectTab = (index: number) => {
|
const onSelectTab = (index: number) => {
|
||||||
setTabIndex(index);
|
setActiveTab(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
@ -66,17 +106,17 @@ function RSTabs() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const tabQuery = url.searchParams.get('tab');
|
const tabQuery = url.searchParams.get('tab');
|
||||||
setTabIndex(Number(tabQuery) || RSTabsList.CARD);
|
setActiveTab(Number(tabQuery) || RSTabsList.CARD);
|
||||||
}, [setTabIndex]);
|
}, [setActiveTab]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (init) {
|
if (init) {
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const currentActive = url.searchParams.get('active');
|
const currentActive = url.searchParams.get('active');
|
||||||
const currentTab = url.searchParams.get('tab');
|
const currentTab = url.searchParams.get('tab');
|
||||||
const saveHistory = tabIndex === RSTabsList.CST_EDIT && currentActive !== String(activeID);
|
const saveHistory = activeTab === RSTabsList.CST_EDIT && currentActive !== String(activeID);
|
||||||
if (currentTab !== String(tabIndex)) {
|
if (currentTab !== String(activeTab)) {
|
||||||
url.searchParams.set('tab', String(tabIndex));
|
url.searchParams.set('tab', String(activeTab));
|
||||||
}
|
}
|
||||||
if (activeID) {
|
if (activeID) {
|
||||||
if (currentActive !== String(activeID)) {
|
if (currentActive !== String(activeID)) {
|
||||||
|
@ -91,7 +131,7 @@ function RSTabs() {
|
||||||
window.history.replaceState(null, '', url.toString());
|
window.history.replaceState(null, '', url.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [tabIndex, activeID, init]);
|
}, [activeTab, activeID, init]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full'>
|
<div className='w-full'>
|
||||||
|
@ -101,9 +141,19 @@ function RSTabs() {
|
||||||
<>
|
<>
|
||||||
{showUpload && <DlgUploadRSForm hideWindow={() => { setShowUpload(false); }}/>}
|
{showUpload && <DlgUploadRSForm hideWindow={() => { setShowUpload(false); }}/>}
|
||||||
{showClone && <DlgCloneRSForm hideWindow={() => { setShowClone(false); }}/>}
|
{showClone && <DlgCloneRSForm hideWindow={() => { setShowClone(false); }}/>}
|
||||||
{showAST && <DlgShowAST syntaxTree={syntaxTree} hideWindow={() => { setShowAST(false); }}/>}
|
{showAST &&
|
||||||
|
<DlgShowAST
|
||||||
|
syntaxTree={syntaxTree}
|
||||||
|
hideWindow={() => { setShowAST(false); }}
|
||||||
|
/>}
|
||||||
|
{showCreateCst &&
|
||||||
|
<DlgCreateCst
|
||||||
|
hideWindow={() => { setShowCreateCst(false); }}
|
||||||
|
onCreate={handleAddNew}
|
||||||
|
defaultType={defaultType}
|
||||||
|
/>}
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedIndex={tabIndex}
|
selectedIndex={activeTab}
|
||||||
onSelect={onSelectTab}
|
onSelect={onSelectTab}
|
||||||
defaultFocus={true}
|
defaultFocus={true}
|
||||||
selectedTabClassName='font-bold'
|
selectedTabClassName='font-bold'
|
||||||
|
@ -127,13 +177,14 @@ function RSTabs() {
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel className='w-full'>
|
<TabPanel className='w-full'>
|
||||||
<EditorItems onOpenEdit={onEditCst} />
|
<EditorItems onOpenEdit={onEditCst} onShowCreateCst={onShowCreateCst} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<EditorConstituenta onShowAST={onShowAST} />
|
<EditorConstituenta onShowAST={onShowAST} onShowCreateCst={onShowCreateCst} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Tabs></>
|
</Tabs>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user