diff --git a/src/app/shared/nodes/generic-node/generic-node.ts b/src/app/shared/nodes/generic-node/generic-node.ts index 774bb0a..b712005 100644 --- a/src/app/shared/nodes/generic-node/generic-node.ts +++ b/src/app/shared/nodes/generic-node/generic-node.ts @@ -856,7 +856,7 @@ export class GenericNodeComponent implements OnDestroy { this.schemaLoading = true; this.schemaReady = false; try { - const blockType = this.blocksService.peekBlockType(type) ?? await this.blocksService.getBlockType(type); + const blockType = await this.resolveNodeDescriptor(type); this.blockDescriptor = blockType ?? null; this.blockSchema = (blockType?.schema ?? null) as Record | null; this.schemaRequirements = extractSchemaRequirements(this.blockSchema); @@ -882,6 +882,19 @@ export class GenericNodeComponent implements OnDestroy { } } + /** Where this node's type is described: the block catalog here, another one for another kind of node. */ + protected async resolveNodeDescriptor(type: string): Promise { + return this.blocksService.peekBlockType(type) ?? await this.blocksService.getBlockType(type) ?? null; + } + + /** + * A block is recreated on the server when a field that shapes its ports changes. A node with no + * ports has nothing for the server to recompute. + */ + protected get createsOnServer(): boolean { + return true; + } + private shouldRetrySchemaLoad(): boolean { if (this.schemaLoading) return false; if (!this.blockType) return false; @@ -2319,6 +2332,7 @@ export class GenericNodeComponent implements OnDestroy { } private maybeCreateBlockOnServer() { + if (!this.createsOnServer) return; const nodeData = this.data?.data as Record | undefined; if (!nodeData?.['__needsServerCreate']) return; if (nodeData['__isCreatingOnServer'] === true) return; diff --git a/src/app/shared/nodes/resource-node/resource-node.ts b/src/app/shared/nodes/resource-node/resource-node.ts index 2cc1827..dd2882f 100644 --- a/src/app/shared/nodes/resource-node/resource-node.ts +++ b/src/app/shared/nodes/resource-node/resource-node.ts @@ -3,9 +3,11 @@ // Attribution term under AGPL-3.0 section 7(b): see LICENSE-ADDENDUM. import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatTooltipModule } from '@angular/material/tooltip'; +import { BlockType, RESOURCE_NODE_CAPABILITIES } from '@models/flow'; +import { ResourcesService } from '@services/resources/resources'; import { ReteModule } from 'rete-angular-plugin/21'; import { GenericNodeComponent } from '../generic-node/generic-node'; import { NodeParametersComponent } from '../node-parameters/node-parameters'; @@ -29,6 +31,30 @@ import { NodeParametersComponent } from '../node-parameters/node-parameters'; }) export class ResourceNodeComponent extends GenericNodeComponent { + private readonly resourcesService = inject(ResourcesService); + + /** Described by the resource catalog: the block catalog has never heard of it. */ + protected override async resolveNodeDescriptor(type: string): Promise { + const resourceType = this.resourcesService.peekResourceType(type) + ?? (await this.resourcesService.getAllResourceTypes())().find((candidate) => candidate.type === type); + if (!resourceType) return null; + return { + type: resourceType.type, + family: 'resource', + description: resourceType.description, + userInteractive: false, + configurationType: resourceType.configurationType, + configurationClass: resourceType.configurationClass, + schema: resourceType.schema, + capabilities: RESOURCE_NODE_CAPABILITIES + }; + } + + /** It has no ports, so there is nothing for the server to rebuild when a field changes. */ + protected override get createsOnServer(): boolean { + return false; + } + /** The type of resource, as the palette names it: what a block's title would say. */ resourceTitle(): string { return String(this.data?.data?.typeName ?? 'Resource');