mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Implementing inline synthesis pt1. Frontend
This commit is contained in:
parent
56cb7236ca
commit
f8364d1a06
117
rsconcept/frontend/src/components/SchemaPicker.tsx
Normal file
117
rsconcept/frontend/src/components/SchemaPicker.tsx
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/DataTable';
|
||||||
|
import SearchBar from '@/components/ui/SearchBar';
|
||||||
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
|
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
||||||
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
|
|
||||||
|
import FlexColumn from './ui/FlexColumn';
|
||||||
|
|
||||||
|
interface SchemaPickerProps {
|
||||||
|
id?: string;
|
||||||
|
initialFilter?: string;
|
||||||
|
rows?: number;
|
||||||
|
|
||||||
|
value?: LibraryItemID;
|
||||||
|
onSelectValue: (newValue: LibraryItemID) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const columnHelper = createColumnHelper<ILibraryItem>();
|
||||||
|
|
||||||
|
function SchemaPicker({ id, initialFilter = '', rows = 4, value, onSelectValue }: SchemaPickerProps) {
|
||||||
|
const intl = useIntl();
|
||||||
|
const { colors } = useConceptTheme();
|
||||||
|
|
||||||
|
const library = useLibrary();
|
||||||
|
const [filterText, setFilterText] = useState(initialFilter);
|
||||||
|
const [filter, setFilter] = useState<ILibraryFilter>({});
|
||||||
|
const [items, setItems] = useState<ILibraryItem[]>([]);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setFilter({
|
||||||
|
query: filterText
|
||||||
|
});
|
||||||
|
}, [filterText]);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setItems(library.applyFilter(filter));
|
||||||
|
}, [library, filter, filter.query]);
|
||||||
|
|
||||||
|
const columns = useMemo(
|
||||||
|
() => [
|
||||||
|
columnHelper.accessor('alias', {
|
||||||
|
id: 'alias',
|
||||||
|
header: 'Шифр',
|
||||||
|
size: 150,
|
||||||
|
minSize: 80,
|
||||||
|
maxSize: 150
|
||||||
|
}),
|
||||||
|
columnHelper.accessor('title', {
|
||||||
|
id: 'title',
|
||||||
|
header: 'Название',
|
||||||
|
size: 1200,
|
||||||
|
minSize: 200,
|
||||||
|
maxSize: 1200,
|
||||||
|
cell: props => <div className='text-ellipsis'>{props.getValue()}</div>
|
||||||
|
}),
|
||||||
|
columnHelper.accessor('time_update', {
|
||||||
|
id: 'time_update',
|
||||||
|
header: 'Дата',
|
||||||
|
cell: props => (
|
||||||
|
<div className='whitespace-nowrap'>
|
||||||
|
{new Date(props.getValue()).toLocaleString(intl.locale, {
|
||||||
|
year: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit'
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
],
|
||||||
|
[intl]
|
||||||
|
);
|
||||||
|
|
||||||
|
const conditionalRowStyles = useMemo(
|
||||||
|
(): IConditionalStyle<ILibraryItem>[] => [
|
||||||
|
{
|
||||||
|
when: (item: ILibraryItem) => item.id === value,
|
||||||
|
style: { backgroundColor: colors.bgSelected }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[value, colors]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='border divide-y'>
|
||||||
|
<SearchBar
|
||||||
|
id={id ? `${id}__search` : undefined}
|
||||||
|
noBorder
|
||||||
|
value={filterText}
|
||||||
|
onChange={newValue => setFilterText(newValue)}
|
||||||
|
/>
|
||||||
|
<DataTable
|
||||||
|
id={id}
|
||||||
|
rows={rows}
|
||||||
|
dense
|
||||||
|
noHeader
|
||||||
|
noFooter
|
||||||
|
className='overflow-y-auto text-sm select-none'
|
||||||
|
data={items}
|
||||||
|
columns={columns}
|
||||||
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
|
noDataComponent={
|
||||||
|
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
||||||
|
<p>Список схем пуст</p>
|
||||||
|
<p>Измените параметры фильтра</p>
|
||||||
|
</FlexColumn>
|
||||||
|
}
|
||||||
|
onRowClicked={rowData => onSelectValue(rowData.id)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SchemaPicker;
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { LibraryItemID } from '@/models/library';
|
||||||
|
import { IRSForm } from '@/models/rsform';
|
||||||
|
|
||||||
|
interface ConstituentsTabProps {
|
||||||
|
schema?: IRSForm;
|
||||||
|
loading?: boolean;
|
||||||
|
selected: LibraryItemID[];
|
||||||
|
setSelected: React.Dispatch<LibraryItemID[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// { schema, loading, selected, setSelected }: ConstituentsTabProps
|
||||||
|
function ConstituentsTab(props: ConstituentsTabProps) {
|
||||||
|
return <>2 - {props.loading}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConstituentsTab;
|
|
@ -0,0 +1,101 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
|
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||||
|
import TabLabel from '@/components/ui/TabLabel';
|
||||||
|
import useRSFormDetails from '@/hooks/useRSFormDetails';
|
||||||
|
import { LibraryItemID } from '@/models/library';
|
||||||
|
import { ICstSubstituteData, IRSForm, IRSFormInlineData } from '@/models/rsform';
|
||||||
|
|
||||||
|
import ConstituentsTab from './ConstituentsTab';
|
||||||
|
import SchemaTab from './SchemaTab';
|
||||||
|
import SubstitutionsTab from './SubstitutionsTab';
|
||||||
|
|
||||||
|
interface DlgInlineSynthesisProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
receiver: IRSForm;
|
||||||
|
onInlineSynthesis: (data: IRSFormInlineData) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TabID {
|
||||||
|
SCHEMA = 0,
|
||||||
|
SELECTIONS = 1,
|
||||||
|
SUBSTITUTIONS = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInlineSynthesisProps) {
|
||||||
|
const [activeTab, setActiveTab] = useState(TabID.SCHEMA);
|
||||||
|
|
||||||
|
const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined);
|
||||||
|
const [selected, setSelected] = useState<LibraryItemID[]>([]);
|
||||||
|
const [substitutions, setSubstitutions] = useState<ICstSubstituteData[]>([]);
|
||||||
|
|
||||||
|
const source = useRSFormDetails({ target: donorID ? String(donorID) : undefined });
|
||||||
|
|
||||||
|
const validated = useMemo(() => false, []);
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
if (!source.schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data: IRSFormInlineData = {
|
||||||
|
source: source.schema?.id,
|
||||||
|
receiver: receiver.id,
|
||||||
|
items: selected,
|
||||||
|
substitutions: substitutions
|
||||||
|
};
|
||||||
|
onInlineSynthesis(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
header='Импорт концептуальной схем'
|
||||||
|
submitText='Добавить конституенты'
|
||||||
|
className='w-[35rem] h-[30rem] px-6'
|
||||||
|
hideWindow={hideWindow}
|
||||||
|
canSubmit={validated}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
>
|
||||||
|
<Tabs
|
||||||
|
forceRenderTabPanel
|
||||||
|
selectedTabClassName='clr-selected'
|
||||||
|
className='flex flex-col'
|
||||||
|
selectedIndex={activeTab}
|
||||||
|
onSelect={setActiveTab}
|
||||||
|
>
|
||||||
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||||
|
<TabLabel label='Схема' title='Выбор импортируемой схемы' className='w-[8rem]' />
|
||||||
|
<TabLabel label='Содержание' title='Выбор переносимого содержания' className='w-[8rem]' />
|
||||||
|
<TabLabel label='Отождествления' title='Отождествление добавляемый конституент' className='w-[8rem]' />
|
||||||
|
</TabList>
|
||||||
|
|
||||||
|
<TabPanel style={{ display: activeTab === TabID.SCHEMA ? '' : 'none' }}>
|
||||||
|
<SchemaTab selected={donorID} setSelected={setDonorID} />
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel style={{ display: activeTab === TabID.SELECTIONS ? '' : 'none' }}>
|
||||||
|
<ConstituentsTab
|
||||||
|
schema={source.schema}
|
||||||
|
loading={source.loading}
|
||||||
|
selected={selected}
|
||||||
|
setSelected={setSelected}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel style={{ display: activeTab === TabID.SUBSTITUTIONS ? '' : 'none' }}>
|
||||||
|
<SubstitutionsTab
|
||||||
|
receiver={receiver}
|
||||||
|
source={source.schema}
|
||||||
|
loading={source.loading}
|
||||||
|
substitutions={substitutions}
|
||||||
|
setSubstitutions={setSubstitutions}
|
||||||
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
</Tabs>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DlgInlineSynthesis;
|
|
@ -0,0 +1,36 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
import SchemaPicker from '@/components/SchemaPicker';
|
||||||
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
|
import TextInput from '@/components/ui/TextInput';
|
||||||
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
|
import { LibraryItemID } from '@/models/library';
|
||||||
|
|
||||||
|
interface SchemaTabProps {
|
||||||
|
selected?: LibraryItemID;
|
||||||
|
setSelected: React.Dispatch<LibraryItemID | undefined>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SchemaTab({ selected, setSelected }: SchemaTabProps) {
|
||||||
|
const library = useLibrary();
|
||||||
|
const selectedInfo = useMemo(() => library.items.find(item => item.id === selected), [selected, library.items]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlexColumn>
|
||||||
|
<TextInput
|
||||||
|
id='dlg_selected_schema_title'
|
||||||
|
label='Выбрана'
|
||||||
|
noBorder
|
||||||
|
placeholder='Выберите из списка ниже'
|
||||||
|
value={selectedInfo?.title}
|
||||||
|
disabled
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
<SchemaPicker rows={6} value={selected} onSelectValue={setSelected} />
|
||||||
|
</FlexColumn>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SchemaTab;
|
|
@ -0,0 +1,18 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { ICstSubstituteData, IRSForm } from '@/models/rsform';
|
||||||
|
|
||||||
|
interface SubstitutionsTabProps {
|
||||||
|
receiver?: IRSForm;
|
||||||
|
source?: IRSForm;
|
||||||
|
loading?: boolean;
|
||||||
|
substitutions: ICstSubstituteData[];
|
||||||
|
setSubstitutions: React.Dispatch<ICstSubstituteData[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// { source, receiver, loading, substitutions, setSubstitutions }: SubstitutionsTabProps
|
||||||
|
function SubstitutionsTab(props: SubstitutionsTabProps) {
|
||||||
|
return <>3 - {props.loading}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubstitutionsTab;
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from './DlgInlineSynthesis';
|
|
@ -21,14 +21,15 @@ import DlgCreateVersion from '@/dialogs/DlgCreateVersion';
|
||||||
import DlgDeleteCst from '@/dialogs/DlgDeleteCst';
|
import DlgDeleteCst from '@/dialogs/DlgDeleteCst';
|
||||||
import DlgEditVersions from '@/dialogs/DlgEditVersions';
|
import DlgEditVersions from '@/dialogs/DlgEditVersions';
|
||||||
import DlgEditWordForms from '@/dialogs/DlgEditWordForms';
|
import DlgEditWordForms from '@/dialogs/DlgEditWordForms';
|
||||||
|
import DlgInlineSynthesis from '@/dialogs/DlgInlineSynthesis';
|
||||||
import DlgRenameCst from '@/dialogs/DlgRenameCst';
|
import DlgRenameCst from '@/dialogs/DlgRenameCst';
|
||||||
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
|
import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
|
||||||
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
|
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
|
||||||
import { IVersionData } from '@/models/library';
|
import { IVersionData } from '@/models/library';
|
||||||
import { UserAccessMode } from '@/models/miscellaneous';
|
import { UserAccessMode } from '@/models/miscellaneous';
|
||||||
import {
|
import {
|
||||||
|
ConstituentaID,
|
||||||
CstType,
|
CstType,
|
||||||
EntityID,
|
|
||||||
IConstituenta,
|
IConstituenta,
|
||||||
IConstituentaMeta,
|
IConstituentaMeta,
|
||||||
ICstCreateData,
|
ICstCreateData,
|
||||||
|
@ -69,6 +70,7 @@ interface IRSEditContext {
|
||||||
download: () => void;
|
download: () => void;
|
||||||
reindex: () => void;
|
reindex: () => void;
|
||||||
produceStructure: () => void;
|
produceStructure: () => void;
|
||||||
|
inlineSynthesis: () => void;
|
||||||
substitute: () => void;
|
substitute: () => void;
|
||||||
|
|
||||||
createVersion: () => void;
|
createVersion: () => void;
|
||||||
|
@ -85,13 +87,13 @@ export const useRSEdit = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
interface RSEditStateProps {
|
interface RSEditStateProps {
|
||||||
selected: EntityID[];
|
selected: ConstituentaID[];
|
||||||
isModified: boolean;
|
isModified: boolean;
|
||||||
setSelected: React.Dispatch<React.SetStateAction<EntityID[]>>;
|
setSelected: React.Dispatch<React.SetStateAction<ConstituentaID[]>>;
|
||||||
activeCst?: IConstituenta;
|
activeCst?: IConstituenta;
|
||||||
|
|
||||||
onCreateCst?: (newCst: IConstituentaMeta) => void;
|
onCreateCst?: (newCst: IConstituentaMeta) => void;
|
||||||
onDeleteCst?: (newActive?: EntityID) => void;
|
onDeleteCst?: (newActive?: ConstituentaID) => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +129,7 @@ export const RSEditState = ({
|
||||||
const [showSubstitute, setShowSubstitute] = useState(false);
|
const [showSubstitute, setShowSubstitute] = useState(false);
|
||||||
const [showCreateVersion, setShowCreateVersion] = useState(false);
|
const [showCreateVersion, setShowCreateVersion] = useState(false);
|
||||||
const [showEditVersions, setShowEditVersions] = useState(false);
|
const [showEditVersions, setShowEditVersions] = useState(false);
|
||||||
|
const [showInlineSynthesis, setShowInlineSynthesis] = useState(false);
|
||||||
|
|
||||||
const [createInitialData, setCreateInitialData] = useState<ICstCreateData>();
|
const [createInitialData, setCreateInitialData] = useState<ICstCreateData>();
|
||||||
const [showCreateCst, setShowCreateCst] = useState(false);
|
const [showCreateCst, setShowCreateCst] = useState(false);
|
||||||
|
@ -134,7 +137,7 @@ export const RSEditState = ({
|
||||||
const [renameInitialData, setRenameInitialData] = useState<ICstRenameData>();
|
const [renameInitialData, setRenameInitialData] = useState<ICstRenameData>();
|
||||||
const [showRenameCst, setShowRenameCst] = useState(false);
|
const [showRenameCst, setShowRenameCst] = useState(false);
|
||||||
|
|
||||||
const [insertCstID, setInsertCstID] = useState<EntityID | undefined>(undefined);
|
const [insertCstID, setInsertCstID] = useState<ConstituentaID | undefined>(undefined);
|
||||||
const [showTemplates, setShowTemplates] = useState(false);
|
const [showTemplates, setShowTemplates] = useState(false);
|
||||||
|
|
||||||
useLayoutEffect(
|
useLayoutEffect(
|
||||||
|
@ -192,7 +195,7 @@ export const RSEditState = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDeleteCst = useCallback(
|
const handleDeleteCst = useCallback(
|
||||||
(deleted: EntityID[]) => {
|
(deleted: ConstituentaID[]) => {
|
||||||
if (!model.schema) {
|
if (!model.schema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -479,6 +482,7 @@ export const RSEditState = ({
|
||||||
share,
|
share,
|
||||||
toggleSubscribe,
|
toggleSubscribe,
|
||||||
reindex,
|
reindex,
|
||||||
|
inlineSynthesis: () => setShowInlineSynthesis(true),
|
||||||
produceStructure,
|
produceStructure,
|
||||||
substitute,
|
substitute,
|
||||||
|
|
||||||
|
@ -549,6 +553,13 @@ export const RSEditState = ({
|
||||||
onUpdate={handleUpdateVersion}
|
onUpdate={handleUpdateVersion}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{showInlineSynthesis ? (
|
||||||
|
<DlgInlineSynthesis
|
||||||
|
receiver={model.schema}
|
||||||
|
hideWindow={() => setShowInlineSynthesis(false)}
|
||||||
|
onInlineSynthesis={() => toast('Testing')}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
@ -586,10 +597,10 @@ function ProcessError({
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNextActiveOnDelete(
|
function getNextActiveOnDelete(
|
||||||
activeID: number | undefined,
|
activeID: ConstituentaID | undefined,
|
||||||
items: IConstituenta[],
|
items: IConstituenta[],
|
||||||
deleted: number[]
|
deleted: ConstituentaID[]
|
||||||
): number | undefined {
|
): ConstituentaID | undefined {
|
||||||
if (items.length === deleted.length) {
|
if (items.length === deleted.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BiAnalyse,
|
|
||||||
BiDiamond,
|
BiDiamond,
|
||||||
BiDownload,
|
BiDownload,
|
||||||
BiDuplicate,
|
BiDuplicate,
|
||||||
|
@ -13,7 +12,16 @@ import {
|
||||||
BiUpload
|
BiUpload
|
||||||
} from 'react-icons/bi';
|
} from 'react-icons/bi';
|
||||||
import { FiEdit } from 'react-icons/fi';
|
import { FiEdit } from 'react-icons/fi';
|
||||||
import { LuAlertTriangle, LuArchive, LuCrown, LuGlasses, LuNetwork, LuReplace } from 'react-icons/lu';
|
import {
|
||||||
|
LuAlertTriangle,
|
||||||
|
LuArchive,
|
||||||
|
LuBookCopy,
|
||||||
|
LuCrown,
|
||||||
|
LuGlasses,
|
||||||
|
LuNetwork,
|
||||||
|
LuReplace,
|
||||||
|
LuWand2
|
||||||
|
} from 'react-icons/lu';
|
||||||
import { VscLibrary } from 'react-icons/vsc';
|
import { VscLibrary } from 'react-icons/vsc';
|
||||||
|
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
|
@ -95,6 +103,11 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
|
||||||
controller.produceStructure();
|
controller.produceStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleInlineSynthesis() {
|
||||||
|
editMenu.hide();
|
||||||
|
controller.inlineSynthesis();
|
||||||
|
}
|
||||||
|
|
||||||
function handleChangeMode(newMode: UserAccessMode) {
|
function handleChangeMode(newMode: UserAccessMode) {
|
||||||
accessMenu.hide();
|
accessMenu.hide();
|
||||||
setMode(newMode);
|
setMode(newMode);
|
||||||
|
@ -201,12 +214,19 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
|
||||||
icon={<BiDiamond size='1rem' className='icon-green' />}
|
icon={<BiDiamond size='1rem' className='icon-green' />}
|
||||||
onClick={handleTemplates}
|
onClick={handleTemplates}
|
||||||
/>
|
/>
|
||||||
|
<DropdownButton
|
||||||
|
disabled={!controller.isContentEditable || !user.is_staff}
|
||||||
|
text='Применить конструкт'
|
||||||
|
title='Импортировать совокупность конституент из другой схемы'
|
||||||
|
icon={<LuBookCopy size='1rem' className='icon-green' />}
|
||||||
|
onClick={handleInlineSynthesis}
|
||||||
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
disabled={!controller.isContentEditable}
|
disabled={!controller.isContentEditable}
|
||||||
className='border-t-2'
|
className='border-t-2'
|
||||||
text='Сброс имён'
|
text='Сброс имён'
|
||||||
title='Присвоить порядковые имена и обновить выражения'
|
title='Присвоить порядковые имена и обновить выражения'
|
||||||
icon={<BiAnalyse size='1rem' className='icon-primary' />}
|
icon={<LuWand2 size='1rem' className='icon-primary' />}
|
||||||
onClick={handleReindex}
|
onClick={handleReindex}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
|
@ -220,7 +240,7 @@ function RSTabsMenu({ onDestroy }: RSTabsMenuProps) {
|
||||||
disabled={!controller.isContentEditable}
|
disabled={!controller.isContentEditable}
|
||||||
text='Отождествление'
|
text='Отождествление'
|
||||||
title='Заменить вхождения одной конституенты на другую'
|
title='Заменить вхождения одной конституенты на другую'
|
||||||
icon={<LuReplace size='1rem' className='icon-primary' />}
|
icon={<LuReplace size='1rem' className='icon-red' />}
|
||||||
onClick={handleSubstituteCst}
|
onClick={handleSubstituteCst}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user