rfellows commented on code in PR #11144:
URL: https://github.com/apache/nifi/pull/11144#discussion_r3094160847


##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/state/connector-canvas/connector-canvas.effects.ts:
##########
@@ -225,4 +227,36 @@ export class ConnectorCanvasEffects {
             })
         )
     );
+
+    navigateToProvenanceForComponent$ = createEffect(
+        () =>
+            this.actions$.pipe(
+                
ofType(ConnectorCanvasActions.navigateToProvenanceForComponent),
+                map((action) => ({ id: action.id, componentType: 
action.componentType })),
+                concatLatestFrom(() => [
+                    this.store.select(selectConnectorIdFromRoute),
+                    this.store.select(selectProcessGroupIdFromRoute)
+                ]),
+                tap(([{ id: componentId, componentType }, connectorId, 
processGroupId]) => {
+                    this.router.navigate(['/provenance'], {
+                        queryParams: { componentId },
+                        state: {
+                            backNavigation: {
+                                route: [
+                                    '/connectors',
+                                    connectorId,
+                                    'canvas',
+                                    processGroupId,
+                                    componentType,
+                                    componentId
+                                ],
+                                routeBoundary: ['/provenance'],
+                                context: 
this.componentTypeNamePipe.transform(componentType).toLowerCase()

Review Comment:
   The flow designer sets `context: 
this.componentTypeNamePipe.transform(componentType)` (e.g. 'Processor'), but 
the new connector effect appends `.toLowerCase()`, producing 'processor'. This 
means the "Back to ..." nav label would show "Back to processor" instead of 
"Back to Processor" -- inconsistent with the flow designer.



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/ui/connector-canvas/connector-canvas.component.ts:
##########
@@ -67,6 +74,108 @@ export class ConnectorCanvasComponent implements OnInit, 
OnDestroy {
     );
     previewExtensions$: Observable<DocumentedType[]> = of([]);
 
+    private currentUser = this.store.selectSignal(selectCurrentUser);
+    canAccessProvenance = computed(() => 
this.currentUser().provenancePermissions.canRead);
+
+    // 
=========================================================================
+    // Context Menu
+    // 
=========================================================================
+
+    private currentContextMenuContext: ContextMenuContext | null = null;
+
+    contextMenuProvider: ContextMenuDefinitionProvider = {
+        getMenu: (menuId: string): ContextMenuDefinition | undefined => {
+            if (menuId !== 'root') {
+                return undefined;
+            }
+
+            const context = this.currentContextMenuContext;
+            let menuItems: ContextMenuItemDefinition[] = [];
+
+            if (context?.targetType === 'canvas') {
+                menuItems = [
+                    {
+                        text: 'Refresh',
+                        clazz: 'fa fa-refresh',
+                        condition: () => true,
+                        action: () => this.refreshAction(),
+                        shortcut: { control: true, code: 'R' }
+                    },
+                    {
+                        text: 'Leave group',
+                        clazz: 'fa fa-level-up',
+                        condition: () => this.canNavigateToParent,
+                        action: () => this.leaveGroupAction(),
+                        shortcut: { code: 'ESC' }
+                    }
+                ];
+            } else if (context?.targetType === 'component') {
+                const clicked = context.clickedComponent;
+                const isSingleSelection = context.selectedComponents.length <= 
1;
+                const isProcessGroup = clicked?.ui.componentType === 
ComponentType.ProcessGroup;
+                const isConnection = clicked?.ui.componentType === 
ComponentType.Connection;
+                const isProcessor = clicked?.ui.componentType === 
ComponentType.Processor;
+                const isProvenanceTarget =
+                    !!clicked &&
+                    isSingleSelection &&
+                    !isProcessGroup &&
+                    !isConnection &&
+                    clicked.ui.componentType !== 
ComponentType.RemoteProcessGroup &&
+                    clicked.ui.componentType !== ComponentType.Label;
+
+                menuItems = [
+                    {
+                        text: 'Enter group',
+                        clazz: 'fa fa-sign-in',
+                        condition: () => isProcessGroup && isSingleSelection,
+                        action: () => this.enterGroupAction(clicked!.entity.id)
+                    },
+                    { isSeparator: true },
+                    {
+                        text: 'View data provenance',

Review Comment:
   ```suggestion
                           text: 'View Data Provenance',
   ```
   to align with flow designer



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/ui/connector-canvas/connector-canvas.component.ts:
##########
@@ -67,6 +74,108 @@ export class ConnectorCanvasComponent implements OnInit, 
OnDestroy {
     );
     previewExtensions$: Observable<DocumentedType[]> = of([]);
 
+    private currentUser = this.store.selectSignal(selectCurrentUser);
+    canAccessProvenance = computed(() => 
this.currentUser().provenancePermissions.canRead);
+
+    // 
=========================================================================
+    // Context Menu
+    // 
=========================================================================
+
+    private currentContextMenuContext: ContextMenuContext | null = null;
+
+    contextMenuProvider: ContextMenuDefinitionProvider = {
+        getMenu: (menuId: string): ContextMenuDefinition | undefined => {
+            if (menuId !== 'root') {
+                return undefined;
+            }
+
+            const context = this.currentContextMenuContext;
+            let menuItems: ContextMenuItemDefinition[] = [];
+
+            if (context?.targetType === 'canvas') {
+                menuItems = [
+                    {
+                        text: 'Refresh',
+                        clazz: 'fa fa-refresh',
+                        condition: () => true,
+                        action: () => this.refreshAction(),
+                        shortcut: { control: true, code: 'R' }
+                    },
+                    {
+                        text: 'Leave group',
+                        clazz: 'fa fa-level-up',
+                        condition: () => this.canNavigateToParent,
+                        action: () => this.leaveGroupAction(),
+                        shortcut: { code: 'ESC' }
+                    }
+                ];
+            } else if (context?.targetType === 'component') {
+                const clicked = context.clickedComponent;
+                const isSingleSelection = context.selectedComponents.length <= 
1;
+                const isProcessGroup = clicked?.ui.componentType === 
ComponentType.ProcessGroup;
+                const isConnection = clicked?.ui.componentType === 
ComponentType.Connection;
+                const isProcessor = clicked?.ui.componentType === 
ComponentType.Processor;
+                const isProvenanceTarget =
+                    !!clicked &&
+                    isSingleSelection &&
+                    !isProcessGroup &&
+                    !isConnection &&
+                    clicked.ui.componentType !== 
ComponentType.RemoteProcessGroup &&
+                    clicked.ui.componentType !== ComponentType.Label;
+
+                menuItems = [
+                    {
+                        text: 'Enter group',
+                        clazz: 'fa fa-sign-in',
+                        condition: () => isProcessGroup && isSingleSelection,
+                        action: () => this.enterGroupAction(clicked!.entity.id)
+                    },
+                    { isSeparator: true },
+                    {
+                        text: 'View data provenance',
+                        clazz: 'icon icon-provenance',
+                        condition: () => isProvenanceTarget && 
this.canAccessProvenance(),
+                        action: () => 
this.viewDataProvenanceAction(clicked!.entity.id, clicked!.ui.componentType)
+                    },
+                    {
+                        text: 'View state',

Review Comment:
   ```suggestion
                           text: 'View State',
   ```
   to align with flow designer



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/ui/connector-canvas/connector-canvas.component.ts:
##########
@@ -67,6 +74,108 @@ export class ConnectorCanvasComponent implements OnInit, 
OnDestroy {
     );
     previewExtensions$: Observable<DocumentedType[]> = of([]);
 
+    private currentUser = this.store.selectSignal(selectCurrentUser);
+    canAccessProvenance = computed(() => 
this.currentUser().provenancePermissions.canRead);
+
+    // 
=========================================================================
+    // Context Menu
+    // 
=========================================================================
+
+    private currentContextMenuContext: ContextMenuContext | null = null;
+
+    contextMenuProvider: ContextMenuDefinitionProvider = {
+        getMenu: (menuId: string): ContextMenuDefinition | undefined => {
+            if (menuId !== 'root') {
+                return undefined;
+            }
+
+            const context = this.currentContextMenuContext;
+            let menuItems: ContextMenuItemDefinition[] = [];
+
+            if (context?.targetType === 'canvas') {
+                menuItems = [
+                    {
+                        text: 'Refresh',
+                        clazz: 'fa fa-refresh',
+                        condition: () => true,
+                        action: () => this.refreshAction(),
+                        shortcut: { control: true, code: 'R' }
+                    },
+                    {
+                        text: 'Leave group',
+                        clazz: 'fa fa-level-up',
+                        condition: () => this.canNavigateToParent,
+                        action: () => this.leaveGroupAction(),
+                        shortcut: { code: 'ESC' }
+                    }
+                ];
+            } else if (context?.targetType === 'component') {
+                const clicked = context.clickedComponent;
+                const isSingleSelection = context.selectedComponents.length <= 
1;
+                const isProcessGroup = clicked?.ui.componentType === 
ComponentType.ProcessGroup;
+                const isConnection = clicked?.ui.componentType === 
ComponentType.Connection;
+                const isProcessor = clicked?.ui.componentType === 
ComponentType.Processor;
+                const isProvenanceTarget =
+                    !!clicked &&
+                    isSingleSelection &&
+                    !isProcessGroup &&
+                    !isConnection &&
+                    clicked.ui.componentType !== 
ComponentType.RemoteProcessGroup &&
+                    clicked.ui.componentType !== ComponentType.Label;
+
+                menuItems = [
+                    {
+                        text: 'Enter group',
+                        clazz: 'fa fa-sign-in',
+                        condition: () => isProcessGroup && isSingleSelection,
+                        action: () => this.enterGroupAction(clicked!.entity.id)
+                    },
+                    { isSeparator: true },
+                    {
+                        text: 'View data provenance',
+                        clazz: 'icon icon-provenance',
+                        condition: () => isProvenanceTarget && 
this.canAccessProvenance(),
+                        action: () => 
this.viewDataProvenanceAction(clicked!.entity.id, clicked!.ui.componentType)
+                    },
+                    {
+                        text: 'View state',
+                        clazz: 'fa fa-tasks',
+                        condition: () =>
+                            isProcessor &&
+                            isSingleSelection &&
+                            clicked!.entity.component?.persistsState === true 
&&
+                            clicked!.entity.permissions.canRead === true &&
+                            clicked!.entity.permissions.canWrite === true,
+                        action: () => 
this.viewProcessorStateAction(clicked!.entity)
+                    },
+                    { isSeparator: true },
+                    this.getCenterInViewMenuItem()
+                ];
+            }
+
+            return { id: menuId, menuItems };
+        },
+        filterMenuItem: (menuItem: ContextMenuItemDefinition): boolean => {
+            return menuItem.condition ? menuItem.condition(null) : true;
+        },
+        menuItemClicked: (menuItem: ContextMenuItemDefinition, event: 
MouseEvent): void => {
+            menuItem.action?.(null, event);
+        }
+    };
+
+    onContextMenuOpened(context: ContextMenuContext): void {
+        this.currentContextMenuContext = context;
+    }
+
+    private getCenterInViewMenuItem(): ContextMenuItemDefinition {
+        return {
+            text: 'Center in view',

Review Comment:
   ```suggestion
               text: 'Center in View',
   ```
   to align with flow designer



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/ui/connector-canvas/connector-canvas.component.ts:
##########
@@ -67,6 +74,108 @@ export class ConnectorCanvasComponent implements OnInit, 
OnDestroy {
     );
     previewExtensions$: Observable<DocumentedType[]> = of([]);
 
+    private currentUser = this.store.selectSignal(selectCurrentUser);
+    canAccessProvenance = computed(() => 
this.currentUser().provenancePermissions.canRead);
+
+    // 
=========================================================================
+    // Context Menu
+    // 
=========================================================================
+
+    private currentContextMenuContext: ContextMenuContext | null = null;
+
+    contextMenuProvider: ContextMenuDefinitionProvider = {
+        getMenu: (menuId: string): ContextMenuDefinition | undefined => {
+            if (menuId !== 'root') {
+                return undefined;
+            }
+
+            const context = this.currentContextMenuContext;
+            let menuItems: ContextMenuItemDefinition[] = [];
+
+            if (context?.targetType === 'canvas') {
+                menuItems = [
+                    {
+                        text: 'Refresh',
+                        clazz: 'fa fa-refresh',
+                        condition: () => true,
+                        action: () => this.refreshAction(),
+                        shortcut: { control: true, code: 'R' }
+                    },
+                    {
+                        text: 'Leave group',

Review Comment:
   ```suggestion
                           text: 'Leave Group',
   ```
   to align with flow designer



##########
nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/connectors/ui/connector-canvas/connector-canvas.component.ts:
##########
@@ -67,6 +74,108 @@ export class ConnectorCanvasComponent implements OnInit, 
OnDestroy {
     );
     previewExtensions$: Observable<DocumentedType[]> = of([]);
 
+    private currentUser = this.store.selectSignal(selectCurrentUser);
+    canAccessProvenance = computed(() => 
this.currentUser().provenancePermissions.canRead);
+
+    // 
=========================================================================
+    // Context Menu
+    // 
=========================================================================
+
+    private currentContextMenuContext: ContextMenuContext | null = null;
+
+    contextMenuProvider: ContextMenuDefinitionProvider = {
+        getMenu: (menuId: string): ContextMenuDefinition | undefined => {
+            if (menuId !== 'root') {
+                return undefined;
+            }
+
+            const context = this.currentContextMenuContext;
+            let menuItems: ContextMenuItemDefinition[] = [];
+
+            if (context?.targetType === 'canvas') {
+                menuItems = [
+                    {
+                        text: 'Refresh',
+                        clazz: 'fa fa-refresh',
+                        condition: () => true,
+                        action: () => this.refreshAction(),
+                        shortcut: { control: true, code: 'R' }
+                    },
+                    {
+                        text: 'Leave group',
+                        clazz: 'fa fa-level-up',
+                        condition: () => this.canNavigateToParent,
+                        action: () => this.leaveGroupAction(),
+                        shortcut: { code: 'ESC' }
+                    }
+                ];
+            } else if (context?.targetType === 'component') {
+                const clicked = context.clickedComponent;
+                const isSingleSelection = context.selectedComponents.length <= 
1;
+                const isProcessGroup = clicked?.ui.componentType === 
ComponentType.ProcessGroup;
+                const isConnection = clicked?.ui.componentType === 
ComponentType.Connection;
+                const isProcessor = clicked?.ui.componentType === 
ComponentType.Processor;
+                const isProvenanceTarget =
+                    !!clicked &&
+                    isSingleSelection &&
+                    !isProcessGroup &&
+                    !isConnection &&
+                    clicked.ui.componentType !== 
ComponentType.RemoteProcessGroup &&
+                    clicked.ui.componentType !== ComponentType.Label;
+
+                menuItems = [
+                    {
+                        text: 'Enter group',

Review Comment:
   ```suggestion
                           text: 'Enter Group',
   ```
   to align with flow designer



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to