R: Restructuring layout data pt2
This commit is contained in:
parent
3271d9244c
commit
5efce874b2
|
@ -172,7 +172,7 @@ class SetOperationInputSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class OperationSchemaSerializer(serializers.ModelSerializer):
|
class OperationSchemaSerializer(serializers.ModelSerializer):
|
||||||
''' Serializer: Detailed data for OSS. '''
|
''' Serializer: Detailed data for OSS. '''
|
||||||
items = serializers.ListField(
|
operations = serializers.ListField(
|
||||||
child=OperationSerializer()
|
child=OperationSerializer()
|
||||||
)
|
)
|
||||||
arguments = serializers.ListField(
|
arguments = serializers.ListField(
|
||||||
|
@ -193,9 +193,9 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
|
||||||
del result['versions']
|
del result['versions']
|
||||||
oss = OperationSchema(instance)
|
oss = OperationSchema(instance)
|
||||||
result['layout'] = oss.layout().data
|
result['layout'] = oss.layout().data
|
||||||
result['items'] = []
|
result['operations'] = []
|
||||||
for operation in oss.operations().order_by('pk'):
|
for operation in oss.operations().order_by('pk'):
|
||||||
result['items'].append(OperationSerializer(operation).data)
|
result['operations'].append(OperationSerializer(operation).data)
|
||||||
result['arguments'] = []
|
result['arguments'] = []
|
||||||
for argument in oss.arguments().order_by('order'):
|
for argument in oss.arguments().order_by('order'):
|
||||||
result['arguments'].append(ArgumentSerializer(argument).data)
|
result['arguments'].append(ArgumentSerializer(argument).data)
|
||||||
|
|
|
@ -98,7 +98,7 @@ class TestOssOperations(EndpointTester):
|
||||||
self.executeNotFound(data=data, item=self.invalid_id)
|
self.executeNotFound(data=data, item=self.invalid_id)
|
||||||
|
|
||||||
response = self.executeCreated(data=data, item=self.owned_id)
|
response = self.executeCreated(data=data, item=self.owned_id)
|
||||||
self.assertEqual(len(response.data['oss']['items']), 4)
|
self.assertEqual(len(response.data['oss']['operations']), 4)
|
||||||
new_operation = response.data['new_operation']
|
new_operation = response.data['new_operation']
|
||||||
layout = response.data['oss']['layout']
|
layout = response.data['oss']['layout']
|
||||||
item = [item for item in layout['operations'] if item['id'] == new_operation['id']][0]
|
item = [item for item in layout['operations'] if item['id'] == new_operation['id']][0]
|
||||||
|
@ -210,9 +210,9 @@ class TestOssOperations(EndpointTester):
|
||||||
self.login()
|
self.login()
|
||||||
response = self.executeOK(data=data)
|
response = self.executeOK(data=data)
|
||||||
layout = response.data['layout']
|
layout = response.data['layout']
|
||||||
items = [item for item in layout['operations'] if item['id'] == data['target']]
|
deleted_items = [item for item in layout['operations'] if item['id'] == data['target']]
|
||||||
self.assertEqual(len(response.data['items']), 2)
|
self.assertEqual(len(response.data['operations']), 2)
|
||||||
self.assertEqual(len(items), 0)
|
self.assertEqual(len(deleted_items), 0)
|
||||||
|
|
||||||
@decl_endpoint('/api/oss/{item}/create-input', method='patch')
|
@decl_endpoint('/api/oss/{item}/create-input', method='patch')
|
||||||
def test_create_input(self):
|
def test_create_input(self):
|
||||||
|
|
|
@ -82,9 +82,9 @@ class TestOssViewset(EndpointTester):
|
||||||
|
|
||||||
self.assertEqual(response.data['item_type'], LibraryItemType.OPERATION_SCHEMA)
|
self.assertEqual(response.data['item_type'], LibraryItemType.OPERATION_SCHEMA)
|
||||||
|
|
||||||
self.assertEqual(len(response.data['items']), 3)
|
self.assertEqual(len(response.data['operations']), 3)
|
||||||
self.assertEqual(response.data['items'][0]['id'], self.operation1.pk)
|
self.assertEqual(response.data['operations'][0]['id'], self.operation1.pk)
|
||||||
self.assertEqual(response.data['items'][0]['operation_type'], self.operation1.operation_type)
|
self.assertEqual(response.data['operations'][0]['operation_type'], self.operation1.operation_type)
|
||||||
|
|
||||||
self.assertEqual(len(response.data['substitutions']), 1)
|
self.assertEqual(len(response.data['substitutions']), 1)
|
||||||
sub = response.data['substitutions'][0]
|
sub = response.data['substitutions'][0]
|
||||||
|
@ -125,11 +125,13 @@ class TestOssViewset(EndpointTester):
|
||||||
data = {'operations': [], 'blocks': []}
|
data = {'operations': [], 'blocks': []}
|
||||||
self.executeOK(data=data)
|
self.executeOK(data=data)
|
||||||
|
|
||||||
data = {'operations': [
|
data = {
|
||||||
{'id': self.operation1.pk, 'x': 42.1, 'y': 1337},
|
'operations': [
|
||||||
{'id': self.operation2.pk, 'x': 36.1, 'y': 1437},
|
{'id': self.operation1.pk, 'x': 42.1, 'y': 1337},
|
||||||
{'id': self.operation3.pk, 'x': 36.1, 'y': 1435}
|
{'id': self.operation2.pk, 'x': 36.1, 'y': 1437},
|
||||||
], 'blocks': []}
|
{'id': self.operation3.pk, 'x': 36.1, 'y': 1435}
|
||||||
|
], 'blocks': []
|
||||||
|
}
|
||||||
self.toggle_admin(True)
|
self.toggle_admin(True)
|
||||||
self.executeOK(data=data, item=self.unowned_id)
|
self.executeOK(data=data, item=self.unowned_id)
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const useSetAccessPolicy = () => {
|
||||||
client.setQueryData(ossKey, { ...ossData, access_policy: variables.policy });
|
client.setQueryData(ossKey, { ...ossData, access_policy: variables.policy });
|
||||||
return Promise.allSettled([
|
return Promise.allSettled([
|
||||||
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
|
client.invalidateQueries({ queryKey: KEYS.composite.libraryList }),
|
||||||
...ossData.items
|
...ossData.operations
|
||||||
.map(item => {
|
.map(item => {
|
||||||
if (!item.result) {
|
if (!item.result) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const useSetEditors = () => {
|
||||||
if (ossData) {
|
if (ossData) {
|
||||||
client.setQueryData(ossKey, { ...ossData, editors: variables.editors });
|
client.setQueryData(ossKey, { ...ossData, editors: variables.editors });
|
||||||
return Promise.allSettled(
|
return Promise.allSettled(
|
||||||
ossData.items
|
ossData.operations
|
||||||
.map(item => {
|
.map(item => {
|
||||||
if (!item.result) {
|
if (!item.result) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const useSetLocation = () => {
|
||||||
client.setQueryData(ossKey, { ...ossData, location: variables.location });
|
client.setQueryData(ossKey, { ...ossData, location: variables.location });
|
||||||
return Promise.allSettled([
|
return Promise.allSettled([
|
||||||
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }),
|
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }),
|
||||||
...ossData.items
|
...ossData.operations
|
||||||
.map(item => {
|
.map(item => {
|
||||||
if (!item.result) {
|
if (!item.result) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const useSetOwner = () => {
|
||||||
client.setQueryData(ossKey, { ...ossData, owner: variables.owner });
|
client.setQueryData(ossKey, { ...ossData, owner: variables.owner });
|
||||||
return Promise.allSettled([
|
return Promise.allSettled([
|
||||||
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }),
|
client.invalidateQueries({ queryKey: libraryApi.libraryListKey }),
|
||||||
...ossData.items
|
...ossData.operations
|
||||||
.map(item => {
|
.map(item => {
|
||||||
if (!item.result) {
|
if (!item.result) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -12,9 +12,9 @@ import {
|
||||||
type IOperationCreatedResponse,
|
type IOperationCreatedResponse,
|
||||||
type IOperationCreateDTO,
|
type IOperationCreateDTO,
|
||||||
type IOperationDeleteDTO,
|
type IOperationDeleteDTO,
|
||||||
type IOperationPosition,
|
|
||||||
type IOperationSchemaDTO,
|
type IOperationSchemaDTO,
|
||||||
type IOperationUpdateDTO,
|
type IOperationUpdateDTO,
|
||||||
|
type IOssLayout,
|
||||||
type ITargetOperation,
|
type ITargetOperation,
|
||||||
schemaConstituentaReference,
|
schemaConstituentaReference,
|
||||||
schemaOperationCreatedResponse,
|
schemaOperationCreatedResponse,
|
||||||
|
@ -39,19 +39,11 @@ export const ossApi = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateLayout: ({
|
updateLayout: ({ itemID, data, isSilent }: { itemID: number; data: IOssLayout; isSilent?: boolean }) =>
|
||||||
itemID,
|
|
||||||
positions,
|
|
||||||
isSilent
|
|
||||||
}: {
|
|
||||||
itemID: number;
|
|
||||||
positions: IOperationPosition[];
|
|
||||||
isSilent?: boolean;
|
|
||||||
}) =>
|
|
||||||
axiosPatch({
|
axiosPatch({
|
||||||
endpoint: `/api/oss/${itemID}/update-layout`,
|
endpoint: `/api/oss/${itemID}/update-layout`,
|
||||||
request: {
|
request: {
|
||||||
data: { positions: positions },
|
data: data,
|
||||||
successMessage: isSilent ? undefined : infoMsg.changesSaved
|
successMessage: isSilent ? undefined : infoMsg.changesSaved
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class OssLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private prepareLookups() {
|
private prepareLookups() {
|
||||||
this.oss.items.forEach(operation => {
|
this.oss.operations.forEach(operation => {
|
||||||
this.operationByID.set(operation.id, operation);
|
this.operationByID.set(operation.id, operation);
|
||||||
this.graph.addNode(operation.id);
|
this.graph.addNode(operation.id);
|
||||||
});
|
});
|
||||||
|
@ -52,13 +52,16 @@ export class OssLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extractSchemas() {
|
private extractSchemas() {
|
||||||
this.schemaIDs = this.oss.items.map(operation => operation.result).filter(item => item !== null);
|
this.schemaIDs = this.oss.operations.map(operation => operation.result).filter(item => item !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private inferOperationAttributes() {
|
private inferOperationAttributes() {
|
||||||
this.graph.topologicalOrder().forEach(operationID => {
|
this.graph.topologicalOrder().forEach(operationID => {
|
||||||
const operation = this.operationByID.get(operationID)!;
|
const operation = this.operationByID.get(operationID)!;
|
||||||
const schema = this.items.find(item => item.id === operation.result);
|
const schema = this.items.find(item => item.id === operation.result);
|
||||||
|
const position = this.oss.layout.operations.find(item => item.id === operationID);
|
||||||
|
operation.x = position?.x ?? 0;
|
||||||
|
operation.y = position?.y ?? 0;
|
||||||
operation.is_consolidation = this.inferConsolidation(operationID);
|
operation.is_consolidation = this.inferConsolidation(operationID);
|
||||||
operation.is_owned = !schema || (schema.owner === this.oss.owner && schema.location === this.oss.location);
|
operation.is_owned = !schema || (schema.owner === this.oss.owner && schema.location === this.oss.location);
|
||||||
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
|
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
|
||||||
|
@ -82,7 +85,7 @@ export class OssLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateStats(): IOperationSchemaStats {
|
private calculateStats(): IOperationSchemaStats {
|
||||||
const items = this.oss.items;
|
const items = this.oss.operations;
|
||||||
return {
|
return {
|
||||||
count_operations: items.length,
|
count_operations: items.length,
|
||||||
count_inputs: items.filter(item => item.operation_type === OperationType.INPUT).length,
|
count_inputs: items.filter(item => item.operation_type === OperationType.INPUT).length,
|
||||||
|
|
|
@ -23,8 +23,8 @@ export type IOperationDTO = z.infer<typeof schemaOperation>;
|
||||||
/** Represents backend data for {@link IOperationSchema}. */
|
/** Represents backend data for {@link IOperationSchema}. */
|
||||||
export type IOperationSchemaDTO = z.infer<typeof schemaOperationSchema>;
|
export type IOperationSchemaDTO = z.infer<typeof schemaOperationSchema>;
|
||||||
|
|
||||||
/** Represents {@link IOperation} position. */
|
/** Represents {@link schemaOperation} layout. */
|
||||||
export type IOperationPosition = z.infer<typeof schemaOperationPosition>;
|
export type IOssLayout = z.infer<typeof schemaOssLayout>;
|
||||||
|
|
||||||
/** Represents {@link IOperation} data, used in creation process. */
|
/** Represents {@link IOperation} data, used in creation process. */
|
||||||
export type IOperationCreateDTO = z.infer<typeof schemaOperationCreate>;
|
export type IOperationCreateDTO = z.infer<typeof schemaOperationCreate>;
|
||||||
|
@ -35,7 +35,7 @@ export type IOperationCreatedResponse = z.infer<typeof schemaOperationCreatedRes
|
||||||
* Represents target {@link IOperation}.
|
* Represents target {@link IOperation}.
|
||||||
*/
|
*/
|
||||||
export interface ITargetOperation {
|
export interface ITargetOperation {
|
||||||
positions: IOperationPosition[];
|
layout: IOssLayout;
|
||||||
target: number;
|
target: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,9 +69,7 @@ export const schemaOperation = z.strictObject({
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
|
|
||||||
position_x: z.number(),
|
parent: z.number().nullable(),
|
||||||
position_y: z.number(),
|
|
||||||
|
|
||||||
result: z.number().nullable()
|
result: z.number().nullable()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -83,9 +81,21 @@ export const schemaCstSubstituteInfo = schemaCstSubstitute.extend({
|
||||||
substitution_term: z.string()
|
substitution_term: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const schemaPosition = z.strictObject({
|
||||||
|
id: z.number(),
|
||||||
|
x: z.number(),
|
||||||
|
y: z.number()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const schemaOssLayout = z.strictObject({
|
||||||
|
operations: z.array(schemaPosition),
|
||||||
|
blocks: z.array(schemaPosition)
|
||||||
|
});
|
||||||
|
|
||||||
export const schemaOperationSchema = schemaLibraryItem.extend({
|
export const schemaOperationSchema = schemaLibraryItem.extend({
|
||||||
editors: z.number().array(),
|
editors: z.number().array(),
|
||||||
items: z.array(schemaOperation),
|
operations: z.array(schemaOperation),
|
||||||
|
layout: schemaOssLayout,
|
||||||
arguments: z
|
arguments: z
|
||||||
.object({
|
.object({
|
||||||
operation: z.number(),
|
operation: z.number(),
|
||||||
|
@ -95,23 +105,18 @@ export const schemaOperationSchema = schemaLibraryItem.extend({
|
||||||
substitutions: z.array(schemaCstSubstituteInfo)
|
substitutions: z.array(schemaCstSubstituteInfo)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaOperationPosition = z.strictObject({
|
|
||||||
id: z.number(),
|
|
||||||
position_x: z.number(),
|
|
||||||
position_y: z.number()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const schemaOperationCreate = z.strictObject({
|
export const schemaOperationCreate = z.strictObject({
|
||||||
positions: z.array(schemaOperationPosition),
|
layout: schemaOssLayout,
|
||||||
item_data: z.strictObject({
|
item_data: z.strictObject({
|
||||||
alias: z.string().nonempty(),
|
alias: z.string().nonempty(),
|
||||||
operation_type: schemaOperationType,
|
operation_type: schemaOperationType,
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
position_x: z.number(),
|
parent: z.number().nullable(),
|
||||||
position_y: z.number(),
|
|
||||||
result: z.number().nullable()
|
result: z.number().nullable()
|
||||||
}),
|
}),
|
||||||
|
position_x: z.number(),
|
||||||
|
position_y: z.number(),
|
||||||
arguments: z.array(z.number()),
|
arguments: z.array(z.number()),
|
||||||
create_schema: z.boolean()
|
create_schema: z.boolean()
|
||||||
});
|
});
|
||||||
|
@ -123,14 +128,14 @@ export const schemaOperationCreatedResponse = z.strictObject({
|
||||||
|
|
||||||
export const schemaOperationDelete = z.strictObject({
|
export const schemaOperationDelete = z.strictObject({
|
||||||
target: z.number(),
|
target: z.number(),
|
||||||
positions: z.array(schemaOperationPosition),
|
layout: schemaOssLayout,
|
||||||
keep_constituents: z.boolean(),
|
keep_constituents: z.boolean(),
|
||||||
delete_schema: z.boolean()
|
delete_schema: z.boolean()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const schemaInputUpdate = z.strictObject({
|
export const schemaInputUpdate = z.strictObject({
|
||||||
target: z.number(),
|
target: z.number(),
|
||||||
positions: z.array(schemaOperationPosition),
|
layout: schemaOssLayout,
|
||||||
input: z.number().nullable()
|
input: z.number().nullable()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,7 +146,7 @@ export const schemaInputCreatedResponse = z.strictObject({
|
||||||
|
|
||||||
export const schemaOperationUpdate = z.strictObject({
|
export const schemaOperationUpdate = z.strictObject({
|
||||||
target: z.number(),
|
target: z.number(),
|
||||||
positions: z.array(schemaOperationPosition),
|
layout: schemaOssLayout,
|
||||||
item_data: z.strictObject({
|
item_data: z.strictObject({
|
||||||
alias: z.string().nonempty(errorMsg.requiredField),
|
alias: z.string().nonempty(errorMsg.requiredField),
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const useOperationUpdate = () => {
|
||||||
mutationFn: ossApi.operationUpdate,
|
mutationFn: ossApi.operationUpdate,
|
||||||
onSuccess: (data, variables) => {
|
onSuccess: (data, variables) => {
|
||||||
client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data);
|
client.setQueryData(KEYS.composite.ossItem({ itemID: data.id }), data);
|
||||||
const schemaID = data.items.find(item => item.id === variables.data.target)?.result;
|
const schemaID = data.operations.find(item => item.id === variables.data.target)?.result;
|
||||||
if (!schemaID) {
|
if (!schemaID) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useUpdateTimestamp } from '@/features/library/backend/use-update-timest
|
||||||
import { KEYS } from '@/backend/configuration';
|
import { KEYS } from '@/backend/configuration';
|
||||||
|
|
||||||
import { ossApi } from './api';
|
import { ossApi } from './api';
|
||||||
import { type IOperationPosition } from './types';
|
import { type IOperationSchemaDTO, type IOssLayout } from './types';
|
||||||
|
|
||||||
export const useUpdateLayout = () => {
|
export const useUpdateLayout = () => {
|
||||||
const client = useQueryClient();
|
const client = useQueryClient();
|
||||||
|
@ -13,13 +13,25 @@ export const useUpdateLayout = () => {
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-layout'],
|
mutationKey: [KEYS.global_mutation, ossApi.baseKey, 'update-layout'],
|
||||||
mutationFn: ossApi.updateLayout,
|
mutationFn: ossApi.updateLayout,
|
||||||
onSuccess: (_, variables) => updateTimestamp(variables.itemID),
|
onSuccess: (_, variables) => {
|
||||||
|
updateTimestamp(variables.itemID);
|
||||||
|
client.setQueryData(
|
||||||
|
ossApi.getOssQueryOptions({ itemID: variables.itemID }).queryKey,
|
||||||
|
(prev: IOperationSchemaDTO | undefined) =>
|
||||||
|
!prev
|
||||||
|
? prev
|
||||||
|
: {
|
||||||
|
...prev,
|
||||||
|
layout: variables.data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
onError: () => client.invalidateQueries()
|
onError: () => client.invalidateQueries()
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
updateLayout: (data: {
|
updateLayout: (data: {
|
||||||
itemID: number; //
|
itemID: number; //
|
||||||
positions: IOperationPosition[];
|
data: IOssLayout;
|
||||||
isSilent?: boolean;
|
isSilent?: boolean;
|
||||||
}) => mutation.mutateAsync(data)
|
}) => mutation.mutateAsync(data)
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { Label } from '@/components/input';
|
||||||
import { ModalForm } from '@/components/modal';
|
import { ModalForm } from '@/components/modal';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { type IInputUpdateDTO, type IOperationPosition, schemaInputUpdate } from '../backend/types';
|
import { type IInputUpdateDTO, type IOssLayout, schemaInputUpdate } from '../backend/types';
|
||||||
import { useInputUpdate } from '../backend/use-input-update';
|
import { useInputUpdate } from '../backend/use-input-update';
|
||||||
import { type IOperation, type IOperationSchema } from '../models/oss';
|
import { type IOperation, type IOperationSchema } from '../models/oss';
|
||||||
import { sortItemsForOSS } from '../models/oss-api';
|
import { sortItemsForOSS } from '../models/oss-api';
|
||||||
|
@ -21,18 +21,18 @@ import { sortItemsForOSS } from '../models/oss-api';
|
||||||
export interface DlgChangeInputSchemaProps {
|
export interface DlgChangeInputSchemaProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
target: IOperation;
|
target: IOperation;
|
||||||
positions: IOperationPosition[];
|
layout: IOssLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DlgChangeInputSchema() {
|
export function DlgChangeInputSchema() {
|
||||||
const { oss, target, positions } = useDialogsStore(state => state.props as DlgChangeInputSchemaProps);
|
const { oss, target, layout } = useDialogsStore(state => state.props as DlgChangeInputSchemaProps);
|
||||||
const { inputUpdate } = useInputUpdate();
|
const { inputUpdate } = useInputUpdate();
|
||||||
|
|
||||||
const { setValue, handleSubmit, control } = useForm<IInputUpdateDTO>({
|
const { setValue, handleSubmit, control } = useForm<IInputUpdateDTO>({
|
||||||
resolver: zodResolver(schemaInputUpdate),
|
resolver: zodResolver(schemaInputUpdate),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
target: target.id,
|
target: target.id,
|
||||||
positions: positions,
|
layout: layout,
|
||||||
input: target.result
|
input: target.result
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,12 +10,7 @@ import { ModalForm } from '@/components/modal';
|
||||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import {
|
import { type IOperationCreateDTO, type IOssLayout, OperationType, schemaOperationCreate } from '../../backend/types';
|
||||||
type IOperationCreateDTO,
|
|
||||||
type IOperationPosition,
|
|
||||||
OperationType,
|
|
||||||
schemaOperationCreate
|
|
||||||
} from '../../backend/types';
|
|
||||||
import { useOperationCreate } from '../../backend/use-operation-create';
|
import { useOperationCreate } from '../../backend/use-operation-create';
|
||||||
import { describeOperationType, labelOperationType } from '../../labels';
|
import { describeOperationType, labelOperationType } from '../../labels';
|
||||||
import { type IOperationSchema } from '../../models/oss';
|
import { type IOperationSchema } from '../../models/oss';
|
||||||
|
@ -26,7 +21,7 @@ import { TabSynthesisOperation } from './tab-synthesis-operation';
|
||||||
|
|
||||||
export interface DlgCreateOperationProps {
|
export interface DlgCreateOperationProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
positions: IOperationPosition[];
|
layout: IOssLayout;
|
||||||
initialInputs: number[];
|
initialInputs: number[];
|
||||||
defaultX: number;
|
defaultX: number;
|
||||||
defaultY: number;
|
defaultY: number;
|
||||||
|
@ -42,7 +37,7 @@ export type TabID = (typeof TabID)[keyof typeof TabID];
|
||||||
export function DlgCreateOperation() {
|
export function DlgCreateOperation() {
|
||||||
const { operationCreate } = useOperationCreate();
|
const { operationCreate } = useOperationCreate();
|
||||||
|
|
||||||
const { oss, positions, initialInputs, onCreate, defaultX, defaultY } = useDialogsStore(
|
const { oss, layout, initialInputs, onCreate, defaultX, defaultY } = useDialogsStore(
|
||||||
state => state.props as DlgCreateOperationProps
|
state => state.props as DlgCreateOperationProps
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -51,30 +46,31 @@ export function DlgCreateOperation() {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
item_data: {
|
item_data: {
|
||||||
operation_type: initialInputs.length === 0 ? OperationType.INPUT : OperationType.SYNTHESIS,
|
operation_type: initialInputs.length === 0 ? OperationType.INPUT : OperationType.SYNTHESIS,
|
||||||
result: null,
|
|
||||||
position_x: defaultX,
|
|
||||||
position_y: defaultY,
|
|
||||||
alias: '',
|
alias: '',
|
||||||
title: '',
|
title: '',
|
||||||
description: ''
|
description: '',
|
||||||
|
result: null,
|
||||||
|
parent: null
|
||||||
},
|
},
|
||||||
|
position_x: defaultX,
|
||||||
|
position_y: defaultY,
|
||||||
arguments: initialInputs,
|
arguments: initialInputs,
|
||||||
create_schema: false,
|
create_schema: false,
|
||||||
positions: positions
|
layout: layout
|
||||||
},
|
},
|
||||||
mode: 'onChange'
|
mode: 'onChange'
|
||||||
});
|
});
|
||||||
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
|
const alias = useWatch({ control: methods.control, name: 'item_data.alias' });
|
||||||
const [activeTab, setActiveTab] = useState(initialInputs.length === 0 ? TabID.INPUT : TabID.SYNTHESIS);
|
const [activeTab, setActiveTab] = useState(initialInputs.length === 0 ? TabID.INPUT : TabID.SYNTHESIS);
|
||||||
const isValid = !!alias && !oss.items.some(operation => operation.alias === alias);
|
const isValid = !!alias && !oss.operations.some(operation => operation.alias === alias);
|
||||||
|
|
||||||
function onSubmit(data: IOperationCreateDTO) {
|
function onSubmit(data: IOperationCreateDTO) {
|
||||||
const target = calculateInsertPosition(oss, data.arguments, positions, {
|
const target = calculateInsertPosition(oss, data.arguments, layout, {
|
||||||
x: defaultX,
|
x: defaultX,
|
||||||
y: defaultY
|
y: defaultY
|
||||||
});
|
});
|
||||||
data.item_data.position_x = target.x;
|
data.position_x = target.x;
|
||||||
data.item_data.position_y = target.y;
|
data.position_y = target.y;
|
||||||
void operationCreate({ itemID: oss.id, data: data }).then(response => onCreate?.(response.new_operation.id));
|
void operationCreate({ itemID: oss.id, data: data }).then(response => onCreate?.(response.new_operation.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ export function TabSynthesisOperation() {
|
||||||
name='arguments'
|
name='arguments'
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<PickMultiOperation items={oss.items} value={field.value} onChange={field.onChange} rows={6} />
|
<PickMultiOperation items={oss.operations} value={field.value} onChange={field.onChange} rows={6} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,25 +9,25 @@ import { Checkbox, TextInput } from '@/components/input';
|
||||||
import { ModalForm } from '@/components/modal';
|
import { ModalForm } from '@/components/modal';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { type IOperationDeleteDTO, type IOperationPosition, schemaOperationDelete } from '../backend/types';
|
import { type IOperationDeleteDTO, type IOssLayout, schemaOperationDelete } from '../backend/types';
|
||||||
import { useOperationDelete } from '../backend/use-operation-delete';
|
import { useOperationDelete } from '../backend/use-operation-delete';
|
||||||
import { type IOperation, type IOperationSchema } from '../models/oss';
|
import { type IOperation, type IOperationSchema } from '../models/oss';
|
||||||
|
|
||||||
export interface DlgDeleteOperationProps {
|
export interface DlgDeleteOperationProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
target: IOperation;
|
target: IOperation;
|
||||||
positions: IOperationPosition[];
|
layout: IOssLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DlgDeleteOperation() {
|
export function DlgDeleteOperation() {
|
||||||
const { oss, target, positions } = useDialogsStore(state => state.props as DlgDeleteOperationProps);
|
const { oss, target, layout } = useDialogsStore(state => state.props as DlgDeleteOperationProps);
|
||||||
const { operationDelete } = useOperationDelete();
|
const { operationDelete } = useOperationDelete();
|
||||||
|
|
||||||
const { handleSubmit, control } = useForm<IOperationDeleteDTO>({
|
const { handleSubmit, control } = useForm<IOperationDeleteDTO>({
|
||||||
resolver: zodResolver(schemaOperationDelete),
|
resolver: zodResolver(schemaOperationDelete),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
target: target.id,
|
target: target.id,
|
||||||
positions: positions,
|
layout: layout,
|
||||||
keep_constituents: false,
|
keep_constituents: false,
|
||||||
delete_schema: false
|
delete_schema: false
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,7 @@ import { ModalForm } from '@/components/modal';
|
||||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import {
|
import { type IOperationUpdateDTO, type IOssLayout, OperationType, schemaOperationUpdate } from '../../backend/types';
|
||||||
type IOperationPosition,
|
|
||||||
type IOperationUpdateDTO,
|
|
||||||
OperationType,
|
|
||||||
schemaOperationUpdate
|
|
||||||
} from '../../backend/types';
|
|
||||||
import { useOperationUpdate } from '../../backend/use-operation-update';
|
import { useOperationUpdate } from '../../backend/use-operation-update';
|
||||||
import { type IOperation, type IOperationSchema } from '../../models/oss';
|
import { type IOperation, type IOperationSchema } from '../../models/oss';
|
||||||
|
|
||||||
|
@ -27,7 +22,7 @@ import { TabSynthesis } from './tab-synthesis';
|
||||||
export interface DlgEditOperationProps {
|
export interface DlgEditOperationProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
target: IOperation;
|
target: IOperation;
|
||||||
positions: IOperationPosition[];
|
layout: IOssLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabID = {
|
export const TabID = {
|
||||||
|
@ -38,7 +33,7 @@ export const TabID = {
|
||||||
export type TabID = (typeof TabID)[keyof typeof TabID];
|
export type TabID = (typeof TabID)[keyof typeof TabID];
|
||||||
|
|
||||||
export function DlgEditOperation() {
|
export function DlgEditOperation() {
|
||||||
const { oss, target, positions } = useDialogsStore(state => state.props as DlgEditOperationProps);
|
const { oss, target, layout } = useDialogsStore(state => state.props as DlgEditOperationProps);
|
||||||
const { operationUpdate } = useOperationUpdate();
|
const { operationUpdate } = useOperationUpdate();
|
||||||
|
|
||||||
const methods = useForm<IOperationUpdateDTO>({
|
const methods = useForm<IOperationUpdateDTO>({
|
||||||
|
@ -55,7 +50,7 @@ export function DlgEditOperation() {
|
||||||
original: sub.original,
|
original: sub.original,
|
||||||
substitution: sub.substitution
|
substitution: sub.substitution
|
||||||
})),
|
})),
|
||||||
positions: positions
|
layout: layout
|
||||||
},
|
},
|
||||||
mode: 'onChange'
|
mode: 'onChange'
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function TabArguments() {
|
||||||
const { control, setValue } = useFormContext<IOperationUpdateDTO>();
|
const { control, setValue } = useFormContext<IOperationUpdateDTO>();
|
||||||
const { oss, target } = useDialogsStore(state => state.props as DlgEditOperationProps);
|
const { oss, target } = useDialogsStore(state => state.props as DlgEditOperationProps);
|
||||||
const potentialCycle = [target.id, ...oss.graph.expandAllOutputs([target.id])];
|
const potentialCycle = [target.id, ...oss.graph.expandAllOutputs([target.id])];
|
||||||
const filtered = oss.items.filter(item => !potentialCycle.includes(item.id));
|
const filtered = oss.operations.filter(item => !potentialCycle.includes(item.id));
|
||||||
|
|
||||||
function handleChangeArguments(prev: number[], newValue: number[]) {
|
function handleChangeArguments(prev: number[], newValue: number[]) {
|
||||||
setValue('arguments', newValue, { shouldValidate: true });
|
setValue('arguments', newValue, { shouldValidate: true });
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Loader } from '@/components/loader';
|
||||||
import { ModalForm } from '@/components/modal';
|
import { ModalForm } from '@/components/modal';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
import { type ICstRelocateDTO, type IOperationPosition, schemaCstRelocate } from '../backend/types';
|
import { type ICstRelocateDTO, type IOssLayout, schemaCstRelocate } from '../backend/types';
|
||||||
import { useRelocateConstituents } from '../backend/use-relocate-constituents';
|
import { useRelocateConstituents } from '../backend/use-relocate-constituents';
|
||||||
import { useUpdateLayout } from '../backend/use-update-layout';
|
import { useUpdateLayout } from '../backend/use-update-layout';
|
||||||
import { IconRelocationUp } from '../components/icon-relocation-up';
|
import { IconRelocationUp } from '../components/icon-relocation-up';
|
||||||
|
@ -26,11 +26,11 @@ import { getRelocateCandidates } from '../models/oss-api';
|
||||||
export interface DlgRelocateConstituentsProps {
|
export interface DlgRelocateConstituentsProps {
|
||||||
oss: IOperationSchema;
|
oss: IOperationSchema;
|
||||||
initialTarget?: IOperation;
|
initialTarget?: IOperation;
|
||||||
positions: IOperationPosition[];
|
layout?: IOssLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DlgRelocateConstituents() {
|
export function DlgRelocateConstituents() {
|
||||||
const { oss, initialTarget, positions } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
|
const { oss, initialTarget, layout } = useDialogsStore(state => state.props as DlgRelocateConstituentsProps);
|
||||||
const { items: libraryItems } = useLibrary();
|
const { items: libraryItems } = useLibrary();
|
||||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||||
const { relocateConstituents } = useRelocateConstituents();
|
const { relocateConstituents } = useRelocateConstituents();
|
||||||
|
@ -55,7 +55,7 @@ export function DlgRelocateConstituents() {
|
||||||
libraryItems.find(item => item.id === initialTarget?.result) ?? null
|
libraryItems.find(item => item.id === initialTarget?.result) ?? null
|
||||||
);
|
);
|
||||||
|
|
||||||
const operation = oss.items.find(item => item.result === source?.id);
|
const operation = oss.operations.find(item => item.result === source?.id);
|
||||||
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
|
const sourceSchemas = libraryItems.filter(item => oss.schemas.includes(item.id));
|
||||||
const destinationSchemas = (() => {
|
const destinationSchemas = (() => {
|
||||||
if (!operation) {
|
if (!operation) {
|
||||||
|
@ -73,7 +73,7 @@ export function DlgRelocateConstituents() {
|
||||||
if (!sourceData.schema || !destinationItem || !operation) {
|
if (!sourceData.schema || !destinationItem || !operation) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const destinationOperation = oss.items.find(item => item.result === destination);
|
const destinationOperation = oss.operations.find(item => item.result === destination);
|
||||||
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
|
return getRelocateCandidates(operation.id, destinationOperation!.id, sourceData.schema, oss);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -98,17 +98,13 @@ export function DlgRelocateConstituents() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmit(data: ICstRelocateDTO) {
|
function onSubmit(data: ICstRelocateDTO) {
|
||||||
const positionsUnchanged = positions.every(item => {
|
if (!layout || JSON.stringify(layout) === JSON.stringify(oss.layout)) {
|
||||||
const operation = oss.operationByID.get(item.id)!;
|
|
||||||
return operation.position_x === item.position_x && operation.position_y === item.position_y;
|
|
||||||
});
|
|
||||||
if (positionsUnchanged) {
|
|
||||||
return relocateConstituents(data);
|
return relocateConstituents(data);
|
||||||
} else {
|
} else {
|
||||||
return updatePositions({
|
return updatePositions({
|
||||||
isSilent: true,
|
isSilent: true,
|
||||||
itemID: oss.id,
|
itemID: oss.id,
|
||||||
positions: positions
|
data: layout
|
||||||
}).then(() => relocateConstituents(data));
|
}).then(() => relocateConstituents(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { infoMsg } from '@/utils/labels';
|
||||||
import { TextMatcher } from '@/utils/utils';
|
import { TextMatcher } from '@/utils/utils';
|
||||||
|
|
||||||
import { Graph } from '../../../models/graph';
|
import { Graph } from '../../../models/graph';
|
||||||
import { type IOperationPosition } from '../backend/types';
|
import { type IOssLayout } from '../backend/types';
|
||||||
import { describeSubstitutionError } from '../labels';
|
import { describeSubstitutionError } from '../labels';
|
||||||
|
|
||||||
import { type IOperation, type IOperationSchema, SubstitutionErrorType } from './oss';
|
import { type IOperation, type IOperationSchema, SubstitutionErrorType } from './oss';
|
||||||
|
@ -494,40 +494,39 @@ export function getRelocateCandidates(
|
||||||
export function calculateInsertPosition(
|
export function calculateInsertPosition(
|
||||||
oss: IOperationSchema,
|
oss: IOperationSchema,
|
||||||
argumentsOps: number[],
|
argumentsOps: number[],
|
||||||
positions: IOperationPosition[],
|
layout: IOssLayout,
|
||||||
defaultPosition: Position2D
|
defaultPosition: Position2D
|
||||||
): Position2D {
|
): Position2D {
|
||||||
const result = defaultPosition;
|
const result = defaultPosition;
|
||||||
if (positions.length === 0) {
|
const operations = layout.operations;
|
||||||
|
if (operations.length === 0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argumentsOps.length === 0) {
|
if (argumentsOps.length === 0) {
|
||||||
let inputsPositions = positions.filter(pos =>
|
let inputsPositions = operations.filter(pos =>
|
||||||
oss.items.find(operation => operation.arguments.length === 0 && operation.id === pos.id)
|
oss.operations.find(operation => operation.arguments.length === 0 && operation.id === pos.id)
|
||||||
);
|
);
|
||||||
if (inputsPositions.length === 0) {
|
if (inputsPositions.length === 0) {
|
||||||
inputsPositions = positions;
|
inputsPositions = operations;
|
||||||
}
|
}
|
||||||
const maxX = Math.max(...inputsPositions.map(node => node.position_x));
|
const maxX = Math.max(...inputsPositions.map(node => node.x));
|
||||||
const minY = Math.min(...inputsPositions.map(node => node.position_y));
|
const minY = Math.min(...inputsPositions.map(node => node.y));
|
||||||
result.x = maxX + DISTANCE_X;
|
result.x = maxX + DISTANCE_X;
|
||||||
result.y = minY;
|
result.y = minY;
|
||||||
} else {
|
} else {
|
||||||
const argNodes = positions.filter(pos => argumentsOps.includes(pos.id));
|
const argNodes = operations.filter(pos => argumentsOps.includes(pos.id));
|
||||||
const maxY = Math.max(...argNodes.map(node => node.position_y));
|
const maxY = Math.max(...argNodes.map(node => node.y));
|
||||||
const minX = Math.min(...argNodes.map(node => node.position_x));
|
const minX = Math.min(...argNodes.map(node => node.x));
|
||||||
const maxX = Math.max(...argNodes.map(node => node.position_x));
|
const maxX = Math.max(...argNodes.map(node => node.x));
|
||||||
result.x = Math.ceil((maxX + minX) / 2 / GRID_SIZE) * GRID_SIZE;
|
result.x = Math.ceil((maxX + minX) / 2 / GRID_SIZE) * GRID_SIZE;
|
||||||
result.y = maxY + DISTANCE_Y;
|
result.y = maxY + DISTANCE_Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
let flagIntersect = false;
|
let flagIntersect = false;
|
||||||
do {
|
do {
|
||||||
flagIntersect = positions.some(
|
flagIntersect = operations.some(
|
||||||
position =>
|
position => Math.abs(position.x - result.x) < MIN_DISTANCE && Math.abs(position.y - result.y) < MIN_DISTANCE
|
||||||
Math.abs(position.position_x - result.x) < MIN_DISTANCE &&
|
|
||||||
Math.abs(position.position_y - result.y) < MIN_DISTANCE
|
|
||||||
);
|
);
|
||||||
if (flagIntersect) {
|
if (flagIntersect) {
|
||||||
result.x += MIN_DISTANCE;
|
result.x += MIN_DISTANCE;
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { type ICstSubstituteInfo, type IOperationDTO, type IOperationSchemaDTO }
|
||||||
|
|
||||||
/** Represents Operation. */
|
/** Represents Operation. */
|
||||||
export interface IOperation extends IOperationDTO {
|
export interface IOperation extends IOperationDTO {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
is_owned: boolean;
|
is_owned: boolean;
|
||||||
is_consolidation: boolean; // aka 'diamond synthesis'
|
is_consolidation: boolean; // aka 'diamond synthesis'
|
||||||
substitutions: ICstSubstituteInfo[];
|
substitutions: ICstSubstituteInfo[];
|
||||||
|
@ -25,7 +27,7 @@ export interface IOperationSchemaStats {
|
||||||
|
|
||||||
/** Represents OperationSchema. */
|
/** Represents OperationSchema. */
|
||||||
export interface IOperationSchema extends IOperationSchemaDTO {
|
export interface IOperationSchema extends IOperationSchemaDTO {
|
||||||
items: IOperation[];
|
operations: IOperation[];
|
||||||
|
|
||||||
graph: Graph;
|
graph: Graph;
|
||||||
schemas: number[];
|
schemas: number[];
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { useMutatingOss } from '../../../backend/use-mutating-oss';
|
||||||
import { type IOperation } from '../../../models/oss';
|
import { type IOperation } from '../../../models/oss';
|
||||||
import { useOssEdit } from '../oss-edit-context';
|
import { useOssEdit } from '../oss-edit-context';
|
||||||
|
|
||||||
import { useGetPositions } from './use-get-positions';
|
import { useGetLayout } from './use-get-layout';
|
||||||
|
|
||||||
// pixels - size of OSS context menu
|
// pixels - size of OSS context menu
|
||||||
const MENU_WIDTH = 200;
|
const MENU_WIDTH = 200;
|
||||||
|
@ -49,7 +49,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
const { items: libraryItems } = useLibrary();
|
const { items: libraryItems } = useLibrary();
|
||||||
const { schema, navigateOperationSchema, isMutable, canDeleteOperation: canDelete } = useOssEdit();
|
const { schema, navigateOperationSchema, isMutable, canDeleteOperation: canDelete } = useOssEdit();
|
||||||
const isProcessing = useMutatingOss();
|
const isProcessing = useMutatingOss();
|
||||||
const getPositions = useGetPositions();
|
const getLayout = useGetLayout();
|
||||||
|
|
||||||
const { inputCreate } = useInputCreate();
|
const { inputCreate } = useInputCreate();
|
||||||
const { operationExecute } = useOperationExecute();
|
const { operationExecute } = useOperationExecute();
|
||||||
|
@ -104,7 +104,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
showEditInput({
|
showEditInput({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
target: operation,
|
target: operation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
showEditOperation({
|
showEditOperation({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
target: operation,
|
target: operation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
showDeleteOperation({
|
showDeleteOperation({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
target: operation,
|
target: operation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
onHide();
|
onHide();
|
||||||
void operationExecute({
|
void operationExecute({
|
||||||
itemID: schema.id, //
|
itemID: schema.id, //
|
||||||
data: { target: operation.id, positions: getPositions() }
|
data: { target: operation.id, layout: getLayout() }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
onHide();
|
onHide();
|
||||||
void inputCreate({
|
void inputCreate({
|
||||||
itemID: schema.id,
|
itemID: schema.id,
|
||||||
data: { target: operation.id, positions: getPositions() }
|
data: { target: operation.id, layout: getLayout() }
|
||||||
}).then(new_schema => router.push({ path: urls.schema(new_schema.id), force: true }));
|
}).then(new_schema => router.push({ path: urls.schema(new_schema.id), force: true }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
||||||
showRelocateConstituents({
|
showRelocateConstituents({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
initialTarget: operation,
|
initialTarget: operation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { useOssEdit } from '../oss-edit-context';
|
||||||
import { OssNodeTypes } from './graph/oss-node-types';
|
import { OssNodeTypes } from './graph/oss-node-types';
|
||||||
import { type ContextMenuData, NodeContextMenu } from './node-context-menu';
|
import { type ContextMenuData, NodeContextMenu } from './node-context-menu';
|
||||||
import { ToolbarOssGraph } from './toolbar-oss-graph';
|
import { ToolbarOssGraph } from './toolbar-oss-graph';
|
||||||
import { useGetPositions } from './use-get-positions';
|
import { useGetLayout } from './use-get-layout';
|
||||||
|
|
||||||
const ZOOM_MAX = 2;
|
const ZOOM_MAX = 2;
|
||||||
const ZOOM_MIN = 0.5;
|
const ZOOM_MIN = 0.5;
|
||||||
|
@ -52,7 +52,7 @@ export function OssFlow() {
|
||||||
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
||||||
const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
|
const edgeStraight = useOSSGraphStore(state => state.edgeStraight);
|
||||||
|
|
||||||
const getPositions = useGetPositions();
|
const getLayout = useGetLayout();
|
||||||
const { updateLayout: updatePositions } = useUpdateLayout();
|
const { updateLayout: updatePositions } = useUpdateLayout();
|
||||||
|
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||||
|
@ -78,10 +78,10 @@ export function OssFlow() {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNodes(
|
setNodes(
|
||||||
schema.items.map(operation => ({
|
schema.operations.map(operation => ({
|
||||||
id: String(operation.id),
|
id: String(operation.id),
|
||||||
data: { label: operation.alias, operation: operation },
|
data: { label: operation.alias, operation: operation },
|
||||||
position: { x: operation.position_x, y: operation.position_y },
|
position: { x: operation.x, y: operation.y },
|
||||||
type: operation.operation_type.toString()
|
type: operation.operation_type.toString()
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
@ -93,8 +93,7 @@ export function OssFlow() {
|
||||||
type: edgeStraight ? 'straight' : 'simplebezier',
|
type: edgeStraight ? 'straight' : 'simplebezier',
|
||||||
animated: edgeAnimate,
|
animated: edgeAnimate,
|
||||||
targetHandle:
|
targetHandle:
|
||||||
schema.operationByID.get(argument.argument)!.position_x >
|
schema.operationByID.get(argument.argument)!.x > schema.operationByID.get(argument.operation)!.x
|
||||||
schema.operationByID.get(argument.operation)!.position_x
|
|
||||||
? 'right'
|
? 'right'
|
||||||
: 'left'
|
: 'left'
|
||||||
}))
|
}))
|
||||||
|
@ -103,16 +102,7 @@ export function OssFlow() {
|
||||||
}, [schema, setNodes, setEdges, toggleReset, edgeStraight, edgeAnimate, fitView]);
|
}, [schema, setNodes, setEdges, toggleReset, edgeStraight, edgeAnimate, fitView]);
|
||||||
|
|
||||||
function handleSavePositions() {
|
function handleSavePositions() {
|
||||||
const positions = getPositions();
|
void updatePositions({ itemID: schema.id, data: getLayout() });
|
||||||
void updatePositions({ itemID: schema.id, positions: positions }).then(() => {
|
|
||||||
positions.forEach(item => {
|
|
||||||
const operation = schema.operationByID.get(item.id);
|
|
||||||
if (operation) {
|
|
||||||
operation.position_x = item.position_x;
|
|
||||||
operation.position_y = item.position_y;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateOperation() {
|
function handleCreateOperation() {
|
||||||
|
@ -121,7 +111,7 @@ export function OssFlow() {
|
||||||
oss: schema,
|
oss: schema,
|
||||||
defaultX: targetPosition.x,
|
defaultX: targetPosition.x,
|
||||||
defaultY: targetPosition.y,
|
defaultY: targetPosition.y,
|
||||||
positions: getPositions(),
|
layout: getLayout(),
|
||||||
initialInputs: selected,
|
initialInputs: selected,
|
||||||
onCreate: () =>
|
onCreate: () =>
|
||||||
setTimeout(() => fitView({ duration: PARAMETER.zoomDuration, padding: VIEW_PADDING }), PARAMETER.refreshTimeout)
|
setTimeout(() => fitView({ duration: PARAMETER.zoomDuration, padding: VIEW_PADDING }), PARAMETER.refreshTimeout)
|
||||||
|
@ -139,7 +129,7 @@ export function OssFlow() {
|
||||||
showDeleteOperation({
|
showDeleteOperation({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
target: operation,
|
target: operation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ import { useOSSGraphStore } from '../../../stores/oss-graph';
|
||||||
import { useOssEdit } from '../oss-edit-context';
|
import { useOssEdit } from '../oss-edit-context';
|
||||||
|
|
||||||
import { VIEW_PADDING } from './oss-flow';
|
import { VIEW_PADDING } from './oss-flow';
|
||||||
import { useGetPositions } from './use-get-positions';
|
import { useGetLayout } from './use-get-layout';
|
||||||
|
|
||||||
interface ToolbarOssGraphProps extends Styling {
|
interface ToolbarOssGraphProps extends Styling {
|
||||||
onCreate: () => void;
|
onCreate: () => void;
|
||||||
|
@ -53,7 +53,7 @@ export function ToolbarOssGraph({
|
||||||
const isProcessing = useMutatingOss();
|
const isProcessing = useMutatingOss();
|
||||||
const { fitView } = useReactFlow();
|
const { fitView } = useReactFlow();
|
||||||
const selectedOperation = schema.operationByID.get(selected[0]);
|
const selectedOperation = schema.operationByID.get(selected[0]);
|
||||||
const getPositions = useGetPositions();
|
const getLayout = useGetLayout();
|
||||||
|
|
||||||
const showGrid = useOSSGraphStore(state => state.showGrid);
|
const showGrid = useOSSGraphStore(state => state.showGrid);
|
||||||
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
const edgeAnimate = useOSSGraphStore(state => state.edgeAnimate);
|
||||||
|
@ -93,16 +93,7 @@ export function ToolbarOssGraph({
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSavePositions() {
|
function handleSavePositions() {
|
||||||
const positions = getPositions();
|
void updatePositions({ itemID: schema.id, data: getLayout() });
|
||||||
void updatePositions({ itemID: schema.id, positions: positions }).then(() => {
|
|
||||||
positions.forEach(item => {
|
|
||||||
const operation = schema.operationByID.get(item.id);
|
|
||||||
if (operation) {
|
|
||||||
operation.position_x = item.position_x;
|
|
||||||
operation.position_y = item.position_y;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleOperationExecute() {
|
function handleOperationExecute() {
|
||||||
|
@ -111,7 +102,7 @@ export function ToolbarOssGraph({
|
||||||
}
|
}
|
||||||
void operationExecute({
|
void operationExecute({
|
||||||
itemID: schema.id, //
|
itemID: schema.id, //
|
||||||
data: { target: selectedOperation.id, positions: getPositions() }
|
data: { target: selectedOperation.id, layout: getLayout() }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +113,7 @@ export function ToolbarOssGraph({
|
||||||
showEditOperation({
|
showEditOperation({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
target: selectedOperation,
|
target: selectedOperation,
|
||||||
positions: getPositions()
|
layout: getLayout()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { useReactFlow } from 'reactflow';
|
||||||
|
|
||||||
|
import { type IOssLayout } from '@/features/oss/backend/types';
|
||||||
|
|
||||||
|
export function useGetLayout() {
|
||||||
|
const { getNodes } = useReactFlow();
|
||||||
|
return function getLayout(): IOssLayout {
|
||||||
|
return {
|
||||||
|
operations: getNodes().map(node => ({
|
||||||
|
id: Number(node.id),
|
||||||
|
x: node.position.x,
|
||||||
|
y: node.position.y
|
||||||
|
})),
|
||||||
|
blocks: []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
import { useReactFlow } from 'reactflow';
|
|
||||||
|
|
||||||
export function useGetPositions() {
|
|
||||||
const { getNodes } = useReactFlow();
|
|
||||||
return function getPositions() {
|
|
||||||
return getNodes().map(node => ({
|
|
||||||
id: Number(node.id),
|
|
||||||
position_x: node.position.x,
|
|
||||||
position_y: node.position.y
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -21,8 +21,7 @@ export function MenuEditOss() {
|
||||||
menu.hide();
|
menu.hide();
|
||||||
showRelocateConstituents({
|
showRelocateConstituents({
|
||||||
oss: schema,
|
oss: schema,
|
||||||
initialTarget: undefined,
|
initialTarget: undefined
|
||||||
positions: []
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user