This is an automated email from the ASF dual-hosted git repository.

scottyaslan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 830b7443d5 NIFI-13081: Adding support to edit a label (#8681)
830b7443d5 is described below

commit 830b7443d5f311413658b0453a80db4bff92d918
Author: Matt Gilman <matt.c.gil...@gmail.com>
AuthorDate: Mon Apr 22 16:05:28 2024 -0400

    NIFI-13081: Adding support to edit a label (#8681)
    
    * NIFI-13081:
    - Adding support to edit a label.
    
    * NIFI-13081:
    - Fixing lint issues.
    
    This closes #8681
---
 .../service/canvas-context-menu.service.ts         |   2 +-
 .../pages/flow-designer/state/flow/flow.actions.ts |   5 +
 .../pages/flow-designer/state/flow/flow.effects.ts |  35 +++++++
 .../label/edit-label/edit-label.component.html     |  58 +++++++++++
 .../label/edit-label/edit-label.component.scss     |  26 +++++
 .../label/edit-label/edit-label.component.spec.ts  |  93 +++++++++++++++++
 .../items/label/edit-label/edit-label.component.ts | 116 +++++++++++++++++++++
 7 files changed, 334 insertions(+), 1 deletion(-)

diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts
index 418f9ae54f..8e6ec08eee 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts
@@ -1213,7 +1213,7 @@ export class CanvasContextMenu implements 
ContextMenuDefinitionProvider {
             },
             {
                 condition: (selection: d3.Selection<any, any, any, any>) => {
-                    return this.canvasUtils.isDisconnected(selection);
+                    return this.canvasUtils.isDisconnected(selection) && 
this.canvasUtils.canModify(selection);
                 },
                 clazz: 'fa icon-group',
                 text: 'Group',
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts
index 5f2c30ae9f..c00c48bc3f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts
@@ -426,6 +426,11 @@ export const openEditRemoteProcessGroupDialog = 
createAction(
     props<{ request: EditComponentDialogRequest }>()
 );
 
+export const openEditLabelDialog = createAction(
+    `${CANVAS_PREFIX} Open Edit Label Dialog`,
+    props<{ request: EditComponentDialogRequest }>()
+);
+
 export const navigateToManageRemotePorts = createAction(
     `${CANVAS_PREFIX} Open Remote Process Group Manage Remote Ports`,
     props<{ request: RpgManageRemotePortsRequest }>()
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts
index eb92454cd2..d5f9d96b55 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts
@@ -129,6 +129,7 @@ import { ExtensionTypesService } from 
'../../../../service/extension-types.servi
 import { ChangeComponentVersionDialog } from 
'../../../../ui/common/change-component-version-dialog/change-component-version-dialog';
 import { SnippetService } from '../../service/snippet.service';
 import { selectTransform } from '../transform/transform.selectors';
+import { EditLabel } from 
'../../ui/canvas/items/label/edit-label/edit-label.component';
 
 @Injectable()
 export class FlowEffects {
@@ -1053,6 +1054,8 @@ export class FlowEffects {
                     case ComponentType.InputPort:
                     case ComponentType.OutputPort:
                         return of(FlowActions.openEditPortDialog({ request }));
+                    case ComponentType.Label:
+                        return of(FlowActions.openEditLabelDialog({ request 
}));
                     default:
                         return of(FlowActions.flowApiError({ error: 
'Unsupported type of Component.' }));
                 }
@@ -1119,6 +1122,38 @@ export class FlowEffects {
         { dispatch: false }
     );
 
+    openEditLabelDialog$ = createEffect(
+        () =>
+            this.actions$.pipe(
+                ofType(FlowActions.openEditLabelDialog),
+                map((action) => action.request),
+                tap((request) => {
+                    this.dialog
+                        .open(EditLabel, {
+                            ...MEDIUM_DIALOG,
+                            data: request
+                        })
+                        .afterClosed()
+                        .subscribe(() => {
+                            
this.store.dispatch(FlowActions.clearFlowApiError());
+                            this.store.dispatch(
+                                FlowActions.selectComponents({
+                                    request: {
+                                        components: [
+                                            {
+                                                id: request.entity.id,
+                                                componentType: request.type
+                                            }
+                                        ]
+                                    }
+                                })
+                            );
+                        });
+                })
+            ),
+        { dispatch: false }
+    );
+
     openEditProcessorDialog$ = createEffect(
         () =>
             this.actions$.pipe(
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.html
new file mode 100644
index 0000000000..8e66d176cc
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.html
@@ -0,0 +1,58 @@
+<!--
+  ~ 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.
+  -->
+
+<h2 mat-dialog-title>{{ readonly ? 'Label Details' : 'Edit Label' }}</h2>
+<form class="edit-label-form" [formGroup]="editLabelForm">
+    <error-banner></error-banner>
+    <mat-dialog-content>
+        <div>
+            <mat-form-field>
+                <mat-label>Label Value</mat-label>
+                <textarea matInput formControlName="value" type="text" 
rows="5" [readonly]="readonly"></textarea>
+            </mat-form-field>
+        </div>
+        <div>
+            <mat-form-field subscriptSizing="dynamic">
+                <mat-label>Font Size</mat-label>
+                <mat-select formControlName="fontSize">
+                    @for (option of fontSizeOptions; track option) {
+                        <mat-option [value]="option.value" 
[disabled]="readonly">
+                            {{ option.text }}
+                        </mat-option>
+                    }
+                </mat-select>
+            </mat-form-field>
+        </div>
+    </mat-dialog-content>
+    @if ({ value: (saving$ | async)! }; as saving) {
+        <mat-dialog-actions align="end">
+            @if (readonly) {
+                <button mat-button mat-dialog-close 
color="primary">Close</button>
+            } @else {
+                <button mat-button mat-dialog-close>Cancel</button>
+                <button
+                    [disabled]="!editLabelForm.dirty || editLabelForm.invalid 
|| saving.value"
+                    type="button"
+                    color="primary"
+                    (click)="editLabel()"
+                    mat-button>
+                    <span *nifiSpinner="saving.value">Apply</span>
+                </button>
+            }
+        </mat-dialog-actions>
+    }
+</form>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.scss
new file mode 100644
index 0000000000..425fde60b0
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.scss
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+@use '@angular/material' as mat;
+
+.edit-label-form {
+    @include mat.button-density(-1);
+
+    .mat-mdc-form-field {
+        width: 100%;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.spec.ts
new file mode 100644
index 0000000000..67007081c6
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.spec.ts
@@ -0,0 +1,93 @@
+/*
+ * 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 { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EditLabel } from './edit-label.component';
+import { EditComponentDialogRequest } from '../../../../../state/flow';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ComponentType } from '../../../../../../../state/shared';
+import { provideMockStore } from '@ngrx/store/testing';
+import { initialState } from '../../../../../state/flow/flow.reducer';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { ClusterConnectionService } from 
'../../../../../../../service/cluster-connection.service';
+
+describe('EditLabel', () => {
+    let component: EditLabel;
+    let fixture: ComponentFixture<EditLabel>;
+
+    const data: EditComponentDialogRequest = {
+        type: ComponentType.Label,
+        uri: 
'https://localhost:4200/nifi-api/labels/d7c98831-018e-1000-6a26-6d74b57897e5',
+        entity: {
+            revision: {
+                version: 0
+            },
+            id: 'd7c98831-018e-1000-6a26-6d74b57897e5',
+            uri: 
'https://localhost:4200/nifi-api/labels/d7c98831-018e-1000-6a26-6d74b57897e5',
+            position: {
+                x: 424,
+                y: -432
+            },
+            permissions: {
+                canRead: true,
+                canWrite: true
+            },
+            dimensions: {
+                width: 150,
+                height: 150
+            },
+            zIndex: 4,
+            component: {
+                id: 'd7c98831-018e-1000-6a26-6d74b57897e5',
+                versionedComponentId: 'c99e7867-73c6-3687-8f27-9b1ee5d761c4',
+                parentGroupId: 'f588fccd-018d-1000-e6dd-56d56dead186',
+                position: {
+                    x: 424,
+                    y: -432
+                },
+                width: 150,
+                height: 150,
+                zIndex: 4,
+                style: {}
+            }
+        }
+    };
+
+    beforeEach(() => {
+        TestBed.configureTestingModule({
+            imports: [EditLabel, NoopAnimationsModule],
+            providers: [
+                { provide: MAT_DIALOG_DATA, useValue: data },
+                provideMockStore({ initialState }),
+                {
+                    provide: ClusterConnectionService,
+                    useValue: {
+                        isDisconnectionAcknowledged: jest.fn()
+                    }
+                }
+            ]
+        });
+        fixture = TestBed.createComponent(EditLabel);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.ts
new file mode 100644
index 0000000000..abf2ed0ce9
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/label/edit-label/edit-label.component.ts
@@ -0,0 +1,116 @@
+/*
+ * 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 { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
+import { CanvasState } from '../../../../../state';
+import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators 
} from '@angular/forms';
+import { Store } from '@ngrx/store';
+import { updateComponent } from '../../../../../state/flow/flow.actions';
+import { Client } from '../../../../../../../service/client.service';
+import { EditComponentDialogRequest } from '../../../../../state/flow';
+import { SelectOption } from '../../../../../../../state/shared';
+import { ErrorBanner } from 
'../../../../../../../ui/common/error-banner/error-banner.component';
+import { MatInputModule } from '@angular/material/input';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatButtonModule } from '@angular/material/button';
+import { AsyncPipe } from '@angular/common';
+import { selectSaving } from '../../../../../state/flow/flow.selectors';
+import { NifiSpinnerDirective } from 
'../../../../../../../ui/common/spinner/nifi-spinner.directive';
+import { ClusterConnectionService } from 
'../../../../../../../service/cluster-connection.service';
+import { MatOption } from '@angular/material/autocomplete';
+import { MatSelect } from '@angular/material/select';
+import { NifiTooltipDirective } from 
'../../../../../../../ui/common/tooltips/nifi-tooltip.directive';
+
+@Component({
+    selector: 'edit-label',
+    standalone: true,
+    templateUrl: './edit-label.component.html',
+    imports: [
+        ReactiveFormsModule,
+        ErrorBanner,
+        MatDialogModule,
+        MatInputModule,
+        MatCheckboxModule,
+        MatButtonModule,
+        AsyncPipe,
+        NifiSpinnerDirective,
+        MatOption,
+        MatSelect,
+        NifiTooltipDirective
+    ],
+    styleUrls: ['./edit-label.component.scss']
+})
+export class EditLabel {
+    saving$ = this.store.select(selectSaving);
+
+    editLabelForm: FormGroup;
+    readonly: boolean;
+
+    fontSizeOptions: SelectOption[] = [12, 14, 16, 18, 20, 22, 
24].map((fontSize) => {
+        return {
+            text: `${fontSize}px`,
+            value: `${fontSize}px`
+        };
+    });
+
+    constructor(
+        @Inject(MAT_DIALOG_DATA) public request: EditComponentDialogRequest,
+        private formBuilder: FormBuilder,
+        private store: Store<CanvasState>,
+        private client: Client,
+        private clusterConnectionService: ClusterConnectionService
+    ) {
+        this.readonly = !request.entity.permissions.canWrite;
+
+        let fontSize = this.fontSizeOptions[0].value;
+        if (request.entity.component.style['font-size']) {
+            fontSize = request.entity.component.style['font-size'];
+        }
+
+        // build the form
+        this.editLabelForm = this.formBuilder.group({
+            value: new FormControl(request.entity.component.label, 
Validators.required),
+            fontSize: new FormControl(fontSize, Validators.required)
+        });
+    }
+
+    editLabel() {
+        const payload: any = {
+            revision: this.client.getRevision(this.request.entity),
+            disconnectedNodeAcknowledged: 
this.clusterConnectionService.isDisconnectionAcknowledged(),
+            component: {
+                id: this.request.entity.id,
+                label: this.editLabelForm.get('value')?.value,
+                style: {
+                    'font-size': this.editLabelForm.get('fontSize')?.value
+                }
+            }
+        };
+
+        this.store.dispatch(
+            updateComponent({
+                request: {
+                    id: this.request.entity.id,
+                    type: this.request.type,
+                    uri: this.request.uri,
+                    payload
+                }
+            })
+        );
+    }
+}

Reply via email to