You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by sc...@apache.org on 2024/02/07 17:02:20 UTC
(nifi) branch main updated: NIFI-12734: Import from Registry (#8354)
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 <ma...@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