You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by "mcgilman (via GitHub)" <gi...@apache.org> on 2026/09/29 18:54:16 UTC

[PR] NIFI-16395: Added canonical canvas entity and request contracts [nifi]

mcgilman opened a new pull request, #11733:
URL: https://github.com/apache/nifi/pull/11733

   - Added Java-vetted response contracts for all canvas component types
   - Consolidated shared Position and revision primitives
   - Added typed create, mutation, status, and snippet request contracts
   - Covered readable, denied-read, and request boundary cases
   
   # Summary
   
   [NIFI-16395](https://issues.apache.org/jira/browse/NIFI-16395)
   
   Introduces canonical TypeScript contracts for NiFi canvas REST entities and request payloads.
   
   - Adds Java-vetted response contracts for processors, connections, ports, process groups, funnels, labels, remote process groups, controller services, and registered flow snapshots
   - Distinguishes top-level REST entities from embedded entities and permission-gated response bodies
   - Adds typed create, update, status, and snippet request contracts
   - Requires revision version zero for component creation requests
   - Consolidates shared position and revision primitives
   - Migrates connector canvas and flow designer consumers to the canonical contracts
   - Safely handles bulletins omitted because of insufficient read permissions
   - Adds contract tests covering readable entities, denied-read responses, and request boundaries
   
   # Tracking
   
   Please complete the following tracking steps prior to pull request creation.
   
   ### Issue Tracking
   
   - [Apache NiFi Jira](https://issues.apache.org/jira/browse/NIFI) issue created
   
   ### Pull Request Tracking
   
   - Pull Request title starts with Apache NiFi Jira issue number, such as `NIFI-00000`
   - Pull Request commit message starts with Apache NiFi Jira issue number, as such `NIFI-00000`
   - Pull request contains [commits signed](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) with a registered key indicating `Verified` status
   
   ### Pull Request Formatting
   
   - Pull Request based on current revision of the `main` branch
   - Pull Request refers to a feature branch with one commit containing changes
   
   # Verification
   
   - Shared library tests passed: 949 tests
   - NiFi application tests passed: 2,918 tests
   - Strict TypeScript checks passed for affected projects
   - Lint and formatting checks passed
   - Production builds passed for affected projects
   - `git diff --check` passed
   
   ### Build
   
   - [ ] Build completed using `./mvnw clean install -P contrib-check`
     - [ ] JDK 21
     - [ ] JDK 25
   
   ### Licensing
   
   - [x] No new dependencies introduced
   - [x] No `LICENSE` or `NOTICE` changes required
   
   ### Documentation
   
   - [x] No documentation files changed


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16395: Added canonical canvas entity and request contracts [nifi]

Posted by "rfellows (via GitHub)" <gi...@apache.org>.
rfellows merged PR #11733:
URL: https://github.com/apache/nifi/pull/11733


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16395: Added canonical canvas entity and request contracts [nifi]

Posted by "rfellows (via GitHub)" <gi...@apache.org>.
rfellows commented on code in PR #11733:
URL: https://github.com/apache/nifi/pull/11733#discussion_r4137989594


##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/registered-flow-snapshot.ts:
##########
@@ -0,0 +1,343 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle, Position } from '../rest-api.types';
+
+/**
+ * Fully typed graph reachable from ProcessGroupEntity.versionedFlowSnapshot.
+ *
+ * @nifi-source: nifi-api/src/main/java/org/apache/nifi/registry/flow/RegisteredFlowSnapshot.java
+ * @nifi-revision: eefa952edddc (2026-09-29)

Review Comment:
   The source cited by this header belongs to the separate `apache/nifi-api` repository, but `@nifi-revision: eefa952edddc` is an `apache/nifi` commit. That SHA does not exist in `nifi-api`, so it cannot attest the version of the Java source used for this model.
   
   The current `apache/nifi-api` source checked here is `dc575b83e2c0cddf6ac6d3adc51d3448a70654eb`. Could this annotation be made repository-qualified, for example:
   
   ```text
   @nifi-revision: apache/nifi-api@dc575b83e2c0cddf6ac6d3adc51d3448a70654eb
   ```
   
   Otherwise the drift marker appears valid while referring to an unrelated repository history.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/property-descriptor-dto.ts:
##########
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle } from '../rest-api.types';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface PropertyDescriptorDTO {
+    name: string;
+    displayName: string;
+    description?: string;
+    defaultValue?: string;
+    allowableValues?: AllowableValueEntity[];
+    required: boolean;
+    sensitive: boolean;
+    dynamic: boolean;
+    supportsEl: boolean;
+    expressionLanguageScope?: string;
+    identifiesControllerService?: string;
+    identifiesControllerServiceBundle?: Bundle;
+    dependencies: PropertyDependencyDTO[];
+}
+
+export interface AllowableValueEntity {
+    allowableValue?: AllowableValueDTO;

Review Comment:
   `allowableValue` is currently optional:
   
   ```ts
   export interface AllowableValueEntity {
       allowableValue?: AllowableValueDTO;
       canRead: boolean;
   }
   ```
   
   Unlike `BulletinEntity`, `EntityFactory.createAllowableValueEntity` always sets its nested body, including when `canRead` is false:
   
   ```java
   entity.setCanRead(canRead);
   entity.setAllowableValue(dto);
   ```
   
   The descriptor factory also constructs the DTO before creating every entity. Please make this field required:
   
   ```ts
   allowableValue: AllowableValueDTO;
   ```
   
   This distinction matters because permission gates are field-specific; carrying bulletin-style optionality here weakens a body that NiFi always supplies.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/processor-entity.ts:
##########
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle, Permissions } from '../rest-api.types';
+import { PositionableComponentDTO, PositionableComponentEntityBase } from './component-entity';
+import { ProcessingPerformanceStatusDTO } from './processing-performance-status-dto';
+import { PropertyDescriptorDTO, RelationshipDTO } from './property-descriptor-dto';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface ProcessorEntity extends PositionableComponentEntityBase<ProcessorDTO> {
+    operatePermissions: Permissions;
+    status?: ProcessorStatusDTO;
+    inputRequirement: string;
+    physicalState: string;
+}
+
+export interface ProcessorDTO extends PositionableComponentDTO {
+    name: string;
+    type: string;
+    bundle: Bundle;
+    state: string;
+    relationships: RelationshipDTO[];
+    supportsParallelProcessing: boolean;
+    supportsBatching: boolean;
+    supportsSensitiveDynamicProperties: boolean;
+    supportsBacklogReporting: boolean;
+    persistsState: boolean;
+    restricted: boolean;
+    deprecated: boolean;
+    extensionMissing: boolean;
+    executionNodeRestricted: boolean;
+    multipleVersionsAvailable: boolean;
+    inputRequirement: string;
+    physicalState: string;
+    config: ProcessorConfigDTO;
+    validationStatus: string;
+    style?: Record<string, string>;
+    description?: string;
+    validationErrors?: string[];
+}
+
+export interface ProcessorConfigDTO {
+    schedulingPeriod: string;
+    schedulingStrategy: string;
+    executionNode: string;
+    penaltyDuration: string;
+    yieldDuration: string;
+    bulletinLevel: string;
+    runDurationMillis: number;
+    concurrentlySchedulableTaskCount: number;
+    autoTerminatedRelationships: string[];
+    lossTolerant: boolean;
+    retryCount: number;
+    retriedRelationships: string[];
+    backoffMechanism: string;
+    maxBackoffPeriod: string;
+    properties?: Record<string, string | null>;
+    descriptors?: Record<string, PropertyDescriptorDTO>;
+    annotationData?: string;
+    defaultConcurrentTasks?: Record<string, string>;
+    defaultSchedulingPeriod?: Record<string, string>;
+    sensitiveDynamicPropertyNames?: string[];
+    comments?: string;
+    customUiUrl?: string;
+}
+
+export interface ProcessorStatusDTO {
+    groupId: string;
+    id: string;
+    runStatus: string;
+    statsLastRefreshed: string;
+    aggregateSnapshot: ProcessorStatusSnapshotDTO;
+    name?: string;

Review Comment:
   These identity fields are optional even though `DtoFactory.createProcessorStatusDto` populates them on every response:
   
   ```java
   dto.setName(procStatus.getName());
   snapshot.setName(procStatus.getName());
   snapshot.setType(procStatus.getType());
   ```
   
   Under this PR's response-only contract, I believe these should be required:
   
   ```ts
   export interface ProcessorStatusDTO {
       name: string;
       // `type` remains optional: the factory does not set it on the outer DTO.
   }
   
   export interface ProcessorStatusSnapshotDTO {
       name: string;
       type: string;
   }
   ```
   
   The same factory pattern appears for connection, port, process-group, and remote-process-group status names. Could those status DTOs be tightened consistently as part of this Java-vetted model?



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/registered-flow-snapshot.ts:
##########
@@ -0,0 +1,343 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle, Position } from '../rest-api.types';
+
+/**
+ * Fully typed graph reachable from ProcessGroupEntity.versionedFlowSnapshot.
+ *
+ * @nifi-source: nifi-api/src/main/java/org/apache/nifi/registry/flow/RegisteredFlowSnapshot.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface RegisteredFlowSnapshot {
+    snapshotMetadata?: RegisteredFlowSnapshotMetadata;
+    flow?: RegisteredFlow;
+    bucket?: FlowRegistryBucket;
+    flowContents?: VersionedProcessGroup;
+    externalControllerServices?: Record<string, ExternalControllerServiceReference>;
+    parameterContexts?: Record<string, VersionedParameterContext>;
+    flowEncodingVersion?: string;
+    parameterProviders?: Record<string, ParameterProviderReference>;
+    latest: boolean;
+}
+
+export interface RegisteredFlowSnapshotMetadata {
+    registryIdentifier?: string;
+    registryName?: string;
+    branch?: string;
+    bucketIdentifier?: string;
+    flowIdentifier?: string;
+    flowName?: string;
+    version?: string;
+    timestamp: number;
+    author?: string;
+    comments?: string;
+}
+
+export interface RegisteredFlow {
+    identifier?: string;
+    name?: string;
+    description?: string;
+    branch?: string;
+    bucketIdentifier?: string;
+    bucketName?: string;
+    createdTimestamp: number;
+    lastModifiedTimestamp: number;
+    permissions?: FlowRegistryPermissions;
+    versionCount: number;
+    versionInfo?: RegisteredFlowVersionInfo;
+}
+
+export interface RegisteredFlowVersionInfo {
+    version: number;
+}
+
+export interface FlowRegistryBucket {
+    identifier?: string;
+    name?: string;
+    description?: string;
+    createdTimestamp: number;
+    permissions?: FlowRegistryPermissions;
+}
+
+export interface FlowRegistryPermissions {
+    canRead: boolean;
+    canWrite: boolean;
+    canDelete: boolean;
+}
+
+export interface ExternalControllerServiceReference {
+    identifier?: string;
+    name?: string;
+}
+
+export interface ParameterProviderReference {
+    identifier?: string;
+    name?: string;
+    type?: string;
+    bundle?: Bundle;
+}
+
+export type VersionedComponentType =
+    | 'PROCESSOR'
+    | 'CONTROLLER_SERVICE'
+    | 'PROCESS_GROUP'
+    | 'REMOTE_PROCESS_GROUP'
+    | 'INPUT_PORT'
+    | 'OUTPUT_PORT'
+    | 'CONNECTION'
+    | 'FUNNEL'
+    | 'LABEL'
+    | 'REPORTING_TASK'
+    | 'FLOW_REGISTRY_CLIENT'
+    | 'PARAMETER_PROVIDER'
+    | 'FLOW_ANALYSIS_RULE'
+    | 'PARAMETER_CONTEXT'
+    | 'CONNECTOR'
+    | 'REMOTE_INPUT_PORT'
+    | 'REMOTE_OUTPUT_PORT';
+
+export interface VersionedComponent {
+    identifier?: string;
+    instanceIdentifier?: string;
+    groupIdentifier?: string;
+    name?: string;
+    comments?: string;
+    position?: Position;
+    componentType: VersionedComponentType;
+}
+
+export interface VersionedConfigurableExtension extends VersionedComponent {
+    type?: string;
+    bundle?: Bundle;
+    properties?: Record<string, string | null>;
+    propertyDescriptors?: Record<string, VersionedPropertyDescriptor>;
+    componentState?: VersionedComponentState;
+}
+
+export interface VersionedProcessGroup extends VersionedComponent {
+    componentType: 'PROCESS_GROUP';
+    processGroups: VersionedProcessGroup[];
+    remoteProcessGroups: VersionedRemoteProcessGroup[];
+    processors: VersionedProcessor[];
+    inputPorts: VersionedPort[];
+    outputPorts: VersionedPort[];
+    connections: VersionedConnection[];
+    labels: VersionedLabel[];
+    funnels: VersionedFunnel[];
+    controllerServices: VersionedControllerService[];
+    versionedFlowCoordinates?: VersionedFlowCoordinates;
+    parameterContextName?: string;
+    flowFileConcurrency?: string;
+    flowFileOutboundPolicy?: string;
+    defaultFlowFileExpiration?: string;
+    defaultBackPressureObjectThreshold?: number;
+    defaultBackPressureDataSizeThreshold?: string;
+    scheduledState?: ScheduledState;
+    executionEngine?: ExecutionEngine;
+    maxConcurrentTasks?: number;
+    statelessFlowTimeout?: string;
+    logFileSuffix?: string;

Review Comment:
   `VersionedProcessGroup` is missing two fields from the cited `nifi-api` model:
   
   ```java
   private String statelessFlowFileContentInMemoryMax;
   private Integer statelessFlowFileContentInMemoryHeapPercentage;
   ```
   
   Since this file is intended to model the complete graph reachable from `RegisteredFlowSnapshot`, please add both as optional fields:
   
   ```ts
   statelessFlowFileContentInMemoryMax?: string;
   statelessFlowFileContentInMemoryHeapPercentage?: number;
   ```
   
   Both are nullable in Java, so optionality is appropriate. Without them, a valid snapshot is silently narrowed and cannot be round-tripped at full fidelity.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16395: Added canonical canvas entity and request contracts [nifi]

Posted by "rfellows (via GitHub)" <gi...@apache.org>.
rfellows commented on code in PR #11733:
URL: https://github.com/apache/nifi/pull/11733#discussion_r4145578317


##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/controller-service-entity.ts:
##########
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle, Permissions } from '../rest-api.types';
+import { ComponentDTO, EmbeddedComponentEntityBase } from './component-entity';
+import { PropertyDescriptorDTO } from './property-descriptor-dto';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface ControllerServiceDTO extends ComponentDTO {
+    name: string;
+    type: string;
+    bundle: Bundle;
+    controllerServiceApis: ControllerServiceApiDTO[];
+    state: string;
+    bulletinLevel: string;
+    persistsState: boolean;
+    restricted: boolean;
+    deprecated: boolean;
+    extensionMissing: boolean;
+    multipleVersionsAvailable: boolean;
+    supportsSensitiveDynamicProperties: boolean;
+    properties: Record<string, string | null>;
+    descriptors: Record<string, PropertyDescriptorDTO>;
+    validationStatus: string;
+    comments?: string;
+    annotationData?: string;
+    customUiUrl?: string;
+    sensitiveDynamicPropertyNames?: string[];
+    referencingComponents?: ControllerServiceReferencingComponentEntity[];
+    validationErrors?: string[];
+}
+
+export interface ControllerServiceApiDTO {
+    type: string;
+    bundle: Bundle;
+}
+
+export interface ControllerServiceReferencingComponentEntity extends EmbeddedComponentEntityBase<ControllerServiceReferencingComponentDTO> {
+    operatePermissions: Permissions;
+}
+
+export interface ControllerServiceReferencingComponentDTO {
+    id: string;
+    groupId?: string;
+    name: string;
+    type?: string;
+    state?: string;
+    properties: Record<string, string | null>;
+    descriptors: Record<string, PropertyDescriptorDTO>;

Review Comment:
   These maps are omitted on valid `uiOnly` responses: `ApplicationResource.stripNonUiRelevantFields()` explicitly sets both `properties` and `descriptors` to null. Please make both fields optional so this response contract represents that path.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/port-entity.ts:
##########
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Permissions } from '../rest-api.types';
+import { PositionableComponentDTO, PositionableComponentEntityBase } from './component-entity';
+
+export type PortType = 'INPUT_PORT' | 'OUTPUT_PORT';
+export type PortFunction = 'STANDARD' | 'FAILURE';
+
+/**
+ * Shared input/output port response, discriminated by portType.
+ *
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface PortEntity extends PositionableComponentEntityBase<PortDTO> {
+    operatePermissions: Permissions;
+    status?: PortStatusDTO;
+    portType: PortType;
+    allowRemoteAccess?: boolean;
+}
+
+export interface PortDTO extends PositionableComponentDTO {
+    state: string;
+    type: PortType;
+    portFunction: PortFunction;
+    concurrentlySchedulableTaskCount: number;
+    name: string;
+    comments?: string;
+    transmitting?: boolean;
+    allowRemoteAccess?: boolean;
+    validationErrors?: string[];
+}
+
+export interface PortStatusDTO {
+    id: string;
+    groupId: string;
+    transmitting: boolean;

Review Comment:
   `transmitting` is nullable for local ports. `AbstractEventAccess` only calls `setTransmitting(...)` when the port is a `PublicPort`; ordinary local input/output ports leave the boxed `Boolean` null. Please make this field optional.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/property-descriptor-dto.ts:
##########
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle } from '../rest-api.types';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface PropertyDescriptorDTO {
+    name: string;
+    displayName: string;
+    description?: string;
+    defaultValue?: string;
+    allowableValues?: AllowableValueEntity[];
+    required: boolean;
+    sensitive: boolean;
+    dynamic: boolean;
+    supportsEl: boolean;
+    expressionLanguageScope?: string;

Review Comment:
   `DtoFactory.createPropertyDescriptorDto()` unconditionally obtains the expression-language scope description and assigns it with `setExpressionLanguageScope(...)`. Under this response-contract model, this field should be required.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/process-group-entity.ts:
##########
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Permissions } from '../rest-api.types';
+import { PositionableComponentDTO, PositionableComponentEntityBase } from './component-entity';
+import { ConnectionDTO, ConnectionStatusSnapshotEntity } from './connection-entity';
+import { ControllerServiceDTO } from './controller-service-entity';
+import { FunnelDTO } from './funnel-entity';
+import { LabelDTO } from './label-entity';
+import { PortDTO, PortStatusSnapshotEntity } from './port-entity';
+import { ProcessingPerformanceStatusDTO } from './processing-performance-status-dto';
+import { ProcessorDTO, ProcessorStatusSnapshotEntity } from './processor-entity';
+import { RegisteredFlowSnapshot } from './registered-flow-snapshot';
+import { RemoteProcessGroupDTO, RemoteProcessGroupStatusSnapshotEntity } from './remote-process-group-entity';
+
+export type ResolvedExecutionEngine = 'STANDARD' | 'STATELESS';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface ProcessGroupEntity extends PositionableComponentEntityBase<ProcessGroupDTO> {
+    status?: ProcessGroupStatusDTO;
+    runningCount: number;
+    stoppedCount: number;
+    invalidCount: number;
+    disabledCount: number;
+    activeRemotePortCount: number;
+    inactiveRemotePortCount: number;
+    upToDateCount: number;
+    locallyModifiedCount: number;
+    staleCount: number;
+    locallyModifiedAndStaleCount: number;
+    syncFailureCount: number;
+    localInputPortCount: number;
+    localOutputPortCount: number;
+    publicInputPortCount: number;
+    publicOutputPortCount: number;
+    inputPortCount: number;
+    outputPortCount: number;
+    resolvedExecutionEngine: ResolvedExecutionEngine;
+    versionedFlowState?: string;
+    parameterContext?: ParameterContextReferenceEntity;
+    versionedFlowSnapshot?: RegisteredFlowSnapshot;
+    processGroupUpdateStrategy?: 'CURRENT_GROUP' | 'CURRENT_GROUP_WITH_CHILDREN';

Review Comment:
   `ProcessGroupResource` parses this value using `ProcessGroupRecursivity.valueOf(...)`, whose valid values are `DIRECT_CHILDREN` and `ALL_DESCENDANTS`. The current literals would be rejected at runtime. Please change this union to `'DIRECT_CHILDREN' | 'ALL_DESCENDANTS'`.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/remote-process-group-entity.ts:
##########
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Permissions } from '../rest-api.types';
+import { PositionableComponentDTO, PositionableComponentEntityBase } from './component-entity';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface RemoteProcessGroupEntity extends PositionableComponentEntityBase<RemoteProcessGroupDTO> {
+    operatePermissions: Permissions;
+    status?: RemoteProcessGroupStatusDTO;
+    inputPortCount?: number;

Review Comment:
   These promoted counts should be required. `StandardRemoteProcessGroup` initializes its counts to `(0, 0)`, `DtoFactory.createRemoteProcessGroupDto()` assigns both values, and `EntityFactory.createRemoteProcessGroupEntity()` promotes both onto every entity created from that DTO. Please remove the optional markers from `inputPortCount` and `outputPortCount`.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/remote-process-group-entity.ts:
##########
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Permissions } from '../rest-api.types';
+import { PositionableComponentDTO, PositionableComponentEntityBase } from './component-entity';
+
+/**
+ * @nifi-source: nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
+ * @nifi-revision: eefa952edddc (2026-09-29)
+ * @vetted: 2026-09-29
+ */
+export interface RemoteProcessGroupEntity extends PositionableComponentEntityBase<RemoteProcessGroupDTO> {
+    operatePermissions: Permissions;
+    status?: RemoteProcessGroupStatusDTO;
+    inputPortCount?: number;
+    outputPortCount?: number;
+}
+
+export interface RemoteProcessGroupDTO extends PositionableComponentDTO {
+    targetUris: string;
+    communicationsTimeout: string;
+    yieldDuration: string;
+    transportProtocol: string;
+    transmitting: boolean;
+    activeRemoteInputPortCount: number;
+    inactiveRemoteInputPortCount: number;
+    activeRemoteOutputPortCount: number;
+    inactiveRemoteOutputPortCount: number;
+    flowRefreshed: string;

Review Comment:
   `flowRefreshed` can be absent before the first remote-flow refresh. `StandardRemoteProcessGroup.getLastRefreshTime()` explicitly returns null while `refreshContentsTimestamp` is null. Please make this field optional.



##########
nifi-frontend/src/main/frontend/libs/shared/src/types/rest-api.types.ts:
##########
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export interface Revision {
+    version: number;
+    clientId?: string;
+    lastModifier?: string;
+}
+
+export interface RevisionRequest {
+    version?: number;
+    clientId?: string;
+}
+
+export interface CreateRevisionRequest extends RevisionRequest {
+    version: 0;
+}
+
+export interface Position {
+    x: number;
+    y: number;
+}
+
+export interface Permissions {
+    canRead: boolean;
+    canWrite: boolean;
+}
+
+export interface Bundle {
+    artifact: string;
+    group: string;
+    version: string;
+}
+
+export interface BulletinEntity {
+    canRead: boolean;
+    id: number;
+    sourceId: string;

Review Comment:
   System bulletins do not have component identity: `BulletinFactory.createBulletin(category, severity, message)` sets no source ID, source name, or group ID. Connector bulletins also explicitly use a null group ID. `DtoFactory` and `EntityFactory` pass those nullable values through unchanged. Please make `sourceId` and `groupId` optional on the envelope, and `sourceId`, `groupId`, and `sourceName` optional inside `bulletin`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16395: Added canonical canvas entity and request contracts [nifi]

Posted by "rfellows (via GitHub)" <gi...@apache.org>.
rfellows commented on code in PR #11733:
URL: https://github.com/apache/nifi/pull/11733#discussion_r4146577424


##########
nifi-frontend/src/main/frontend/libs/shared/src/types/entities/registered-flow-snapshot.ts:
##########
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Bundle, Position } from '../rest-api.types';
+
+/**
+ * Fully typed graph reachable from ProcessGroupEntity.versionedFlowSnapshot.
+ *
+ * @nifi-source: nifi-api/src/main/java/org/apache/nifi/registry/flow/RegisteredFlowSnapshot.java
+ * @nifi-revision: apache/nifi-api@dc575b83e2c0cddf6ac6d3adc51d3448a70654eb
+ * @vetted: 2026-09-29
+ */
+export interface RegisteredFlowSnapshot {
+    snapshotMetadata?: RegisteredFlowSnapshotMetadata;
+    flow?: RegisteredFlow;
+    bucket?: FlowRegistryBucket;
+    flowContents?: VersionedProcessGroup;
+    externalControllerServices?: Record<string, ExternalControllerServiceReference>;
+    parameterContexts?: Record<string, VersionedParameterContext>;
+    flowEncodingVersion?: string;
+    parameterProviders?: Record<string, ParameterProviderReference>;
+    latest: boolean;
+}
+
+export interface RegisteredFlowSnapshotMetadata {
+    registryIdentifier?: string;
+    registryName?: string;
+    branch?: string;
+    bucketIdentifier?: string;
+    flowIdentifier?: string;
+    flowName?: string;
+    version?: string;
+    timestamp: number;
+    author?: string;
+    comments?: string;
+}
+
+export interface RegisteredFlow {
+    identifier?: string;
+    name?: string;
+    description?: string;
+    branch?: string;
+    bucketIdentifier?: string;
+    bucketName?: string;
+    createdTimestamp: number;
+    lastModifiedTimestamp: number;
+    permissions?: FlowRegistryPermissions;
+    versionCount: number;
+    versionInfo?: RegisteredFlowVersionInfo;
+}
+
+export interface RegisteredFlowVersionInfo {
+    version: number;
+}
+
+export interface FlowRegistryBucket {
+    identifier?: string;
+    name?: string;
+    description?: string;
+    createdTimestamp: number;
+    permissions?: FlowRegistryPermissions;
+}
+
+export interface FlowRegistryPermissions {
+    canRead: boolean;
+    canWrite: boolean;
+    canDelete: boolean;
+}
+
+export interface ExternalControllerServiceReference {
+    identifier?: string;
+    name?: string;
+}
+
+export interface ParameterProviderReference {
+    identifier?: string;
+    name?: string;
+    type?: string;
+    bundle?: Bundle;
+}
+
+export type VersionedComponentType =
+    | 'PROCESSOR'
+    | 'CONTROLLER_SERVICE'
+    | 'PROCESS_GROUP'
+    | 'REMOTE_PROCESS_GROUP'
+    | 'INPUT_PORT'
+    | 'OUTPUT_PORT'
+    | 'CONNECTION'
+    | 'FUNNEL'
+    | 'LABEL'
+    | 'REPORTING_TASK'
+    | 'FLOW_REGISTRY_CLIENT'
+    | 'PARAMETER_PROVIDER'
+    | 'FLOW_ANALYSIS_RULE'
+    | 'PARAMETER_CONTEXT'
+    | 'CONNECTOR'
+    | 'REMOTE_INPUT_PORT'
+    | 'REMOTE_OUTPUT_PORT';
+
+export interface VersionedComponent {
+    identifier?: string;
+    instanceIdentifier?: string;
+    groupIdentifier?: string;
+    name?: string;
+    comments?: string;
+    position?: Position;
+    componentType: VersionedComponentType;
+}
+
+export interface VersionedConfigurableExtension extends VersionedComponent {
+    type?: string;
+    bundle?: Bundle;
+    properties?: Record<string, string | null>;
+    propertyDescriptors?: Record<string, VersionedPropertyDescriptor>;
+    componentState?: VersionedComponentState;
+}
+
+export interface VersionedProcessGroup extends VersionedComponent {
+    componentType: 'PROCESS_GROUP';
+    processGroups: VersionedProcessGroup[];
+    remoteProcessGroups: VersionedRemoteProcessGroup[];
+    processors: VersionedProcessor[];
+    inputPorts: VersionedPort[];
+    outputPorts: VersionedPort[];
+    connections: VersionedConnection[];
+    labels: VersionedLabel[];
+    funnels: VersionedFunnel[];
+    controllerServices: VersionedControllerService[];
+    versionedFlowCoordinates?: VersionedFlowCoordinates;
+    parameterContextName?: string;
+    flowFileConcurrency?: string;
+    flowFileOutboundPolicy?: string;
+    defaultFlowFileExpiration?: string;
+    defaultBackPressureObjectThreshold?: number;
+    defaultBackPressureDataSizeThreshold?: string;
+    scheduledState?: ScheduledState;
+    executionEngine?: ExecutionEngine;
+    maxConcurrentTasks?: number;
+    statelessFlowTimeout?: string;
+    statelessFlowFileContentInMemoryMax?: string;
+    statelessFlowFileContentInMemoryHeapPercentage?: number;
+    logFileSuffix?: string;
+}
+
+export interface VersionedFlowCoordinates {
+    registryId?: string;
+    storageLocation?: string;
+    branch?: string;
+    bucketId?: string;
+    flowId?: string;
+    version?: string;
+    latest?: boolean;
+}
+
+export type ScheduledState = 'ENABLED' | 'DISABLED' | 'RUNNING';
+export type ExecutionEngine = 'STATELESS' | 'STANDARD' | 'INHERITED';
+
+export interface VersionedProcessor extends VersionedConfigurableExtension {
+    componentType: 'PROCESSOR';
+    style?: Record<string, string>;
+    annotationData?: string;
+    schedulingPeriod?: string;
+    schedulingStrategy?: string;
+    executionNode?: string;
+    penaltyDuration?: string;
+    yieldDuration?: string;
+    bulletinLevel?: string;
+    runDurationMillis?: number;
+    concurrentlySchedulableTaskCount?: number;
+    autoTerminatedRelationships?: string[];
+    scheduledState?: ScheduledState;
+    retryCount?: number;
+    retriedRelationships?: string[];
+    backoffMechanism?: string;
+    maxBackoffPeriod?: string;
+}
+
+export interface VersionedPort extends VersionedComponent {
+    componentType: 'INPUT_PORT' | 'OUTPUT_PORT';
+    type?: 'INPUT_PORT' | 'OUTPUT_PORT';
+    concurrentlySchedulableTaskCount?: number;
+    scheduledState?: ScheduledState;
+    allowRemoteAccess?: boolean;
+    portFunction?: 'STANDARD' | 'FAILURE';
+}
+
+export interface VersionedConnection extends VersionedComponent {
+    componentType: 'CONNECTION';
+    source?: VersionedConnectableComponent;
+    destination?: VersionedConnectableComponent;
+    labelIndex?: number;
+    zIndex?: number;
+    selectedRelationships?: string[];
+    backPressureObjectThreshold?: number;
+    backPressureDataSizeThreshold?: string;
+    flowFileExpiration?: string;
+    prioritizers?: string[];
+    bends?: Position[];
+    loadBalanceStrategy?: string;
+    partitioningAttribute?: string;
+    loadBalanceCompression?: string;
+}
+
+export interface VersionedConnectableComponent {
+    id?: string;
+    instanceIdentifier?: string;
+    type?: VersionedConnectableComponentType;
+    groupId?: string;
+    name?: string;
+    comments?: string;
+}
+
+export type VersionedConnectableComponentType =
+    | 'PROCESSOR'
+    | 'REMOTE_INPUT_PORT'
+    | 'REMOTE_OUTPUT_PORT'
+    | 'INPUT_PORT'
+    | 'OUTPUT_PORT'
+    | 'FUNNEL';
+
+export interface VersionedRemoteProcessGroup extends VersionedComponent {
+    componentType: 'REMOTE_PROCESS_GROUP';
+    targetUris?: string;
+    communicationsTimeout?: string;
+    yieldDuration?: string;
+    transportProtocol?: string;
+    localNetworkInterface?: string;
+    proxyHost?: string;
+    proxyPort?: number;
+    proxyUser?: string;
+    proxyPassword?: string;
+    inputPorts?: VersionedRemoteGroupPort[];
+    outputPorts?: VersionedRemoteGroupPort[];
+}
+
+export interface VersionedRemoteGroupPort extends VersionedComponent {
+    componentType: 'REMOTE_INPUT_PORT' | 'REMOTE_OUTPUT_PORT';
+    remoteGroupId?: string;
+    concurrentlySchedulableTaskCount?: number;
+    useCompression?: boolean;
+    batchSize?: VersionedBatchSize;
+    targetId?: string;
+    scheduledState?: ScheduledState;
+}
+
+export interface VersionedBatchSize {
+    count?: number;
+    size?: string;
+    duration?: string;
+}
+
+export interface VersionedLabel extends VersionedComponent {
+    componentType: 'LABEL';
+    label?: string;
+    zIndex?: number;
+    width?: number;
+    height?: number;
+    style?: Record<string, string>;
+}
+
+export interface VersionedFunnel extends VersionedComponent {
+    componentType: 'FUNNEL';
+}
+
+export interface VersionedControllerService extends VersionedConfigurableExtension {
+    componentType: 'CONTROLLER_SERVICE';
+    controllerServiceApis?: VersionedControllerServiceApi[];
+    annotationData?: string;
+    scheduledState?: ScheduledState;
+    bulletinLevel?: string;
+}
+
+export interface VersionedControllerServiceApi {
+    type?: string;
+    bundle?: Bundle;
+}
+
+export interface VersionedPropertyDescriptor {
+    name?: string;
+    displayName?: string;
+    identifiesControllerService: boolean;
+    sensitive: boolean;
+    dynamic: boolean;
+    resourceDefinition?: VersionedResourceDefinition;
+    listenPortDefinition?: VersionedListenPortDefinition;
+}
+
+export interface VersionedResourceDefinition {
+    cardinality?: 'SINGLE' | 'MULTIPLE';
+    resourceTypes?: Array<'FILE' | 'DIRECTORY' | 'TEXT' | 'URL'>;
+}
+
+export interface VersionedListenPortDefinition {
+    transportProtocol?: 'TCP' | 'UDP';
+    applicationProtocols?: string[];
+}
+
+export interface VersionedComponentState {
+    clusterState?: Record<string, string>;
+    localNodeStates?: VersionedNodeState[];

Review Comment:
   `localNodeStates` must allow null ordinal placeholders. Clustered component-state export deliberately produces sparse lists: `VersionedComponentFlowMapper` initializes preceding ordinals with null, `TestVersionedComponentFlowMapper.testClusteredExportCapturesBothLocalAndClusterState()` explicitly verifies `[null, VersionedNodeState]`, and `ExportProcessGroupEndpointMerger` preserves/adds null slots. Please change this to `Array<VersionedNodeState | null>` and add a type-focused fixture for the clustered response shape.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org