M: Improve node positioning in OSS
This commit is contained in:
parent
044a484607
commit
e96206b7db
|
@ -197,6 +197,7 @@ class OperationSchema:
|
|||
parent = parents.get(cst.pk)
|
||||
assert parent is not None
|
||||
Inheritance.objects.create(
|
||||
operation=operation,
|
||||
child=cst,
|
||||
parent=parent
|
||||
)
|
||||
|
|
|
@ -140,13 +140,11 @@ function PickSubstitutions({
|
|||
() => [
|
||||
columnHelper.accessor(item => item.substitution_source?.alias ?? 'N/A', {
|
||||
id: 'left_schema',
|
||||
header: 'Операция',
|
||||
size: 100,
|
||||
cell: props => <div className='min-w-[10.5rem] text-ellipsis text-right'>{props.getValue()}</div>
|
||||
cell: props => <div className='min-w-[10.5rem] text-ellipsis text-left'>{props.getValue()}</div>
|
||||
}),
|
||||
columnHelper.accessor(item => item.substitution?.alias ?? 'N/A', {
|
||||
id: 'left_alias',
|
||||
header: () => <span className='pl-3'>Имя</span>,
|
||||
size: 65,
|
||||
cell: props =>
|
||||
props.row.original.substitution ? (
|
||||
|
@ -157,13 +155,11 @@ function PickSubstitutions({
|
|||
}),
|
||||
columnHelper.display({
|
||||
id: 'status',
|
||||
header: '',
|
||||
size: 40,
|
||||
cell: () => <IconPageRight size='1.2rem' />
|
||||
}),
|
||||
columnHelper.accessor(item => item.original?.alias ?? 'N/A', {
|
||||
id: 'right_alias',
|
||||
header: () => <span className='pl-3'>Имя</span>,
|
||||
size: 65,
|
||||
cell: props =>
|
||||
props.row.original.original ? (
|
||||
|
@ -174,9 +170,8 @@ function PickSubstitutions({
|
|||
}),
|
||||
columnHelper.accessor(item => item.original_source?.alias ?? 'N/A', {
|
||||
id: 'right_schema',
|
||||
header: 'Операция',
|
||||
size: 100,
|
||||
cell: props => <div className='min-w-[8rem] text-ellipsis'>{props.getValue()}</div>
|
||||
cell: props => <div className='min-w-[8rem] text-ellipsis text-right'>{props.getValue()}</div>
|
||||
}),
|
||||
columnHelper.display({
|
||||
id: 'actions',
|
||||
|
|
|
@ -118,7 +118,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
|||
/>
|
||||
</TabPanel>
|
||||
),
|
||||
[alias, comment, title, attachedID, oss, createSchema]
|
||||
[alias, comment, title, attachedID, oss, createSchema, setAlias]
|
||||
);
|
||||
|
||||
const synthesisPanel = useMemo(
|
||||
|
@ -137,7 +137,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre
|
|||
/>
|
||||
</TabPanel>
|
||||
),
|
||||
[oss, alias, comment, title, inputs]
|
||||
[oss, alias, comment, title, inputs, setAlias]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -92,7 +92,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
|||
/>
|
||||
</TabPanel>
|
||||
),
|
||||
[alias, comment, title]
|
||||
[alias, comment, title, setAlias]
|
||||
);
|
||||
|
||||
const argumentsPanel = useMemo(
|
||||
|
@ -106,7 +106,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio
|
|||
/>
|
||||
</TabPanel>
|
||||
),
|
||||
[oss, target, inputs]
|
||||
[oss, target, inputs, setInputs]
|
||||
);
|
||||
|
||||
const synthesisPanel = useMemo(
|
||||
|
|
|
@ -46,7 +46,7 @@ function FormCreateItem() {
|
|||
|
||||
const location = useMemo(() => combineLocation(head, body), [head, body]);
|
||||
const isValid = useMemo(() => validateLocation(location), [location]);
|
||||
const [initLocation] = useLocalStorage<string>(storage.librarySearchLocation, '');
|
||||
const [initLocation, setInitLocation] = useLocalStorage<string>(storage.librarySearchLocation, '');
|
||||
|
||||
const [fileName, setFileName] = useState('');
|
||||
const [file, setFile] = useState<File | undefined>();
|
||||
|
@ -81,6 +81,7 @@ function FormCreateItem() {
|
|||
file: file,
|
||||
fileName: file?.name
|
||||
};
|
||||
setInitLocation(location);
|
||||
createItem(data, newItem => {
|
||||
toast.success(information.newLibraryItem);
|
||||
if (itemType == LibraryItemType.RSFORM) {
|
||||
|
|
|
@ -33,7 +33,7 @@ function InputNode(node: OssNodeInternal) {
|
|||
disabled={!hasFile}
|
||||
/>
|
||||
</Overlay>
|
||||
<div id={`${prefixes.operation_list}${node.id}`} className='flex-grow text-center text-sm'>
|
||||
<div id={`${prefixes.operation_list}${node.id}`} className='flex-grow text-center'>
|
||||
{node.data.label}
|
||||
{controller.showTooltip && !node.dragging ? (
|
||||
<TooltipOperation anchor={`#${prefixes.operation_list}${node.id}`} node={node} />
|
||||
|
|
|
@ -33,7 +33,7 @@ function OperationNode(node: OssNodeInternal) {
|
|||
/>
|
||||
</Overlay>
|
||||
|
||||
<div id={`${prefixes.operation_list}${node.id}`} className='flex-grow text-center text-sm'>
|
||||
<div id={`${prefixes.operation_list}${node.id}`} className='flex-grow text-center'>
|
||||
{node.data.label}
|
||||
{controller.showTooltip && !node.dragging ? (
|
||||
<TooltipOperation anchor={`#${prefixes.operation_list}${node.id}`} node={node} />
|
||||
|
|
|
@ -24,7 +24,7 @@ import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
|||
import { useOSS } from '@/context/OssContext';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
import { OssNode } from '@/models/miscellaneous';
|
||||
import { OperationID } from '@/models/oss';
|
||||
import { OperationID, OperationType } from '@/models/oss';
|
||||
import { PARAMETER, storage } from '@/utils/constants';
|
||||
import { errors } from '@/utils/labels';
|
||||
|
||||
|
@ -127,19 +127,32 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
if (!controller.schema) {
|
||||
return;
|
||||
}
|
||||
|
||||
let target = { x: 0, y: 0 };
|
||||
const positions = getPositions();
|
||||
|
||||
if (inputs.length <= 1) {
|
||||
if (positions.length == 0) {
|
||||
target = flow.project({ x: window.innerWidth / 2, y: window.innerHeight / 2 });
|
||||
}
|
||||
if (inputs.length <= 1) {
|
||||
let inputsNodes = positions.filter(pos =>
|
||||
controller.schema!.items.find(
|
||||
operation => operation.operation_type === OperationType.INPUT && operation.id === pos.id
|
||||
)
|
||||
);
|
||||
if (inputsNodes.length > 0) {
|
||||
inputsNodes = positions;
|
||||
}
|
||||
const maxX = Math.max(...inputsNodes.map(node => node.position_x));
|
||||
const minY = Math.min(...inputsNodes.map(node => node.position_y));
|
||||
target.x = maxX + 180;
|
||||
target.y = minY;
|
||||
} else {
|
||||
const inputsNodes = positions.filter(pos => inputs.includes(pos.id));
|
||||
const maxY = Math.max(...inputsNodes.map(node => node.position_y));
|
||||
const minX = Math.min(...inputsNodes.map(node => node.position_x));
|
||||
const maxX = Math.max(...inputsNodes.map(node => node.position_x));
|
||||
|
||||
target.y = maxY + 100;
|
||||
target.x = Math.ceil((maxX + minX) / 2 / PARAMETER.ossGridSize) * PARAMETER.ossGridSize;
|
||||
target.y = maxY + 100;
|
||||
}
|
||||
|
||||
let flagIntersect = false;
|
||||
|
@ -154,8 +167,13 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
target.y += PARAMETER.ossMinDistance;
|
||||
}
|
||||
} while (flagIntersect);
|
||||
|
||||
controller.promptCreateOperation(target.x, target.y, inputs, positions);
|
||||
controller.promptCreateOperation({
|
||||
x: target.x,
|
||||
y: target.y,
|
||||
inputs: inputs,
|
||||
positions: positions,
|
||||
callback: () => flow.fitView({ duration: PARAMETER.zoomDuration })
|
||||
});
|
||||
},
|
||||
[controller, getPositions, flow]
|
||||
);
|
||||
|
|
|
@ -26,8 +26,17 @@ import {
|
|||
OperationID
|
||||
} from '@/models/oss';
|
||||
import { UserID, UserLevel } from '@/models/user';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { information } from '@/utils/labels';
|
||||
|
||||
export interface ICreateOperationPrompt {
|
||||
x: number;
|
||||
y: number;
|
||||
inputs: OperationID[];
|
||||
positions: IOperationPosition[];
|
||||
callback: (newID: OperationID) => void;
|
||||
}
|
||||
|
||||
export interface IOssEditContext {
|
||||
schema?: IOperationSchema;
|
||||
selected: OperationID[];
|
||||
|
@ -51,7 +60,7 @@ export interface IOssEditContext {
|
|||
openOperationSchema: (target: OperationID) => void;
|
||||
|
||||
savePositions: (positions: IOperationPosition[], callback?: () => void) => void;
|
||||
promptCreateOperation: (x: number, y: number, inputs: OperationID[], positions: IOperationPosition[]) => void;
|
||||
promptCreateOperation: (props: ICreateOperationPrompt) => void;
|
||||
deleteOperation: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
createInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
promptEditInput: (target: OperationID, positions: IOperationPosition[]) => void;
|
||||
|
@ -97,6 +106,8 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
const [showCreateOperation, setShowCreateOperation] = useState(false);
|
||||
const [insertPosition, setInsertPosition] = useState<Position2D>({ x: 0, y: 0 });
|
||||
const [initialInputs, setInitialInputs] = useState<OperationID[]>([]);
|
||||
const [createCallback, setCreateCallback] = useState<((newID: OperationID) => void) | undefined>(undefined);
|
||||
|
||||
const [positions, setPositions] = useState<IOperationPosition[]>([]);
|
||||
const [targetOperationID, setTargetOperationID] = useState<OperationID | undefined>(undefined);
|
||||
const targetOperation = useMemo(
|
||||
|
@ -209,24 +220,27 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
[model]
|
||||
);
|
||||
|
||||
const promptCreateOperation = useCallback(
|
||||
(x: number, y: number, inputs: OperationID[], positions: IOperationPosition[]) => {
|
||||
const promptCreateOperation = useCallback(({ x, y, inputs, positions, callback }: ICreateOperationPrompt) => {
|
||||
setInsertPosition({ x: x, y: y });
|
||||
setInitialInputs(inputs);
|
||||
setPositions(positions);
|
||||
setCreateCallback(() => callback);
|
||||
setShowCreateOperation(true);
|
||||
},
|
||||
[]
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleCreateOperation = useCallback(
|
||||
(data: IOperationCreateData) => {
|
||||
data.positions = positions;
|
||||
data.item_data.position_x = insertPosition.x;
|
||||
data.item_data.position_y = insertPosition.y;
|
||||
model.createOperation(data, operation => toast.success(information.newOperation(operation.alias)));
|
||||
model.createOperation(data, operation => {
|
||||
toast.success(information.newOperation(operation.alias));
|
||||
if (createCallback) {
|
||||
setTimeout(() => createCallback(operation.id), PARAMETER.refreshTimeout);
|
||||
}
|
||||
});
|
||||
},
|
||||
[model, positions, insertPosition]
|
||||
[model, positions, insertPosition, createCallback]
|
||||
);
|
||||
|
||||
const promptEditOperation = useCallback((target: OperationID, positions: IOperationPosition[]) => {
|
||||
|
|
|
@ -145,12 +145,12 @@ function EditorRSExpression({
|
|||
const controls = useMemo(
|
||||
() => (
|
||||
<RSEditorControls
|
||||
isOpen={showControls && (!disabled || model.processing)}
|
||||
isOpen={showControls && (!disabled || (model.processing && !activeCst?.is_inherited))}
|
||||
disabled={disabled}
|
||||
onEdit={handleEdit}
|
||||
/>
|
||||
),
|
||||
[showControls, disabled, model.processing, handleEdit]
|
||||
[showControls, disabled, model.processing, handleEdit, activeCst]
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -66,6 +66,8 @@
|
|||
border: 1px solid;
|
||||
padding: 2px;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
|
||||
border-radius: 5px;
|
||||
background-color: var(--cl-bg-120);
|
||||
|
|
|
@ -17,6 +17,8 @@ export const PARAMETER = {
|
|||
ossContextMenuWidth: 200, // pixels - width of OSS context menu
|
||||
ossGridSize: 10, // pixels - size of OSS grid
|
||||
ossMinDistance: 20, // pixels - minimum distance between node centers
|
||||
ossDistanceX: 180, // pixels - insert x-distance between node centers
|
||||
ossDistanceY: 100, // pixels - insert y-distance between node centers
|
||||
|
||||
graphHoverXLimit: 0.4, // ratio to clientWidth used to determine which side of screen popup should be
|
||||
graphHoverYLimit: 0.6, // ratio to clientHeight used to determine which side of screen popup should be
|
||||
|
|
Loading…
Reference in New Issue
Block a user