Skip to content

Commit

Permalink
NIFI-12401: Allow combo editor to reference parameters (apache#8068)
Browse files Browse the repository at this point in the history
* NIFI-12401:
- Allow combo editor to reference parameters.

* NIFI-12401:
- Addressing review feedback.
- Handling corner cases where there is no parameter context and where there are no parameters in a bound parameter context.

* NIFI-12401:
- Fixing formatting issues.

This closes apache#8068
  • Loading branch information
mcgilman authored Nov 29, 2023
1 parent 9d50c6d commit ebfb5bc
Show file tree
Hide file tree
Showing 11 changed files with 495 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,35 @@
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/nifi'),
subdir: '.',
reporters: [
{ type: 'html' },
{ type: 'text-summary' }
]
},
reporters: ['progress', 'kjhtml'],
browsers: ['ChromeHeadless'],
restartOnFileChange: true
});
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
jasmine: {
// you can add configuration options for Jasmine here
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
// for example, you can disable the random execution with `random: false`
// or set a specific seed with `seed: 4321`
},
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
jasmineHtmlReporter: {
suppressAll: true // removes the duplicated traces
},
coverageReporter: {
dir: require('path').join(__dirname, './coverage/nifi'),
subdir: '.',
reporters: [{ type: 'html' }, { type: 'text-summary' }]
},
reporters: ['progress', 'kjhtml'],
browsers: ['ChromeHeadless'],
restartOnFileChange: true
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@
"@angular-devkit/build-angular": "^16.2.0",
"@angular/cli": "~16.2.0",
"@angular/compiler-cli": "^16.2.0",
"@types/codemirror": "^5.60.13",
"@types/d3": "^7.4.0",
"@types/humanize-duration": "^3.27.1",
"@types/jasmine": "~4.3.0",
"@types/webfontloader": "^1.6.35",
"@types/codemirror": "^5.60.13",
"autoprefixer": "^10.4.15",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@
</a>
<ng-template #resultLink>
<a [routerLink]="['/process-groups', result.parentGroup.id, path, result.id]">
{{ result.name }}
{{ result.name ? result.name : result.id }}
</a>
</ng-template>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ export interface ParameterContextReference {

export interface AffectedComponentEntity {
permissions: Permissions;
id: string;
revision: Revision;
bulletins: BulletinEntity[];
component: AffectedComponent;
processGroup: ProcessGroupName;
Expand Down Expand Up @@ -289,8 +291,8 @@ export interface PropertyDescriptor {
name: string;
displayName: string;
description: string;
defaultValue: string;
allowableValues: AllowableValueEntity[];
defaultValue?: string;
allowableValues?: AllowableValueEntity[];
required: boolean;
sensitive: boolean;
dynamic: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
formControlName="value"
[placeholder]="getComboPlaceholder()"
[panelClass]="'combo-panel'"
(mousedown)="preventDrag($event)">
(mousedown)="preventDrag($event)"
(selectionChange)="allowableValueChanged($event.value)">
<ng-container *ngFor="let allowableValue of allowableValues">
<ng-container *ngIf="allowableValue.description; else noDescription">
<mat-option
Expand All @@ -49,6 +50,41 @@
</ng-container>
</mat-select>
</div>
<div *ngIf="showParameterAllowableValues">
<div *ngIf="!parametersLoaded; else showParameters">
<ngx-skeleton-loader count="1"></ngx-skeleton-loader>
</div>
<ng-template #showParameters>
<mat-select
class="combo"
formControlName="parameterReference"
[panelClass]="'combo-panel'"
(mousedown)="preventDrag($event)">
<ng-container *ngFor="let parameterAllowableValue of parameterAllowableValues">
<ng-container *ngIf="parameterAllowableValue.description; else noDescription">
<mat-option
[value]="parameterAllowableValue.id"
(mousedown)="preventDrag($event)"
nifiTooltip
[tooltipComponentType]="TextTip"
[tooltipInputData]="getAllowableValueOptionTipData(parameterAllowableValue)"
[delayClose]="false">
<span class="option-text" [class.unset]="parameterAllowableValue.value == null">{{
parameterAllowableValue.displayName
}}</span>
</mat-option>
</ng-container>
<ng-template #noDescription>
<mat-option [value]="parameterAllowableValue.id" (mousedown)="preventDrag($event)">
<span class="option-text" [class.unset]="parameterAllowableValue.value == null">{{
parameterAllowableValue.displayName
}}</span>
</mat-option>
</ng-template>
</ng-container>
</mat-select>
</ng-template>
</div>
<div class="flex justify-end items-center gap-x-2">
<button
color="accent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,67 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ComboEditor } from './combo-editor.component';
import { PropertyItem } from '../../property-table.component';
import { Parameter } from '../../../../../state/shared';
import { of } from 'rxjs';

describe('ComboEditor', () => {
let component: ComboEditor;
let fixture: ComponentFixture<ComboEditor>;

let item: PropertyItem | null = null;
let parameters: Parameter[] = [
{
name: 'one',
description: 'Description for one.',
sensitive: false,
value: 'value',
provided: false,
referencingComponents: [],
parameterContext: {
id: '95d4f3d2-018b-1000-b7c7-b830c49a8026',
permissions: {
canRead: true,
canWrite: true
},
component: {
id: '95d4f3d2-018b-1000-b7c7-b830c49a8026',
name: 'params 1'
}
},
inherited: false
},
{
name: 'two',
description: 'Description for two.',
sensitive: false,
value: 'value',
provided: false,
referencingComponents: [],
parameterContext: {
id: '95d4f3d2-018b-1000-b7c7-b830c49a8026',
permissions: {
canRead: true,
canWrite: true
},
component: {
id: '95d4f3d2-018b-1000-b7c7-b830c49a8026',
name: 'params 1'
}
},
inherited: false
}
];

beforeEach(() => {
TestBed.configureTestingModule({
imports: [ComboEditor]
});
fixture = TestBed.createComponent(ComboEditor);
component = fixture.componentInstance;
component.supportsParameters = false;
component.item = {

// re-establish the item before each test execution
item = {
property: 'Destination',
value: 'flowfile-attribute',
descriptor: {
Expand Down Expand Up @@ -69,10 +117,114 @@ describe('ComboEditor', () => {
dirty: false,
type: 'required'
};
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
if (item) {
component.item = item;
fixture.detectChanges();

expect(component).toBeTruthy();
}
});

it('verify combo value', () => {
if (item) {
component.item = item;
fixture.detectChanges();

const formValue = component.comboEditorForm.get('value')?.value;
expect(component.itemLookup.get(formValue)?.value).toEqual(item.value);
expect(component.comboEditorForm.get('parameterReference')).toBeNull();

spyOn(component.ok, 'next');
component.okClicked();
expect(component.ok.next).toHaveBeenCalledWith(item.value);
}
});

it('verify combo not required with null value and default', () => {
if (item) {
item.value = null;
item.descriptor.required = false;

component.item = item;
fixture.detectChanges();

const formValue = component.comboEditorForm.get('value')?.value;
expect(component.itemLookup.get(formValue)?.value).toEqual(item.descriptor.defaultValue);
expect(component.comboEditorForm.get('parameterReference')).toBeNull();

spyOn(component.ok, 'next');
component.okClicked();
expect(component.ok.next).toHaveBeenCalledWith(item.descriptor.defaultValue);
}
});

it('verify combo not required with null value and no default', () => {
if (item) {
item.value = null;
item.descriptor.required = false;
item.descriptor.defaultValue = undefined;

component.item = item;
fixture.detectChanges();

const formValue = component.comboEditorForm.get('value')?.value;
expect(component.itemLookup.get(formValue)?.value).toEqual(item.value);
expect(component.comboEditorForm.get('parameterReference')).toBeNull();

spyOn(component.ok, 'next');
component.okClicked();
expect(component.ok.next).toHaveBeenCalledWith(item.value);
}
});

it('verify combo with parameter reference', () => {
if (item) {
item.value = '#{one}';

component.item = item;
component.getParameters = (sensitive: boolean) => {
return of(parameters);
};
fixture.detectChanges();
fixture.whenStable().then(() => {
const formValue = component.comboEditorForm.get('value')?.value;
expect(component.itemLookup.get(formValue)?.value).toEqual(item?.value);
expect(component.comboEditorForm.get('parameterReference')).toBeDefined();

const parameterReferenceValue = component.comboEditorForm.get('parameterReference')?.value;
expect(component.itemLookup.get(parameterReferenceValue)?.value).toEqual(item?.value);

spyOn(component.ok, 'next');
component.okClicked();
expect(component.ok.next).toHaveBeenCalledWith(item?.value);
});
}
});

it('verify combo with missing parameter reference', () => {
if (item) {
item.value = '#{three}';

component.item = item;
component.getParameters = (sensitive: boolean) => {
return of(parameters);
};
fixture.detectChanges();
fixture.whenStable().then(() => {
const formValue = component.comboEditorForm.get('value')?.value;
expect(component.itemLookup.get(formValue)?.value).toEqual('#{' + parameters[0].value + '}');
expect(component.comboEditorForm.get('parameterReference')).toBeDefined();

const parameterReferenceValue = component.comboEditorForm.get('parameterReference')?.value;
expect(component.itemLookup.get(parameterReferenceValue)?.value).toEqual(item?.value);

spyOn(component.ok, 'next');
component.okClicked();
expect(component.ok.next).toHaveBeenCalledWith('#{' + parameters[0].value + '}');
});
}
});
});
Loading

0 comments on commit ebfb5bc

Please sign in to comment.