F: Remove unnecessary updates and fix UI
Some checks are pending
Backend CI / build (3.12) (push) Waiting to run
Backend CI / notify-failure (push) Blocked by required conditions
Frontend CI / build (22.x) (push) Waiting to run
Frontend CI / notify-failure (push) Blocked by required conditions

This commit is contained in:
Ivan 2025-07-07 17:33:17 +03:00
parent dc5ff50175
commit 96b05d1fe6
10 changed files with 23 additions and 24 deletions

View File

@ -18,6 +18,8 @@ from .basics import NodeSerializer, SubstitutionExSerializer
class OperationSerializer(serializers.ModelSerializer):
''' Serializer: Operation data. '''
is_import = serializers.BooleanField(default=False, required=False)
class Meta:
''' serializer metadata. '''
model = Operation
@ -407,7 +409,13 @@ class OperationSchemaSerializer(serializers.ModelSerializer):
result['arguments'] = []
result['substitutions'] = []
for operation in oss.operations().order_by('pk'):
result['operations'].append(OperationSerializer(operation).data)
operation_data = OperationSerializer(operation).data
operation_result = operation.result
operation_data['is_import'] = \
operation_result is not None and \
(operation_result.owner_id != instance.owner_id or
operation_result.location != instance.location)
result['operations'].append(operation_data)
for block in oss.blocks().order_by('pk'):
result['blocks'].append(BlockSerializer(block).data)
for argument in oss.arguments().order_by('order'):

View File

@ -2,8 +2,6 @@
* Module: OSS data loading and processing.
*/
import { type ILibraryItem } from '@/features/library';
import { Graph } from '@/models/graph';
import { type RO } from '@/utils/meta';
@ -29,11 +27,9 @@ export class OssLoader {
private itemByNodeID = new Map<string, IOssItem>();
private blockByID = new Map<number, IBlock>();
private schemaIDs: number[] = [];
private items: RO<ILibraryItem[]>;
constructor(input: RO<IOperationSchemaDTO>, items: RO<ILibraryItem[]>) {
constructor(input: RO<IOperationSchemaDTO>) {
this.oss = structuredClone(input) as IOperationSchema;
this.items = items;
}
produceOSS(): IOperationSchema {
@ -89,12 +85,10 @@ export class OssLoader {
private inferOperationAttributes() {
this.graph.topologicalOrder().forEach(operationID => {
const operation = this.operationByID.get(operationID)!;
const schema = this.items.find(item => item.id === operation.result);
const position = this.oss.layout.find(item => item.nodeID === operation.nodeID);
operation.x = position?.x ?? 0;
operation.y = position?.y ?? 0;
operation.is_consolidation = this.inferConsolidation(operationID);
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.arguments = this.oss.arguments
.filter(item => item.operation === operationID)
@ -132,7 +126,7 @@ export class OssLoader {
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
count_schemas: this.schemaIDs.length,
count_owned: operations.filter(item => !!item.result && item.is_owned).length,
count_owned: operations.filter(item => !!item.result && !item.is_import).length,
count_block: this.oss.blocks.length
};
}

View File

@ -86,6 +86,7 @@ export const schemaOperation = z.strictObject({
title: z.string(),
description: z.string(),
parent: z.number().nullable(),
is_import: z.boolean(),
result: z.number().nullable()
});

View File

@ -1,28 +1,24 @@
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
import { useLibrary, useLibrarySuspense } from '@/features/library/backend/use-library';
import { queryClient } from '@/backend/query-client';
import { ossApi } from './api';
import { OssLoader } from './oss-loader';
export function useOss({ itemID }: { itemID?: number }) {
const { items: libraryItems, isLoading: libraryLoading } = useLibrary();
const { data, isLoading, error } = useQuery({
...ossApi.getOssQueryOptions({ itemID })
});
const schema = data && !libraryLoading ? new OssLoader(data, libraryItems).produceOSS() : undefined;
return { schema: schema, isLoading: isLoading || libraryLoading, error: error };
const schema = data ? new OssLoader(data).produceOSS() : undefined;
return { schema: schema, isLoading: isLoading, error: error };
}
export function useOssSuspense({ itemID }: { itemID: number }) {
const { items: libraryItems } = useLibrarySuspense();
const { data } = useSuspenseQuery({
...ossApi.getOssQueryOptions({ itemID })
});
const schema = new OssLoader(data!, libraryItems).produceOSS();
const schema = new OssLoader(data!).produceOSS();
return { schema };
}

View File

@ -47,7 +47,7 @@ export function InfoOperation({ operation }: InfoOperationProps) {
<p>
<b>Тип:</b> {labelOperationType(operation.operation_type)}
</p>
{!operation.is_owned ? (
{operation.is_import ? (
<p>
<b>КС не принадлежит ОСС</b>
</p>

View File

@ -68,13 +68,13 @@ export function DlgDeleteOperation() {
<Checkbox
label='Удалить схему'
titleHtml={
!target.is_owned || target.result === null
target.is_import || target.result === null
? 'Привязанную схему нельзя удалить'
: 'Удалить схему вместе с операцией'
}
value={field.value}
onChange={field.onChange}
disabled={!target.is_owned || target.result === null}
disabled={target.is_import || target.result === null}
/>
)}
/>

View File

@ -24,7 +24,7 @@ export interface IOperation extends IOperationDTO {
nodeType: typeof NodeType.OPERATION;
x: number;
y: number;
is_owned: boolean;
is_import: boolean;
is_consolidation: boolean; // aka 'diamond synthesis'
substitutions: ICstSubstituteInfo[];
arguments: number[];

View File

@ -70,8 +70,8 @@ export function NodeCore({ node }: NodeCoreProps) {
<div className='absolute top-[3px] right-1/2 translate-x-1/2 border-t w-[30px]' />
) : null}
{!node.data.operation.is_owned ? (
<div className='absolute left-[2px] top-[6px] border-r rounded-none bg-input h-[22px]' />
{node.data.operation.is_import ? (
<div className='absolute left-[3px] top-1/2 -translate-y-1/2 border-r rounded-none bg-input h-[22px]' />
) : null}
<div

View File

@ -16,7 +16,7 @@ export function BlockStats({ target, oss }: BlockStatsProps) {
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
count_schemas: operations.filter(item => !!item.result).length,
count_owned: operations.filter(item => !!item.result && item.is_owned).length,
count_owned: operations.filter(item => !!item.result && !item.is_import).length,
count_block: contents.length - operations.length
};

View File

@ -69,7 +69,7 @@ export function SidePanel({ isMounted, className }: SidePanelProps) {
<div className='text-center text-sm cc-fade-in'>Отсутствует концептуальная схема для выбранной операции</div>
) : selectedOperation && selectedSchema && debouncedMounted ? (
<Suspense fallback={<Loader />}>
<ViewSchema schemaID={selectedSchema} isMutable={isMutable && selectedOperation.is_owned} />
<ViewSchema schemaID={selectedSchema} isMutable={isMutable && !selectedOperation.is_import} />
</Suspense>
) : null}
{selectedBlock ? <BlockStats target={selectedBlock} oss={schema} /> : null}