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 7ec2dd07c9 NIFI-12734: Import from Registry (#8354) 7ec2dd07c9 is described below commit 7ec2dd07c9d3fe7ca2239c4d0950fa81e825c136 Author: Matt Gilman <matt.c.gil...@gmail.com> AuthorDate: Wed Feb 7 12:02:13 2024 -0500 NIFI-12734: Import from Registry (#8354) * NIFI-12734: - Import from Registry. * NIFI-12734: - Providing better guidance when there are no registry clients available based on user permissions. - Showing form validation errors when there are no buckets or no flows. This closes #8354 --- .../flow-designer/service/registry.service.ts | 58 ++++ .../pages/flow-designer/state/flow/flow.actions.ts | 14 +- .../pages/flow-designer/state/flow/flow.effects.ts | 115 ++++++- .../app/pages/flow-designer/state/flow/index.ts | 15 + .../ui/canvas/header/header.component.html | 5 + .../new-canvas-item/new-canvas-item.component.scss | 29 +- .../import-from-registry.component.html | 154 ++++++++++ .../import-from-registry.component.scss} | 34 ++- .../import-from-registry.component.spec.ts | 136 +++++++++ .../import-from-registry.component.ts | 337 +++++++++++++++++++++ .../no-registry-clients-dialog.component.html} | 20 +- .../no-registry-clients-dialog.component.scss} | 21 +- .../no-registry-clients-dialog.component.spec.ts | 50 +++ .../no-registry-clients-dialog.component.ts} | 33 +- .../settings/service/registry-client.service.ts | 5 +- .../pages/settings/state/registry-clients/index.ts | 12 +- .../registry-clients/registry-clients.selectors.ts | 3 +- .../registry-client-table.component.ts | 3 +- .../registry-clients/registry-clients.component.ts | 3 +- .../flow-configuration.selectors.ts | 5 + .../src/main/nifi/src/app/state/shared/index.ts | 54 +++- .../ui/common/ok-dialog/ok-dialog.component.html | 2 +- .../nifi/src/assets/fonts/flowfont/flowfont.css | 21 +- .../nifi/src/assets/fonts/flowfont/flowfont.eot | Bin 25120 -> 25276 bytes .../nifi/src/assets/fonts/flowfont/flowfont.svg | 68 +++-- .../nifi/src/assets/fonts/flowfont/flowfont.ttf | Bin 24952 -> 25108 bytes .../nifi/src/assets/fonts/flowfont/flowfont.woff | Bin 12664 -> 13660 bytes .../nifi/src/assets/fonts/flowfont/flowfont.woff2 | Bin 10780 -> 11600 bytes 28 files changed, 1069 insertions(+), 128 deletions(-) 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/registry.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/registry.service.ts new file mode 100644 index 0000000000..971fb4b455 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/registry.service.ts @@ -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. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { ImportFromRegistryRequest } from '../state/flow'; + +@Injectable({ providedIn: 'root' }) +export class RegistryService { + private static readonly API: string = '../nifi-api'; + + constructor(private httpClient: HttpClient) {} + + getRegistryClients(): Observable<any> { + return this.httpClient.get(`${RegistryService.API}/flow/registries`); + } + + getBuckets(registryId: string): Observable<any> { + return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets`); + } + + getFlows(registryId: string, bucketId: string): Observable<any> { + return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows`); + } + + getFlowVersions(registryId: string, bucketId: string, flowId: string): Observable<any> { + return this.httpClient.get( + `${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows/${flowId}/versions` + ); + } + + importFromRegistry(processGroupId: string, request: ImportFromRegistryRequest): Observable<any> { + return this.httpClient.post( + `${RegistryService.API}/process-groups/${processGroupId}/process-groups`, + request.payload, + { + params: { + parameterContextHandlingStrategy: request.keepExistingParameterContext ? 'KEEP_EXISTING' : 'REPLACE' + } + } + ); + } +} 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 53f7f10f2d..8b79c0bcc8 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 @@ -71,7 +71,9 @@ import { NavigateToQueueListing, StartProcessGroupResponse, StopProcessGroupResponse, - CenterComponentRequest + CenterComponentRequest, + ImportFromRegistryDialogRequest, + ImportFromRegistryRequest } from './index'; import { StatusHistoryRequest } from '../../../../state/status-history'; @@ -275,6 +277,16 @@ export const openNewPortDialog = createAction( export const createPort = createAction(`${CANVAS_PREFIX} Create Port`, props<{ request: CreatePortRequest }>()); +export const openImportFromRegistryDialog = createAction( + `${CANVAS_PREFIX} Open Import From Registry Dialog`, + props<{ request: ImportFromRegistryDialogRequest }>() +); + +export const importFromRegistry = createAction( + `${CANVAS_PREFIX} Import From Registry`, + props<{ request: ImportFromRegistryRequest }>() +); + export const createComponentSuccess = createAction( `${CANVAS_PREFIX} Create Component Success`, props<{ response: CreateComponentResponse }>() 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 05ca83d1f3..d77eb0cc08 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 @@ -40,6 +40,7 @@ import { CreateProcessGroupDialogRequest, DeleteComponentResponse, GroupComponentsDialogRequest, + ImportFromRegistryDialogRequest, LoadProcessGroupRequest, LoadProcessGroupResponse, Snippet, @@ -63,7 +64,13 @@ import { ConnectionManager } from '../../service/manager/connection-manager.serv import { MatDialog } from '@angular/material/dialog'; import { CreatePort } from '../../ui/canvas/items/port/create-port/create-port.component'; import { EditPort } from '../../ui/canvas/items/port/edit-port/edit-port.component'; -import { ComponentType } from '../../../../state/shared'; +import { + BucketEntity, + ComponentType, + RegistryClientEntity, + VersionedFlowEntity, + VersionedFlowSnapshotMetadataEntity +} from '../../../../state/shared'; import { Router } from '@angular/router'; import { Client } from '../../../../service/client.service'; import { CanvasUtils } from '../../service/canvas-utils.service'; @@ -83,6 +90,10 @@ import { ControllerServiceService } from '../../service/controller-service.servi import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; import { PropertyTableHelperService } from '../../../../service/property-table-helper.service'; import { ParameterHelperService } from '../../service/parameter-helper.service'; +import { RegistryService } from '../../service/registry.service'; +import { ImportFromRegistry } from '../../ui/canvas/items/flow/import-from-registry/import-from-registry.component'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { NoRegistryClientsDialog } from '../../ui/common/no-registry-clients-dialog/no-registry-clients-dialog.component'; @Injectable() export class FlowEffects { @@ -91,6 +102,7 @@ export class FlowEffects { private store: Store<NiFiState>, private flowService: FlowService, private controllerServiceService: ControllerServiceService, + private registryService: RegistryService, private client: Client, private canvasUtils: CanvasUtils, private canvasView: CanvasView, @@ -217,6 +229,18 @@ export class FlowEffects { case ComponentType.InputPort: case ComponentType.OutputPort: return of(FlowActions.openNewPortDialog({ request })); + case ComponentType.Flow: + return from(this.registryService.getRegistryClients()).pipe( + map((response) => { + const dialogRequest: ImportFromRegistryDialogRequest = { + request, + registryClients: response.registries + }; + + return FlowActions.openImportFromRegistryDialog({ request: dialogRequest }); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); default: return of(FlowActions.flowApiError({ error: 'Unsupported type of Component.' })); } @@ -587,6 +611,95 @@ export class FlowEffects { ) ); + openImportFromRegistryDialog$ = createEffect( + () => + this.actions$.pipe( + ofType(FlowActions.openImportFromRegistryDialog), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectCurrentUser)), + tap(([request, currentUser]) => { + const someRegistries = request.registryClients.some( + (registryClient: RegistryClientEntity) => registryClient.permissions.canRead + ); + + if (someRegistries) { + const dialogReference = this.dialog.open(ImportFromRegistry, { + data: request, + panelClass: 'medium-dialog' + }); + + dialogReference.componentInstance.getBuckets = ( + registryId: string + ): Observable<BucketEntity[]> => { + return this.registryService.getBuckets(registryId).pipe( + take(1), + map((response) => response.buckets) + ); + }; + + dialogReference.componentInstance.getFlows = ( + registryId: string, + bucketId: string + ): Observable<VersionedFlowEntity[]> => { + return this.registryService.getFlows(registryId, bucketId).pipe( + take(1), + map((response) => response.versionedFlows) + ); + }; + + dialogReference.componentInstance.getFlowVersions = ( + registryId: string, + bucketId: string, + flowId: string + ): Observable<VersionedFlowSnapshotMetadataEntity[]> => { + return this.registryService.getFlowVersions(registryId, bucketId, flowId).pipe( + take(1), + map((response) => response.versionedFlowSnapshotMetadataSet) + ); + }; + + dialogReference.afterClosed().subscribe(() => { + this.store.dispatch(FlowActions.setDragging({ dragging: false })); + }); + } else { + this.dialog + .open(NoRegistryClientsDialog, { + data: { + controllerPermissions: currentUser.controllerPermissions + }, + panelClass: 'medium-dialog' + }) + .afterClosed() + .subscribe(() => { + this.store.dispatch(FlowActions.setDragging({ dragging: false })); + }); + } + }) + ), + { dispatch: false } + ); + + importFromRegistry$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.importFromRegistry), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + switchMap(([request, processGroupId]) => + from(this.registryService.importFromRegistry(processGroupId, request)).pipe( + map((response) => + FlowActions.createComponentSuccess({ + response: { + type: ComponentType.ProcessGroup, + payload: response + } + }) + ), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ) + ) + ) + ); + createComponentSuccess$ = createEffect(() => this.actions$.pipe( ofType(FlowActions.createComponentSuccess), 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/index.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/index.ts index 1352c36e2b..bb4f9ddb70 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/index.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/index.ts @@ -23,6 +23,7 @@ import { DocumentedType, ParameterContextReferenceEntity, Permissions, + RegistryClientEntity, Revision, SelectOption } from '../../../../state/shared'; @@ -165,6 +166,20 @@ export interface CreateProcessGroupDialogRequest { parameterContexts: ParameterContextEntity[]; } +export interface NoRegistryClientsDialogRequest { + controllerPermissions: Permissions; +} + +export interface ImportFromRegistryDialogRequest { + request: CreateComponentRequest; + registryClients: RegistryClientEntity[]; +} + +export interface ImportFromRegistryRequest { + payload: any; + keepExistingParameterContext: boolean; +} + export interface OpenGroupComponentsDialogRequest { position: Position; moveComponents: MoveComponentRequest[]; 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/header/header.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/header/header.component.html index 963b88a462..2eb6996f03 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/header.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/header/header.component.html @@ -48,6 +48,11 @@ [disabled]="!canvasPermissions.canWrite" iconClass="icon-funnel" iconHoverClass="icon-funnel-add"></new-canvas-item> + <new-canvas-item + [type]="ComponentType.Flow" + [disabled]="!canvasPermissions.canWrite" + iconClass="icon-import-from-registry" + iconHoverClass="icon-import-from-registry-add"></new-canvas-item> <new-canvas-item [type]="ComponentType.Label" [disabled]="!canvasPermissions.canWrite" 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/header/new-canvas-item/new-canvas-item.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/header/new-canvas-item/new-canvas-item.component.scss index e0695991a6..f02f654e26 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.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/header/new-canvas-item/new-canvas-item.component.scss @@ -15,23 +15,24 @@ * limitations under the License. */ -.icon { - font-size: 32px; +.new-canvas-item { + .icon { + font-size: 32px; - &.hovering { - cursor: move; - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; - } + &.hovering { + cursor: grab; + } + + &.dragging { + cursor: grabbing; + } - &.dragging { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; + &:disabled { + box-shadow: none; + } } - &:disabled { - box-shadow: none; + .icon-import-from-registry-add:before { + margin-left: 1px; } } 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/flow/import-from-registry/import-from-registry.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/flow/import-from-registry/import-from-registry.component.html new file mode 100644 index 0000000000..54b9222806 --- /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/flow/import-from-registry/import-from-registry.component.html @@ -0,0 +1,154 @@ +<!-- + ~ 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>Import From Registry</h2> +<form class="import-from-registry-form" [formGroup]="importFromRegistryForm"> + <error-banner></error-banner> + <mat-dialog-content> + <mat-form-field> + <mat-label>Registry</mat-label> + <mat-select formControlName="registry" (selectionChange)="registryChanged($event.value)"> + <ng-container *ngFor="let option of registryClientOptions"> + <ng-container *ngIf="option.description; else noDescription"> + <mat-option + [value]="option.value" + nifiTooltip + [tooltipComponentType]="TextTip" + [tooltipInputData]="getSelectOptionTipData(option)" + [delayClose]="false" + >{{ option.text }}</mat-option + > + </ng-container> + <ng-template #noDescription> + <mat-option [value]="option.value">{{ option.text }}</mat-option> + </ng-template> + </ng-container> + </mat-select> + </mat-form-field> + <mat-form-field> + <mat-label>Bucket</mat-label> + <mat-select formControlName="bucket" (selectionChange)="bucketChanged($event.value)"> + <ng-container *ngFor="let option of bucketOptions"> + <ng-container *ngIf="option.description; else noDescription"> + <mat-option + [value]="option.value" + nifiTooltip + [tooltipComponentType]="TextTip" + [tooltipInputData]="getSelectOptionTipData(option)" + [delayClose]="false" + >{{ option.text }}</mat-option + > + </ng-container> + <ng-template #noDescription> + <mat-option [value]="option.value">{{ option.text }}</mat-option> + </ng-template> + </ng-container> + </mat-select> + <mat-error *ngIf="importFromRegistryForm.controls['bucket'].hasError('required')" + >No buckets available</mat-error + > + </mat-form-field> + <mat-form-field> + <mat-label>Flow</mat-label> + <mat-select formControlName="flow" (selectionChange)="flowChanged($event.value)"> + <ng-container *ngFor="let option of flowOptions"> + <ng-container *ngIf="option.description; else noDescription"> + <mat-option + [value]="option.value" + nifiTooltip + [tooltipComponentType]="TextTip" + [tooltipInputData]="getSelectOptionTipData(option)" + [delayClose]="false" + >{{ option.text }}</mat-option + > + </ng-container> + <ng-template #noDescription> + <mat-option [value]="option.value">{{ option.text }}</mat-option> + </ng-template> + </ng-container> + </mat-select> + <mat-error *ngIf="importFromRegistryForm.controls['flow'].hasError('required')" + >No flows available</mat-error + > + </mat-form-field> + <div class="mb-5"> + <mat-checkbox color="primary" formControlName="keepParameterContexts"> + Keep existing Parameter Contexts + </mat-checkbox> + </div> + <div class="flex flex-col mb-5"> + <div>Flow Description</div> + <div class="value">{{ selectedFlowDescription || 'No description provided' }}</div> + </div> + <div class="listing-table"> + <div class="h-48 overflow-y-auto overflow-x-hidden border"> + <table + mat-table + [dataSource]="dataSource" + matSort + matSortDisableClear + (matSortChange)="sortData($event)" + [matSortActive]="sort.active" + [matSortDirection]="sort.direction"> + <!-- Version Column --> + <ng-container matColumnDef="version"> + <th mat-header-cell *matHeaderCellDef mat-sort-header>Version</th> + <td mat-cell *matCellDef="let item"> + {{ item.version }} + </td> + </ng-container> + + <!-- Create Column --> + <ng-container matColumnDef="created"> + <th mat-header-cell *matHeaderCellDef mat-sort-header>Created</th> + <td mat-cell *matCellDef="let item"> + {{ formatTimestamp(item) }} + </td> + </ng-container> + + <!-- Comments Column --> + <ng-container matColumnDef="comments"> + <th mat-header-cell *matHeaderCellDef mat-sort-header>Comments</th> + <td mat-cell *matCellDef="let item"> + {{ item.comments }} + </td> + </ng-container> + + <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> + <tr + mat-row + *matRowDef="let row; let even = even; columns: displayedColumns" + (click)="select(row)" + (dblclick)="importFromRegistry()" + [class.selected]="isSelected(row)" + [class.even]="even"></tr> + </table> + </div> + </div> + </mat-dialog-content> + <mat-dialog-actions align="end" *ngIf="{ value: (saving$ | async)! } as saving"> + <button color="primary" mat-stroked-button mat-dialog-close>Cancel</button> + <button + [disabled]="importFromRegistryForm.invalid || saving.value" + type="button" + color="primary" + (click)="importFromRegistry()" + mat-raised-button> + <span *nifiSpinner="saving.value">Import</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/header/new-canvas-item/new-canvas-item.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/flow/import-from-registry/import-from-registry.component.scss similarity index 63% copy from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.scss copy to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/flow/import-from-registry/import-from-registry.component.scss index e0695991a6..bba2634bef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.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/flow/import-from-registry/import-from-registry.component.scss @@ -15,23 +15,31 @@ * limitations under the License. */ -.icon { - font-size: 32px; +@use '@angular/material' as mat; - &.hovering { - cursor: move; - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; +.import-from-registry-form { + @include mat.button-density(-1); + + .mat-mdc-form-field { + width: 100%; } - &.dragging { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; + .mat-mdc-form-field-error { + font-size: 12px; } - &:disabled { - box-shadow: none; + .listing-table { + table { + width: auto; + table-layout: unset; + + .mat-column-version { + width: 75px; + } + + .mat-column-created { + width: 200px; + } + } } } 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/flow/import-from-registry/import-from-registry.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/flow/import-from-registry/import-from-registry.component.spec.ts new file mode 100644 index 0000000000..bdcb15836e --- /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/flow/import-from-registry/import-from-registry.component.spec.ts @@ -0,0 +1,136 @@ +/* + * 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 { ImportFromRegistry } from './import-from-registry.component'; +import { ImportFromRegistryDialogRequest } 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 { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { EMPTY } from 'rxjs'; + +describe('ImportFromRegistry', () => { + let component: ImportFromRegistry; + let fixture: ComponentFixture<ImportFromRegistry>; + + const data: ImportFromRegistryDialogRequest = { + request: { + revision: { + clientId: '88cd6620-bd6d-41fa-aa5a-be2b33501e31', + version: 0 + }, + type: ComponentType.Flow, + position: { + x: 461, + y: 58 + } + }, + registryClients: [ + { + revision: { + version: 0 + }, + id: '6a088515-018d-1000-ce79-5ae44266bc20', + uri: 'https://localhost:4200/nifi-api/controller/registry-clients/6a088515-018d-1000-ce79-5ae44266bc20', + permissions: { + canRead: true, + canWrite: true + }, + component: { + id: '6a088515-018d-1000-ce79-5ae44266bc20', + name: 'My Registry', + description: '', + type: 'org.apache.nifi.registry.flow.NifiRegistryFlowRegistryClient', + bundle: { + group: 'org.apache.nifi', + artifact: 'nifi-flow-registry-client-nar', + version: '2.0.0-SNAPSHOT' + }, + properties: { + url: 'http://localhost:18080/nifi-registry', + 'ssl-context-service': null + }, + descriptors: { + url: { + name: 'url', + displayName: 'URL', + description: 'URL of the NiFi Registry', + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 'ssl-context-service': { + name: 'ssl-context-service', + displayName: 'SSL Context Service', + description: 'Specifies the SSL Context Service to use for communicating with NiFiRegistry', + allowableValues: [], + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + identifiesControllerService: 'org.apache.nifi.ssl.SSLContextService', + identifiesControllerServiceBundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + }, + dependencies: [] + } + }, + supportsSensitiveDynamicProperties: false, + restricted: false, + deprecated: false, + validationStatus: 'VALID', + multipleVersionsAvailable: false, + extensionMissing: false + } + } + ] + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ImportFromRegistry, BrowserAnimationsModule], + providers: [{ provide: MAT_DIALOG_DATA, useValue: data }, provideMockStore({ initialState })] + }); + fixture = TestBed.createComponent(ImportFromRegistry); + component = fixture.componentInstance; + + component.getBuckets = () => { + return EMPTY; + }; + component.getFlows = () => { + return EMPTY; + }; + component.getFlowVersions = () => { + return EMPTY; + }; + + 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/flow/import-from-registry/import-from-registry.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/flow/import-from-registry/import-from-registry.component.ts new file mode 100644 index 0000000000..3496b0512f --- /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/flow/import-from-registry/import-from-registry.component.ts @@ -0,0 +1,337 @@ +/* + * 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, Input, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { ImportFromRegistryDialogRequest } from '../../../../../state/flow'; +import { Store } from '@ngrx/store'; +import { CanvasState } from '../../../../../state'; +import { + BucketEntity, + isDefinedAndNotNull, + RegistryClientEntity, + SelectOption, + TextTipInput, + VersionedFlow, + VersionedFlowEntity, + VersionedFlowSnapshotMetadata, + VersionedFlowSnapshotMetadataEntity +} from '../../../../../../../state/shared'; +import { selectSaving } from '../../../../../state/flow/flow.selectors'; +import { AsyncPipe, JsonPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; +import { ErrorBanner } from '../../../../../../../ui/common/error-banner/error-banner.component'; +import { MatButtonModule } from '@angular/material/button'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatOptionModule } from '@angular/material/core'; +import { MatSelectModule } from '@angular/material/select'; +import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nifi-spinner.directive'; +import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; +import { TextTip } from '../../../../../../../ui/common/tooltips/text-tip/text-tip.component'; +import { NifiTooltipDirective } from '../../../../../../../ui/common/tooltips/nifi-tooltip.directive'; +import { MatIconModule } from '@angular/material/icon'; +import { Observable, take } from 'rxjs'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatTableDataSource, MatTableModule } from '@angular/material/table'; +import { MatSortModule, Sort } from '@angular/material/sort'; +import { NiFiCommon } from '../../../../../../../service/nifi-common.service'; +import { selectTimeOffset } from '../../../../../../../state/flow-configuration/flow-configuration.selectors'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { Client } from '../../../../../../../service/client.service'; +import { importFromRegistry } from '../../../../../state/flow/flow.actions'; + +@Component({ + selector: 'import-from-registry', + standalone: true, + imports: [ + AsyncPipe, + ErrorBanner, + MatButtonModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule, + NgIf, + NifiSpinnerDirective, + ReactiveFormsModule, + MatOptionModule, + MatSelectModule, + NgForOf, + NifiTooltipDirective, + MatIconModule, + NgTemplateOutlet, + JsonPipe, + MatCheckboxModule, + MatSortModule, + MatTableModule + ], + templateUrl: './import-from-registry.component.html', + styleUrls: ['./import-from-registry.component.scss'] +}) +export class ImportFromRegistry implements OnInit { + @Input() getBuckets!: (registryId: string) => Observable<BucketEntity[]>; + @Input() getFlows!: (registryId: string, bucketId: string) => Observable<VersionedFlowEntity[]>; + @Input() getFlowVersions!: ( + registryId: string, + bucketId: string, + flowId: string + ) => Observable<VersionedFlowSnapshotMetadataEntity[]>; + + saving$ = this.store.select(selectSaving); + timeOffset = 0; + + protected readonly TextTip = TextTip; + + importFromRegistryForm: FormGroup; + registryClientOptions: SelectOption[] = []; + bucketOptions: SelectOption[] = []; + flowOptions: SelectOption[] = []; + + flowLookup: Map<string, VersionedFlow> = new Map<string, VersionedFlow>(); + selectedFlowDescription: string | undefined; + + sort: Sort = { + active: 'version', + direction: 'desc' + }; + displayedColumns: string[] = ['version', 'created', 'comments']; + dataSource: MatTableDataSource<VersionedFlowSnapshotMetadata> = + new MatTableDataSource<VersionedFlowSnapshotMetadata>(); + selectedFlowVersion: number | null = null; + + constructor( + @Inject(MAT_DIALOG_DATA) private dialogRequest: ImportFromRegistryDialogRequest, + private formBuilder: FormBuilder, + private store: Store<CanvasState>, + private nifiCommon: NiFiCommon, + private client: Client + ) { + this.store + .select(selectTimeOffset) + .pipe(isDefinedAndNotNull(), takeUntilDestroyed()) + .subscribe((timeOffset: number) => { + this.timeOffset = timeOffset; + }); + + const sortedRegistries = dialogRequest.registryClients.slice().sort((a, b) => { + return this.nifiCommon.compareString(a.component.name, b.component.name); + }); + + sortedRegistries.forEach((registryClient: RegistryClientEntity) => { + if (registryClient.permissions.canRead) { + this.registryClientOptions.push({ + text: registryClient.component.name, + value: registryClient.id, + description: registryClient.component.description + }); + } + }); + + this.importFromRegistryForm = this.formBuilder.group({ + registry: new FormControl(this.registryClientOptions[0].value, Validators.required), + bucket: new FormControl(null, Validators.required), + flow: new FormControl(null, Validators.required), + keepParameterContexts: new FormControl(true, Validators.required) + }); + } + + ngOnInit(): void { + const selectedRegistryId = this.importFromRegistryForm.get('registry')?.value; + + if (selectedRegistryId) { + this.loadBuckets(selectedRegistryId); + } + } + + getSelectOptionTipData(option: SelectOption): TextTipInput { + return { + // @ts-ignore + text: option.description + }; + } + + registryChanged(registryId: string): void { + this.loadBuckets(registryId); + } + + bucketChanged(bucketId: string): void { + const registryId = this.importFromRegistryForm.get('registry')?.value; + this.loadFlows(registryId, bucketId); + } + + flowChanged(flowId: string): void { + const registryId = this.importFromRegistryForm.get('registry')?.value; + const bucketId = this.importFromRegistryForm.get('bucket')?.value; + this.loadVersions(registryId, bucketId, flowId); + } + + loadBuckets(registryId: string): void { + this.bucketOptions = []; + + this.getBuckets(registryId) + .pipe(take(1)) + .subscribe((buckets: BucketEntity[]) => { + if (buckets.length > 0) { + buckets.forEach((entity: BucketEntity) => { + if (entity.permissions.canRead) { + this.bucketOptions.push({ + text: entity.bucket.name, + value: entity.id, + description: entity.bucket.description + }); + } + }); + + const bucketId = this.bucketOptions[0].value; + if (bucketId) { + this.importFromRegistryForm.get('bucket')?.setValue(bucketId); + this.loadFlows(registryId, bucketId); + } + } + }); + } + + loadFlows(registryId: string, bucketId: string): void { + this.flowOptions = []; + this.flowLookup.clear(); + + this.getFlows(registryId, bucketId) + .pipe(take(1)) + .subscribe((versionedFlows: VersionedFlowEntity[]) => { + if (versionedFlows.length > 0) { + versionedFlows.forEach((entity: VersionedFlowEntity) => { + this.flowLookup.set(entity.versionedFlow.flowId, entity.versionedFlow); + + this.flowOptions.push({ + text: entity.versionedFlow.flowName, + value: entity.versionedFlow.flowId, + description: entity.versionedFlow.description + }); + }); + + const flowId = this.flowOptions[0].value; + if (flowId) { + this.importFromRegistryForm.get('flow')?.setValue(flowId); + this.loadVersions(registryId, bucketId, flowId); + } + } + }); + } + + loadVersions(registryId: string, bucketId: string, flowId: string): void { + this.dataSource.data = []; + this.selectedFlowDescription = this.flowLookup.get(flowId)?.description; + + this.getFlowVersions(registryId, bucketId, flowId) + .pipe(take(1)) + .subscribe((metadataEntities: VersionedFlowSnapshotMetadataEntity[]) => { + if (metadataEntities.length > 0) { + const flowVersions = metadataEntities.map( + (entity: VersionedFlowSnapshotMetadataEntity) => entity.versionedFlowSnapshotMetadata + ); + + const sortedFlowVersions = this.sortVersions(flowVersions, this.sort); + this.selectedFlowVersion = sortedFlowVersions[0].version; + + this.dataSource.data = sortedFlowVersions; + } + }); + } + + formatTimestamp(flowVersion: VersionedFlowSnapshotMetadata) { + // get the current user time to properly convert the server time + const now: Date = new Date(); + + // convert the user offset to millis + const userTimeOffset: number = now.getTimezoneOffset() * 60 * 1000; + + // create the proper date by adjusting by the offsets + const date: Date = new Date(flowVersion.timestamp + userTimeOffset + this.timeOffset); + return this.nifiCommon.formatDateTime(date); + } + + sortData(sort: Sort) { + this.sort = sort; + this.dataSource.data = this.sortVersions(this.dataSource.data, sort); + } + + sortVersions(data: VersionedFlowSnapshotMetadata[], sort: Sort): VersionedFlowSnapshotMetadata[] { + if (!data) { + return []; + } + return data.slice().sort((a, b) => { + const isAsc = sort.direction === 'asc'; + let retVal = 0; + switch (sort.active) { + case 'version': + retVal = this.nifiCommon.compareNumber(a.version, b.version); + break; + case 'created': + retVal = this.nifiCommon.compareNumber(a.timestamp, b.timestamp); + break; + case 'comments': + retVal = this.nifiCommon.compareString(a.comments, b.comments); + break; + } + return retVal * (isAsc ? 1 : -1); + }); + } + + select(flowVersion: VersionedFlowSnapshotMetadata): void { + this.selectedFlowVersion = flowVersion.version; + } + + isSelected(flowVersion: VersionedFlowSnapshotMetadata): boolean { + if (this.selectedFlowVersion) { + return flowVersion.version == this.selectedFlowVersion; + } + return false; + } + + importFromRegistry(): void { + if (this.selectedFlowVersion != null) { + const payload: any = { + revision: this.client.getRevision({ + revision: { + version: 0 + } + }), + // disconnectedNodeAcknowledged: nfStorage.isDisconnectionAcknowledged(), + component: { + position: { + x: this.dialogRequest.request.position.x, + y: this.dialogRequest.request.position.y + }, + versionControlInformation: { + registryId: this.importFromRegistryForm.get('registry')?.value, + bucketId: this.importFromRegistryForm.get('bucket')?.value, + flowId: this.importFromRegistryForm.get('flow')?.value, + version: this.selectedFlowVersion + } + } + }; + + this.store.dispatch( + importFromRegistry({ + request: { + payload, + keepExistingParameterContext: this.importFromRegistryForm.get('keepParameterContexts')?.value + } + }) + ); + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.html similarity index 52% copy from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.component.html copy to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/no-registry-clients-dialog/no-registry-clients-dialog.component.html index 76f19dd22d..e6fa0fc55c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.html @@ -15,10 +15,24 @@ ~ limitations under the License. --> -<h2 mat-dialog-title>{{ request.title }}</h2> +<h2 mat-dialog-title>No Registry clients available</h2> <mat-dialog-content> - <div class="text-sm">{{ request.message }}</div> + <div class="text-sm max-w-sm"> + {{ + request.controllerPermissions.canRead + ? 'In order to import a flow a Registry Client must be configured in Controller Settings.' + : 'Cannot import a Flow because there are no available Registry Clients.' + }} + </div> </mat-dialog-content> <mat-dialog-actions align="end"> - <button mat-raised-button mat-dialog-close cdkFocusInitial color="primary">Ok</button> + <ng-container *ngIf="request.controllerPermissions.canRead; else noPermissions"> + <button mat-stroked-button mat-dialog-close color="primary">Cancel</button> + <button mat-raised-button mat-dialog-close color="primary" [routerLink]="['/settings', 'registry-clients']"> + Configure + </button> + </ng-container> + <ng-template #noPermissions> + <button mat-raised-button mat-dialog-close color="primary">Ok</button> + </ng-template> </mat-dialog-actions> 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/header/new-canvas-item/new-canvas-item.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.scss similarity index 71% copy from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.scss copy to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/no-registry-clients-dialog/no-registry-clients-dialog.component.scss index e0695991a6..fc444ed325 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.scss @@ -15,23 +15,8 @@ * limitations under the License. */ -.icon { - font-size: 32px; +@use '@angular/material' as mat; - &.hovering { - cursor: move; - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; - } - - &.dragging { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; - } - - &:disabled { - box-shadow: none; - } +mat-dialog-actions { + @include mat.button-density(-1); } 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/common/no-registry-clients-dialog/no-registry-clients-dialog.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.spec.ts new file mode 100644 index 0000000000..64117f14a8 --- /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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.spec.ts @@ -0,0 +1,50 @@ +/* + * 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 { NoRegistryClientsDialog } from './no-registry-clients-dialog.component'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; + +describe('NoRegistryClientsDialog', () => { + let component: NoRegistryClientsDialog; + let fixture: ComponentFixture<NoRegistryClientsDialog>; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [NoRegistryClientsDialog], + providers: [ + { + provide: MAT_DIALOG_DATA, + useValue: { + controllerPermissions: { + canRead: true, + canWrite: true + } + } + } + ] + }); + fixture = TestBed.createComponent(NoRegistryClientsDialog); + 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/header/new-canvas-item/new-canvas-item.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.ts similarity index 51% copy from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.scss copy to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/no-registry-clients-dialog/no-registry-clients-dialog.component.ts index e0695991a6..f7897b2904 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.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/common/no-registry-clients-dialog/no-registry-clients-dialog.component.ts @@ -15,23 +15,20 @@ * limitations under the License. */ -.icon { - font-size: 32px; +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { MatButtonModule } from '@angular/material/button'; +import { NoRegistryClientsDialogRequest } from '../../../state/flow'; +import { NgIf } from '@angular/common'; +import { RouterLink } from '@angular/router'; - &.hovering { - cursor: move; - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; - } - - &.dragging { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; - } - - &:disabled { - box-shadow: none; - } +@Component({ + selector: 'no-registry-clients-dialog', + standalone: true, + imports: [MatDialogModule, MatButtonModule, NgIf, RouterLink], + templateUrl: './no-registry-clients-dialog.component.html', + styleUrls: ['./no-registry-clients-dialog.component.scss'] +}) +export class NoRegistryClientsDialog { + constructor(@Inject(MAT_DIALOG_DATA) public request: NoRegistryClientsDialogRequest) {} } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/registry-client.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/registry-client.service.ts index 94ed22fd26..514043c7a7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/registry-client.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/service/registry-client.service.ts @@ -23,10 +23,9 @@ import { NiFiCommon } from '../../../service/nifi-common.service'; import { CreateRegistryClientRequest, DeleteRegistryClientRequest, - EditRegistryClientRequest, - RegistryClientEntity + EditRegistryClientRequest } from '../state/registry-clients'; -import { PropertyDescriptorRetriever } from '../../../state/shared'; +import { PropertyDescriptorRetriever, RegistryClientEntity } from '../../../state/shared'; @Injectable({ providedIn: 'root' }) export class RegistryClientService implements PropertyDescriptorRetriever { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts index 4cbe47e3ee..7d8ff8bdae 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { BulletinEntity, DocumentedType, Permissions, Revision } from '../../../../state/shared'; +import { DocumentedType, RegistryClientEntity, Revision } from '../../../../state/shared'; export const registryClientsFeatureKey = 'registryClients'; @@ -70,16 +70,6 @@ export interface SelectRegistryClientRequest { id: string; } -export interface RegistryClientEntity { - permissions: Permissions; - operatePermissions?: Permissions; - revision: Revision; - bulletins?: BulletinEntity[]; - id: string; - uri: string; - component: any; -} - export interface RegistryClientsState { registryClients: RegistryClientEntity[]; saving: boolean; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.selectors.ts index 49dcbd5ecf..b98e007ae3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.selectors.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.selectors.ts @@ -18,7 +18,8 @@ import { createSelector } from '@ngrx/store'; import { selectSettingsState, SettingsState } from '../index'; import { selectCurrentRoute } from '../../../../state/router/router.selectors'; -import { RegistryClientEntity, registryClientsFeatureKey, RegistryClientsState } from './index'; +import { registryClientsFeatureKey, RegistryClientsState } from './index'; +import { RegistryClientEntity } from '../../../../state/shared'; export const selectRegistryClientsState = createSelector( selectSettingsState, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-client-table/registry-client-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-client-table/registry-client-table.component.ts index 7b05aa0351..c0384e2caf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-client-table/registry-client-table.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-client-table/registry-client-table.component.ts @@ -23,8 +23,7 @@ import { TextTip } from '../../../../../ui/common/tooltips/text-tip/text-tip.com import { BulletinsTip } from '../../../../../ui/common/tooltips/bulletins-tip/bulletins-tip.component'; import { ValidationErrorsTip } from '../../../../../ui/common/tooltips/validation-errors-tip/validation-errors-tip.component'; import { NiFiCommon } from '../../../../../service/nifi-common.service'; -import { BulletinsTipInput, ValidationErrorsTipInput } from '../../../../../state/shared'; -import { RegistryClientEntity } from '../../../state/registry-clients'; +import { BulletinsTipInput, RegistryClientEntity, ValidationErrorsTipInput } from '../../../../../state/shared'; @Component({ selector: 'registry-client-table', diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-clients.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-clients.component.ts index 55690c4bfb..ef64be5cc3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-clients.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/registry-clients.component.ts @@ -32,12 +32,13 @@ import { resetRegistryClientsState, selectClient } from '../../state/registry-clients/registry-clients.actions'; -import { RegistryClientEntity, RegistryClientsState } from '../../state/registry-clients'; +import { RegistryClientsState } from '../../state/registry-clients'; import { initialState } from '../../state/registry-clients/registry-clients.reducer'; import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; import { NiFiState } from '../../../../state'; import { filter, switchMap, take } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { RegistryClientEntity } from '../../../../state/shared'; @Component({ selector: 'registry-clients', diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/flow-configuration/flow-configuration.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/flow-configuration/flow-configuration.selectors.ts index 458bf59dff..f9a49749c7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/flow-configuration/flow-configuration.selectors.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/flow-configuration/flow-configuration.selectors.ts @@ -29,3 +29,8 @@ export const selectSupportsManagedAuthorizer = createSelector( selectFlowConfiguration, (flowConfiguration: FlowConfiguration | null) => flowConfiguration?.supportsManagedAuthorizer ); + +export const selectTimeOffset = createSelector( + selectFlowConfiguration, + (flowConfiguration: FlowConfiguration | null) => flowConfiguration?.timeOffset +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts index aec81d5933..63eed665d9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts @@ -386,7 +386,8 @@ export enum ComponentType { ReportingTask = 'ReportingTask', FlowAnalysisRule = 'FlowAnalysisRule', ParameterProvider = 'ParameterProvider', - FlowRegistryClient = 'FlowRegistryClient' + FlowRegistryClient = 'FlowRegistryClient', + Flow = 'Flow' } export interface ControllerServiceReferencingComponent { @@ -481,6 +482,57 @@ export interface AllowableValueEntity { allowableValue: AllowableValue; } +export interface RegistryClientEntity { + permissions: Permissions; + operatePermissions?: Permissions; + revision: Revision; + bulletins?: BulletinEntity[]; + id: string; + uri: string; + component: any; +} + +export interface BucketEntity { + id: string; + permissions: Permissions; + bucket: Bucket; +} + +export interface Bucket { + created: number; + description: string; + id: string; + name: string; +} + +export interface VersionedFlowEntity { + versionedFlow: VersionedFlow; +} + +export interface VersionedFlow { + registryId: string; + bucketId: string; + flowId: string; + flowName: string; + description: string; + comments: string; + action: string; +} + +export interface VersionedFlowSnapshotMetadataEntity { + registryId: string; + versionedFlowSnapshotMetadata: VersionedFlowSnapshotMetadata; +} + +export interface VersionedFlowSnapshotMetadata { + bucketIdentifier: string; + flowIdentifier: string; + version: number; + timestamp: number; + author: string; + comments: string; +} + export interface SelectOption { text: string; value: string | null; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.component.html index 76f19dd22d..945c2f7395 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/ok-dialog/ok-dialog.component.html @@ -17,7 +17,7 @@ <h2 mat-dialog-title>{{ request.title }}</h2> <mat-dialog-content> - <div class="text-sm">{{ request.message }}</div> + <div class="text-sm max-w-sm">{{ request.message }}</div> </mat-dialog-content> <mat-dialog-actions align="end"> <button mat-raised-button mat-dialog-close cdkFocusInitial color="primary">Ok</button> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.css b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.css old mode 100755 new mode 100644 index 76585dbab7..826fce7576 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.css +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.css @@ -1,12 +1,12 @@ @font-face { font-family: 'flowfont'; - src: url('./flowfont.eot?33669169'); + src: url('./flowfont.eot?8516181'); src: - url('./flowfont.eot?33669169#iefix') format('embedded-opentype'), - url('./flowfont.woff2?33669169') format('woff2'), - url('./flowfont.woff?33669169') format('woff'), - url('./flowfont.ttf?33669169') format('truetype'), - url('./flowfont.svg?33669169#flowfont') format('svg'); + url('./flowfont.eot?8516181#iefix') format('embedded-opentype'), + url('./flowfont.woff2?8516181') format('woff2'), + url('./flowfont.woff?8516181') format('woff'), + url('./flowfont.ttf?8516181') format('truetype'), + url('./flowfont.svg?8516181#flowfont') format('svg'); font-weight: normal; font-style: normal; } @@ -16,11 +16,10 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'flowfont'; - src: url('../font/flowfont.svg?33669169#flowfont') format('svg'); + src: url('../font/flowfont.svg?8516181#flowfont') format('svg'); } } */ - [class^='icon-']:before, [class*=' icon-']:before { font-family: 'flowfont'; @@ -126,6 +125,12 @@ .icon-lineage:before { content: '\e816'; } /* '' */ +.icon-import-from-registry-add:before { + content: '\e81d'; +} /* '' */ +.icon-import-from-registry:before { + content: '\e81e'; +} /* '' */ .icon-port-in:before { content: '\e832'; } /* '' */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.eot b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.eot old mode 100755 new mode 100644 index 48a3ab1cd4..f0d0fe0410 Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.eot and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.eot differ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.svg b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.svg old mode 100755 new mode 100644 index 4b7cd8a84d..5427d62811 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.svg +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.svg @@ -1,68 +1,72 @@ <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg"> -<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata> +<metadata>Copyright (C) 2023 by original authors @ fontello.com</metadata> <defs> <font id="flowfont" horiz-adv-x="1000" > -<font-face font-family="flowfont" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="860" descent="-140" /> +<font-face font-family="flowfont" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> <missing-glyph horiz-adv-x="1000" /> -<glyph glyph-name="funnel-add" unicode="" d="M948 796h-114a52 52 0 0 1-53-52v-147l-183-77a305 305 0 0 1-35 11l78 110h51a52 52 0 0 1 52 52v115a52 52 0 0 1-52 52h-114a52 52 0 0 1-52-52v-114a52 52 0 0 1 52-53h29l-74-108c-9 0-18-2-28-2s-19 4-28 3l-73 107h18a52 52 0 0 1 52 52v115a52 52 0 0 1-52 52h-114a52 52 0 0 1-51-52v-114a52 52 0 0 1 51-53h61l75-111a379 379 0 0 1-38-8l-187 75v147a52 52 0 0 1-53 52h-114a52 52 0 0 1-52-52v-114a52 52 0 0 1 52-51h156l159-68a39 39 0 0 1-28-29c0-28 74-51 [...] +<glyph glyph-name="funnel-add" unicode="" d="M948 786h-114a52 52 0 0 1-53-52v-147l-183-77a305 305 0 0 1-35 11l78 110h51a52 52 0 0 1 52 52v115a52 52 0 0 1-52 52h-114a52 52 0 0 1-52-52v-114a52 52 0 0 1 52-53h29l-74-108c-9 0-18-2-28-2s-19 4-28 3l-73 107h18a52 52 0 0 1 52 52v115a52 52 0 0 1-52 52h-114a52 52 0 0 1-51-52v-114a52 52 0 0 1 51-53h61l75-111a379 379 0 0 1-38-8l-187 75v147a52 52 0 0 1-53 52h-114a52 52 0 0 1-52-52v-114a52 52 0 0 1 52-51h156l159-68a39 39 0 0 1-28-29c0-28 74-51 [...] -<glyph glyph-name="counter" unicode="" d="M878-7h-756c-67 0-122 54-122 121v492c0 67 55 121 122 121h756c68 0 122-54 122-121v-492c0-67-54-121-122-121z m-756 670c-32 0-58-26-58-57v-492c0-31 26-57 58-57h756c32 0 58 26 58 57v492c0 31-26 57-58 57h-756z m358-535h-314v62l148 158c20 22 35 42 45 58 10 17 15 33 15 47 0 21-5 37-15 48-11 12-25 18-45 18-20 0-36-7-48-21-12-15-18-33-18-56h-91c0 28 7 53 20 76 13 23 32 41 56 54 25 13 52 20 83 20 47 0 84-11 110-34s39-55 39-96c0-22-6-45-18-69-11-23- [...] +<glyph glyph-name="counter" unicode="" d="M878-17h-756c-67 0-122 54-122 121v492c0 67 55 121 122 121h756c68 0 122-54 122-121v-492c0-67-54-121-122-121z m-756 670c-32 0-58-26-58-57v-492c0-31 26-57 58-57h756c32 0 58 26 58 57v492c0 31-26 57-58 57h-756z m358-535h-314v62l148 158c20 22 35 42 45 58 10 17 15 33 15 47 0 21-5 37-15 48-11 12-25 18-45 18-20 0-36-7-48-21-12-15-18-33-18-56h-91c0 28 7 53 20 76 13 23 32 41 56 54 25 13 52 20 83 20 47 0 84-11 110-34s39-55 39-96c0-22-6-45-18-69-11-23 [...] -<glyph glyph-name="enable-false" unicode="" d="M912-113l-297 296-144-308c-5-9-14-15-25-15-3 0-6 1-9 1-13 4-21 17-18 30l96 392-71 70-150-37c-3-1-5-1-7-1-7 0-14 2-19 7-7 5-10 14-8 23l38 154-251 250 41 42 865-862-41-42z m-117 683c5 9 3 20-4 27-5 5-12 9-20 9-3 0-5-1-7-1l-238-59 102 278c2 4 3 7 3 11 0 14-12 25-27 25h-197c-12 0-23-8-26-19l-42-172 343-342 113 243z" horiz-adv-x="1000" /> +<glyph glyph-name="enable-false" unicode="" d="M912-123l-297 296-144-308c-5-9-14-15-25-15-3 0-6 1-9 1-13 4-21 17-18 30l96 392-71 70-150-37c-3-1-5-1-7-1-7 0-14 2-19 7-7 5-10 14-8 23l38 154-251 250 41 42 865-862-41-42z m-117 683c5 9 3 20-4 27-5 5-12 9-20 9-3 0-5-1-7-1l-238-59 102 278c2 4 3 7 3 11 0 14-12 25-27 25h-197c-12 0-23-8-26-19l-42-172 343-342 113 243z" horiz-adv-x="1000" /> -<glyph glyph-name="funnel" unicode="" d="M782 744v-147l-183-77c-11 2-21 9-35 11l77 111h51c28 0 52 23 52 52v114c0 29-24 52-52 52h-114c-29 0-52-23-52-52v-114c0-29 23-52 52-52h29l-74-108c-9 0-18-2-28-2-9 0-19 3-28 3l-73 107h18c29 0 52 23 52 52v114c0 29-23 52-52 52h-113c-29 0-53-23-53-52v-114c0-29 24-52 53-52h60l75-111c-13-2-27-6-38-9l-188 75v147c0 29-23 52-52 52h-114c-29 0-52-23-52-52v-114c0-29 23-52 52-52h157l158-68c-18-8-28-19-28-29 0-27 74-50 166-50 92 0 166 22 166 49 0 10-10 22- [...] +<glyph glyph-name="funnel" unicode="" d="M782 734v-147l-183-77c-11 2-21 9-35 11l77 111h51c28 0 52 23 52 52v114c0 29-24 52-52 52h-114c-29 0-52-23-52-52v-114c0-29 23-52 52-52h29l-74-108c-9 0-18-2-28-2-9 0-19 3-28 3l-73 107h18c29 0 52 23 52 52v114c0 29-23 52-52 52h-113c-29 0-53-23-53-52v-114c0-29 24-52 53-52h60l75-111c-13-2-27-6-38-9l-188 75v147c0 29-23 52-52 52h-114c-29 0-52-23-52-52v-114c0-29 23-52 52-52h157l158-68c-18-8-28-19-28-29 0-27 74-50 166-50 92 0 166 22 166 49 0 10-10 22- [...] -<glyph glyph-name="group" unicode="" d="M82 852c-45 0-82-36-82-82v-110h192v192h-110z m53-134h-77v36c0 22 18 41 41 41h36v-77z m783 134h-110v-192h192v110c0 46-37 82-82 82z m24-134h-77v77h36c23 0 41-19 41-41v-36z m-942-658v-110c0-46 37-82 82-82h110v192h-192z m135-135h-36c-23 0-41 19-41 41v36h77v-77z m673 135v-192h110c45 0 82 36 82 82v110h-192z m134-94c0-22-18-41-41-41h-36v77h77v-36z m-883 126v536h75v-536h-75z m807 0v536h75v-536h-75z m-634 627v75h536v-75h-536z m0-793v75h536v-75h-536z [...] +<glyph glyph-name="group" unicode="" d="M82 842c-45 0-82-36-82-82v-110h192v192h-110z m53-134h-77v36c0 22 18 41 41 41h36v-77z m783 134h-110v-192h192v110c0 46-37 82-82 82z m24-134h-77v77h36c23 0 41-19 41-41v-36z m-942-658v-110c0-46 37-82 82-82h110v192h-192z m135-135h-36c-23 0-41 19-41 41v36h77v-77z m673 135v-192h110c45 0 82 36 82 82v110h-192z m134-94c0-22-18-41-41-41h-36v77h77v-36z m-883 126v536h75v-536h-75z m807 0v536h75v-536h-75z m-634 627v75h536v-75h-536z m0-793v75h536v-75h-536z [...] -<glyph glyph-name="group-remote" unicode="" d="M82 852c-45 0-82-36-82-82v-110h192v192h-110z m53-134h-77v36c0 22 18 41 41 41h36v-77z m783 134h-110v-192h192v110c0 46-37 82-82 82z m24-134h-77v77h36c23 0 41-19 41-41v-36z m-942-658v-110c0-46 37-82 82-82h110v192h-192z m135-135h-36c-23 0-41 19-41 41v36h77v-77z m673 135v-192h110c45 0 82 36 82 82v110h-192z m134-94c0-22-18-41-41-41h-36v77h77v-36z m-211 433c-5 78-69 138-147 138-42 0-82-18-110-49-16 17-38 26-61 26-48 0-87-39-87-86l0-2c-4 1-7 [...] +<glyph glyph-name="group-remote" unicode="" d="M82 842c-45 0-82-36-82-82v-110h192v192h-110z m53-134h-77v36c0 22 18 41 41 41h36v-77z m783 134h-110v-192h192v110c0 46-37 82-82 82z m24-134h-77v77h36c23 0 41-19 41-41v-36z m-942-658v-110c0-46 37-82 82-82h110v192h-192z m135-135h-36c-23 0-41 19-41 41v36h77v-77z m673 135v-192h110c45 0 82 36 82 82v110h-192z m134-94c0-22-18-41-41-41h-36v77h77v-36z m-211 433c-5 78-69 138-147 138-42 0-82-18-110-49-16 17-38 26-61 26-48 0-87-39-87-86l0-2c-4 1-7 [...] -<glyph glyph-name="label" unicode="" d="M670 167c2 4 5 7 8 11l322 321v-43l-303-303c-3-3-7-6-11-8l-36-18 20 40z m-225-271l315 93c7 2 13 6 18 11l222 222v83l-207-207c-3-3-5-5-6-8l-40-65c-5-8-12-14-21-17l-167-61-5 10c-15 33-41 59-74 75l-10 5 60 166c3 9 10 17 18 21l62 38c3 2 6 4 8 6l382 382v83l-475-473c-5-5-8-11-10-18l-96-320c-5-16 10-31 26-26z m160 712c40 0 70 18 70 41s-30 40-70 40h-535c-40 0-70-17-70-40s30-41 70-41h535z m-59-136c40 0 70 18 70 41s-30 41-70 41h-476c-40 0-70-18-70-41s3 [...] +<glyph glyph-name="label" unicode="" d="M670 157c2 4 5 7 8 11l322 321v-43l-303-303c-3-3-7-6-11-8l-36-18 20 40z m-225-271l315 93c7 2 13 6 18 11l222 222v83l-207-207c-3-3-5-5-6-8l-40-65c-5-8-12-14-21-17l-167-61-5 10c-15 33-41 59-74 75l-10 5 60 166c3 9 10 17 18 21l62 38c3 2 6 4 8 6l382 382v83l-475-473c-5-5-8-11-10-18l-96-320c-5-16 10-31 26-26z m160 712c40 0 70 18 70 41s-30 40-70 40h-535c-40 0-70-17-70-40s30-41 70-41h535z m-59-136c40 0 70 18 70 41s-30 41-70 41h-476c-40 0-70-18-70-41s3 [...] -<glyph glyph-name="processor" unicode="" d="M101 842l-50-50-39-88 39 39v-120l-39-88 39 39v-120l-39-87 39 39v-121l-39-87 39 39v-121l-39-87 39 39v-121l-39-87 63 63h121l-15-63 63 63h121l-15-63 63 63h120l-14-63 63 63h120l-14-63 63 63h120l-15-63 114 113c11 12 18 28 18 44v760c0 46-37 83-83 83h-760c-16 0-32-7-44-18z m798-850h-738c-23 0-41 18-41 41v738c0 23 18 42 41 42h738c23 0 42-19 42-42v-738c0-23-19-41-42-41z m-119 564c-2 9-4 19-11 27-57 75-144 119-239 119-65 0-128-21-180-60-127-96-15 [...] +<glyph glyph-name="processor" unicode="" d="M101 832l-50-50-39-88 39 39v-120l-39-88 39 39v-120l-39-87 39 39v-121l-39-87 39 39v-121l-39-87 39 39v-121l-39-87 63 63h121l-15-63 63 63h121l-15-63 63 63h120l-14-63 63 63h120l-14-63 63 63h120l-15-63 114 113c11 12 18 28 18 44v760c0 46-37 83-83 83h-760c-16 0-32-7-44-18z m798-850h-738c-23 0-41 18-41 41v738c0 23 18 42 41 42h738c23 0 42-19 42-42v-738c0-23-19-41-42-41z m-119 564c-2 9-4 19-11 27-57 75-144 119-239 119-65 0-128-21-180-60-127-96-15 [...] -<glyph glyph-name="provenance" unicode="" d="M827 170v-258c0-29-23-52-51-52h-724c-29 0-52 23-52 52v724c0 28 23 51 52 51h258v-465c0-29 23-52 52-52h465z m-193 293c-17 0-31 14-31 31v271h-150c-17 0-31-13-31-30v-422c0-17 14-30 31-30h422c17 0 30 13 30 30v150h-271z m366 145v193c0 33-26 59-59 59h-193c-32 0-58-26-58-59v-193c0-32 26-58 58-58h193c33 0 59 26 59 58z m-241 183h172v-172h-172v172z" horiz-adv-x="1000" /> +<glyph glyph-name="provenance" unicode="" d="M827 160v-258c0-29-23-52-51-52h-724c-29 0-52 23-52 52v724c0 28 23 51 52 51h258v-465c0-29 23-52 52-52h465z m-193 293c-17 0-31 14-31 31v271h-150c-17 0-31-13-31-30v-422c0-17 14-30 31-30h422c17 0 30 13 30 30v150h-271z m366 145v193c0 33-26 59-59 59h-193c-32 0-58-26-58-59v-193c0-32 26-58 58-58h193c33 0 59 26 59 58z m-241 183h172v-172h-172v172z" horiz-adv-x="1000" /> -<glyph glyph-name="template" unicode="" d="M995 423v-157a31 31 0 0 0-31-31h-231l-195-156h153a31 31 0 0 0 32-31v-157a31 31 0 0 0-32-31h-434a31 31 0 0 0-31 31v157a31 31 0 0 0 31 31h231l196 156h-153a31 31 0 0 0-31 31v157a31 31 0 0 0 31 31h122l-373 187h-244a31 31 0 0 0-31 32v156a31 31 0 0 0 31 31h433a31 31 0 0 0 31-31v-156a31 31 0 0 0-31-32h-122l373-187h244a31 31 0 0 0 31-31z" horiz-adv-x="1000" /> +<glyph glyph-name="template" unicode="" d="M995 413v-157a31 31 0 0 0-31-31h-231l-195-156h153a31 31 0 0 0 32-31v-157a31 31 0 0 0-32-31h-434a31 31 0 0 0-31 31v157a31 31 0 0 0 31 31h231l196 156h-153a31 31 0 0 0-31 31v157a31 31 0 0 0 31 31h122l-373 187h-244a31 31 0 0 0-31 32v156a31 31 0 0 0 31 31h433a31 31 0 0 0 31-31v-156a31 31 0 0 0-31-32h-122l373-187h244a31 31 0 0 0 31-31z" horiz-adv-x="1000" /> -<glyph glyph-name="transmit-false" unicode="" d="M44 845l-44-44 163-163c-52-74-83-165-83-262 0-255 206-461 460-461 98 0 189 32 264 85l125-125 44 44-929 926z m287-374l60-60c-2-11-4-23-4-36 0-84 68-153 153-153 12 0 24 2 36 5l60-60c-29-14-62-22-96-22-127 0-230 103-230 230 0 35 8 67 21 96z m209-479c-212 0-383 172-383 383 0 77 23 148 62 208l55-55c-26-45-41-97-41-153 0-169 138-306 307-306 56 0 108 15 153 41l56-55c-60-40-132-63-209-63z m0 767c212 0 383-172 383-383 0-75-21-145-58-204l55- [...] +<glyph glyph-name="transmit-false" unicode="" d="M44 835l-44-44 163-163c-52-74-83-165-83-262 0-255 206-461 460-461 98 0 189 32 264 85l125-125 44 44-929 926z m287-374l60-60c-2-11-4-23-4-36 0-84 68-153 153-153 12 0 24 2 36 5l60-60c-29-14-62-22-96-22-127 0-230 103-230 230 0 35 8 67 21 96z m209-479c-212 0-383 172-383 383 0 77 23 148 62 208l55-55c-26-45-41-97-41-153 0-169 138-306 307-306 56 0 108 15 153 41l56-55c-60-40-132-63-209-63z m0 767c212 0 383-172 383-383 0-75-21-145-58-204l55- [...] -<glyph glyph-name="zoom-actual" unicode="" d="M42-140c-23 0-42 19-42 42v916c0 23 19 42 42 42h83c23 0 42-19 42-42v-916c0-23-19-42-42-42h-83z m416 233c-22 0-41 19-41 42v108c0 23 19 42 41 42h84c23 0 41-19 41-42v-108c0-23-18-42-41-42h-84z m0 343c-22 0-41 18-41 41v108c0 23 19 42 41 42h84c23 0 41-19 41-42v-108c0-23-18-41-41-41h-84z m417-576c-23 0-42 19-42 42v916c0 23 19 42 42 42h83c23 0 42-19 42-42v-916c0-23-19-42-42-42h-83z" horiz-adv-x="1000" /> +<glyph glyph-name="zoom-actual" unicode="" d="M42-150c-23 0-42 19-42 42v916c0 23 19 42 42 42h83c23 0 42-19 42-42v-916c0-23-19-42-42-42h-83z m416 233c-22 0-41 19-41 42v108c0 23 19 42 41 42h84c23 0 41-19 41-42v-108c0-23-18-42-41-42h-84z m0 343c-22 0-41 18-41 41v108c0 23 19 42 41 42h84c23 0 41-19 41-42v-108c0-23-18-41-41-41h-84z m417-576c-23 0-42 19-42 42v916c0 23 19 42 42 42h83c23 0 42-19 42-42v-916c0-23-19-42-42-42h-83z" horiz-adv-x="1000" /> -<glyph glyph-name="zoom-fit" unicode="" d="M637 789c-12 12-15 30-9 45 7 16 22 26 39 26h291c23 0 42-19 42-42v-291c0-17-10-32-25-39-6-2-11-3-17-3-11 0-21 5-29 12l-292 292z m-566-292c-8-7-18-12-29-12-6 0-11 1-16 3-16 7-26 22-26 39v291c0 23 19 42 42 42h291c17 0 32-10 39-26 6-15 3-33-9-45l-292-292z m292-566c12-12 15-30 9-45-7-16-22-26-39-26h-291c-23 0-42 19-42 42v291c0 17 10 32 26 39 15 6 33 3 45-9l292-292z m566 292c12 12 30 15 46 9 15-7 25-22 25-39v-291c0-23-19-42-42-42h-291c-17 0-32 [...] +<glyph glyph-name="zoom-fit" unicode="" d="M637 779c-12 12-15 30-9 45 7 16 22 26 39 26h291c23 0 42-19 42-42v-291c0-17-10-32-25-39-6-2-11-3-17-3-11 0-21 5-29 12l-292 292z m-566-292c-8-7-18-12-29-12-6 0-11 1-16 3-16 7-26 22-26 39v291c0 23 19 42 42 42h291c17 0 32-10 39-26 6-15 3-33-9-45l-292-292z m292-566c12-12 15-30 9-45-7-16-22-26-39-26h-291c-23 0-42 19-42 42v291c0 17 10 32 26 39 15 6 33 3 45-9l292-292z m566 292c12 12 30 15 46 9 15-7 25-22 25-39v-291c0-23-19-42-42-42h-291c-17 0-32 [...] -<glyph glyph-name="label-add" unicode="" d="M670 167a42 42 0 0 0 8 11l322 321v-43l-303-303a42 42 0 0 0-11-8l-36-17z m-65 441c40 0 70 18 70 41s-31 40-70 40h-535c-39 0-70-16-70-40s31-41 70-41h535z m-58-135c40 0 70 17 70 40s-32 41-70 41h-477c-39 0-70-18-70-41s31-40 70-40h477z m-51 271c40 0 70 17 70 40s-31 41-70 41h-426c-39 0-70-17-70-41s31-40 70-40h426z m-426-406h6a283 283 0 0 0 137 81h-143c-39-1-70-18-70-41s31-41 70-41z m214 40a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a [...] +<glyph glyph-name="label-add" unicode="" d="M670 157a42 42 0 0 0 8 11l322 321v-43l-303-303a42 42 0 0 0-11-8l-36-17z m-65 441c40 0 70 18 70 41s-31 40-70 40h-535c-39 0-70-16-70-40s31-41 70-41h535z m-58-135c40 0 70 17 70 40s-32 41-70 41h-477c-39 0-70-18-70-41s31-40 70-40h477z m-51 271c40 0 70 17 70 40s-31 41-70 41h-426c-39 0-70-17-70-41s31-40 70-40h426z m-426-406h6a283 283 0 0 0 137 81h-143c-39-1-70-18-70-41s31-41 70-41z m214 40a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a [...] -<glyph glyph-name="template-add" unicode="" d="M723 48v-157a31 31 0 0 0-32-31h-406a283 283 0 0 1 276 219h132a31 31 0 0 0 30-31z m241 406h-244l-372 187h121a31 31 0 0 1 31 32v156a31 31 0 0 1-31 31h-433a31 31 0 0 1-31-31v-156a31 31 0 0 1 31-32h244l372-187h-121a31 31 0 0 1-31-31v-94a283 283 0 0 0 53-94h132l-117-94a284 284 0 0 0-5-43l170 137h231a31 31 0 0 1 31 31v157a31 31 0 0 1-31 31z m-446-310a234 234 0 1 0-234 234 234 234 0 0 0 234-234z m-94 32a9 9 0 0 1-9 9h-81a9 9 0 0 0-9 9v81a9 [...] +<glyph glyph-name="template-add" unicode="" d="M723 38v-157a31 31 0 0 0-32-31h-406a283 283 0 0 1 276 219h132a31 31 0 0 0 30-31z m241 406h-244l-372 187h121a31 31 0 0 1 31 32v156a31 31 0 0 1-31 31h-433a31 31 0 0 1-31-31v-156a31 31 0 0 1 31-32h244l372-187h-121a31 31 0 0 1-31-31v-94a283 283 0 0 0 53-94h132l-117-94a284 284 0 0 0-5-43l170 137h231a31 31 0 0 1 31 31v157a31 31 0 0 1-31 31z m-446-310a234 234 0 1 0-234 234 234 234 0 0 0 234-234z m-94 32a9 9 0 0 1-9 9h-81a9 9 0 0 0-9 9v81a9 [...] -<glyph glyph-name="group-add" unicode="" d="M82 852a82 82 0 0 1-82-82v-110h192v192h-110z m53-134h-77v35a41 41 0 0 0 41 41h36v-76z m783 134h-110v-192h192v110a82 82 0 0 1-82 82z m24-134h-77v76h36a41 41 0 0 0 41-41v-35z m-134-657v-192h110a82 82 0 0 1 82 81v110h-192z m134-94a41 41 0 0 0-41-40h-36v76h77v-36z m-76 126v535h75v-536h-75z m-634 626v74h536v-75h-536z m536-719v-75h-302a285 285 0 0 1 62 75h240z m-485 375a234 234 0 1 1 235-234 234 234 0 0 1-234 237z m141-265a9 9 0 0 0-9-9h-81a9 [...] +<glyph glyph-name="group-add" unicode="" d="M82 842a82 82 0 0 1-82-82v-110h192v192h-110z m53-134h-77v35a41 41 0 0 0 41 41h36v-76z m783 134h-110v-192h192v110a82 82 0 0 1-82 82z m24-134h-77v76h36a41 41 0 0 0 41-41v-35z m-134-657v-192h110a82 82 0 0 1 82 81v110h-192z m134-94a41 41 0 0 0-41-40h-36v76h77v-36z m-76 126v535h75v-536h-75z m-634 626v74h536v-75h-536z m536-719v-75h-302a285 285 0 0 1 62 75h240z m-485 375a234 234 0 1 1 235-234 234 234 0 0 1-234 237z m141-265a9 9 0 0 0-9-9h-81a9 [...] -<glyph glyph-name="template-import" unicode="" d="M990 442v-153a31 31 0 0 0-31-31h-430a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h116l-361 172h-243a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h430a31 31 0 0 0 31-31v-153a31 31 0 0 0-31-32h-115l360-171h243a31 31 0 0 0 31-31z m-656-558h-113a63 63 0 0 0-57 38h-154v-31a31 31 0 0 1 31-31h474a31 31 0 0 1 31 31v31h-154a63 63 0 0 0-57-39z m-115 31h115a31 31 0 0 1 31 31v151a13 13 0 0 0 14 13h159c8 0 10 4 5 9l-256 259a13 13 0 0 1-19 0l-255-258c-5-5 [...] +<glyph glyph-name="template-import" unicode="" d="M990 432v-153a31 31 0 0 0-31-31h-430a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h116l-361 172h-243a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h430a31 31 0 0 0 31-31v-153a31 31 0 0 0-31-32h-115l360-171h243a31 31 0 0 0 31-31z m-656-558h-113a63 63 0 0 0-57 38h-154v-31a31 31 0 0 1 31-31h474a31 31 0 0 1 31 31v31h-154a63 63 0 0 0-57-39z m-115 31h115a31 31 0 0 1 31 31v151a13 13 0 0 0 14 13h159c8 0 10 4 5 9l-256 259a13 13 0 0 1-19 0l-255-258c-5-5 [...] -<glyph glyph-name="template-save" unicode="" d="M990 442v-153a31 31 0 0 0-31-31h-430a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h116l-361 172h-243a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h430a31 31 0 0 0 31-31v-153a31 31 0 0 0-31-32h-115l360-171h243a31 31 0 0 0 31-31z m-508-560a22 22 0 0 0-22-22h-438a22 22 0 0 0-22 22v437a22 22 0 0 0 22 22h312a47 47 0 0 0 29-12l106-106a47 47 0 0 0 12-28v-313z m-40 18v286a25 25 0 0 1-7 15l-91 92a44 44 0 0 1-23 9v-139a22 22 0 0 0-22-22h-197a22 22 0 0 0- [...] +<glyph glyph-name="template-save" unicode="" d="M990 432v-153a31 31 0 0 0-31-31h-430a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h116l-361 172h-243a31 31 0 0 0-31 31v153a31 31 0 0 0 31 31h430a31 31 0 0 0 31-31v-153a31 31 0 0 0-31-32h-115l360-171h243a31 31 0 0 0 31-31z m-508-560a22 22 0 0 0-22-22h-438a22 22 0 0 0-22 22v437a22 22 0 0 0 22 22h312a47 47 0 0 0 29-12l106-106a47 47 0 0 0 12-28v-313z m-40 18v286a25 25 0 0 1-7 15l-91 92a44 44 0 0 1-23 9v-139a22 22 0 0 0-22-22h-197a22 22 0 0 0- [...] -<glyph glyph-name="group-remote-add" unicode="" d="M82 852a82 82 0 0 1-82-82v-110h192v192h-110z m53-134h-77v35a41 41 0 0 0 41 41h36v-76z m783 134h-110v-192h192v110a82 82 0 0 1-82 82z m24-134h-77v76h36a41 41 0 0 0 41-41v-35z m-134-657v-192h110a82 82 0 0 1 82 81v110h-192z m134-94a41 41 0 0 0-41-40h-36v76h77v-36z m0 126h-75v535h75v-536z m-710 626v74h536v-75h-536z m536-719v-75h-302a285 285 0 0 1 62 75h240z m-485 375a234 234 0 1 1 235-234 234 234 0 0 1-234 237z m141-265a9 9 0 0 0-9-9h [...] +<glyph glyph-name="group-remote-add" unicode="" d="M82 842a82 82 0 0 1-82-82v-110h192v192h-110z m53-134h-77v35a41 41 0 0 0 41 41h36v-76z m783 134h-110v-192h192v110a82 82 0 0 1-82 82z m24-134h-77v76h36a41 41 0 0 0 41-41v-35z m-134-657v-192h110a82 82 0 0 1 82 81v110h-192z m134-94a41 41 0 0 0-41-40h-36v76h77v-36z m0 126h-75v535h75v-536z m-710 626v74h536v-75h-536z m536-719v-75h-302a285 285 0 0 1 62 75h240z m-485 375a234 234 0 1 1 235-234 234 234 0 0 1-234 237z m141-265a9 9 0 0 0-9-9h [...] -<glyph glyph-name="port-out-add" unicode="" d="M284 378a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a9 9 0 0 0-9-9h-81a9 9 0 0 1-9-9v-81a9 9 0 0 0-9-9h-66a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-80a9 9 0 0 0-9 9v66a9 9 0 0 0 9 9h81a9 9 0 0 1 10 9v82a9 9 0 0 0 7 8h65a9 9 0 0 0 9-9v-81a9 9 0 0 1 9-9h81a9 9 0 0 0 9-9v-66z m365 594v-102l-39 39v63a38 38 0 0 1-39 37h-615a38 38 0 0 1-38-37v-390a281 281 0 0 1-58-170v579l41 41a58 58 0 0 0 41 17h630a77 77 0 0 0 77-77z m205-421l-341-339c-9 [...] +<glyph glyph-name="port-out-add" unicode="" d="M284 368a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a9 9 0 0 0-9-9h-81a9 9 0 0 1-9-9v-81a9 9 0 0 0-9-9h-66a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-80a9 9 0 0 0-9 9v66a9 9 0 0 0 9 9h81a9 9 0 0 1 10 9v82a9 9 0 0 0 7 8h65a9 9 0 0 0 9-9v-81a9 9 0 0 1 9-9h81a9 9 0 0 0 9-9v-66z m365 594v-102l-39 39v63a38 38 0 0 1-39 37h-615a38 38 0 0 1-38-37v-390a281 281 0 0 1-58-170v579l41 41a58 58 0 0 0 41 17h630a77 77 0 0 0 77-77z m205-421l-341-339c-9 [...] -<glyph glyph-name="port-in-add" unicode="" d="M786 158h-54v276h54v-276z m-179 154l-353 351c-9 10-16 6-16-6v-200a23 23 0 0 0-22-23h-193a23 23 0 0 1-23-22v-231a22 22 0 0 1 2-8 281 281 0 0 0 62 149v38a11 11 0 0 0 11 11h39a281 281 0 0 0 170 57h18v88c0 7 3 8 8 4l218-217a11 11 0 0 0 0-15 281 281 0 0 0 27-60l53 52a23 23 0 0 1-1 32z m-323 66a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a9 9 0 0 0-9-9h-81a9 9 0 0 1-9-9v-81a9 9 0 0 0-9-9h-66a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-80a9 9 0 [...] +<glyph glyph-name="port-in-add" unicode="" d="M786 148h-54v276h54v-276z m-179 154l-353 351c-9 10-16 6-16-6v-200a23 23 0 0 0-22-23h-193a23 23 0 0 1-23-22v-231a22 22 0 0 1 2-8 281 281 0 0 0 62 149v38a11 11 0 0 0 11 11h39a281 281 0 0 0 170 57h18v88c0 7 3 8 8 4l218-217a11 11 0 0 0 0-15 281 281 0 0 0 27-60l53 52a23 23 0 0 1-1 32z m-323 66a234 234 0 1 1 234-234 234 234 0 0 1-234 234z m140-268a9 9 0 0 0-9-9h-81a9 9 0 0 1-9-9v-81a9 9 0 0 0-9-9h-66a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-80a9 9 0 [...] -<glyph glyph-name="processor-add" unicode="" d="M988 777v-761a63 63 0 0 0-19-43l-113-113 15 62h-121l-62-62 14 62h-120l-63-62 15 62h-73a285 285 0 0 1 62 69h375a42 42 0 0 1 42 42v738a42 42 0 0 1-42 42h-737a42 42 0 0 1-42-42v-396a285 285 0 0 1-68-69v99l-39-38 39 87v120l-39-39 39 88v120l-39-39 39 88 50 50a63 63 0 0 0 44 18h760a83 83 0 0 0 83-83z m-469-634a234 234 0 1 0-234 235 234 234 0 0 0 233-234z m-94 32a9 9 0 0 1-9 9h-81a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-67a9 9 0 0 1-9-9v-81a9 9 0 [...] +<glyph glyph-name="processor-add" unicode="" d="M988 767v-761a63 63 0 0 0-19-43l-113-113 15 62h-121l-62-62 14 62h-120l-63-62 15 62h-73a285 285 0 0 1 62 69h375a42 42 0 0 1 42 42v738a42 42 0 0 1-42 42h-737a42 42 0 0 1-42-42v-396a285 285 0 0 1-68-69v99l-39-38 39 87v120l-39-39 39 88v120l-39-39 39 88 50 50a63 63 0 0 0 44 18h760a83 83 0 0 0 83-83z m-469-634a234 234 0 1 0-234 235 234 234 0 0 0 233-234z m-94 32a9 9 0 0 1-9 9h-81a9 9 0 0 0-9 9v81a9 9 0 0 1-9 9h-67a9 9 0 0 1-9-9v-81a9 9 0 [...] -<glyph glyph-name="lineage" unicode="" d="M785 415a214 214 0 0 1-83-17l-58 87a215 215 0 1 1-266-18l-82-184a215 215 0 1 1 72-31l82 185a210 210 0 0 1 127 8l59-90a215 215 0 1 1 149 60z m-539-438a98 98 0 1 0 98 98 98 98 0 0 0-98-98z m157 668a98 98 0 1 0 97-97 98 98 0 0 0-97 97z m382-543a98 98 0 1 0 98 98 98 98 0 0 0-98-98z" horiz-adv-x="1000" /> +<glyph glyph-name="lineage" unicode="" d="M785 405a214 214 0 0 1-83-17l-58 87a215 215 0 1 1-266-18l-82-184a215 215 0 1 1 72-31l82 185a210 210 0 0 1 127 8l59-90a215 215 0 1 1 149 60z m-539-438a98 98 0 1 0 98 98 98 98 0 0 0-98-98z m157 668a98 98 0 1 0 97-97 98 98 0 0 0-97 97z m382-543a98 98 0 1 0 98 98 98 98 0 0 0-98-98z" horiz-adv-x="1000" /> -<glyph glyph-name="port-in" unicode="" d="M1000 0v735l-42 43a60 60 0 0 1-42 18h-671a63 63 0 0 1-62-63l41-40v22a40 40 0 0 0 40 40h637a40 40 0 0 0 39-40v-636a40 40 0 0 0-39-40h-449l-60-60h587z m-1000 412v-231a23 23 0 0 1 23-23h192a23 23 0 0 0 23-22v-200c0-13 7-15 16-7l353 351a23 23 0 0 1 0 32l-353 351c-9 10-16 6-16-6v-200a23 23 0 0 0-22-23h-193a23 23 0 0 1-23-22z m63-52a11 11 0 0 0 11 11h216a11 11 0 0 1 12 12v133c0 7 3 8 8 4l218-217a11 11 0 0 0 0-15l-218-217c-5-4-8-3-8 4v135a11 11 [...] +<glyph glyph-name="import-from-registry-add" unicode="" d="M890 579c7 37 2 91-47 125-52 37-106 21-135 7-24 43-92 131-251 125-84-3-149-29-190-78-45-51-53-114-54-145-48-8-161-42-160-195 0-58 29-99 65-127 9 12 17 22 27 32-28 20-50 50-50 95-1 151 134 155 140 155h23l-3 22c0 0-7 77 43 134 34 39 88 61 160 64 177 7 219-115 220-120l10-27 23 17c0 0 57 40 108 5 49-35 27-98 25-100l-9-25 27-3c6 0 146-17 136-157-7-109-143-107-148-108h-121v-42h124c63 0 180 30 187 147 8 129-84 183-150 198v1z m-4 [...] -<glyph glyph-name="port-out" unicode="" d="M0 13v710l41 41a58 58 0 0 0 41 17h630a77 77 0 0 0 77-77v-102l-39 39v63a38 38 0 0 1-39 37h-615a38 38 0 0 1-38-37v-616a38 38 0 0 1 38-38h482v-58h-558z m653-69l341 339a22 22 0 0 1 0 31l-341 339c-9 9-16 6-16-6v-193a22 22 0 0 0-22-22h-187a22 22 0 0 1-22-22v-222a22 22 0 0 1 22-22h187a22 22 0 0 0 22-22v-193c0-13 7-16 16-7z m45 141v131a11 11 0 0 1-10 11h-208a11 11 0 0 0-11 11v122a11 11 0 0 0 11 11h208a11 11 0 0 1 10 11v130c0 6 4 7 8 3l212-209a11 [...] +<glyph glyph-name="import-from-registry" unicode="" d="M913 579c6 37 1 91-47 125-53 37-107 21-136 7-23 43-92 131-251 125-84-3-148-29-190-78-45-51-52-114-53-145-48-8-162-42-160-195 1-142 159-182 242-184h28v42h-28c-10 0-200 7-201 143-1 151 134 154 140 154h22l-2 23c0 0-7 77 42 134 34 39 89 61 161 63 177 8 218-114 220-119l9-27 24 16c0 0 57 41 108 5 49-34 27-97 25-100l-9-25 26-2c6 0 146-16 137-158-7-108-143-106-148-107h-121v-42h123c64 0 180 30 188 147 8 129-84 183-150 198h1z m-246-168 [...] -<glyph glyph-name="connect" unicode="" d="M853 713a500 500 0 1 0-753-53 31 31 0 0 0 46 2l279-279a16 16 0 0 0 0-22l-93-94a8 8 0 0 1 3-13l332-74a8 8 0 0 1 9 9l-72 334a8 8 0 0 1-13 3l-94-93a16 16 0 0 0-22 0l-278 280a31 31 0 0 0 4 47 500 500 0 0 0 652-47z" horiz-adv-x="1000" /> +<glyph glyph-name="port-in" unicode="" d="M1000-10v735l-42 43a60 60 0 0 1-42 18h-671a63 63 0 0 1-62-63l41-40v22a40 40 0 0 0 40 40h637a40 40 0 0 0 39-40v-636a40 40 0 0 0-39-40h-449l-60-60h587z m-1000 412v-231a23 23 0 0 1 23-23h192a23 23 0 0 0 23-22v-200c0-13 7-15 16-7l353 351a23 23 0 0 1 0 32l-353 351c-9 10-16 6-16-6v-200a23 23 0 0 0-22-23h-193a23 23 0 0 1-23-22z m63-52a11 11 0 0 0 11 11h216a11 11 0 0 1 12 12v133c0 7 3 8 8 4l218-217a11 11 0 0 0 0-15l-218-217c-5-4-8-3-8 4v135a11 11 [...] -<glyph glyph-name="connect-add" unicode="" d="M853 713a500 500 0 1 0-752-53 31 31 0 0 0 46 2l154-154a16 16 0 0 0 0-22l-94-94a8 8 0 0 1 4-13l333-73a8 8 0 0 1 9 10l-74 331a8 8 0 0 1-13 4l-94-94a16 16 0 0 0-22 0l-152 156a31 31 0 0 0 3 47 500 500 0 0 0 652-47z m-55-523a8 8 0 0 1 8 8v70a8 8 0 0 0 7 8h70a8 8 0 0 1 8 8v56a8 8 0 0 1-8 8h-70a8 8 0 0 0-8 8v70a8 8 0 0 1-8 8h-56a8 8 0 0 1-8-8v-70a8 8 0 0 0-8-8h-69a8 8 0 0 1-8-8v-56a8 8 0 0 1 8-8h71a8 8 0 0 0 7-8v-70a8 8 0 0 1 8-8h56z" horiz- [...] +<glyph glyph-name="port-out" unicode="" d="M0 3v710l41 41a58 58 0 0 0 41 17h630a77 77 0 0 0 77-77v-102l-39 39v63a38 38 0 0 1-39 37h-615a38 38 0 0 1-38-37v-616a38 38 0 0 1 38-38h482v-58h-558z m653-69l341 339a22 22 0 0 1 0 31l-341 339c-9 9-16 6-16-6v-193a22 22 0 0 0-22-22h-187a22 22 0 0 1-22-22v-222a22 22 0 0 1 22-22h187a22 22 0 0 0 22-22v-193c0-13 7-16 16-7z m45 141v131a11 11 0 0 1-10 11h-208a11 11 0 0 0-11 11v122a11 11 0 0 0 11 11h208a11 11 0 0 1 10 11v130c0 6 4 7 8 3l212-209a11 [...] -<glyph glyph-name="threads" unicode="" d="M308 360a149 149 0 1 0-149 149 149 149 0 0 0 149-149z m10 341a159 159 0 1 1-159-158 159 159 0 0 1 159 158z m-66 0a94 94 0 1 0-94 94 94 94 0 0 0 94-94z m248 149a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m-182-831a159 159 0 1 1-159-159 159 159 0 0 1 159 159z m-66 0a94 94 0 1 0-94 94 94 94 0 0 0 94-94z m248 149a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m341 0a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m159 192a159 159 0 1 1-159-159 1 [...] +<glyph glyph-name="connect" unicode="" d="M853 703a500 500 0 1 0-753-53 31 31 0 0 0 46 2l279-279a16 16 0 0 0 0-22l-93-94a8 8 0 0 1 3-13l332-74a8 8 0 0 1 9 9l-72 334a8 8 0 0 1-13 3l-94-93a16 16 0 0 0-22 0l-278 280a31 31 0 0 0 4 47 500 500 0 0 0 652-47z" horiz-adv-x="1000" /> -<glyph glyph-name="drop" unicode="" d="M507-28v104a8 8 0 0 0 8 8h104v-112h-112z m0-111a333 333 0 0 1 112 21v56h-104a8 8 0 0 1-8-8v-70z m237 236v112h-103a8 8 0 0 1-8-8v-103h111z m14-139a23 23 0 0 1 6 17v89h-111v-112h88a23 23 0 0 1 17 7z m-98-98a334 334 0 0 1 83 51h-83v-51z m174 238a332 332 0 0 1 22 111h-78v-111h56z m-28-126a333 333 0 0 1 50 83h-50v-83z m0 0a333 333 0 0 1 50 83h-50v-83z m21 258h-209a8 8 0 0 1-8-8v-117h-117a8 8 0 0 1-8-8v-209a342 342 0 0 0-341 343c0 162 127 318 214 [...] +<glyph glyph-name="connect-add" unicode="" d="M853 703a500 500 0 1 0-752-53 31 31 0 0 0 46 2l154-154a16 16 0 0 0 0-22l-94-94a8 8 0 0 1 4-13l333-73a8 8 0 0 1 9 10l-74 331a8 8 0 0 1-13 4l-94-94a16 16 0 0 0-22 0l-152 156a31 31 0 0 0 3 47 500 500 0 0 0 652-47z m-55-523a8 8 0 0 1 8 8v70a8 8 0 0 0 7 8h70a8 8 0 0 1 8 8v56a8 8 0 0 1-8 8h-70a8 8 0 0 0-8 8v70a8 8 0 0 1-8 8h-56a8 8 0 0 1-8-8v-70a8 8 0 0 0-8-8h-69a8 8 0 0 1-8-8v-56a8 8 0 0 1 8-8h71a8 8 0 0 0 7-8v-70a8 8 0 0 1 8-8h56z" horiz- [...] + +<glyph glyph-name="threads" unicode="" d="M308 350a149 149 0 1 0-149 149 149 149 0 0 0 149-149z m10 341a159 159 0 1 1-159-158 159 159 0 0 1 159 158z m-66 0a94 94 0 1 0-94 94 94 94 0 0 0 94-94z m248 149a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m-182-831a159 159 0 1 1-159-159 159 159 0 0 1 159 159z m-66 0a94 94 0 1 0-94 94 94 94 0 0 0 94-94z m248 149a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m341 0a149 149 0 1 1 149-149 149 149 0 0 1-149 149z m159 192a159 159 0 1 1-159-159 1 [...] + +<glyph glyph-name="drop" unicode="" d="M507-38v104a8 8 0 0 0 8 8h104v-112h-112z m0-111a333 333 0 0 1 112 21v56h-104a8 8 0 0 1-8-8v-70z m237 236v112h-103a8 8 0 0 1-8-8v-103h111z m14-139a23 23 0 0 1 6 17v89h-111v-112h88a23 23 0 0 1 17 7z m-98-98a334 334 0 0 1 83 51h-83v-51z m174 238a332 332 0 0 1 22 111h-78v-111h56z m-28-126a333 333 0 0 1 50 83h-50v-83z m0 0a333 333 0 0 1 50 83h-50v-83z m21 258h-209a8 8 0 0 1-8-8v-117h-117a8 8 0 0 1-8-8v-209a342 342 0 0 0-341 343c0 162 127 318 214 [...] </font> </defs> -</svg> \ No newline at end of file +</svg> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.ttf b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.ttf old mode 100755 new mode 100644 index 519f7cbf10..c16425cc28 Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.ttf and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.ttf differ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff old mode 100755 new mode 100644 index eea3656405..799454c3b2 Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff differ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff2 b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff2 old mode 100755 new mode 100644 index 0138d2a8e5..1917ea71cd Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff2 and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/assets/fonts/flowfont/flowfont.woff2 differ