From e96206b7dbee1823a86d7f99212c8ddb57d2ed47 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:17:27 +0300 Subject: [PATCH] M: Improve node positioning in OSS --- .../apps/oss/models/OperationSchema.py | 1 + .../components/select/PickSubstitutions.tsx | 9 +---- .../DlgCreateOperation/DlgCreateOperation.tsx | 4 +- .../DlgEditOperation/DlgEditOperation.tsx | 4 +- .../pages/CreateItemPage/FormCreateItem.tsx | 3 +- .../OssPage/EditorOssGraph/InputNode.tsx | 2 +- .../OssPage/EditorOssGraph/OperationNode.tsx | 2 +- .../pages/OssPage/EditorOssGraph/OssFlow.tsx | 32 ++++++++++++---- .../src/pages/OssPage/OssEditContext.tsx | 38 +++++++++++++------ .../EditorRSExpression/EditorRSExpression.tsx | 4 +- rsconcept/frontend/src/styling/overrides.css | 2 + rsconcept/frontend/src/utils/constants.ts | 2 + 12 files changed, 68 insertions(+), 35 deletions(-) diff --git a/rsconcept/backend/apps/oss/models/OperationSchema.py b/rsconcept/backend/apps/oss/models/OperationSchema.py index 71cc2e77..402d62d4 100644 --- a/rsconcept/backend/apps/oss/models/OperationSchema.py +++ b/rsconcept/backend/apps/oss/models/OperationSchema.py @@ -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 ) diff --git a/rsconcept/frontend/src/components/select/PickSubstitutions.tsx b/rsconcept/frontend/src/components/select/PickSubstitutions.tsx index 3fc50fe4..dfb35f9a 100644 --- a/rsconcept/frontend/src/components/select/PickSubstitutions.tsx +++ b/rsconcept/frontend/src/components/select/PickSubstitutions.tsx @@ -140,13 +140,11 @@ function PickSubstitutions({ () => [ columnHelper.accessor(item => item.substitution_source?.alias ?? 'N/A', { id: 'left_schema', - header: 'Операция', size: 100, - cell: props =>
{props.getValue()}
+ cell: props =>
{props.getValue()}
}), columnHelper.accessor(item => item.substitution?.alias ?? 'N/A', { id: 'left_alias', - header: () => Имя, size: 65, cell: props => props.row.original.substitution ? ( @@ -157,13 +155,11 @@ function PickSubstitutions({ }), columnHelper.display({ id: 'status', - header: '', size: 40, cell: () => }), columnHelper.accessor(item => item.original?.alias ?? 'N/A', { id: 'right_alias', - header: () => Имя, 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 =>
{props.getValue()}
+ cell: props =>
{props.getValue()}
}), columnHelper.display({ id: 'actions', diff --git a/rsconcept/frontend/src/dialogs/DlgCreateOperation/DlgCreateOperation.tsx b/rsconcept/frontend/src/dialogs/DlgCreateOperation/DlgCreateOperation.tsx index 4d6533f0..db8224d3 100644 --- a/rsconcept/frontend/src/dialogs/DlgCreateOperation/DlgCreateOperation.tsx +++ b/rsconcept/frontend/src/dialogs/DlgCreateOperation/DlgCreateOperation.tsx @@ -118,7 +118,7 @@ function DlgCreateOperation({ hideWindow, oss, onCreate, initialInputs }: DlgCre /> ), - [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 /> ), - [oss, alias, comment, title, inputs] + [oss, alias, comment, title, inputs, setAlias] ); return ( diff --git a/rsconcept/frontend/src/dialogs/DlgEditOperation/DlgEditOperation.tsx b/rsconcept/frontend/src/dialogs/DlgEditOperation/DlgEditOperation.tsx index 3ce5be3f..06fae65f 100644 --- a/rsconcept/frontend/src/dialogs/DlgEditOperation/DlgEditOperation.tsx +++ b/rsconcept/frontend/src/dialogs/DlgEditOperation/DlgEditOperation.tsx @@ -92,7 +92,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio /> ), - [alias, comment, title] + [alias, comment, title, setAlias] ); const argumentsPanel = useMemo( @@ -106,7 +106,7 @@ function DlgEditOperation({ hideWindow, oss, target, onSubmit }: DlgEditOperatio /> ), - [oss, target, inputs] + [oss, target, inputs, setInputs] ); const synthesisPanel = useMemo( diff --git a/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx b/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx index cf0bdd78..ae6fd15c 100644 --- a/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx +++ b/rsconcept/frontend/src/pages/CreateItemPage/FormCreateItem.tsx @@ -46,7 +46,7 @@ function FormCreateItem() { const location = useMemo(() => combineLocation(head, body), [head, body]); const isValid = useMemo(() => validateLocation(location), [location]); - const [initLocation] = useLocalStorage(storage.librarySearchLocation, ''); + const [initLocation, setInitLocation] = useLocalStorage(storage.librarySearchLocation, ''); const [fileName, setFileName] = useState(''); const [file, setFile] = useState(); @@ -81,6 +81,7 @@ function FormCreateItem() { file: file, fileName: file?.name }; + setInitLocation(location); createItem(data, newItem => { toast.success(information.newLibraryItem); if (itemType == LibraryItemType.RSFORM) { diff --git a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/InputNode.tsx b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/InputNode.tsx index 59c1ad26..13e76f6c 100644 --- a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/InputNode.tsx +++ b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/InputNode.tsx @@ -33,7 +33,7 @@ function InputNode(node: OssNodeInternal) { disabled={!hasFile} /> -
+
{node.data.label} {controller.showTooltip && !node.dragging ? ( diff --git a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OperationNode.tsx b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OperationNode.tsx index 18e056f9..d93cb9ec 100644 --- a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OperationNode.tsx +++ b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OperationNode.tsx @@ -33,7 +33,7 @@ function OperationNode(node: OssNodeInternal) { /> -
+
{node.data.label} {controller.showTooltip && !node.dragging ? ( diff --git a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OssFlow.tsx b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OssFlow.tsx index 6ba1c55e..1e0cc8d2 100644 --- a/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OssFlow.tsx +++ b/rsconcept/frontend/src/pages/OssPage/EditorOssGraph/OssFlow.tsx @@ -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] ); diff --git a/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx b/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx index f4a20896..dc6ebbea 100644 --- a/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx +++ b/rsconcept/frontend/src/pages/OssPage/OssEditContext.tsx @@ -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({ x: 0, y: 0 }); const [initialInputs, setInitialInputs] = useState([]); + const [createCallback, setCreateCallback] = useState<((newID: OperationID) => void) | undefined>(undefined); + const [positions, setPositions] = useState([]); const [targetOperationID, setTargetOperationID] = useState(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[]) => { - setInsertPosition({ x: x, y: y }); - setInitialInputs(inputs); - setPositions(positions); - setShowCreateOperation(true); - }, - [] - ); + 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[]) => { diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx index ee12a3db..b1d2f2a8 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx @@ -145,12 +145,12 @@ function EditorRSExpression({ const controls = useMemo( () => ( ), - [showControls, disabled, model.processing, handleEdit] + [showControls, disabled, model.processing, handleEdit, activeCst] ); return ( diff --git a/rsconcept/frontend/src/styling/overrides.css b/rsconcept/frontend/src/styling/overrides.css index 90e5f4cc..db41764b 100644 --- a/rsconcept/frontend/src/styling/overrides.css +++ b/rsconcept/frontend/src/styling/overrides.css @@ -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); diff --git a/rsconcept/frontend/src/utils/constants.ts b/rsconcept/frontend/src/utils/constants.ts index cb8efd6f..9ecb11d1 100644 --- a/rsconcept/frontend/src/utils/constants.ts +++ b/rsconcept/frontend/src/utils/constants.ts @@ -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