mirror of https://github.com/apache/nifi.git
NIFI-13127 Add branching support to Registry dialogs
This closes #8817 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
bffacdec98
commit
0c9ef91507
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { ImportFromRegistryRequest } from '../state/flow';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
|
@ -30,17 +30,36 @@ export class RegistryService {
|
|||
return this.httpClient.get(`${RegistryService.API}/flow/registries`);
|
||||
}
|
||||
|
||||
getBuckets(registryId: string): Observable<any> {
|
||||
return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets`);
|
||||
getBranches(registryId: string): Observable<any> {
|
||||
return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/branches`);
|
||||
}
|
||||
|
||||
getFlows(registryId: string, bucketId: string): Observable<any> {
|
||||
return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows`);
|
||||
getBuckets(registryId: string, branch?: string): Observable<any> {
|
||||
const params: HttpParams = new HttpParams();
|
||||
if (branch) {
|
||||
params.set('branch', branch);
|
||||
}
|
||||
return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets`, { params });
|
||||
}
|
||||
|
||||
getFlowVersions(registryId: string, bucketId: string, flowId: string): Observable<any> {
|
||||
getFlows(registryId: string, bucketId: string, branch?: string): Observable<any> {
|
||||
const params: HttpParams = new HttpParams();
|
||||
if (branch) {
|
||||
params.set('branch', branch);
|
||||
}
|
||||
return this.httpClient.get(`${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows`, {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
getFlowVersions(registryId: string, bucketId: string, flowId: string, branch?: string): Observable<any> {
|
||||
const params: HttpParams = new HttpParams();
|
||||
if (branch) {
|
||||
params.set('branch', branch);
|
||||
}
|
||||
return this.httpClient.get(
|
||||
`${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows/${flowId}/versions`
|
||||
`${RegistryService.API}/flow/registries/${registryId}/buckets/${bucketId}/flows/${flowId}/versions`,
|
||||
{ params }
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ 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 {
|
||||
BranchEntity,
|
||||
BucketEntity,
|
||||
ComponentType,
|
||||
isDefinedAndNotNull,
|
||||
|
@ -809,10 +810,29 @@ export class FlowEffects {
|
|||
data: request
|
||||
});
|
||||
|
||||
dialogReference.componentInstance.getBuckets = (
|
||||
dialogReference.componentInstance.getBranches = (
|
||||
registryId: string
|
||||
): Observable<BranchEntity[]> => {
|
||||
return this.registryService.getBranches(registryId).pipe(
|
||||
take(1),
|
||||
map((response) => response.branches),
|
||||
tap({
|
||||
error: (errorResponse: HttpErrorResponse) => {
|
||||
this.store.dispatch(
|
||||
FlowActions.flowBannerError({
|
||||
error: this.errorHelper.getErrorString(errorResponse)
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
dialogReference.componentInstance.getBuckets = (
|
||||
registryId: string,
|
||||
branch?: string
|
||||
): Observable<BucketEntity[]> => {
|
||||
return this.registryService.getBuckets(registryId).pipe(
|
||||
return this.registryService.getBuckets(registryId, branch).pipe(
|
||||
take(1),
|
||||
map((response) => response.buckets),
|
||||
tap({
|
||||
|
@ -829,9 +849,10 @@ export class FlowEffects {
|
|||
|
||||
dialogReference.componentInstance.getFlows = (
|
||||
registryId: string,
|
||||
bucketId: string
|
||||
bucketId: string,
|
||||
branch?: string
|
||||
): Observable<VersionedFlowEntity[]> => {
|
||||
return this.registryService.getFlows(registryId, bucketId).pipe(
|
||||
return this.registryService.getFlows(registryId, bucketId, branch).pipe(
|
||||
take(1),
|
||||
map((response) => response.versionedFlows),
|
||||
tap({
|
||||
|
@ -849,9 +870,10 @@ export class FlowEffects {
|
|||
dialogReference.componentInstance.getFlowVersions = (
|
||||
registryId: string,
|
||||
bucketId: string,
|
||||
flowId: string
|
||||
flowId: string,
|
||||
branch?: string
|
||||
): Observable<VersionedFlowSnapshotMetadataEntity[]> => {
|
||||
return this.registryService.getFlowVersions(registryId, bucketId, flowId).pipe(
|
||||
return this.registryService.getFlowVersions(registryId, bucketId, flowId, branch).pipe(
|
||||
take(1),
|
||||
map((response) => response.versionedFlowSnapshotMetadataSet),
|
||||
tap({
|
||||
|
@ -3192,8 +3214,29 @@ export class FlowEffects {
|
|||
data: request
|
||||
});
|
||||
|
||||
dialogReference.componentInstance.getBuckets = (registryId: string): Observable<BucketEntity[]> => {
|
||||
return this.registryService.getBuckets(registryId).pipe(
|
||||
dialogReference.componentInstance.getBranches = (
|
||||
registryId: string
|
||||
): Observable<BranchEntity[]> => {
|
||||
return this.registryService.getBranches(registryId).pipe(
|
||||
take(1),
|
||||
map((response) => response.branches),
|
||||
tap({
|
||||
error: (errorResponse: HttpErrorResponse) => {
|
||||
this.store.dispatch(
|
||||
FlowActions.flowBannerError({
|
||||
error: this.errorHelper.getErrorString(errorResponse)
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
dialogReference.componentInstance.getBuckets = (
|
||||
registryId: string,
|
||||
branch?: string
|
||||
): Observable<BucketEntity[]> => {
|
||||
return this.registryService.getBuckets(registryId, branch).pipe(
|
||||
take(1),
|
||||
map((response) => response.buckets),
|
||||
tap({
|
||||
|
|
|
@ -238,6 +238,7 @@ export interface SaveVersionRequest {
|
|||
flowDescription?: string;
|
||||
comments?: string;
|
||||
existingFlowId?: string;
|
||||
branch?: string;
|
||||
}
|
||||
|
||||
export interface VersionControlInformation {
|
||||
|
@ -253,6 +254,7 @@ export interface VersionControlInformation {
|
|||
storageLocation?: string;
|
||||
state: string;
|
||||
stateExplanation: string;
|
||||
branch?: string;
|
||||
}
|
||||
|
||||
export interface VersionControlInformationEntity {
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<h2 mat-dialog-title>Change Version</h2>
|
||||
<h2 mat-dialog-title>
|
||||
Change Version <span class="font-light">({{ versionControlInformation.version }})</span>
|
||||
</h2>
|
||||
<div class="change-version">
|
||||
<mat-dialog-content>
|
||||
<div class="dialog-content flex flex-col gap-y-4 w-full">
|
||||
|
@ -26,18 +28,20 @@
|
|||
<div class="accent-color font-medium">{{ versionControlInformation.registryName }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>Flow Name</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.flowName }}</div>
|
||||
<div>Bucket</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.bucketName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col gap-y-4">
|
||||
<div>
|
||||
<div>Bucket</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.bucketName }}</div>
|
||||
@if (versionControlInformation.branch) {
|
||||
<div>Branch</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.branch }}</div>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<div>Current Version</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.version }}</div>
|
||||
<div>Flow Name</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.flowName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -61,7 +65,11 @@
|
|||
<!-- 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>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div class="overflow-ellipsis overflow-hidden whitespace-nowrap" [title]="item.version">
|
||||
{{ item.version }}
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Create Column -->
|
||||
|
@ -73,7 +81,13 @@
|
|||
<!-- 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>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div
|
||||
class="overflow-ellipsis overflow-hidden whitespace-nowrap"
|
||||
[title]="item.comments">
|
||||
{{ item.comments }}
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||
|
|
|
@ -22,14 +22,12 @@
|
|||
|
||||
.listing-table {
|
||||
table {
|
||||
table-layout: unset;
|
||||
|
||||
.mat-column-version {
|
||||
width: 75px;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.mat-column-created {
|
||||
width: 200px;
|
||||
width: 180px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,138 +19,163 @@
|
|||
<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"
|
||||
<div class="dialog-content flex flex-col h-full gap-y-2">
|
||||
<div>
|
||||
<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]="option.description"
|
||||
[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>
|
||||
|
||||
@if (supportsBranching) {
|
||||
<mat-form-field>
|
||||
<mat-label>Branch</mat-label>
|
||||
<mat-select formControlName="branch" (selectionChange)="branchChanged($event.value)">
|
||||
<ng-container *ngFor="let option of branchOptions">
|
||||
<mat-option [value]="option.value">{{ option.text }}</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
@if (importFromRegistryForm.controls['branch'].hasError('required')) {
|
||||
<mat-error>No branches available</mat-error>
|
||||
}
|
||||
</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]="option.description"
|
||||
[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]="option.description"
|
||||
[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
|
||||
<i
|
||||
class="fa fa-info-circle"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
[tooltipInputData]="option.description"
|
||||
[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]="option.description"
|
||||
[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]="option.description"
|
||||
[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
|
||||
<i
|
||||
class="fa fa-info-circle"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
tooltipInputData="When not selected, only directly associated Parameter Contexts will be copied, inherited Contexts with no direct assignment to a Process Group are ignored."></i>
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Flow Description</div>
|
||||
<div class="accent-color font-medium">
|
||||
{{ selectedFlowDescription || 'No description provided' }}
|
||||
tooltipInputData="When not selected, only directly associated Parameter Contexts will be copied, inherited Contexts with no direct assignment to a Process Group are ignored."></i>
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<div class="flex flex-col mb-5">
|
||||
<div>Flow Description</div>
|
||||
<div class="accent-color font-medium">
|
||||
{{ selectedFlowDescription || 'No description provided' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listing-table">
|
||||
<div class="h-48 overflow-y-auto overflow-x-hidden">
|
||||
<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>
|
||||
<div class="listing-table flex-1 relative min-h-48">
|
||||
<div class="absolute inset-0 overflow-y-auto overflow-x-hidden">
|
||||
<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">
|
||||
<div class="overflow-ellipsis overflow-hidden whitespace-nowrap" [title]="item.version">
|
||||
{{ item.version }}
|
||||
</div>
|
||||
</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>
|
||||
<!-- 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>
|
||||
<!-- Comments Column -->
|
||||
<ng-container matColumnDef="comments">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Comments</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
<div
|
||||
class="overflow-ellipsis overflow-hidden whitespace-nowrap"
|
||||
[title]="item.comments">
|
||||
{{ item.comments }}
|
||||
</div>
|
||||
</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>
|
||||
<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>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end" *ngIf="{ value: (saving$ | async)! } as saving">
|
||||
<button mat-button mat-dialog-close>Cancel</button>
|
||||
<button
|
||||
[disabled]="importFromRegistryForm.invalid || saving.value"
|
||||
[disabled]="importFromRegistryForm.invalid || saving.value || !selectedFlowVersion"
|
||||
type="button"
|
||||
color="primary"
|
||||
(click)="importFromRegistry()"
|
||||
|
|
|
@ -30,14 +30,12 @@
|
|||
|
||||
.listing-table {
|
||||
table {
|
||||
table-layout: unset;
|
||||
|
||||
.mat-column-version {
|
||||
width: 75px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.mat-column-created {
|
||||
width: 200px;
|
||||
width: 180px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import { ImportFromRegistryDialogRequest } from '../../../../../state/flow';
|
|||
import { Store } from '@ngrx/store';
|
||||
import { CanvasState } from '../../../../../state';
|
||||
import {
|
||||
BranchEntity,
|
||||
BucketEntity,
|
||||
isDefinedAndNotNull,
|
||||
RegistryClientEntity,
|
||||
|
@ -43,7 +44,7 @@ import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators }
|
|||
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 { Observable, of, take } from 'rxjs';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { MatSortModule, Sort } from '@angular/material/sort';
|
||||
|
@ -82,12 +83,14 @@ import { ClusterConnectionService } from '../../../../../../../service/cluster-c
|
|||
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() getBranches: (registryId: string) => Observable<BranchEntity[]> = () => of([]);
|
||||
@Input() getBuckets!: (registryId: string, branch?: string) => Observable<BucketEntity[]>;
|
||||
@Input() getFlows!: (registryId: string, bucketId: string, branch?: string) => Observable<VersionedFlowEntity[]>;
|
||||
@Input() getFlowVersions!: (
|
||||
registryId: string,
|
||||
bucketId: string,
|
||||
flowId: string
|
||||
flowId: string,
|
||||
branch?: string
|
||||
) => Observable<VersionedFlowSnapshotMetadataEntity[]>;
|
||||
|
||||
saving$ = this.store.select(selectSaving);
|
||||
|
@ -97,11 +100,14 @@ export class ImportFromRegistry implements OnInit {
|
|||
|
||||
importFromRegistryForm: FormGroup;
|
||||
registryClientOptions: SelectOption[] = [];
|
||||
branchOptions: SelectOption[] = [];
|
||||
bucketOptions: SelectOption[] = [];
|
||||
flowOptions: SelectOption[] = [];
|
||||
|
||||
flowLookup: Map<string, VersionedFlow> = new Map<string, VersionedFlow>();
|
||||
selectedFlowDescription: string | undefined;
|
||||
supportsBranching = false;
|
||||
private clientBranchingSupportMap: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
||||
sort: Sort = {
|
||||
active: 'created',
|
||||
|
@ -139,10 +145,12 @@ export class ImportFromRegistry implements OnInit {
|
|||
description: registryClient.component.description
|
||||
});
|
||||
}
|
||||
this.clientBranchingSupportMap.set(registryClient.id, registryClient.component.supportsBranching);
|
||||
});
|
||||
|
||||
this.importFromRegistryForm = this.formBuilder.group({
|
||||
registry: new FormControl(this.registryClientOptions[0].value, Validators.required),
|
||||
branch: new FormControl('default', Validators.required),
|
||||
bucket: new FormControl(null, Validators.required),
|
||||
flow: new FormControl(null, Validators.required),
|
||||
keepParameterContexts: new FormControl(true, Validators.required)
|
||||
|
@ -153,13 +161,36 @@ export class ImportFromRegistry implements OnInit {
|
|||
const selectedRegistryId = this.importFromRegistryForm.get('registry')?.value;
|
||||
|
||||
if (selectedRegistryId) {
|
||||
this.loadBuckets(selectedRegistryId);
|
||||
this.supportsBranching = this.clientBranchingSupportMap.get(selectedRegistryId) || false;
|
||||
if (this.supportsBranching) {
|
||||
this.loadBranches(selectedRegistryId);
|
||||
} else {
|
||||
this.loadBuckets(selectedRegistryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registryChanged(registryId: string): void {
|
||||
this.supportsBranching = this.clientBranchingSupportMap.get(registryId) || false;
|
||||
if (this.supportsBranching) {
|
||||
this.clearBranches();
|
||||
this.loadBranches(registryId);
|
||||
} else {
|
||||
this.clearBuckets();
|
||||
this.loadBuckets(registryId);
|
||||
}
|
||||
}
|
||||
|
||||
private clearBranches(): void {
|
||||
this.branchOptions = [];
|
||||
this.importFromRegistryForm.get('branch')?.setValue('default');
|
||||
this.clearBuckets();
|
||||
this.loadBuckets(registryId);
|
||||
}
|
||||
|
||||
branchChanged(branch: string): void {
|
||||
this.clearBuckets();
|
||||
const registryId = this.importFromRegistryForm.get('registry')?.value;
|
||||
this.loadBuckets(registryId, branch);
|
||||
}
|
||||
|
||||
private clearBuckets(): void {
|
||||
|
@ -186,10 +217,35 @@ export class ImportFromRegistry implements OnInit {
|
|||
this.loadVersions(registryId, bucketId, flowId);
|
||||
}
|
||||
|
||||
loadBuckets(registryId: string): void {
|
||||
loadBranches(registryId: string): void {
|
||||
if (registryId) {
|
||||
this.branchOptions = [];
|
||||
|
||||
this.getBranches(registryId)
|
||||
.pipe(take(1))
|
||||
.subscribe((branches: BranchEntity[]) => {
|
||||
if (branches.length > 0) {
|
||||
branches.forEach((entity: BranchEntity) => {
|
||||
this.branchOptions.push({
|
||||
text: entity.branch.name,
|
||||
value: entity.branch.name
|
||||
});
|
||||
});
|
||||
|
||||
const branchId = this.branchOptions[0].value;
|
||||
if (branchId) {
|
||||
this.importFromRegistryForm.get('branch')?.setValue(branchId);
|
||||
this.loadBuckets(registryId, branchId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadBuckets(registryId: string, branch?: string): void {
|
||||
this.bucketOptions = [];
|
||||
|
||||
this.getBuckets(registryId)
|
||||
this.getBuckets(registryId, branch)
|
||||
.pipe(take(1))
|
||||
.subscribe((buckets: BucketEntity[]) => {
|
||||
if (buckets.length > 0) {
|
||||
|
@ -206,17 +262,17 @@ export class ImportFromRegistry implements OnInit {
|
|||
const bucketId = this.bucketOptions[0].value;
|
||||
if (bucketId) {
|
||||
this.importFromRegistryForm.get('bucket')?.setValue(bucketId);
|
||||
this.loadFlows(registryId, bucketId);
|
||||
this.loadFlows(registryId, bucketId, branch);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadFlows(registryId: string, bucketId: string): void {
|
||||
loadFlows(registryId: string, bucketId: string, branch?: string): void {
|
||||
this.flowOptions = [];
|
||||
this.flowLookup.clear();
|
||||
|
||||
this.getFlows(registryId, bucketId)
|
||||
this.getFlows(registryId, bucketId, branch)
|
||||
.pipe(take(1))
|
||||
.subscribe((versionedFlows: VersionedFlowEntity[]) => {
|
||||
if (versionedFlows.length > 0) {
|
||||
|
@ -233,17 +289,17 @@ export class ImportFromRegistry implements OnInit {
|
|||
const flowId = this.flowOptions[0].value;
|
||||
if (flowId) {
|
||||
this.importFromRegistryForm.get('flow')?.setValue(flowId);
|
||||
this.loadVersions(registryId, bucketId, flowId);
|
||||
this.loadVersions(registryId, bucketId, flowId, branch);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadVersions(registryId: string, bucketId: string, flowId: string): void {
|
||||
loadVersions(registryId: string, bucketId: string, flowId: string, branch?: string): void {
|
||||
this.dataSource.data = [];
|
||||
this.selectedFlowDescription = this.flowLookup.get(flowId)?.description;
|
||||
|
||||
this.getFlowVersions(registryId, bucketId, flowId)
|
||||
this.getFlowVersions(registryId, bucketId, flowId, branch)
|
||||
.pipe(take(1))
|
||||
.subscribe((metadataEntities: VersionedFlowSnapshotMetadataEntity[]) => {
|
||||
if (metadataEntities.length > 0) {
|
||||
|
@ -340,6 +396,10 @@ export class ImportFromRegistry implements OnInit {
|
|||
}
|
||||
};
|
||||
|
||||
if (this.supportsBranching) {
|
||||
payload.component.versionControlInformation.branch = this.importFromRegistryForm.get('branch')?.value;
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
importFromRegistry({
|
||||
request: {
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
<div>Registry</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.registryName }}</div>
|
||||
</div>
|
||||
@if (versionControlInformation.branch) {
|
||||
<div>
|
||||
<div>Branch</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.branch }}</div>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<div>Bucket</div>
|
||||
<div class="accent-color font-medium">{{ versionControlInformation.bucketName }}</div>
|
||||
|
@ -65,6 +71,20 @@
|
|||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
@if (supportsBranching) {
|
||||
<mat-form-field>
|
||||
<mat-label>Branch</mat-label>
|
||||
<mat-select formControlName="branch" (selectionChange)="branchChanged($event.value)">
|
||||
<ng-container *ngFor="let option of branchOptions">
|
||||
<mat-option [value]="option.value">{{ option.text }}</mat-option>
|
||||
</ng-container>
|
||||
</mat-select>
|
||||
@if (saveVersionForm.controls['branch'].hasError('required')) {
|
||||
<mat-error>No branches available</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Bucket</mat-label>
|
||||
<mat-select formControlName="bucket">
|
||||
|
|
|
@ -30,7 +30,7 @@ import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nif
|
|||
import { MatError, MatFormField, MatLabel } from '@angular/material/form-field';
|
||||
import { MatOption, MatSelect } from '@angular/material/select';
|
||||
import { Observable, of, take } from 'rxjs';
|
||||
import { BucketEntity, RegistryClientEntity, SelectOption } from '../../../../../../../state/shared';
|
||||
import { BranchEntity, BucketEntity, RegistryClientEntity, SelectOption } from '../../../../../../../state/shared';
|
||||
import { NiFiCommon } from '../../../../../../../service/nifi-common.service';
|
||||
import { SaveVersionDialogRequest, SaveVersionRequest, VersionControlInformation } from '../../../../../state/flow';
|
||||
import { TextTip } from '../../../../../../../ui/common/tooltips/text-tip/text-tip.component';
|
||||
|
@ -64,16 +64,21 @@ import { MatInput } from '@angular/material/input';
|
|||
styleUrl: './save-version-dialog.component.scss'
|
||||
})
|
||||
export class SaveVersionDialog implements OnInit {
|
||||
@Input() getBuckets: (registryId: string) => Observable<BucketEntity[]> = () => of([]);
|
||||
@Input() getBranches: (registryId: string) => Observable<BranchEntity[]> = () => of([]);
|
||||
@Input() getBuckets: (registryId: string, branch?: string) => Observable<BucketEntity[]> = () => of([]);
|
||||
@Input({ required: true }) saving!: Signal<boolean>;
|
||||
|
||||
@Output() save: EventEmitter<SaveVersionRequest> = new EventEmitter<SaveVersionRequest>();
|
||||
|
||||
saveVersionForm: FormGroup;
|
||||
registryClientOptions: SelectOption[] = [];
|
||||
branchOptions: SelectOption[] = [];
|
||||
bucketOptions: SelectOption[] = [];
|
||||
versionControlInformation?: VersionControlInformation;
|
||||
forceCommit = false;
|
||||
supportsBranching = false;
|
||||
|
||||
private clientBranchingSupportMap: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) private dialogRequest: SaveVersionDialogRequest,
|
||||
|
@ -96,10 +101,12 @@ export class SaveVersionDialog implements OnInit {
|
|||
description: registryClient.component.description
|
||||
});
|
||||
}
|
||||
this.clientBranchingSupportMap.set(registryClient.id, registryClient.component.supportsBranching);
|
||||
});
|
||||
|
||||
this.saveVersionForm = formBuilder.group({
|
||||
registry: new FormControl(this.registryClientOptions[0].value, Validators.required),
|
||||
branch: new FormControl('default', Validators.required),
|
||||
bucket: new FormControl(null, Validators.required),
|
||||
flowName: new FormControl(null, Validators.required),
|
||||
flowDescription: new FormControl(null),
|
||||
|
@ -117,16 +124,46 @@ export class SaveVersionDialog implements OnInit {
|
|||
const selectedRegistryId: string | null = this.saveVersionForm.get('registry')?.value;
|
||||
|
||||
if (selectedRegistryId) {
|
||||
this.loadBuckets(selectedRegistryId);
|
||||
this.supportsBranching = this.clientBranchingSupportMap.get(selectedRegistryId) || false;
|
||||
if (this.supportsBranching) {
|
||||
this.loadBranches(selectedRegistryId);
|
||||
} else {
|
||||
this.loadBuckets(selectedRegistryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadBuckets(registryId: string): void {
|
||||
loadBranches(registryId: string): void {
|
||||
if (registryId) {
|
||||
this.branchOptions = [];
|
||||
|
||||
this.getBranches(registryId)
|
||||
.pipe(take(1))
|
||||
.subscribe((branches: BranchEntity[]) => {
|
||||
if (branches.length > 0) {
|
||||
branches.forEach((entity: BranchEntity) => {
|
||||
this.branchOptions.push({
|
||||
text: entity.branch.name,
|
||||
value: entity.branch.name
|
||||
});
|
||||
});
|
||||
|
||||
const branchId = this.branchOptions[0].value;
|
||||
if (branchId) {
|
||||
this.saveVersionForm.get('branch')?.setValue(branchId);
|
||||
this.loadBuckets(registryId, branchId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadBuckets(registryId: string, branch?: string): void {
|
||||
if (registryId) {
|
||||
this.bucketOptions = [];
|
||||
|
||||
this.getBuckets(registryId)
|
||||
this.getBuckets(registryId, branch)
|
||||
.pipe(take(1))
|
||||
.subscribe((buckets: BucketEntity[]) => {
|
||||
if (buckets.length > 0) {
|
||||
|
@ -150,7 +187,17 @@ export class SaveVersionDialog implements OnInit {
|
|||
}
|
||||
|
||||
registryChanged(registryId: string): void {
|
||||
this.loadBuckets(registryId);
|
||||
this.supportsBranching = this.clientBranchingSupportMap.get(registryId) || false;
|
||||
if (this.supportsBranching) {
|
||||
this.loadBranches(registryId);
|
||||
} else {
|
||||
this.loadBuckets(registryId);
|
||||
}
|
||||
}
|
||||
|
||||
branchChanged(branch: string): void {
|
||||
const registryId = this.saveVersionForm.get('registry')?.value;
|
||||
this.loadBuckets(registryId, branch);
|
||||
}
|
||||
|
||||
submitForm() {
|
||||
|
@ -165,7 +212,8 @@ export class SaveVersionDialog implements OnInit {
|
|||
bucket: vci.bucketId,
|
||||
comments: this.saveVersionForm.get('comments')?.value,
|
||||
flowDescription: vci.flowDescription,
|
||||
flowName: vci.flowName
|
||||
flowName: vci.flowName,
|
||||
branch: vci.branch
|
||||
};
|
||||
} else {
|
||||
request = {
|
||||
|
@ -177,6 +225,9 @@ export class SaveVersionDialog implements OnInit {
|
|||
flowDescription: this.saveVersionForm.get('flowDescription')?.value,
|
||||
flowName: this.saveVersionForm.get('flowName')?.value
|
||||
};
|
||||
if (this.supportsBranching) {
|
||||
request.branch = this.saveVersionForm.get('branch')?.value;
|
||||
}
|
||||
}
|
||||
this.save.next(request);
|
||||
}
|
||||
|
|
|
@ -566,6 +566,16 @@ export interface Bucket {
|
|||
name: string;
|
||||
}
|
||||
|
||||
export interface BranchEntity {
|
||||
id: string;
|
||||
permissions: Permissions;
|
||||
branch: Branch;
|
||||
}
|
||||
|
||||
export interface Branch {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface VersionedFlowEntity {
|
||||
versionedFlow: VersionedFlow;
|
||||
}
|
||||
|
@ -602,6 +612,7 @@ export interface VersionedFlowSnapshotMetadata {
|
|||
timestamp: number;
|
||||
author: string;
|
||||
comments: string;
|
||||
branch?: string;
|
||||
}
|
||||
|
||||
export interface SelectOption {
|
||||
|
|
Loading…
Reference in New Issue