mirror of https://github.com/apache/nifi.git
NIFI-14031: Ensuring all Parameter Contexts are added when Editing a … (#9539)
* NIFI-14031: Ensuring all Parameter Contexts are added when Editing a Process Group. For contexts the user lacks access to will be added as disabled options. * NIFI-14031: Addressing review feedback allowing the currently selected value to be reselected even when the user lacks permissions because the back end skips the check when the value isn't changing. * NIFI-14031: Fixing PropertyItem instances in unit tests. This closes #9539
This commit is contained in:
parent
685f5712b7
commit
b421ccad21
|
@ -37,7 +37,7 @@
|
||||||
@if (option.description) {
|
@if (option.description) {
|
||||||
<mat-option
|
<mat-option
|
||||||
[value]="option.value"
|
[value]="option.value"
|
||||||
[disabled]="readonly"
|
[disabled]="readonly || option.disabled"
|
||||||
nifiTooltip
|
nifiTooltip
|
||||||
[tooltipComponentType]="TextTip"
|
[tooltipComponentType]="TextTip"
|
||||||
[tooltipInputData]="option.description"
|
[tooltipInputData]="option.description"
|
||||||
|
@ -45,9 +45,11 @@
|
||||||
>{{ option.text }}</mat-option
|
>{{ option.text }}</mat-option
|
||||||
>
|
>
|
||||||
} @else {
|
} @else {
|
||||||
<mat-option [value]="option.value" [disabled]="readonly">{{
|
<mat-option
|
||||||
option.text
|
[value]="option.value"
|
||||||
}}</mat-option>
|
[disabled]="readonly || option.disabled"
|
||||||
|
>{{ option.text }}</mat-option
|
||||||
|
>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
|
|
@ -31,10 +31,8 @@ import { ParameterContextEntity } from '../../../../../../../state/shared';
|
||||||
import { Client } from '../../../../../../../service/client.service';
|
import { Client } from '../../../../../../../service/client.service';
|
||||||
import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nifi-spinner.directive';
|
import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nifi-spinner.directive';
|
||||||
import { NifiTooltipDirective, TextTip } from '@nifi/shared';
|
import { NifiTooltipDirective, TextTip } from '@nifi/shared';
|
||||||
import { ControllerServiceTable } from '../../../../../../../ui/common/controller-service/controller-service-table/controller-service-table.component';
|
|
||||||
import { EditComponentDialogRequest } from '../../../../../state/flow';
|
import { EditComponentDialogRequest } from '../../../../../state/flow';
|
||||||
import { ClusterConnectionService } from '../../../../../../../service/cluster-connection.service';
|
import { ClusterConnectionService } from '../../../../../../../service/cluster-connection.service';
|
||||||
import { ErrorBanner } from '../../../../../../../ui/common/error-banner/error-banner.component';
|
|
||||||
import { TabbedDialog } from '../../../../../../../ui/common/tabbed-dialog/tabbed-dialog.component';
|
import { TabbedDialog } from '../../../../../../../ui/common/tabbed-dialog/tabbed-dialog.component';
|
||||||
import { ErrorContextKey } from '../../../../../../../state/error';
|
import { ErrorContextKey } from '../../../../../../../state/error';
|
||||||
import { ContextErrorBanner } from '../../../../../../../ui/common/context-error-banner/context-error-banner.component';
|
import { ContextErrorBanner } from '../../../../../../../ui/common/context-error-banner/context-error-banner.component';
|
||||||
|
@ -56,8 +54,6 @@ import { ContextErrorBanner } from '../../../../../../../ui/common/context-error
|
||||||
NifiSpinnerDirective,
|
NifiSpinnerDirective,
|
||||||
NifiTooltipDirective,
|
NifiTooltipDirective,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ControllerServiceTable,
|
|
||||||
ErrorBanner,
|
|
||||||
ContextErrorBanner
|
ContextErrorBanner
|
||||||
],
|
],
|
||||||
styleUrls: ['./edit-process-group.component.scss']
|
styleUrls: ['./edit-process-group.component.scss']
|
||||||
|
@ -71,6 +67,12 @@ export class EditProcessGroup extends TabbedDialog {
|
||||||
value: parameterContext.id,
|
value: parameterContext.id,
|
||||||
description: parameterContext.component.description
|
description: parameterContext.component.description
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.parameterContextsOptions.push({
|
||||||
|
text: parameterContext.id,
|
||||||
|
value: parameterContext.id,
|
||||||
|
disabled: this.request.entity.component.parameterContext.id !== parameterContext.id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<ng-container *ngIf="allowableValue.description; else noDescription">
|
<ng-container *ngIf="allowableValue.description; else noDescription">
|
||||||
<mat-option
|
<mat-option
|
||||||
[value]="allowableValue.id"
|
[value]="allowableValue.id"
|
||||||
[disabled]="readonly"
|
[disabled]="readonly || allowableValue.disabled"
|
||||||
(mousedown)="preventDrag($event)"
|
(mousedown)="preventDrag($event)"
|
||||||
nifiTooltip
|
nifiTooltip
|
||||||
[tooltipComponentType]="TextTip"
|
[tooltipComponentType]="TextTip"
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
<ng-template #noDescription>
|
<ng-template #noDescription>
|
||||||
<mat-option
|
<mat-option
|
||||||
[value]="allowableValue.id"
|
[value]="allowableValue.id"
|
||||||
[disabled]="readonly"
|
[disabled]="readonly || allowableValue.disabled"
|
||||||
(mousedown)="preventDrag($event)">
|
(mousedown)="preventDrag($event)">
|
||||||
<span
|
<span
|
||||||
class="option-text"
|
class="option-text"
|
||||||
|
|
|
@ -115,6 +115,7 @@ describe('ComboEditor', () => {
|
||||||
deleted: false,
|
deleted: false,
|
||||||
added: false,
|
added: false,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
savedValue: 'flowfile-attribute',
|
||||||
type: 'required'
|
type: 'required'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
|
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { PropertyItem } from '../../property-table.component';
|
import { PropertyItem } from '../../property-table.component';
|
||||||
import { CdkDrag, CdkDragHandle } from '@angular/cdk/drag-drop';
|
import { CdkDrag } from '@angular/cdk/drag-drop';
|
||||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';
|
import { NgForOf, NgIf } from '@angular/common';
|
||||||
import { AllowableValue, Parameter, ParameterConfig, PropertyDescriptor } from '../../../../../state/shared';
|
import { AllowableValue, Parameter, ParameterConfig, PropertyDescriptor } from '../../../../../state/shared';
|
||||||
import { MatOptionModule } from '@angular/material/core';
|
import { MatOptionModule } from '@angular/material/core';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
@ -33,6 +33,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||||
|
|
||||||
export interface AllowableValueItem extends AllowableValue {
|
export interface AllowableValueItem extends AllowableValue {
|
||||||
id: number;
|
id: number;
|
||||||
|
disabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -41,13 +42,11 @@ export interface AllowableValueItem extends AllowableValue {
|
||||||
templateUrl: './combo-editor.component.html',
|
templateUrl: './combo-editor.component.html',
|
||||||
imports: [
|
imports: [
|
||||||
CdkDrag,
|
CdkDrag,
|
||||||
CdkDragHandle,
|
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
NgTemplateOutlet,
|
|
||||||
NifiTooltipDirective,
|
NifiTooltipDirective,
|
||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
|
@ -68,6 +67,7 @@ export class ComboEditor {
|
||||||
|
|
||||||
this.descriptor = item.descriptor;
|
this.descriptor = item.descriptor;
|
||||||
this.sensitive = item.descriptor.sensitive;
|
this.sensitive = item.descriptor.sensitive;
|
||||||
|
this.savedValue = item.savedValue;
|
||||||
|
|
||||||
this.itemSet = true;
|
this.itemSet = true;
|
||||||
this.initialAllowableValues();
|
this.initialAllowableValues();
|
||||||
|
@ -102,6 +102,7 @@ export class ComboEditor {
|
||||||
|
|
||||||
itemSet = false;
|
itemSet = false;
|
||||||
configuredValue: string | null = null;
|
configuredValue: string | null = null;
|
||||||
|
savedValue: string | null = null;
|
||||||
parameters: Parameter[] | null = null;
|
parameters: Parameter[] | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -125,6 +126,7 @@ export class ComboEditor {
|
||||||
if (!this.descriptor.required) {
|
if (!this.descriptor.required) {
|
||||||
const noValue: AllowableValueItem = {
|
const noValue: AllowableValueItem = {
|
||||||
id: i++,
|
id: i++,
|
||||||
|
disabled: false,
|
||||||
displayName: 'No value',
|
displayName: 'No value',
|
||||||
value: null
|
value: null
|
||||||
};
|
};
|
||||||
|
@ -141,7 +143,10 @@ export class ComboEditor {
|
||||||
(allowableValueEntity) => {
|
(allowableValueEntity) => {
|
||||||
const allowableValue: AllowableValueItem = {
|
const allowableValue: AllowableValueItem = {
|
||||||
...allowableValueEntity.allowableValue,
|
...allowableValueEntity.allowableValue,
|
||||||
id: i++
|
id: i++,
|
||||||
|
disabled:
|
||||||
|
!allowableValueEntity.canRead &&
|
||||||
|
allowableValueEntity.allowableValue.value !== this.savedValue
|
||||||
};
|
};
|
||||||
this.itemLookup.set(allowableValue.id, allowableValue);
|
this.itemLookup.set(allowableValue.id, allowableValue);
|
||||||
|
|
||||||
|
@ -160,6 +165,7 @@ export class ComboEditor {
|
||||||
// and hiding the parameter options select
|
// and hiding the parameter options select
|
||||||
const referencesParameterOption: AllowableValueItem = {
|
const referencesParameterOption: AllowableValueItem = {
|
||||||
id: i++,
|
id: i++,
|
||||||
|
disabled: false,
|
||||||
displayName: 'Reference Parameter...',
|
displayName: 'Reference Parameter...',
|
||||||
value: null
|
value: null
|
||||||
};
|
};
|
||||||
|
@ -187,6 +193,7 @@ export class ComboEditor {
|
||||||
this.parameters.forEach((parameter) => {
|
this.parameters.forEach((parameter) => {
|
||||||
const parameterItem: AllowableValueItem = {
|
const parameterItem: AllowableValueItem = {
|
||||||
id: i++,
|
id: i++,
|
||||||
|
disabled: false,
|
||||||
displayName: parameter.name,
|
displayName: parameter.name,
|
||||||
value: `#{${parameter.name}}`,
|
value: `#{${parameter.name}}`,
|
||||||
description: parameter.description
|
description: parameter.description
|
||||||
|
|
|
@ -62,6 +62,7 @@ describe('NfEditor', () => {
|
||||||
deleted: false,
|
deleted: false,
|
||||||
added: false,
|
added: false,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
savedValue: value,
|
||||||
type: 'required'
|
type: 'required'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ describe('NfEditor', () => {
|
||||||
deleted: false,
|
deleted: false,
|
||||||
added: false,
|
added: false,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
savedValue: value,
|
||||||
type: 'required'
|
type: 'required'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||||
import { NiFiCommon, NifiTooltipDirective, TextTip } from '@nifi/shared';
|
import { NiFiCommon, NifiTooltipDirective, TextTip } from '@nifi/shared';
|
||||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
import { NgTemplateOutlet } from '@angular/common';
|
||||||
import {
|
import {
|
||||||
AllowableValueEntity,
|
AllowableValueEntity,
|
||||||
ComponentHistory,
|
ComponentHistory,
|
||||||
|
@ -57,7 +57,6 @@ import {
|
||||||
import { ComboEditor } from './editors/combo-editor/combo-editor.component';
|
import { ComboEditor } from './editors/combo-editor/combo-editor.component';
|
||||||
import { Observable, take } from 'rxjs';
|
import { Observable, take } from 'rxjs';
|
||||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||||
import { RouterLink } from '@angular/router';
|
|
||||||
import { ConvertToParameterResponse } from '../../../pages/flow-designer/service/parameter-helper.service';
|
import { ConvertToParameterResponse } from '../../../pages/flow-designer/service/parameter-helper.service';
|
||||||
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
|
||||||
|
|
||||||
|
@ -68,6 +67,7 @@ export interface PropertyItem extends Property {
|
||||||
dirty: boolean;
|
dirty: boolean;
|
||||||
added: boolean;
|
added: boolean;
|
||||||
type: 'required' | 'userDefined' | 'optional';
|
type: 'required' | 'userDefined' | 'optional';
|
||||||
|
savedValue: string | null;
|
||||||
serviceLink?: string[];
|
serviceLink?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,8 +85,6 @@ export interface PropertyItem extends Property {
|
||||||
CdkOverlayOrigin,
|
CdkOverlayOrigin,
|
||||||
CdkConnectedOverlay,
|
CdkConnectedOverlay,
|
||||||
ComboEditor,
|
ComboEditor,
|
||||||
RouterLink,
|
|
||||||
AsyncPipe,
|
|
||||||
MatMenu,
|
MatMenu,
|
||||||
MatMenuItem,
|
MatMenuItem,
|
||||||
MatMenuTrigger
|
MatMenuTrigger
|
||||||
|
@ -299,6 +297,7 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor {
|
||||||
deleted: false,
|
deleted: false,
|
||||||
added: false,
|
added: false,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
|
savedValue: property.value,
|
||||||
type: property.descriptor.required
|
type: property.descriptor.required
|
||||||
? 'required'
|
? 'required'
|
||||||
: property.descriptor.dynamic
|
: property.descriptor.dynamic
|
||||||
|
@ -383,6 +382,7 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor {
|
||||||
deleted: false,
|
deleted: false,
|
||||||
added: true,
|
added: true,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
savedValue: property.value,
|
||||||
type: property.descriptor.required
|
type: property.descriptor.required
|
||||||
? 'required'
|
? 'required'
|
||||||
: property.descriptor.dynamic
|
: property.descriptor.dynamic
|
||||||
|
@ -571,6 +571,10 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor {
|
||||||
|
|
||||||
savePropertyValue(item: PropertyItem, newValue: string | null): void {
|
savePropertyValue(item: PropertyItem, newValue: string | null): void {
|
||||||
if (item.value != newValue) {
|
if (item.value != newValue) {
|
||||||
|
if (!item.savedValue) {
|
||||||
|
item.savedValue = item.value;
|
||||||
|
}
|
||||||
|
|
||||||
item.value = newValue;
|
item.value = newValue;
|
||||||
item.dirty = true;
|
item.dirty = true;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue