mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Implement constituenta relocation pt1
This commit is contained in:
parent
ed30714628
commit
5700462ad5
|
@ -5,6 +5,7 @@ import { useLayoutEffect, useMemo, useState } from 'react';
|
|||
|
||||
import DataTable, { createColumnHelper, RowSelectionState } from '@/components/ui/DataTable';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { Graph } from '@/models/Graph';
|
||||
import { CstMatchMode } from '@/models/miscellaneous';
|
||||
import { ConstituentaID, IConstituenta, IRSForm } from '@/models/rsform';
|
||||
import { isBasicConcept, matchConstituenta } from '@/models/rsformAPI';
|
||||
|
@ -17,7 +18,9 @@ import ToolbarGraphSelection from './ToolbarGraphSelection';
|
|||
|
||||
interface PickMultiConstituentaProps {
|
||||
id?: string;
|
||||
schema?: IRSForm;
|
||||
schema: IRSForm;
|
||||
data: IConstituenta[];
|
||||
|
||||
prefixID: string;
|
||||
rows?: number;
|
||||
|
||||
|
@ -27,12 +30,39 @@ interface PickMultiConstituentaProps {
|
|||
|
||||
const columnHelper = createColumnHelper<IConstituenta>();
|
||||
|
||||
function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelected }: PickMultiConstituentaProps) {
|
||||
function PickMultiConstituenta({
|
||||
id,
|
||||
schema,
|
||||
data,
|
||||
prefixID,
|
||||
rows,
|
||||
selected,
|
||||
setSelected
|
||||
}: PickMultiConstituentaProps) {
|
||||
const { colors } = useConceptOptions();
|
||||
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
||||
const [filtered, setFiltered] = useState<IConstituenta[]>(schema?.items ?? []);
|
||||
const [filtered, setFiltered] = useState<IConstituenta[]>(data);
|
||||
const [filterText, setFilterText] = useState('');
|
||||
|
||||
const foldedGraph = useMemo(() => {
|
||||
if (data.length === schema.items.length) {
|
||||
return schema.graph;
|
||||
}
|
||||
const newGraph = new Graph();
|
||||
schema.graph.nodes.forEach(node => {
|
||||
newGraph.addNode(node.id);
|
||||
node.outputs.forEach(output => {
|
||||
newGraph.addEdge(node.id, output);
|
||||
});
|
||||
});
|
||||
schema.items
|
||||
.filter(item => data.find(cst => cst.id === item.id) === undefined)
|
||||
.forEach(item => {
|
||||
newGraph.foldNode(item.id);
|
||||
});
|
||||
return newGraph;
|
||||
}, [schema.graph, data]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (filtered.length === 0) {
|
||||
setRowSelection({});
|
||||
|
@ -46,17 +76,17 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
|||
}, [filtered, setRowSelection, selected]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!schema || schema.items.length === 0) {
|
||||
if (data.length === 0) {
|
||||
setFiltered([]);
|
||||
} else if (filterText) {
|
||||
setFiltered(schema.items.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL)));
|
||||
setFiltered(data.filter(cst => matchConstituenta(cst, filterText, CstMatchMode.ALL)));
|
||||
} else {
|
||||
setFiltered(schema.items);
|
||||
setFiltered(data);
|
||||
}
|
||||
}, [filterText, schema?.items, schema]);
|
||||
}, [filterText, data]);
|
||||
|
||||
function handleRowSelection(updater: React.SetStateAction<RowSelectionState>) {
|
||||
if (!schema) {
|
||||
if (!data) {
|
||||
setSelected([]);
|
||||
} else {
|
||||
const newRowSelection = typeof updater === 'function' ? updater(rowSelection) : updater;
|
||||
|
@ -91,7 +121,7 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
|||
<div>
|
||||
<div className='flex justify-between items-center clr-input px-3 border-x border-t rounded-t-md'>
|
||||
<div className='w-[24ch] select-none whitespace-nowrap'>
|
||||
Выбраны {selected.length} из {schema?.items.length ?? 0}
|
||||
Выбраны {selected.length} из {data.length}
|
||||
</div>
|
||||
<SearchBar
|
||||
id='dlg_constituents_search'
|
||||
|
@ -100,16 +130,14 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
|||
value={filterText}
|
||||
onChange={setFilterText}
|
||||
/>
|
||||
{schema ? (
|
||||
<ToolbarGraphSelection
|
||||
graph={schema.graph}
|
||||
isCore={cstID => isBasicConcept(schema.cstByID.get(cstID)?.cst_type)}
|
||||
isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited}
|
||||
setSelected={setSelected}
|
||||
emptySelection={selected.length === 0}
|
||||
className='w-fit'
|
||||
/>
|
||||
) : null}
|
||||
<ToolbarGraphSelection
|
||||
graph={foldedGraph}
|
||||
isCore={cstID => isBasicConcept(schema.cstByID.get(cstID)?.cst_type)}
|
||||
isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited}
|
||||
setSelected={setSelected}
|
||||
emptySelection={selected.length === 0}
|
||||
className='w-fit'
|
||||
/>
|
||||
</div>
|
||||
<DataTable
|
||||
id={id}
|
||||
|
|
|
@ -9,7 +9,7 @@ import TabLabel from '@/components/ui/TabLabel';
|
|||
import useRSFormDetails from '@/hooks/useRSFormDetails';
|
||||
import { LibraryItemID } from '@/models/library';
|
||||
import { ICstSubstitute } from '@/models/oss';
|
||||
import { IInlineSynthesisData, IRSForm } from '@/models/rsform';
|
||||
import { ConstituentaID, IInlineSynthesisData, IRSForm } from '@/models/rsform';
|
||||
|
||||
import TabConstituents from './TabConstituents';
|
||||
import TabSchema from './TabSchema';
|
||||
|
@ -30,7 +30,7 @@ function DlgInlineSynthesis({ hideWindow, receiver, onInlineSynthesis }: DlgInli
|
|||
const [activeTab, setActiveTab] = useState(TabID.SCHEMA);
|
||||
|
||||
const [donorID, setDonorID] = useState<LibraryItemID | undefined>(undefined);
|
||||
const [selected, setSelected] = useState<LibraryItemID[]>([]);
|
||||
const [selected, setSelected] = useState<ConstituentaID[]>([]);
|
||||
const [substitutions, setSubstitutions] = useState<ICstSubstitute[]>([]);
|
||||
|
||||
const source = useRSFormDetails({ target: donorID ? String(donorID) : undefined });
|
||||
|
|
|
@ -17,13 +17,16 @@ interface TabConstituentsProps {
|
|||
function TabConstituents({ schema, error, loading, selected, setSelected }: TabConstituentsProps) {
|
||||
return (
|
||||
<DataLoader id='dlg-constituents-tab' isLoading={loading} error={error} hasNoData={!schema}>
|
||||
<PickMultiConstituenta
|
||||
schema={schema}
|
||||
rows={13}
|
||||
prefixID={prefixes.cst_inline_synth_list}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
{schema ? (
|
||||
<PickMultiConstituenta
|
||||
schema={schema}
|
||||
data={schema.items}
|
||||
rows={13}
|
||||
prefixID={prefixes.cst_inline_synth_list}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
) : null}
|
||||
</DataLoader>
|
||||
);
|
||||
}
|
||||
|
|
96
rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx
Normal file
96
rsconcept/frontend/src/dialogs/DlgRelocateConstituents.tsx
Normal file
|
@ -0,0 +1,96 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
import PickMultiConstituenta from '@/components/select/PickMultiConstituenta';
|
||||
import SelectLibraryItem from '@/components/select/SelectLibraryItem';
|
||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||
import DataLoader from '@/components/wrap/DataLoader';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import useRSFormDetails from '@/hooks/useRSFormDetails';
|
||||
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
||||
import { ICstRelocateData, IOperation, IOperationSchema } from '@/models/oss';
|
||||
import { getRelocateCandidates } from '@/models/ossAPI';
|
||||
import { ConstituentaID } from '@/models/rsform';
|
||||
import { prefixes } from '@/utils/constants';
|
||||
|
||||
interface DlgRelocateConstituentsProps extends Pick<ModalProps, 'hideWindow'> {
|
||||
oss: IOperationSchema;
|
||||
target: IOperation;
|
||||
onSubmit: (data: ICstRelocateData) => void;
|
||||
}
|
||||
|
||||
function DlgRelocateConstituents({ oss, hideWindow, target, onSubmit }: DlgRelocateConstituentsProps) {
|
||||
const library = useLibrary();
|
||||
const schemas = useMemo(() => {
|
||||
const node = oss.graph.at(target.id)!;
|
||||
const ids: LibraryItemID[] = [
|
||||
...node.inputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null),
|
||||
...node.outputs.map(id => oss.operationByID.get(id)!.result).filter(id => id !== null)
|
||||
];
|
||||
return ids.map(id => library.items.find(item => item.id === id)).filter(item => item !== undefined);
|
||||
}, [oss, library.items]);
|
||||
|
||||
const [destination, setDestination] = useState<ILibraryItem | undefined>(undefined);
|
||||
const [selected, setSelected] = useState<ConstituentaID[]>([]);
|
||||
|
||||
const source = useRSFormDetails({ target: String(target.result!) });
|
||||
const filtered = useMemo(() => {
|
||||
if (!source.schema || !destination) {
|
||||
return [];
|
||||
}
|
||||
const destinationOperation = oss.items.find(item => item.result === destination.id);
|
||||
return getRelocateCandidates(target.id, destinationOperation!.id, source.schema, oss);
|
||||
}, [destination, source.schema?.items]);
|
||||
|
||||
const isValid = useMemo(() => !!destination && selected.length > 0, [destination, selected]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setSelected([]);
|
||||
}, [destination]);
|
||||
|
||||
const handleSelectDestination = useCallback((newValue: ILibraryItem | undefined) => {
|
||||
setDestination(newValue);
|
||||
}, []);
|
||||
|
||||
const handleSubmit = useCallback(() => {
|
||||
const data: ICstRelocateData = {
|
||||
destination: target.result ?? 0,
|
||||
items: []
|
||||
};
|
||||
onSubmit(data);
|
||||
}, [target, onSubmit]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
header='Перемещение конституент'
|
||||
submitText='Переместить'
|
||||
hideWindow={hideWindow}
|
||||
canSubmit={isValid}
|
||||
onSubmit={handleSubmit}
|
||||
className={clsx('w-[40rem] h-[33rem]', 'py-3 px-6')}
|
||||
>
|
||||
<DataLoader id='dlg-relocate-constituents' className='cc-column' isLoading={source.loading} error={source.error}>
|
||||
<SelectLibraryItem
|
||||
placeholder='Выберите целевую схему'
|
||||
items={schemas}
|
||||
value={destination}
|
||||
onSelectValue={handleSelectDestination}
|
||||
/>
|
||||
{source.schema ? (
|
||||
<PickMultiConstituenta
|
||||
schema={source.schema}
|
||||
data={filtered}
|
||||
rows={12}
|
||||
prefixID={prefixes.dlg_cst_constituents_list}
|
||||
selected={selected}
|
||||
setSelected={setSelected}
|
||||
/>
|
||||
) : null}
|
||||
</DataLoader>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default DlgRelocateConstituents;
|
|
@ -86,30 +86,25 @@ export class Graph {
|
|||
return !!this.nodes.get(target);
|
||||
}
|
||||
|
||||
removeNode(target: number): GraphNode | null {
|
||||
const nodeToRemove = this.nodes.get(target);
|
||||
if (!nodeToRemove) {
|
||||
return null;
|
||||
}
|
||||
removeNode(target: number): void {
|
||||
this.nodes.forEach(node => {
|
||||
node.removeInput(nodeToRemove.id);
|
||||
node.removeOutput(nodeToRemove.id);
|
||||
node.removeInput(target);
|
||||
node.removeOutput(target);
|
||||
});
|
||||
this.nodes.delete(target);
|
||||
return nodeToRemove;
|
||||
}
|
||||
|
||||
foldNode(target: number): GraphNode | null {
|
||||
foldNode(target: number): void {
|
||||
const nodeToRemove = this.nodes.get(target);
|
||||
if (!nodeToRemove) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
nodeToRemove.inputs.forEach(input => {
|
||||
nodeToRemove.outputs.forEach(output => {
|
||||
this.addEdge(input, output);
|
||||
});
|
||||
});
|
||||
return this.removeNode(target);
|
||||
this.removeNode(target);
|
||||
}
|
||||
|
||||
removeIsolated(): GraphNode[] {
|
||||
|
@ -124,6 +119,9 @@ export class Graph {
|
|||
}
|
||||
|
||||
addEdge(source: number, destination: number): void {
|
||||
if (this.hasEdge(source, destination)) {
|
||||
return;
|
||||
}
|
||||
const sourceNode = this.addNode(source);
|
||||
const destinationNode = this.addNode(destination);
|
||||
sourceNode.addOutput(destinationNode.id);
|
||||
|
|
|
@ -125,6 +125,14 @@ export interface ICstSubstituteData {
|
|||
substitutions: ICstSubstitute[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents data, used relocating {@link IConstituenta}s between {@link ILibraryItem}s.
|
||||
*/
|
||||
export interface ICstRelocateData {
|
||||
destination: LibraryItemID;
|
||||
items: ConstituentaID[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents substitution for multi synthesis table.
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@ import { TextMatcher } from '@/utils/utils';
|
|||
|
||||
import { Graph } from './Graph';
|
||||
import { ILibraryItem, LibraryItemID } from './library';
|
||||
import { ICstSubstitute, IOperation, IOperationSchema, SubstitutionErrorType } from './oss';
|
||||
import { ICstSubstitute, IOperation, IOperationSchema, OperationID, SubstitutionErrorType } from './oss';
|
||||
import { ConstituentaID, CstClass, CstType, IConstituenta, IRSForm } from './rsform';
|
||||
import { AliasMapping, ParsingStatus } from './rslang';
|
||||
import { applyAliasMapping, applyTypificationMapping, extractGlobals, isSetTypification } from './rslangAPI';
|
||||
|
@ -424,3 +424,45 @@ export class SubstitutionValidator {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter relocate candidates from gives schema.
|
||||
*/
|
||||
export function getRelocateCandidates(
|
||||
source: OperationID,
|
||||
destination: OperationID,
|
||||
schema: IRSForm,
|
||||
oss: IOperationSchema
|
||||
): IConstituenta[] {
|
||||
const destinationSchema = oss.operationByID.get(destination)?.result;
|
||||
if (!destinationSchema) {
|
||||
return [];
|
||||
}
|
||||
const node = oss.graph.at(source);
|
||||
if (!node) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const addedCst = schema.items.filter(item => !item.is_inherited);
|
||||
if (node.outputs.includes(destination)) {
|
||||
return addedCst;
|
||||
}
|
||||
|
||||
const unreachableBases: ConstituentaID[] = [];
|
||||
for (const cst of schema.items.filter(item => item.is_inherited)) {
|
||||
if (cst.parent_schema == destinationSchema) {
|
||||
continue;
|
||||
}
|
||||
const parent = schema.inheritance.find(item => item.child === cst.id && item.child_source === cst.schema)?.parent;
|
||||
if (parent) {
|
||||
const original = oss.substitutions.find(sub => sub.substitution === parent)?.original;
|
||||
if (original) {
|
||||
continue;
|
||||
// TODO: test if original schema is destination schema
|
||||
}
|
||||
}
|
||||
unreachableBases.push(cst.id);
|
||||
}
|
||||
const unreachable = schema.graph.expandAllOutputs(unreachableBases);
|
||||
return addedCst.filter(cst => !unreachable.includes(cst.id));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,15 @@
|
|||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { IconConnect, IconDestroy, IconEdit2, IconExecute, IconNewRSForm, IconRSForm } from '@/components/Icons';
|
||||
import {
|
||||
IconChild,
|
||||
IconConnect,
|
||||
IconDestroy,
|
||||
IconEdit2,
|
||||
IconExecute,
|
||||
IconNewRSForm,
|
||||
IconRSForm
|
||||
} from '@/components/Icons';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import useClickedOutside from '@/hooks/useClickedOutside';
|
||||
|
@ -25,6 +33,7 @@ interface NodeContextMenuProps extends ContextMenuData {
|
|||
onEditSchema: (target: OperationID) => void;
|
||||
onEditOperation: (target: OperationID) => void;
|
||||
onExecuteOperation: (target: OperationID) => void;
|
||||
onRelocateConstituents: (target: OperationID) => void;
|
||||
}
|
||||
|
||||
function NodeContextMenu({
|
||||
|
@ -36,7 +45,8 @@ function NodeContextMenu({
|
|||
onCreateInput,
|
||||
onEditSchema,
|
||||
onEditOperation,
|
||||
onExecuteOperation
|
||||
onExecuteOperation,
|
||||
onRelocateConstituents
|
||||
}: NodeContextMenuProps) {
|
||||
const controller = useOssEdit();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
@ -100,6 +110,11 @@ function NodeContextMenu({
|
|||
onExecuteOperation(operation.id);
|
||||
};
|
||||
|
||||
const handleRelocateConstituents = () => {
|
||||
handleHide();
|
||||
onRelocateConstituents(operation.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={ref} className='absolute select-none' style={{ top: cursorY, left: cursorX }}>
|
||||
<Dropdown
|
||||
|
@ -156,6 +171,16 @@ function NodeContextMenu({
|
|||
/>
|
||||
) : null}
|
||||
|
||||
{controller.isMutable && operation.result ? (
|
||||
<DropdownButton
|
||||
text='Конституенты'
|
||||
titleHtml='Перемещение конституент</br>между схемами'
|
||||
icon={<IconChild size='1rem' className='icon-green' />}
|
||||
disabled={controller.isProcessing}
|
||||
onClick={handleRelocateConstituents}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<DropdownButton
|
||||
text='Удалить операцию'
|
||||
icon={<IconDestroy size='1rem' className='icon-red' />}
|
||||
|
|
|
@ -197,6 +197,13 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
handleExecuteOperation(controller.selected[0]);
|
||||
}, [controller, handleExecuteOperation]);
|
||||
|
||||
const handleRelocateConstituents = useCallback(
|
||||
(target: OperationID) => {
|
||||
controller.promptRelocateConstituents(target);
|
||||
},
|
||||
[controller]
|
||||
);
|
||||
|
||||
const handleFitView = useCallback(() => {
|
||||
flow.fitView({ duration: PARAMETER.zoomDuration });
|
||||
}, [flow]);
|
||||
|
@ -376,6 +383,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
onEditSchema={handleEditSchema}
|
||||
onEditOperation={handleEditOperation}
|
||||
onExecuteOperation={handleExecuteOperation}
|
||||
onRelocateConstituents={handleRelocateConstituents}
|
||||
{...menuProps}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -17,10 +17,12 @@ 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 { Position2D } from '@/models/miscellaneous';
|
||||
import { calculateInsertPosition } from '@/models/miscellaneousAPI';
|
||||
import {
|
||||
ICstRelocateData,
|
||||
IOperationCreateData,
|
||||
IOperationDeleteData,
|
||||
IOperationPosition,
|
||||
|
@ -74,6 +76,7 @@ export interface IOssEditContext extends ILibraryItemEditor {
|
|||
promptEditInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptEditOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
executeOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptRelocateConstituents: (target: OperationID) => void;
|
||||
}
|
||||
|
||||
const OssEditContext = createContext<IOssEditContext | null>(null);
|
||||
|
@ -110,6 +113,7 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
|||
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 });
|
||||
|
@ -359,6 +363,23 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
|||
[model]
|
||||
);
|
||||
|
||||
const promptRelocateConstituents = useCallback(
|
||||
(target: OperationID) => {
|
||||
setTargetOperationID(target);
|
||||
setShowRelocateConstituents(true);
|
||||
},
|
||||
[model]
|
||||
);
|
||||
|
||||
const handleRelocateConstituents = useCallback(
|
||||
(data: ICstRelocateData) => {
|
||||
// TODO: implement backed call
|
||||
console.log(data);
|
||||
toast.success('В разработке');
|
||||
},
|
||||
[model]
|
||||
);
|
||||
|
||||
return (
|
||||
<OssEditContext.Provider
|
||||
value={{
|
||||
|
@ -388,7 +409,8 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
|||
createInput,
|
||||
promptEditInput,
|
||||
promptEditOperation,
|
||||
executeOperation
|
||||
executeOperation,
|
||||
promptRelocateConstituents
|
||||
}}
|
||||
>
|
||||
{model.schema ? (
|
||||
|
@ -438,6 +460,15 @@ export const OssEditState = ({ selected, setSelected, children }: React.PropsWit
|
|||
onSubmit={deleteOperation}
|
||||
/>
|
||||
) : null}
|
||||
{showRelocateConstituents ? (
|
||||
<DlgRelocateConstituents
|
||||
hideWindow={() => setShowRelocateConstituents(false)}
|
||||
target={targetOperation!}
|
||||
oss={model.schema}
|
||||
onSubmit={handleRelocateConstituents}
|
||||
/>
|
||||
) : null}
|
||||
)
|
||||
</AnimatePresence>
|
||||
) : null}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ function ConstituentsSearch({ schema, activeID, activeExpression, dense, setFilt
|
|||
);
|
||||
|
||||
return (
|
||||
<div className='flex border-b clr-input'>
|
||||
<div className='flex border-b clr-input rounded-t-md'>
|
||||
<SearchBar
|
||||
id='constituents_search'
|
||||
noBorder
|
||||
|
|
|
@ -182,5 +182,6 @@ export const prefixes = {
|
|||
user_editors: 'user_editors_',
|
||||
wordform_list: 'wordform_list_',
|
||||
rsedit_btn: 'rsedit_btn_',
|
||||
dlg_cst_substitutes_list: 'dlg_cst_substitutes_list_'
|
||||
dlg_cst_substitutes_list: 'dlg_cst_substitutes_list_',
|
||||
dlg_cst_constituents_list: 'dlg_cst_constituents_list_'
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user