autocomplete component added (#3701)

This commit is contained in:
bbcodrin
2018-09-12 16:21:44 +03:00
committed by Eugenio Romano
parent 978d4153ed
commit 21d7a8aec2
6 changed files with 81 additions and 33 deletions

View File

@@ -26,7 +26,7 @@ var ProcessListPage = function () {
var processListTitle = element(by.css("p[class='adf-empty-content__title']")); var processListTitle = element(by.css("p[class='adf-empty-content__title']"));
var processListSubtitle = element(by.css("p[class='adf-empty-content__subtitle']")); var processListSubtitle = element(by.css("p[class='adf-empty-content__subtitle']"));
var processDetailsMessage = element(by.css("adf-process-instance-details div[class='ng-star-inserted']")); var processDetailsMessage = element(by.css("adf-process-instance-details div[class='ng-star-inserted']"));
var openProcessDropdown = element(by.css('mat-select[aria-label="Select Process"]')); var openProcessDropdown = element(by.css("input[aria-label='Number']"));
var selectProcessDropdown = element.all(by.css('span[class="mat-option-text"]')); var selectProcessDropdown = element.all(by.css('span[class="mat-option-text"]'));
var startProcessButton = element(by.css('button[data-automation-id="btn-start"]')); var startProcessButton = element(by.css('button[data-automation-id="btn-start"]'));

View File

@@ -21,8 +21,8 @@ var StartProcessPage = function () {
var defaultProcessName = element(by.css("input[id='processName']")); var defaultProcessName = element(by.css("input[id='processName']"));
var processNameInput = element(by.id('processName')); var processNameInput = element(by.id('processName'));
var selectProcessDropdownArrow = element(by.css("div[class='mat-select-arrow-wrapper'] div")); var selectProcessDropdownArrow = element(by.css("input[aria-label='Number']"));
var cancelProcessButton = element(by.id('cancle_process')); var cancelProcessButton = element(by.id('cancel_process'));
var formStartProcessButton = element(by.css('button[data-automation-id="adf-form-start process"]')); var formStartProcessButton = element(by.css('button[data-automation-id="adf-form-start process"]'));
var startProcessButton = element(by.css("button[data-automation-id='btn-start']")); var startProcessButton = element(by.css("button[data-automation-id='btn-start']"));
var noProcess = element(by.id('no-process-message')); var noProcess = element(by.id('no-process-message'));

View File

@@ -106,6 +106,8 @@ describe('Process Filters Test', () => {
startProcessPage.selectFromProcessDropdown(app.process_title); startProcessPage.selectFromProcessDropdown(app.process_title);
startProcessPage.clickFormStartProcessButton(); startProcessPage.clickFormStartProcessButton();
processFiltersPage.clickRunningFilterButton();
processFiltersPage.checkFilterIsHighlighted(processFilter.running); processFiltersPage.checkFilterIsHighlighted(processFilter.running);
processFiltersPage.selectFromProcessList(processTitle.running); processFiltersPage.selectFromProcessList(processTitle.running);

View File

@@ -9,27 +9,25 @@
<input matInput placeholder="{{'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.NAME'|translate}}" [(ngModel)]="name" id="processName" required /> <input matInput placeholder="{{'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.NAME'|translate}}" [(ngModel)]="name" id="processName" required />
</mat-form-field> </mat-form-field>
<div *ngIf="showSelectProcessDropdown"> <mat-form-field *ngIf="showSelectProcessDropdown">
<mat-form-field> <input type="text" placeholder="{{'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.TYPE'|translate}}" required aria-label="Number" matInput [formControl]="processControl" [matAutocomplete]="auto">
<mat-select [(value)]="selectedProcessDef" placeholder="{{'ADF_PROCESS_LIST.START_PROCESS.FORM.LABEL.TYPE'|translate}}" required> <mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn" (optionSelected)="onItemSelect($event.option.value)">
<mat-option *ngIf="!hasSingleProcessDefinition()">{{'ADF_PROCESS_LIST.START_PROCESS.FORM.TYPE_PLACEHOLDER' | translate}}</mat-option> <mat-option *ngIf="!hasSingleProcessDefinition()">{{'ADF_PROCESS_LIST.START_PROCESS.FORM.TYPE_PLACEHOLDER' | translate}}</mat-option>
<mat-option *ngFor="let processDef of processDefinitions" [value]="processDef"> <mat-option *ngFor="let processDef of filteredOptions | async" [value]="processDef">
{{ processDef.name }} {{ processDef.name }}
</mat-option> </mat-option>
</mat-select> </mat-autocomplete>
</mat-form-field> </mat-form-field>
</div>
<adf-start-form <adf-start-form
#startForm #startForm
*ngIf="hasStartForm()" *ngIf="hasStartForm()"
[data]="values" [data]="values"
[disableStartProcessButton]="!hasProcessName()" [disableStartProcessButton]="!hasProcessName()"
[processDefinitionId]="selectedProcessDef.id" [processDefinitionId]="selectedProcessDef.id"
(outcomeClick)="onOutcomeClick($event)" (outcomeClick)="onOutcomeClick($event)"
[showRefreshButton]="false"> [showRefreshButton]="false">
<button form-custom-button mat-button (click)="cancelStartProcess()" id="cancle_process" class=""> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.CANCEL'| translate}} </button> <button form-custom-button mat-button (click)="cancelStartProcess()" id="cancel_process" class=""> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.CANCEL'| translate}} </button> </adf-start-form>
</adf-start-form>
</mat-card-content> </mat-card-content>
<mat-card-content *ngIf="hasErrorMessage()"> <mat-card-content *ngIf="hasErrorMessage()">
<mat-card-subtitle class="error-message" id="no-process-message"> <mat-card-subtitle class="error-message" id="no-process-message">
@@ -37,7 +35,7 @@
</mat-card-subtitle> </mat-card-subtitle>
</mat-card-content> </mat-card-content>
<mat-card-actions *ngIf="!hasStartForm()"> <mat-card-actions *ngIf="!hasStartForm()">
<button mat-button *ngIf="!hasStartForm()" (click)="cancelStartProcess()" id="cancle_process" class=""> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.CANCEL'| translate}} </button> <button mat-button *ngIf="!hasStartForm()" (click)="cancelStartProcess()" id="cancel_process" class=""> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.CANCEL'| translate}} </button>
<button color="primary" mat-button *ngIf="!hasStartForm()" [disabled]="!validateForm()" (click)="startProcess()" data-automation-id="btn-start" id="button-start" class="btn-start"> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.START' | translate}} </button> <button color="primary" mat-button *ngIf="!hasStartForm()" [disabled]="!validateForm()" (click)="startProcess()" data-automation-id="btn-start" id="button-start" class="btn-start"> {{'ADF_PROCESS_LIST.START_PROCESS.FORM.ACTION.START' | translate}} </button>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>

View File

@@ -143,7 +143,7 @@ describe('StartFormComponent', () => {
}); });
})); }));
it('should have start button disabled if the process is not seleted', async(() => { it('should have start button disabled if the process is not selected', async(() => {
component.name = 'My new process'; component.name = 'My new process';
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
@@ -154,7 +154,7 @@ describe('StartFormComponent', () => {
it('should emit cancel event on cancel Button', async(() => { it('should emit cancel event on cancel Button', async(() => {
fixture.detectChanges(); fixture.detectChanges();
let cancelButton = fixture.nativeElement.querySelector('#cancle_process'); let cancelButton = fixture.nativeElement.querySelector('#cancel_process');
let cancelSpy: jasmine.Spy = spyOn(component.cancel, 'emit'); let cancelSpy: jasmine.Spy = spyOn(component.cancel, 'emit');
cancelButton.click(); cancelButton.click();
fixture.detectChanges(); fixture.detectChanges();
@@ -222,8 +222,7 @@ describe('StartFormComponent', () => {
component.ngOnChanges({}); component.ngOnChanges({});
fixture.detectChanges(); fixture.detectChanges();
let selectElement = fixture.nativeElement.querySelector('mat-select'); expect(component.processDefinitions.length).toBe(2);
expect(selectElement.children.length).toBe(1);
}); });
it('should display the option def details', () => { it('should display the option def details', () => {
@@ -232,7 +231,7 @@ describe('StartFormComponent', () => {
component.processDefinitions = testMultipleProcessDefs; component.processDefinitions = testMultipleProcessDefs;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
let selectElement = fixture.nativeElement.querySelector('mat-select > .mat-select-trigger'); let selectElement = fixture.nativeElement.querySelector('mat-autocomplete');
let optionElement = fixture.nativeElement.querySelectorAll('mat-option'); let optionElement = fixture.nativeElement.querySelectorAll('mat-option');
selectElement.click(); selectElement.click();
expect(selectElement).not.toBeNull(); expect(selectElement).not.toBeNull();
@@ -242,7 +241,7 @@ describe('StartFormComponent', () => {
}); });
}); });
it('should indicate an error to the user if process defs cannot be loaded', async(() => { it('should indicate an error to the user if process definitions cannot be loaded', async(() => {
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(throwError({})); getDefinitionsSpy = getDefinitionsSpy.and.returnValue(throwError({}));
component.appId = 123; component.appId = 123;
component.ngOnChanges({}); component.ngOnChanges({});
@@ -279,7 +278,7 @@ describe('StartFormComponent', () => {
}); });
})); }));
it('should select automatically the processDefinition if the app contain oly one', async(() => { it('should select automatically the processDefinition if the app contain only one', async(() => {
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(testProcessDefinitions)); getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(testProcessDefinitions));
component.appId = 123; component.appId = 123;
component.ngOnChanges({}); component.ngOnChanges({});
@@ -289,6 +288,17 @@ describe('StartFormComponent', () => {
}); });
})); }));
it('should have start button enabled when process is selected', async(() => {
component.selectedProcessDef = testProcessDefRepr;
component.name = 'My process';
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let startBtn = fixture.nativeElement.querySelector('#button-start');
expect(startBtn.disabled).toBe(false);
});
}));
describe('dropdown', () => { describe('dropdown', () => {
it('should hide the process dropdown if showSelectProcessDropdown is false', async(() => { it('should hide the process dropdown if showSelectProcessDropdown is false', async(() => {
@@ -298,12 +308,12 @@ describe('StartFormComponent', () => {
component.ngOnChanges({}); component.ngOnChanges({});
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
let selectElement = fixture.nativeElement.querySelector('mat-select > .mat-select-trigger'); let selectElement = fixture.nativeElement.querySelector('mat-autocomplete');
expect(selectElement).toBeNull(); expect(selectElement).toBeNull();
}); });
})); }));
it('should show the process dropdown if showSelectProcessDropdown is false', async(() => { it('should show the process dropdown if showSelectProcessDropdown is true', async(() => {
getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(testMultipleProcessDefs)); getDefinitionsSpy = getDefinitionsSpy.and.returnValue(of(testMultipleProcessDefs));
component.appId = 123; component.appId = 123;
component.processDefinitionName = 'My Process 2'; component.processDefinitionName = 'My Process 2';
@@ -311,7 +321,7 @@ describe('StartFormComponent', () => {
component.ngOnChanges({}); component.ngOnChanges({});
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
let selectElement = fixture.nativeElement.querySelector('mat-select > .mat-select-trigger'); let selectElement = fixture.nativeElement.querySelector('mat-autocomplete');
expect(selectElement).not.toBeNull(); expect(selectElement).not.toBeNull();
}); });
})); }));
@@ -323,7 +333,7 @@ describe('StartFormComponent', () => {
component.ngOnChanges({}); component.ngOnChanges({});
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
let selectElement = fixture.nativeElement.querySelector('mat-select > .mat-select-trigger'); let selectElement = fixture.nativeElement.querySelector('mat-autocomplete');
expect(selectElement).not.toBeNull(); expect(selectElement).not.toBeNull();
}); });
})); }));
@@ -351,7 +361,7 @@ describe('StartFormComponent', () => {
}); });
})); }));
it('should get current processDeff', () => { it('should get current processDef', () => {
component.appId = 456; component.appId = 456;
component.ngOnChanges({ appId: change }); component.ngOnChanges({ appId: change });
fixture.detectChanges(); fixture.detectChanges();
@@ -392,7 +402,7 @@ describe('StartFormComponent', () => {
}); });
})); }));
it('should call service to start process with the variables setted', async(() => { it('should call service to start process with the variables set up', async(() => {
let inputProcessVariable: ProcessInstanceVariable[] = []; let inputProcessVariable: ProcessInstanceVariable[] = [];
let variable: ProcessInstanceVariable = {}; let variable: ProcessInstanceVariable = {};

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnChanges, import { Component, EventEmitter, Input, AfterViewInit, OnChanges,
Output, SimpleChanges, ViewChild, ViewEncapsulation Output, SimpleChanges, ViewChild, ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { ActivitiContentService, AppConfigService, AppConfigValues, import { ActivitiContentService, AppConfigService, AppConfigValues,
@@ -26,6 +26,9 @@ import { ProcessDefinitionRepresentation } from './../models/process-definition.
import { ProcessInstance } from './../models/process-instance.model'; import { ProcessInstance } from './../models/process-instance.model';
import { ProcessService } from './../services/process.service'; import { ProcessService } from './../services/process.service';
import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../../content-widget'; import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../../content-widget';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { map, startWith, delay } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-start-process', selector: 'adf-start-process',
@@ -33,7 +36,7 @@ import { AttachFileWidgetComponent, AttachFolderWidgetComponent } from '../../co
styleUrls: ['./start-process.component.scss'], styleUrls: ['./start-process.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class StartProcessInstanceComponent implements OnChanges { export class StartProcessInstanceComponent implements AfterViewInit, OnChanges {
/** (optional) Limit the list of processes that can be started to those /** (optional) Limit the list of processes that can be started to those
* contained in the specified app. * contained in the specified app.
@@ -84,6 +87,9 @@ export class StartProcessInstanceComponent implements OnChanges {
errorMessageId: string = ''; errorMessageId: string = '';
processControl = new FormControl();
filteredOptions: Observable<any>;
constructor(private activitiProcess: ProcessService, constructor(private activitiProcess: ProcessService,
private formRenderingService: FormRenderingService, private formRenderingService: FormRenderingService,
private activitiContentService: ActivitiContentService, private activitiContentService: ActivitiContentService,
@@ -92,6 +98,17 @@ export class StartProcessInstanceComponent implements OnChanges {
this.formRenderingService.setComponentTypeResolver('select-folder', () => AttachFolderWidgetComponent, true); this.formRenderingService.setComponentTypeResolver('select-folder', () => AttachFolderWidgetComponent, true);
} }
ngAfterViewInit() {
setTimeout(() => {
this.filteredOptions = this.processControl.valueChanges
.pipe(
startWith(''),
delay(0),
map(value => this._filter(value))
);
});
}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (changes['values'] && changes['values'].currentValue) { if (changes['values'] && changes['values'].currentValue) {
this.moveNodeFromCStoPS(); this.moveNodeFromCStoPS();
@@ -100,6 +117,23 @@ export class StartProcessInstanceComponent implements OnChanges {
this.loadStartProcess(); this.loadStartProcess();
} }
private _filter(value) {
let filterValue = '';
if (value && value.name) {
filterValue = value.name.toLowerCase();
} else if (value) {
filterValue = value.toLowerCase();
}
let processDefArray = this.processDefinitions.filter(option => option.name.toLowerCase() === filterValue);
this.selectedProcessDef = processDefArray.length ? processDefArray[0] : null;
return this.processDefinitions.filter(option => option.name.toLowerCase().includes(filterValue));
}
displayFn(processDef): string {
return processDef ? processDef.name : '';
}
public loadStartProcess() { public loadStartProcess() {
this.resetSelectedProcessDefinition(); this.resetSelectedProcessDefinition();
this.resetErrorMessage(); this.resetErrorMessage();
@@ -217,6 +251,10 @@ export class StartProcessInstanceComponent implements OnChanges {
} }
hasProcessName(): boolean { hasProcessName(): boolean {
return this.name ? true : false; return !!this.name;
}
onItemSelect(item) {
this.selectedProcessDef = item;
} }
} }