mirror of https://github.com/apache/nifi.git
NIFI-13670: Improve sensitive value editing. (#9191)
* NIFI-13670: Improve sensitive value editing. - Do not present the user with the masked value. - Do not use the masked value when determining if a value has changed. - Do not include the masked value in the payload if the value hasn't changed. - Updates to ParameterItem model to more easily track changes. * NIFI-13670: Not setting valueRemoved when deleting a parameter. * NIFI-13670: Marking field as dirty following removal of sensitive value set text.
This commit is contained in:
parent
cbdc53a565
commit
7945234f5a
|
@ -113,7 +113,7 @@ export class ParameterContextListingEffects {
|
|||
|
||||
dialogReference.componentInstance.createNewParameter = (
|
||||
existingParameters: string[]
|
||||
): Observable<Parameter> => {
|
||||
): Observable<EditParameterResponse> => {
|
||||
const dialogRequest: EditParameterRequest = { existingParameters };
|
||||
const newParameterDialogReference = this.dialog.open(EditParameterDialog, {
|
||||
...MEDIUM_DIALOG,
|
||||
|
@ -128,13 +128,15 @@ export class ParameterContextListingEffects {
|
|||
newParameterDialogReference.close();
|
||||
|
||||
return {
|
||||
...dialogResponse.parameter
|
||||
...dialogResponse
|
||||
};
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
dialogReference.componentInstance.editParameter = (parameter: Parameter): Observable<Parameter> => {
|
||||
dialogReference.componentInstance.editParameter = (
|
||||
parameter: Parameter
|
||||
): Observable<EditParameterResponse> => {
|
||||
const dialogRequest: EditParameterRequest = {
|
||||
parameter: {
|
||||
...parameter
|
||||
|
@ -153,7 +155,7 @@ export class ParameterContextListingEffects {
|
|||
editParameterDialogReference.close();
|
||||
|
||||
return {
|
||||
...dialogResponse.parameter
|
||||
...dialogResponse
|
||||
};
|
||||
})
|
||||
);
|
||||
|
@ -317,7 +319,7 @@ export class ParameterContextListingEffects {
|
|||
|
||||
editDialogReference.componentInstance.createNewParameter = (
|
||||
existingParameters: string[]
|
||||
): Observable<Parameter> => {
|
||||
): Observable<EditParameterResponse> => {
|
||||
const dialogRequest: EditParameterRequest = { existingParameters };
|
||||
const newParameterDialogReference = this.dialog.open(EditParameterDialog, {
|
||||
...MEDIUM_DIALOG,
|
||||
|
@ -332,7 +334,7 @@ export class ParameterContextListingEffects {
|
|||
newParameterDialogReference.close();
|
||||
|
||||
return {
|
||||
...dialogResponse.parameter
|
||||
...dialogResponse
|
||||
};
|
||||
})
|
||||
);
|
||||
|
@ -340,7 +342,7 @@ export class ParameterContextListingEffects {
|
|||
|
||||
editDialogReference.componentInstance.editParameter = (
|
||||
parameter: Parameter
|
||||
): Observable<Parameter> => {
|
||||
): Observable<EditParameterResponse> => {
|
||||
const dialogRequest: EditParameterRequest = {
|
||||
parameter: {
|
||||
...parameter
|
||||
|
@ -359,7 +361,7 @@ export class ParameterContextListingEffects {
|
|||
editParameterDialogReference.close();
|
||||
|
||||
return {
|
||||
...dialogResponse.parameter
|
||||
...dialogResponse
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
@ -31,6 +31,7 @@ import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spin
|
|||
import { Client } from '../../../../../service/client.service';
|
||||
import { ParameterTable } from '../parameter-table/parameter-table.component';
|
||||
import {
|
||||
EditParameterResponse,
|
||||
Parameter,
|
||||
ParameterContextEntity,
|
||||
ParameterContextUpdateRequestEntity,
|
||||
|
@ -73,8 +74,8 @@ import { NiFiCommon, TextTip, NifiTooltipDirective } from '@nifi/shared';
|
|||
styleUrls: ['./edit-parameter-context.component.scss']
|
||||
})
|
||||
export class EditParameterContext extends TabbedDialog {
|
||||
@Input() createNewParameter!: (existingParameters: string[]) => Observable<Parameter>;
|
||||
@Input() editParameter!: (parameter: Parameter) => Observable<Parameter>;
|
||||
@Input() createNewParameter!: (existingParameters: string[]) => Observable<EditParameterResponse>;
|
||||
@Input() editParameter!: (parameter: Parameter) => Observable<EditParameterResponse>;
|
||||
@Input() updateRequest!: Observable<ParameterContextUpdateRequestEntity | null>;
|
||||
@Input() availableParameterContexts$!: Observable<ParameterContextEntity[]>;
|
||||
@Input() saving$!: Observable<boolean>;
|
||||
|
|
|
@ -41,15 +41,15 @@
|
|||
<div class="flex justify-between items-center">
|
||||
<div
|
||||
class="whitespace-nowrap overflow-hidden text-ellipsis leading-normal"
|
||||
[title]="item.entity.parameter.name">
|
||||
{{ item.entity.parameter.name }}
|
||||
[title]="item.originalEntity.parameter.name">
|
||||
{{ item.originalEntity.parameter.name }}
|
||||
</div>
|
||||
@if (hasDescription(item)) {
|
||||
<i
|
||||
class="fa fa-info-circle primary-color"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
[tooltipInputData]="item.entity.parameter.description"
|
||||
[tooltipInputData]="getDescription(item)"
|
||||
[delayClose]="false"></i>
|
||||
}
|
||||
@if (canOverride(item)) {
|
||||
|
@ -68,42 +68,46 @@
|
|||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef>Value</th>
|
||||
<td mat-cell *matCellDef="let item">
|
||||
@if (isNull(item.entity.parameter.value)) {
|
||||
<div class="unset surface-color">No value set</div>
|
||||
} @else {
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
isSensitiveParameter(item) ? sensitive : nonSensitive;
|
||||
context: { $implicit: item.entity.parameter.value }
|
||||
"></ng-container>
|
||||
<ng-template #sensitive>
|
||||
<div class="sensitive surface-color">Sensitive value set</div>
|
||||
</ng-template>
|
||||
<ng-template #nonSensitive let-value>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="renderValue; context: { $implicit: getValue(item) }"></ng-container>
|
||||
<ng-template #renderValue let-parameterValue>
|
||||
@if (isNull(parameterValue)) {
|
||||
<div class="unset surface-color">No value set</div>
|
||||
} @else {
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
isEmptyString(value) ? blank : nonBlank;
|
||||
context: { $implicit: value }
|
||||
isSensitiveParameter(item) ? sensitive : nonSensitive;
|
||||
context: { $implicit: parameterValue }
|
||||
"></ng-container>
|
||||
</ng-template>
|
||||
<ng-template #blank>
|
||||
<div class="empty surface-color">Empty string set</div>
|
||||
</ng-template>
|
||||
<ng-template #nonBlank let-value>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{{ value }}
|
||||
<ng-template #sensitive>
|
||||
<div class="sensitive surface-color">Sensitive value set</div>
|
||||
</ng-template>
|
||||
<ng-template #nonSensitive let-value>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
isEmptyString(value) ? blank : nonBlank;
|
||||
context: { $implicit: value }
|
||||
"></ng-container>
|
||||
</ng-template>
|
||||
<ng-template #blank>
|
||||
<div class="empty surface-color">Empty string set</div>
|
||||
</ng-template>
|
||||
<ng-template #nonBlank let-value>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="whitespace-nowrap overflow-hidden text-ellipsis">
|
||||
{{ value }}
|
||||
</div>
|
||||
@if (hasExtraWhitespace(value)) {
|
||||
<div
|
||||
class="fa fa-info-circle primary-color"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
tooltipInputData="The specified value contains leading and/or trailing whitespace character(s). This could produce unexpected results if it was not intentional."></div>
|
||||
}
|
||||
</div>
|
||||
@if (hasExtraWhitespace(value)) {
|
||||
<div
|
||||
class="fa fa-info-circle primary-color"
|
||||
nifiTooltip
|
||||
[tooltipComponentType]="TextTip"
|
||||
tooltipInputData="The specified value contains leading and/or trailing whitespace character(s). This could produce unexpected results if it was not intentional."></div>
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
}
|
||||
</ng-template>
|
||||
}
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
@ -171,7 +175,7 @@
|
|||
<div>Parameter</div>
|
||||
<div class="accent-color font-medium">
|
||||
@if (selectedItem) {
|
||||
<span>{{ selectedItem.entity.parameter.name }}</span>
|
||||
<span>{{ selectedItem.originalEntity.parameter.name }}</span>
|
||||
} @else {
|
||||
<span class="unset surface-color">None</span>
|
||||
}
|
||||
|
@ -191,7 +195,7 @@
|
|||
@if (selectedItem) {
|
||||
<parameter-references
|
||||
[parameterReferences]="
|
||||
selectedItem.entity.parameter.referencingComponents
|
||||
selectedItem.originalEntity.parameter.referencingComponents
|
||||
"></parameter-references>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -23,7 +23,7 @@ import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
|||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common';
|
||||
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { Parameter, ParameterEntity } from '../../../../../state/shared';
|
||||
import { EditParameterResponse, Parameter, ParameterEntity } from '../../../../../state/shared';
|
||||
import { NifiTooltipDirective, NiFiCommon, TextTip } from '@nifi/shared';
|
||||
import { Observable, take } from 'rxjs';
|
||||
import { ParameterReferences } from '../../../../../ui/common/parameter-references/parameter-references.component';
|
||||
|
@ -37,7 +37,8 @@ export interface ParameterItem {
|
|||
deleted: boolean;
|
||||
dirty: boolean;
|
||||
added: boolean;
|
||||
entity: ParameterEntity;
|
||||
originalEntity: ParameterEntity; // either new or existing from server
|
||||
updatedEntity?: ParameterEntity;
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
@ -70,8 +71,8 @@ export interface ParameterItem {
|
|||
]
|
||||
})
|
||||
export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
||||
@Input() createNewParameter!: (existingParameters: string[]) => Observable<Parameter>;
|
||||
@Input() editParameter!: (parameter: Parameter) => Observable<Parameter>;
|
||||
@Input() createNewParameter!: (existingParameters: string[]) => Observable<EditParameterResponse>;
|
||||
@Input() editParameter!: (parameter: Parameter) => Observable<EditParameterResponse>;
|
||||
@Input() canAddParameters = true;
|
||||
|
||||
protected readonly TextTip = TextTip;
|
||||
|
@ -128,10 +129,11 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
deleted: false,
|
||||
added: false,
|
||||
dirty: false,
|
||||
entity: {
|
||||
originalEntity: {
|
||||
...entity,
|
||||
parameter: {
|
||||
...entity.parameter
|
||||
...entity.parameter,
|
||||
value: entity.parameter.value === undefined ? null : entity.parameter.value
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -161,7 +163,10 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
let retVal = 0;
|
||||
switch (sort.active) {
|
||||
case 'name':
|
||||
retVal = this.nifiCommon.compareString(a.entity.parameter.name, b.entity.parameter.name);
|
||||
retVal = this.nifiCommon.compareString(
|
||||
a.originalEntity.parameter.name,
|
||||
b.originalEntity.parameter.name
|
||||
);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -176,25 +181,27 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
// unmarked for deletion if the user chooses to enter the same name
|
||||
const existingParameters: string[] = this.dataSource.data
|
||||
.filter((item) => !item.deleted)
|
||||
.filter((item) => !item.entity.parameter.inherited)
|
||||
.map((item) => item.entity.parameter.name);
|
||||
.filter((item) => !item.originalEntity.parameter.inherited)
|
||||
.map((item) => item.originalEntity.parameter.name);
|
||||
|
||||
this.createNewParameter(existingParameters)
|
||||
.pipe(take(1))
|
||||
.subscribe((parameter) => {
|
||||
.subscribe((response: EditParameterResponse) => {
|
||||
const parameter: Parameter = response.parameter;
|
||||
|
||||
const currentParameterItems: ParameterItem[] = this.dataSource.data;
|
||||
|
||||
// identify if a parameter with the same name already exists (must have been marked
|
||||
// for deletion already)
|
||||
const item: ParameterItem | undefined = currentParameterItems.find(
|
||||
(item) => item.entity.parameter.name === parameter.name
|
||||
(item) => item.originalEntity.parameter.name === parameter.name
|
||||
);
|
||||
|
||||
if (item) {
|
||||
// if the item is added that means it hasn't been saved yet. in this case, we
|
||||
// can simply update the existing parameter. if the item has been saved, and the
|
||||
// sensitivity has changed, the user must apply the changes first.
|
||||
if (!item.added && item.entity.parameter.sensitive !== parameter.sensitive) {
|
||||
if (!item.added && item.originalEntity.parameter.sensitive !== parameter.sensitive) {
|
||||
this.store.dispatch(
|
||||
showOkDialog({
|
||||
title: 'Parameter Exists',
|
||||
|
@ -208,15 +215,21 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
// update the existing item
|
||||
item.deleted = false;
|
||||
item.dirty = true;
|
||||
item.entity.parameter = {
|
||||
...parameter
|
||||
};
|
||||
|
||||
// since the item is either new or the sensitivity is the same, accept the sensitivity
|
||||
// from the response to be set on the entities
|
||||
item.originalEntity.parameter.sensitive = parameter.sensitive;
|
||||
if (item.updatedEntity) {
|
||||
item.updatedEntity.parameter.sensitive = parameter.sensitive;
|
||||
}
|
||||
|
||||
this.applyParameterEdit(item, response);
|
||||
} else {
|
||||
const newItem: ParameterItem = {
|
||||
deleted: false,
|
||||
added: true,
|
||||
dirty: true,
|
||||
entity: {
|
||||
originalEntity: {
|
||||
canWrite: true,
|
||||
parameter: {
|
||||
...parameter
|
||||
|
@ -232,11 +245,36 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
}
|
||||
|
||||
hasDescription(item: ParameterItem): boolean {
|
||||
return !this.nifiCommon.isBlank(item.entity.parameter.description);
|
||||
return !this.nifiCommon.isBlank(this.getDescription(item));
|
||||
}
|
||||
|
||||
getDescription(item: ParameterItem): string {
|
||||
if (item.updatedEntity) {
|
||||
return item.updatedEntity.parameter.description;
|
||||
} else {
|
||||
return item.originalEntity.parameter.description;
|
||||
}
|
||||
}
|
||||
|
||||
isSensitiveParameter(item: ParameterItem): boolean {
|
||||
return item.entity.parameter.sensitive;
|
||||
return item.originalEntity.parameter.sensitive;
|
||||
}
|
||||
|
||||
getValue(item: ParameterItem): string | null {
|
||||
if (item.updatedEntity) {
|
||||
if (item.updatedEntity.parameter.valueRemoved) {
|
||||
return null;
|
||||
} else {
|
||||
// if there is an updated value use that, otherwise the original
|
||||
if (item.updatedEntity.parameter.value !== null) {
|
||||
return item.updatedEntity.parameter.value;
|
||||
} else {
|
||||
return item.originalEntity.parameter.value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return item.originalEntity.parameter.value;
|
||||
}
|
||||
}
|
||||
|
||||
isNull(value: string): boolean {
|
||||
|
@ -253,35 +291,37 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
|
||||
canGoToParameter(item: ParameterItem): boolean {
|
||||
return (
|
||||
item.entity.parameter.inherited === true &&
|
||||
item.entity.parameter.parameterContext?.permissions.canRead == true
|
||||
item.originalEntity.parameter.inherited === true &&
|
||||
item.originalEntity.parameter.parameterContext?.permissions.canRead == true
|
||||
);
|
||||
}
|
||||
|
||||
getParameterLink(item: ParameterItem): string[] {
|
||||
if (item.entity.parameter.parameterContext) {
|
||||
if (item.originalEntity.parameter.parameterContext) {
|
||||
// TODO - support routing directly to a parameter
|
||||
return ['/parameter-contexts', item.entity.parameter.parameterContext.id, 'edit'];
|
||||
return ['/parameter-contexts', item.originalEntity.parameter.parameterContext.id, 'edit'];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
canOverride(item: ParameterItem): boolean {
|
||||
return item.entity.parameter.inherited === true;
|
||||
return item.originalEntity.parameter.inherited === true;
|
||||
}
|
||||
|
||||
overrideParameter(item: ParameterItem): void {
|
||||
const overriddenParameter: Parameter = {
|
||||
...item.entity.parameter,
|
||||
...item.originalEntity.parameter,
|
||||
value: null
|
||||
};
|
||||
|
||||
this.editParameter(overriddenParameter)
|
||||
.pipe(take(1))
|
||||
.subscribe((parameter) => {
|
||||
.subscribe((response) => {
|
||||
item.dirty = true;
|
||||
item.entity.parameter = {
|
||||
...parameter
|
||||
item.updatedEntity = {
|
||||
parameter: {
|
||||
...response.parameter
|
||||
}
|
||||
};
|
||||
|
||||
this.handleChanged();
|
||||
|
@ -289,46 +329,93 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
}
|
||||
|
||||
canEdit(item: ParameterItem): boolean {
|
||||
const canWrite: boolean = item.entity.canWrite == true;
|
||||
const provided: boolean = item.entity.parameter.provided == true;
|
||||
const inherited: boolean = item.entity.parameter.inherited == true;
|
||||
const canWrite: boolean = item.originalEntity.canWrite == true;
|
||||
const provided: boolean = item.originalEntity.parameter.provided == true;
|
||||
const inherited: boolean = item.originalEntity.parameter.inherited == true;
|
||||
return canWrite && !provided && !inherited;
|
||||
}
|
||||
|
||||
editClicked(item: ParameterItem): void {
|
||||
this.editParameter(item.entity.parameter)
|
||||
const parameterToEdit: Parameter = {
|
||||
name: item.originalEntity.parameter.name,
|
||||
sensitive: item.originalEntity.parameter.sensitive,
|
||||
description: this.getDescription(item),
|
||||
value: this.getValue(item)
|
||||
};
|
||||
|
||||
this.editParameter(parameterToEdit)
|
||||
.pipe(take(1))
|
||||
.subscribe((parameter) => {
|
||||
const valueChanged: boolean = item.entity.parameter.value != parameter.value;
|
||||
const descriptionChanged: boolean = item.entity.parameter.description != parameter.description;
|
||||
const valueRemovedChanged: boolean = item.entity.parameter.valueRemoved != parameter.valueRemoved;
|
||||
|
||||
if (valueChanged || descriptionChanged || valueRemovedChanged) {
|
||||
item.entity.parameter.value = parameter.value;
|
||||
item.entity.parameter.description = parameter.description;
|
||||
item.entity.parameter.valueRemoved = parameter.valueRemoved;
|
||||
item.dirty = true;
|
||||
|
||||
if (valueChanged) {
|
||||
item.entity.parameter.referencedAssets = undefined;
|
||||
}
|
||||
|
||||
this.handleChanged();
|
||||
}
|
||||
.subscribe((response) => {
|
||||
this.applyParameterEdit(item, response);
|
||||
});
|
||||
}
|
||||
|
||||
private applyParameterEdit(item: ParameterItem, response: EditParameterResponse) {
|
||||
const parameter: Parameter = response.parameter;
|
||||
|
||||
// initialize the updated entity if this is the first time this has been edited
|
||||
if (!item.updatedEntity) {
|
||||
item.updatedEntity = {
|
||||
parameter: {
|
||||
...item.originalEntity.parameter,
|
||||
value: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let hasChanged: boolean = response.valueChanged;
|
||||
|
||||
if (response.valueChanged) {
|
||||
item.updatedEntity.parameter.value = parameter.value;
|
||||
|
||||
// a value has been specified so record it in the updated entity
|
||||
if (parameter.value !== null) {
|
||||
item.updatedEntity.parameter.valueRemoved = undefined;
|
||||
item.updatedEntity.parameter.referencedAssets = undefined;
|
||||
} else {
|
||||
// the value is null, this means that the value should be unchanged
|
||||
// or that the value has been removed. if removed we should
|
||||
// clear our the value.
|
||||
if (parameter.valueRemoved === true) {
|
||||
item.updatedEntity.parameter.value = null;
|
||||
item.updatedEntity.parameter.valueRemoved = true;
|
||||
item.updatedEntity.parameter.referencedAssets = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.updatedEntity.parameter.description !== parameter.description) {
|
||||
hasChanged = true;
|
||||
item.updatedEntity.parameter.description = parameter.description;
|
||||
}
|
||||
|
||||
// if any aspect of the parameter has changed, mark it dirty and trigger handle changed
|
||||
if (hasChanged) {
|
||||
item.dirty = true;
|
||||
this.handleChanged();
|
||||
}
|
||||
}
|
||||
|
||||
canDelete(item: ParameterItem): boolean {
|
||||
const canWrite: boolean = item.entity.canWrite == true;
|
||||
const provided: boolean = item.entity.parameter.provided == true;
|
||||
const inherited: boolean = item.entity.parameter.inherited == true;
|
||||
const canWrite: boolean = item.originalEntity.canWrite == true;
|
||||
const provided: boolean = item.originalEntity.parameter.provided == true;
|
||||
const inherited: boolean = item.originalEntity.parameter.inherited == true;
|
||||
return canWrite && !provided && !inherited;
|
||||
}
|
||||
|
||||
deleteClicked(item: ParameterItem): void {
|
||||
if (!item.deleted) {
|
||||
item.entity.parameter.value = null;
|
||||
item.entity.parameter.valueRemoved = true;
|
||||
if (!item.updatedEntity) {
|
||||
item.updatedEntity = {
|
||||
parameter: {
|
||||
...item.originalEntity.parameter
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
item.updatedEntity.parameter.value = null;
|
||||
item.updatedEntity.parameter.referencedAssets = undefined;
|
||||
|
||||
item.deleted = true;
|
||||
item.dirty = true;
|
||||
this.selectParameter(null);
|
||||
|
@ -360,20 +447,34 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
.filter((item) => !(item.added && item.deleted))
|
||||
.map((item) => {
|
||||
if (item.deleted) {
|
||||
// item is deleted
|
||||
return {
|
||||
parameter: {
|
||||
name: item.entity.parameter.name
|
||||
name: item.originalEntity.parameter.name
|
||||
}
|
||||
};
|
||||
} else if (item.updatedEntity) {
|
||||
// item has been edited
|
||||
return {
|
||||
parameter: {
|
||||
name: item.originalEntity.parameter.name,
|
||||
sensitive: item.originalEntity.parameter.sensitive,
|
||||
description: item.updatedEntity.parameter.description,
|
||||
value: item.updatedEntity.parameter.value,
|
||||
valueRemoved: item.updatedEntity.parameter.valueRemoved,
|
||||
referencedAssets: item.updatedEntity.parameter.referencedAssets
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// item is added (but not subsequently edited)
|
||||
return {
|
||||
parameter: {
|
||||
name: item.entity.parameter.name,
|
||||
sensitive: item.entity.parameter.sensitive,
|
||||
description: item.entity.parameter.description,
|
||||
value: item.entity.parameter.value,
|
||||
valueRemoved: item.entity.parameter.valueRemoved,
|
||||
referencedAssets: item.entity.parameter.referencedAssets
|
||||
name: item.originalEntity.parameter.name,
|
||||
sensitive: item.originalEntity.parameter.sensitive,
|
||||
description: item.originalEntity.parameter.description,
|
||||
value: item.originalEntity.parameter.value,
|
||||
valueRemoved: item.originalEntity.parameter.valueRemoved,
|
||||
referencedAssets: item.originalEntity.parameter.referencedAssets
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -386,7 +487,7 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
|
|||
|
||||
isSelected(item: ParameterItem): boolean {
|
||||
if (this.selectedItem) {
|
||||
return item.entity.parameter.name == this.selectedItem.entity.parameter.name;
|
||||
return item.originalEntity.parameter.name == this.selectedItem.originalEntity.parameter.name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ export interface EditParameterRequest {
|
|||
|
||||
export interface EditParameterResponse {
|
||||
parameter: Parameter;
|
||||
valueChanged: boolean;
|
||||
}
|
||||
|
||||
export interface AdvancedUiParams {
|
||||
|
|
|
@ -37,7 +37,12 @@
|
|||
[tooltipComponentType]="TextTip"
|
||||
tooltipInputData="Parameter values do not support Expression Language or embedded parameter references."></i>
|
||||
</mat-label>
|
||||
<textarea matInput formControlName="value" type="text"></textarea>
|
||||
<textarea
|
||||
matInput
|
||||
formControlName="value"
|
||||
type="text"
|
||||
[class.sensitive]="showSensitiveHelperText"
|
||||
(keydown)="clearSensitiveHelperText()"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="-mt-4 mb-4">
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
import { Component, EventEmitter, Inject, Input, Output } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
||||
import { EditParameterRequest, EditParameterResponse, Parameter, ReferencedAsset } from '../../../state/shared';
|
||||
import { EditParameterRequest, EditParameterResponse, Parameter } from '../../../state/shared';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import {
|
||||
AbstractControl,
|
||||
|
@ -67,6 +67,8 @@ export class EditParameterDialog extends CloseOnEscapeDialog {
|
|||
sensitive: FormControl;
|
||||
editParameterForm: FormGroup;
|
||||
isNew: boolean;
|
||||
showSensitiveHelperText: boolean = false;
|
||||
valueInputTriggered: boolean = false;
|
||||
|
||||
private originalParameter: Parameter | undefined = undefined;
|
||||
|
||||
|
@ -81,10 +83,14 @@ export class EditParameterDialog extends CloseOnEscapeDialog {
|
|||
const parameter: Parameter | undefined = request.parameter;
|
||||
this.originalParameter = parameter;
|
||||
|
||||
let value: string | null;
|
||||
|
||||
const validators: any[] = [Validators.required];
|
||||
if (request.existingParameters) {
|
||||
this.isNew = true;
|
||||
|
||||
value = parameter ? parameter.value : null;
|
||||
|
||||
// since there were existing parameters in the request, add the existing parameters validator because
|
||||
// parameters names must be unique
|
||||
validators.push(this.existingParameterValidator(request.existingParameters));
|
||||
|
@ -100,20 +106,25 @@ export class EditParameterDialog extends CloseOnEscapeDialog {
|
|||
} else {
|
||||
this.isNew = false;
|
||||
|
||||
value = parameter ? parameter.value : null;
|
||||
|
||||
const sensitive = parameter ? parameter.sensitive : false;
|
||||
if (sensitive && value !== null) {
|
||||
value = 'Sensitive value set';
|
||||
this.showSensitiveHelperText = true;
|
||||
}
|
||||
|
||||
// without existingParameters, we are editing an existing parameter. in this case the name and sensitivity cannot be modified
|
||||
this.name = new FormControl(
|
||||
{ value: parameter ? parameter.name : '', disabled: true },
|
||||
Validators.required
|
||||
);
|
||||
this.sensitive = new FormControl(
|
||||
{ value: parameter ? parameter.sensitive : false, disabled: true },
|
||||
Validators.required
|
||||
);
|
||||
this.sensitive = new FormControl({ value: sensitive, disabled: true }, Validators.required);
|
||||
}
|
||||
|
||||
this.editParameterForm = this.formBuilder.group({
|
||||
name: this.name,
|
||||
value: new FormControl(parameter ? parameter.value : null),
|
||||
value: new FormControl(value),
|
||||
empty: new FormControl(parameter ? parameter.value == '' : false),
|
||||
sensitive: this.sensitive,
|
||||
description: new FormControl(parameter ? parameter.description : '')
|
||||
|
@ -146,12 +157,23 @@ export class EditParameterDialog extends CloseOnEscapeDialog {
|
|||
return this.name.hasError('existingParameter') ? 'A parameter with this name already exists.' : '';
|
||||
}
|
||||
|
||||
clearSensitiveHelperText(): void {
|
||||
if (this.showSensitiveHelperText) {
|
||||
this.editParameterForm.get('value')?.setValue('');
|
||||
this.showSensitiveHelperText = false;
|
||||
}
|
||||
|
||||
this.valueInputTriggered = true;
|
||||
}
|
||||
|
||||
setEmptyStringChanged(): void {
|
||||
const emptyStringChecked: AbstractControl | null = this.editParameterForm.get('empty');
|
||||
if (emptyStringChecked) {
|
||||
if (emptyStringChecked.value) {
|
||||
this.editParameterForm.get('value')?.setValue('');
|
||||
this.editParameterForm.get('value')?.disable();
|
||||
|
||||
this.valueInputTriggered = true;
|
||||
} else {
|
||||
this.editParameterForm.get('value')?.enable();
|
||||
}
|
||||
|
@ -162,24 +184,50 @@ export class EditParameterDialog extends CloseOnEscapeDialog {
|
|||
this.cancel.next();
|
||||
}
|
||||
|
||||
okClicked(): void {
|
||||
const value: string = this.editParameterForm.get('value')?.value;
|
||||
const empty: boolean = this.editParameterForm.get('empty')?.value;
|
||||
let referencedAssets: ReferencedAsset[] | undefined = undefined;
|
||||
|
||||
private valueChanged(enteredValue: string | null): boolean {
|
||||
let valueChanged = true;
|
||||
if (this.originalParameter) {
|
||||
referencedAssets = this.originalParameter.referencedAssets;
|
||||
if (this.originalParameter.sensitive) {
|
||||
valueChanged = this.valueInputTriggered;
|
||||
} else {
|
||||
valueChanged = enteredValue !== this.originalParameter.value;
|
||||
}
|
||||
}
|
||||
return valueChanged;
|
||||
}
|
||||
|
||||
okClicked(): void {
|
||||
const value: string | null = this.editParameterForm.get('value')?.value;
|
||||
const empty: boolean = this.editParameterForm.get('empty')?.value;
|
||||
|
||||
const parameter: Parameter = {
|
||||
name: this.editParameterForm.get('name')?.value,
|
||||
value: null,
|
||||
sensitive: this.editParameterForm.get('sensitive')?.value,
|
||||
description: this.editParameterForm.get('description')?.value
|
||||
};
|
||||
|
||||
// update the parameter value
|
||||
let valueChanged = this.valueChanged(value);
|
||||
if (valueChanged) {
|
||||
parameter.value = value;
|
||||
}
|
||||
|
||||
// indicate if the value has been removed
|
||||
const valueRemoved = value === '' && !empty;
|
||||
if (valueRemoved) {
|
||||
valueChanged = true;
|
||||
parameter.value = null;
|
||||
|
||||
// if this is a new parameter there is no need to indicate that the value is removed
|
||||
if (!this.isNew) {
|
||||
parameter.valueRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.editParameter.next({
|
||||
parameter: {
|
||||
name: this.editParameterForm.get('name')?.value,
|
||||
value: value === '' && !empty ? null : value,
|
||||
valueRemoved: value === '' && !empty,
|
||||
sensitive: this.editParameterForm.get('sensitive')?.value,
|
||||
description: this.editParameterForm.get('description')?.value,
|
||||
referencedAssets
|
||||
}
|
||||
parameter,
|
||||
valueChanged
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
</ng-template>
|
||||
</div>
|
||||
<div class="flex flex-col gap-y-0.5 flex-1">
|
||||
<div class="nf-editor flex-1" [class.blank]="blank">
|
||||
<div class="nf-editor flex-1" [class.blank]="blank" [class.sensitive]="showSensitiveHelperText">
|
||||
<ngx-codemirror
|
||||
[options]="getOptions()"
|
||||
formControlName="value"
|
||||
|
|
|
@ -55,7 +55,13 @@ import { Editor } from 'codemirror';
|
|||
})
|
||||
export class NfEditor implements OnDestroy {
|
||||
@Input() set item(item: PropertyItem) {
|
||||
this.nfEditorForm.get('value')?.setValue(item.value);
|
||||
if (item.descriptor.sensitive && item.value !== null) {
|
||||
this.nfEditorForm.get('value')?.setValue('Sensitive value set');
|
||||
this.showSensitiveHelperText = true;
|
||||
} else {
|
||||
this.nfEditorForm.get('value')?.setValue(item.value);
|
||||
}
|
||||
|
||||
if (item.descriptor.required) {
|
||||
this.nfEditorForm.get('value')?.addValidators(Validators.required);
|
||||
} else {
|
||||
|
@ -67,7 +73,6 @@ export class NfEditor implements OnDestroy {
|
|||
this.setEmptyStringChanged();
|
||||
|
||||
this.supportsEl = item.descriptor.supportsEl;
|
||||
this.sensitive = item.descriptor.sensitive;
|
||||
this.mode = this.supportsEl ? this.nfel.getLanguageId() : this.nfpr.getLanguageId();
|
||||
|
||||
this.itemSet = true;
|
||||
|
@ -93,7 +98,7 @@ export class NfEditor implements OnDestroy {
|
|||
getParametersSet = false;
|
||||
|
||||
nfEditorForm: FormGroup;
|
||||
sensitive = false;
|
||||
showSensitiveHelperText = false;
|
||||
supportsEl = false;
|
||||
supportsParameters = false;
|
||||
blank = false;
|
||||
|
@ -124,6 +129,18 @@ export class NfEditor implements OnDestroy {
|
|||
this.editor.execCommand('selectAll');
|
||||
}
|
||||
|
||||
if (this.showSensitiveHelperText) {
|
||||
const clearSensitiveHelperText = () => {
|
||||
if (this.showSensitiveHelperText) {
|
||||
this.nfEditorForm.get('value')?.setValue('');
|
||||
this.nfEditorForm.get('value')?.markAsDirty();
|
||||
this.showSensitiveHelperText = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.editor.on('keydown', clearSensitiveHelperText);
|
||||
}
|
||||
|
||||
// disabling of the input through the form isn't supported until codemirror
|
||||
// has loaded so we must disable again if the value is an empty string
|
||||
if (this.nfEditorForm.get('setEmptyString')?.value) {
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
.unset,
|
||||
.sensitive {
|
||||
font-weight: normal !important;
|
||||
font-style: italic;
|
||||
opacity: 0.8;
|
||||
font-style: italic !important;
|
||||
opacity: 0.8 !important;
|
||||
}
|
||||
|
||||
.context-logo {
|
||||
|
|
Loading…
Reference in New Issue