@@ -20,20 +20,40 @@ import { Actions, createEffect, ofType } from '@ngrx/effects';
2020import { concatLatestFrom } from '@ngrx/operators' ;
2121import { Store } from '@ngrx/store' ;
2222import { Router } from '@angular/router' ;
23- import { of } from 'rxjs' ;
23+ import { NEVER , Observable , of } from 'rxjs' ;
2424import { catchError , filter , map , switchMap , take , tap } from 'rxjs/operators' ;
25- import { ComponentType , ComponentTypeNamePipe } from '@nifi/shared' ;
25+ import { ComponentType , ComponentTypeNamePipe , LARGE_DIALOG , MEDIUM_DIALOG , XL_DIALOG } from '@nifi/shared' ;
26+ import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors' ;
27+ import { selectPrioritizerTypes } from '../../../../state/extension-types/extension-types.selectors' ;
28+ import {
29+ selectPropertyVerificationResults ,
30+ selectPropertyVerificationStatus
31+ } from '../../../../state/property-verification/property-verification.selectors' ;
32+ import { MatDialog } from '@angular/material/dialog' ;
2633import { ConnectorService } from '../../service/connector.service' ;
2734import { ErrorHelper } from '../../../../service/error-helper.service' ;
2835import { ErrorContextKey } from '../../../../state/error' ;
2936import { BackNavigation } from '../../../../state/navigation' ;
37+ import { EditComponentDialogRequest , EditConnectionDialogRequest } from '../../../../state/shared' ;
38+ import { EditProcessor } from '../../../../ui/common/component-dialogs/edit-processor/edit-processor.component' ;
39+ import { EditConnectionComponent } from '../../../../ui/common/component-dialogs/edit-connection/edit-connection.component' ;
40+ import { EditPort } from '../../../../ui/common/component-dialogs/edit-port/edit-port.component' ;
41+ import { EditLabel } from '../../../../ui/common/component-dialogs/edit-label/edit-label.component' ;
42+ import { EditProcessGroup } from '../../../../ui/common/component-dialogs/edit-process-group/edit-process-group.component' ;
43+ import { EditRemoteProcessGroup } from '../../../../ui/common/component-dialogs/edit-remote-process-group/edit-remote-process-group.component' ;
3044import * as ConnectorCanvasActions from './connector-canvas.actions' ;
3145import { SelectedComponent } from './connector-canvas.actions' ;
3246import {
47+ selectBreadcrumbs ,
3348 selectConnectorIdFromRoute ,
49+ selectInputPort ,
50+ selectOutputPort ,
3451 selectParentProcessGroupId ,
52+ selectProcessGroup ,
3553 selectProcessGroupId ,
36- selectProcessGroupIdFromRoute
54+ selectProcessGroupIdFromRoute ,
55+ selectProcessor ,
56+ selectRemoteProcessGroup
3757} from './connector-canvas.selectors' ;
3858
3959@Injectable ( )
@@ -44,6 +64,7 @@ export class ConnectorCanvasEffects {
4464 private connectorService = inject ( ConnectorService ) ;
4565 private errorHelper = inject ( ErrorHelper ) ;
4666 private componentTypeNamePipe = inject ( ComponentTypeNamePipe ) ;
67+ private dialog = inject ( MatDialog ) ;
4768
4869 loadConnectorFlow$ = createEffect ( ( ) =>
4970 this . actions$ . pipe (
@@ -228,6 +249,47 @@ export class ConnectorCanvasEffects {
228249 )
229250 ) ;
230251
252+ /**
253+ * Open a read-only configuration dialog for the given canvas component.
254+ * Forces read-only mode by overriding canWrite regardless of entity permissions
255+ * since the connector canvas is a view-only interface.
256+ */
257+ viewComponentConfiguration$ = createEffect (
258+ ( ) =>
259+ this . actions$ . pipe (
260+ ofType ( ConnectorCanvasActions . viewComponentConfiguration ) ,
261+ map ( ( action ) => action . request ) ,
262+ tap ( ( { entity, componentType } ) => {
263+ const dialogRequest = this . buildDialogRequest ( entity , componentType ) ;
264+
265+ switch ( componentType ) {
266+ case ComponentType . Processor :
267+ this . openReadOnlyProcessorDialog ( dialogRequest ) ;
268+ break ;
269+ case ComponentType . Connection :
270+ this . openReadOnlyConnectionDialog ( dialogRequest ) ;
271+ break ;
272+ case ComponentType . InputPort :
273+ case ComponentType . OutputPort :
274+ this . openReadOnlyPortDialog ( dialogRequest ) ;
275+ break ;
276+ case ComponentType . Label :
277+ this . openReadOnlyLabelDialog ( dialogRequest ) ;
278+ break ;
279+ case ComponentType . ProcessGroup :
280+ this . openReadOnlyProcessGroupDialog ( dialogRequest ) ;
281+ break ;
282+ case ComponentType . RemoteProcessGroup :
283+ this . openReadOnlyRemoteProcessGroupDialog ( dialogRequest ) ;
284+ break ;
285+ default :
286+ break ;
287+ }
288+ } )
289+ ) ,
290+ { dispatch : false }
291+ ) ;
292+
231293 navigateToProvenanceForComponent$ = createEffect (
232294 ( ) =>
233295 this . actions$ . pipe (
@@ -259,4 +321,110 @@ export class ConnectorCanvasEffects {
259321 ) ,
260322 { dispatch : false }
261323 ) ;
324+
325+ /**
326+ * Build a dialog request from the supplied entity. The connector canvas surfaces
327+ * configuration in a strictly read-only mode, so the entity permissions are
328+ * forced to readable-only-without-write before being passed to the dialog.
329+ */
330+ private buildDialogRequest ( entity : any , componentType : ComponentType ) : EditComponentDialogRequest {
331+ const readOnlyEntity = {
332+ ...entity ,
333+ permissions : { ...entity ?. permissions , canWrite : false } ,
334+ operatePermissions : { ...entity ?. operatePermissions , canWrite : false }
335+ } ;
336+ return {
337+ type : componentType ,
338+ uri : readOnlyEntity . uri ,
339+ entity : readOnlyEntity
340+ } ;
341+ }
342+
343+ private openReadOnlyProcessorDialog ( request : EditComponentDialogRequest ) : void {
344+ const dialogRef = this . dialog . open ( EditProcessor , {
345+ ...XL_DIALOG ,
346+ data : request ,
347+ id : request . entity . id
348+ } ) ;
349+ const instance = dialogRef . componentInstance ;
350+ instance . saving$ = of ( false ) ;
351+ instance . propertyVerificationResults$ = this . store . select ( selectPropertyVerificationResults ) ;
352+ instance . propertyVerificationStatus$ = this . store . select ( selectPropertyVerificationStatus ) ;
353+
354+ // provide no-op stubs for callbacks not needed in read-only mode
355+ instance . createNewProperty = ( ) => NEVER ;
356+ instance . createNewService = ( ) => NEVER ;
357+ instance . convertToParameter = ( ) => NEVER ;
358+ instance . goToParameter = ( ) => undefined ;
359+ instance . goToService = ( ) => undefined ;
360+ }
361+
362+ private openReadOnlyConnectionDialog ( request : EditComponentDialogRequest ) : void {
363+ const dialogRef = this . dialog . open ( EditConnectionComponent , {
364+ ...LARGE_DIALOG ,
365+ data : request as EditConnectionDialogRequest
366+ } ) ;
367+ const instance = dialogRef . componentInstance ;
368+ instance . saving$ = of ( false ) ;
369+ instance . availablePrioritizers$ = this . store . select ( selectPrioritizerTypes ) ;
370+ instance . breadcrumbs$ = this . store . select ( selectBreadcrumbs ) ;
371+ instance . getChildOutputPorts = ( groupId : string ) : Observable < any > =>
372+ this . store . select ( selectConnectorIdFromRoute ) . pipe (
373+ take ( 1 ) ,
374+ switchMap ( ( connectorId ) =>
375+ this . connectorService
376+ . getConnectorFlow ( connectorId ! , groupId )
377+ . pipe ( map ( ( response : any ) => response . processGroupFlow . flow . outputPorts ) )
378+ )
379+ ) ;
380+ instance . getChildInputPorts = ( groupId : string ) : Observable < any > =>
381+ this . store . select ( selectConnectorIdFromRoute ) . pipe (
382+ take ( 1 ) ,
383+ switchMap ( ( connectorId ) =>
384+ this . connectorService
385+ . getConnectorFlow ( connectorId ! , groupId )
386+ . pipe ( map ( ( response : any ) => response . processGroupFlow . flow . inputPorts ) )
387+ )
388+ ) ;
389+ instance . selectProcessor = ( id : string ) => this . store . select ( selectProcessor ( id ) ) ;
390+ instance . selectInputPort = ( id : string ) => this . store . select ( selectInputPort ( id ) ) ;
391+ instance . selectOutputPort = ( id : string ) => this . store . select ( selectOutputPort ( id ) ) ;
392+ instance . selectProcessGroup = ( id : string ) => this . store . select ( selectProcessGroup ( id ) ) ;
393+ instance . selectRemoteProcessGroup = ( id : string ) => this . store . select ( selectRemoteProcessGroup ( id ) ) ;
394+ }
395+
396+ private openReadOnlyPortDialog ( request : EditComponentDialogRequest ) : void {
397+ const dialogRef = this . dialog . open ( EditPort , {
398+ ...MEDIUM_DIALOG ,
399+ data : request
400+ } ) ;
401+ dialogRef . componentInstance . saving$ = of ( false ) ;
402+ }
403+
404+ private openReadOnlyLabelDialog ( request : EditComponentDialogRequest ) : void {
405+ const dialogRef = this . dialog . open ( EditLabel , {
406+ ...MEDIUM_DIALOG ,
407+ data : request
408+ } ) ;
409+ dialogRef . componentInstance . saving$ = of ( false ) ;
410+ }
411+
412+ private openReadOnlyProcessGroupDialog ( request : EditComponentDialogRequest ) : void {
413+ const dialogRef = this . dialog . open ( EditProcessGroup , {
414+ ...LARGE_DIALOG ,
415+ data : request
416+ } ) ;
417+ const instance = dialogRef . componentInstance ;
418+ instance . saving$ = of ( false ) ;
419+ instance . currentUser$ = this . store . select ( selectCurrentUser ) ;
420+ instance . parameterContexts = [ ] ;
421+ }
422+
423+ private openReadOnlyRemoteProcessGroupDialog ( request : EditComponentDialogRequest ) : void {
424+ const dialogRef = this . dialog . open ( EditRemoteProcessGroup , {
425+ ...LARGE_DIALOG ,
426+ data : request
427+ } ) ;
428+ dialogRef . componentInstance . saving$ = of ( false ) ;
429+ }
262430}
0 commit comments