TSK-712 Fix access items bug when opening a group

This commit is contained in:
Martin Rojas Miguel Angel 2018-09-17 11:33:56 +02:00 committed by Holger Hagen
parent 1e6fc73f7d
commit 3790fb6327
10 changed files with 103 additions and 87 deletions

View File

@ -1,8 +1,8 @@
<div *ngIf="workbasket" id="wb-information" class="panel panel-default">
<div class="panel-heading">
<div class="pull-right btn-group">
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary" data-toggle="tooltip"
title="Save">
<button type="button" (click)="onSubmit()" [disabled]="action === 'COPY'" class="btn btn-default btn-primary"
data-toggle="tooltip" title="Save">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</button>
<button type="button" (click)="clear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
@ -47,18 +47,20 @@
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</td>
<td *ngIf="accessIdField.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead" [ngClass]="{
<td *ngIf="accessIdField.lookupField else accessIdInput" class="input-group text-align text-width taskana-type-ahead"
[ngClass]="{
'has-warning': (accessItemsClone[index].accessId !== accessItem.value.accessId),
'has-error': !accessItem.value.accessId }">
<taskana-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required"
[validationValue]="toogleValidationAccessIdMap.get(index)" [displayError]="!isFieldValid('accessItem.value.accessId', index)"></taskana-type-ahead>
<taskana-type-ahead formControlName="accessId" placeHolderMessage="* Access id is required" [validationValue]="toogleValidationAccessIdMap.get(index)"
[displayError]="!isFieldValid('accessItem.value.accessId', index)" (onSelect)="accessItemSelected($event, index)"></taskana-type-ahead>
</td>
<ng-template #accessIdInput>
<td class="input-group text-align text-width">
<div [ngClass]="{ 'has-warning': (accessItemsClone[index].accessId !==accessItem.value.accessId), 'has-error':
!accessItem.value.accessId && formSubmitAttempt}">
<input type="text" class="form-control" formControlName="accessId" placeholder="{{accessItem.invalid?
'* Access id is required': ''}}" [@validation]="toogleValidationAccessIdMap.get(index)">
'* Access id is required': ''}}"
[@validation]="toogleValidationAccessIdMap.get(index)">
</div>
</td>
</ng-template>

View File

@ -49,19 +49,19 @@ describe('AccessItemsComponent', () => {
spyOn(workbasketService, 'getWorkBasketAccessItems').and.returnValue(of(new WorkbasketAccessItemsResource(
{
'accessItems': new Array<WorkbasketAccessItems>(
new WorkbasketAccessItems('id1', '1', 'accessID1', false, false, false, false, false, false, false, false,
new WorkbasketAccessItems('id1', '1', 'accessID1', '', false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false),
new WorkbasketAccessItems('id2', '1', 'accessID2'))
}, new Links({ 'href': 'someurl' })
)));
spyOn(workbasketService, 'updateWorkBasketAccessItem').and.returnValue(of(true)),
spyOn(alertService, 'triggerAlert').and.returnValue(of(true)),
debugElement = fixture.debugElement.nativeElement;
accessIdsService = TestBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
'accessID1', 'accessID2'
)));
formsValidatorService = TestBed.get(FormsValidatorService);
debugElement = fixture.debugElement.nativeElement;
accessIdsService = TestBed.get(AccessIdsService);
spyOn(accessIdsService, 'getAccessItemsInformation').and.returnValue(of(new Array<string>(
'accessID1', 'accessID2'
)));
formsValidatorService = TestBed.get(FormsValidatorService);
component.ngOnChanges({
active: new SimpleChange(undefined, 'accessItems', true)
});
@ -96,17 +96,17 @@ describe('AccessItemsComponent', () => {
});
it('should show alert successfull after saving', async(() => {
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.detectChanges();
spyOn(formsValidatorService, 'validateFormAccess').and.returnValue(Promise.resolve(true));
component.onSubmit();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
})
fixture.detectChanges();
}));
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(alertService.triggerAlert).toHaveBeenCalledWith(
new AlertModel(AlertType.SUCCESS, `Workbasket ${component.workbasket.key} Access items were saved successfully`));
})
fixture.detectChanges();
}));
it('should keep accessItemsClone length to previous value after clearing the form.', () => {
expect(component.accessItemsClone.length).toBe(2);

View File

@ -17,8 +17,8 @@ import { RequestInProgressService } from 'app/services/requestInProgress/request
import { CustomFieldsService } from 'app/services/custom-fields/custom-fields.service';
import { highlight } from 'app/shared/animations/validation.animation';
import { FormsValidatorService } from 'app/shared/services/forms/forms-validator.service';
import { AccessIdDefinition } from 'app/models/access-id';
declare const $: any;
@Component({
selector: 'taskana-workbasket-access-items',
templateUrl: './access-items.component.html',
@ -67,7 +67,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
setAccessItemsGroups(accessItems: Array<WorkbasketAccessItems>) {
const AccessItemsFormGroups = accessItems.map(accessItem => this.formBuilder.group(accessItem));
AccessItemsFormGroups.map(accessItemGroup => {
accessItemGroup.controls['accessId'].setValidators(Validators.required);
accessItemGroup.controls['accessId'].setValidators(Validators.required);
});
const AccessItemsFormArray = this.formBuilder.array(AccessItemsFormGroups);
this.AccessItemsForm.setControl('accessItemsGroups', AccessItemsFormArray);
@ -85,7 +85,7 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
private requestInProgressService: RequestInProgressService,
private customFieldsService: CustomFieldsService,
private formBuilder: FormBuilder,
private formsValidatorService: FormsValidatorService) {
private formsValidatorService: FormsValidatorService) {
}
ngOnChanges(changes: SimpleChanges): void {
@ -124,10 +124,10 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
addAccessItem() {
const newForm = this.formBuilder.group(
new WorkbasketAccessItems(undefined, this.workbasket.workbasketId, '', true));
new WorkbasketAccessItems(undefined, this.workbasket.workbasketId, '', '', true));
newForm.controls['accessId'].setValidators(Validators.required);
this.accessItemsGroups.push(newForm);
this.accessItemsClone.push(new WorkbasketAccessItems(undefined, this.workbasket.workbasketId, '', true));
this.accessItemsClone.push(new WorkbasketAccessItems(undefined, this.workbasket.workbasketId, '', '', true));
}
clear() {
@ -148,12 +148,12 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
}
onSubmit() {
this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService.validateFormAccess(this.accessItemsGroups, this.toogleValidationAccessIdMap).then(value => {
if (value) {
this.onSave();
}
});
this.formsValidatorService.formSubmitAttempt = true;
this.formsValidatorService.validateFormAccess(this.accessItemsGroups, this.toogleValidationAccessIdMap).then(value => {
if (value) {
this.onSave();
}
});
}
checkAll(row: number, value: any) {
@ -166,6 +166,11 @@ export class AccessItemsComponent implements OnChanges, OnDestroy {
}
}
accessItemSelected(accessItem: AccessIdDefinition, row: number) {
this.accessItemsGroups.controls[row].get('accessId').setValue(accessItem.accessId);
this.accessItemsGroups.controls[row].get('accessName').setValue(accessItem.name);
}
private onSave() {
this.requestInProgressService.setRequestInProgress(true);
this.workbasketService.updateWorkBasketAccessItem(this.accessItemsResource._links.self.href, this.AccessItemsForm.value.accessItemsGroups)

View File

@ -8,7 +8,8 @@
<button type="button" (click)="onClear()" class="btn btn-default" data-toggle="tooltip" title="Undo Changes">
<span class="glyphicon glyphicon-repeat blue" aria-hidden="true"></span>
</button>
<button type="button" (click)="removeDistributionTargets()" data-toggle="tooltip" title="Remove workbasket as distribuition target" class="btn btn-default remove">
<button type="button" (click)="removeDistributionTargets()" data-toggle="tooltip" title="Remove workbasket as distribuition target"
class="btn btn-default remove">
<span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
</button>
<button type="button" (click)="copyWorkbasket()" data-toggle="tooltip" title="Copy" class="btn btn-default">
@ -27,42 +28,43 @@
<div class="col-md-6">
<div class="form-group required">
<label for="wb-key" class="control-label">Key</label>
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key" [(ngModel)]="workbasket.key"
name="workbasket.key">
<input type="text" required #key="ngModel" class="form-control" id="wb-key" placeholder="Key"
[(ngModel)]="workbasket.key" name="workbasket.key">
<taskana-field-error-display [displayError]="!isFieldValid('workbasket.key')" [validationTrigger]="this.toogleValidationMap.get('workbasket.key')"
errorMessage="* Key is required" >
errorMessage="* Key is required">
</taskana-field-error-display>
</div>
<div class="form-group required">
<label for="wb-name" class="control-label">Name</label>
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name" [(ngModel)]="workbasket.name"
name="workbasket.name">
<input type="text" required #name="ngModel" class="form-control" id="wb-name" placeholder="Name"
[(ngModel)]="workbasket.name" name="workbasket.name">
<taskana-field-error-display [displayError]="!isFieldValid('workbasket.name')" [validationTrigger]="this.toogleValidationMap.get('workbasket.name')"
errorMessage="* Name is required">
</taskana-field-error-display>
</div>
<div class="input-group form-group required">
<div class="input-group form-group col-xs-12 required">
<label for="wb-owner" class="control-label ">Owner</label>
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner" [(ngModel)]="workbasket.owner"
placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"
<taskana-type-ahead *ngIf="ownerField.lookupField else ownerInput" required #owner="ngModel" name="workbasket.owner"
[(ngModel)]="workbasket.owner" placeHolderMessage="* Owner is required" [validationValue]="this.toogleValidationMap.get('workbasket.owner')"
[displayError]="!isFieldValid('workbasket.owner')" width="100%"></taskana-type-ahead>
<ng-template #ownerInput>
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner" [(ngModel)]="workbasket.owner"
name="workbasket.owner">
<taskana-field-error-display [displayError]="!isFieldValid('workbasket.owner')" [validationTrigger]="this.toogleValidationMap.get('workbasket.owner')"
errorMessage="* Owner is required">
<input type="text" required #owner="ngModel" class="form-control" id="wb-owner" placeholder="Owner"
[(ngModel)]="workbasket.owner" name="workbasket.owner">
<taskana-field-error-display [displayError]="!isFieldValid('workbasket.owner')"
[validationTrigger]="this.toogleValidationMap.get('workbasket.owner')" errorMessage="* Owner is required">
</taskana-field-error-display>
</ng-template>
</div>
<div class="form-group ">
<label for="wb-domain" class="control-label">Domain</label>
<input type="text" #domain="ngModel" class="form-control" disabled id="wb-domain" placeholder="Domain" [(ngModel)]="workbasket.domain"
name="workbasket.domain">
<input type="text" #domain="ngModel" class="form-control" disabled id="wb-domain" placeholder="Domain"
[(ngModel)]="workbasket.domain" name="workbasket.domain">
</div>
<div class="form-group">
<label for="wb-type" class="control-label">Type</label>
<div class="dropdown clearfix btn-group">
<button class="btn btn-default" type="button" id="dropdownMenu24" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<button class="btn btn-default" type="button" id="dropdownMenu24" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<taskana-icon-type class="vertical-align" [type]='workbasket.type'></taskana-icon-type>
{{allTypes.get(workbasket.type)}}
<span class="caret"></span>
@ -85,41 +87,45 @@
<div class="col-md-6">
<div class="form-group">
<label for="wb-org-level-1" class="control-label">OrgLevel 1</label>
<input type="text" class="form-control" id="wb-org-level-1" placeholder="OrgLevel 1" [(ngModel)]="workbasket.orgLevel1" name="workbasket.orgLevel1">
<input type="text" class="form-control" id="wb-org-level-1" placeholder="OrgLevel 1" [(ngModel)]="workbasket.orgLevel1"
name="workbasket.orgLevel1">
</div>
<div class="form-group">
<label for="wb-org-level-2" class="control-label">OrgLevel 2</label>
<input type="text" class="form-control" id="wb-org-level-2" placeholder="OrgLevel 2" [(ngModel)]="workbasket.orgLevel2" name="workbasket.orgLevel2">
<input type="text" class="form-control" id="wb-org-level-2" placeholder="OrgLevel 2" [(ngModel)]="workbasket.orgLevel2"
name="workbasket.orgLevel2">
</div>
<div class="form-group">
<label for="wb-org-level-3" class="control-label">OrgLevel 3</label>
<input type="text" class="form-control" id="wb-org-level-3" placeholder="OrgLevel 3" [(ngModel)]="workbasket.orgLevel3" name="workbasket.orgLevel3">
<input type="text" class="form-control" id="wb-org-level-3" placeholder="OrgLevel 3" [(ngModel)]="workbasket.orgLevel3"
name="workbasket.orgLevel3">
</div>
<div class="form-group">
<label for="wb-org-level-4" class="control-label">OrgLevel 4</label>
<input type="text" class="form-control" id="wb-org-level-4" placeholder="OrgLevel 4" [(ngModel)]="workbasket.orgLevel4" name="workbasket.orgLevel4">
<input type="text" class="form-control" id="wb-org-level-4" placeholder="OrgLevel 4" [(ngModel)]="workbasket.orgLevel4"
name="workbasket.orgLevel4">
</div>
<div *ngIf="custom1Field.visible" class="form-group">
<label for="wb-custom-1" class="control-label">{{custom1Field.field}}</label>
<input type="text" class="form-control" id="wb-custom-1" [placeholder]="custom1Field.field" [(ngModel)]="workbasket.custom1"
name="workbasket.custom1">
<input type="text" class="form-control" id="wb-custom-1" [placeholder]="custom1Field.field"
[(ngModel)]="workbasket.custom1" name="workbasket.custom1">
</div>
<div *ngIf="custom2Field.visible" class="form-group">
<label for="wb-custom-2" class="control-label">{{custom2Field.field}}</label>
<input type="text" class="form-control" id="wb-custom-2" [placeholder]="custom2Field.field" [(ngModel)]="workbasket.custom2"
name="workbasket.custom2">
<input type="text" class="form-control" id="wb-custom-2" [placeholder]="custom2Field.field"
[(ngModel)]="workbasket.custom2" name="workbasket.custom2">
</div>
<div *ngIf="custom3Field.visible" class="form-group">
<label for="wb-custom-3" class="control-label">{{custom3Field.field}}</label>
<input type="text" class="form-control" id="wb-custom-3" [placeholder]="custom3Field.field" [(ngModel)]="workbasket.custom3"
name="workbasket.custom3">
<input type="text" class="form-control" id="wb-custom-3" [placeholder]="custom3Field.field"
[(ngModel)]="workbasket.custom3" name="workbasket.custom3">
</div>
<div *ngIf="custom4Field.visible" class="form-group">
<label for="wb-custom-4" class="control-label">{{custom4Field.field}}</label>
<input type="text" class="form-control" id="wb-custom-4" [placeholder]="custom4Field.field" [(ngModel)]="workbasket.custom4"
name="workbasket.custom4">
<input type="text" class="form-control" id="wb-custom-4" [placeholder]="custom4Field.field"
[(ngModel)]="workbasket.custom4" name="workbasket.custom4">
</div>
</div>
</form>
</div>
</div>
</div>

View File

@ -273,15 +273,18 @@ export class WorkbasketInformationComponent
private onRemoveConfirmed() {
this.requestInProgressService.setRequestInProgress(true);
this.workbasketService
.markWorkbasketForDeletion(
this.workbasket._links.self.href
)
.markWorkbasketForDeletion(this.workbasket._links.self.href)
.subscribe(
response => {
this.requestInProgressService.setRequestInProgress(false);
this.workbasketService.triggerWorkBasketSaved();
this.alertService.triggerAlert(
new AlertModel(AlertType.SUCCESS, 'The Workbasket ' + this.workbasket.workbasketId + ' has been marked for deletion')
new AlertModel(
AlertType.SUCCESS,
'The Workbasket ' +
this.workbasket.workbasketId +
' has been marked for deletion'
)
);
this.router.navigate(['administration/workbaskets']);
},

View File

@ -5,6 +5,7 @@ export class WorkbasketAccessItems {
public accessItemId: string = '',
public workbasketId: string = '',
public accessId: string = '',
public accessName: string = '',
public permRead: boolean = false,
public permOpen: boolean = false,
public permAppend: boolean = false,

View File

@ -18,7 +18,7 @@
margin: 0 auto;
width: 15%;
height: 15%;
background-color: #33b784;
background-color: #36bcee;
border-radius: 100%;
-webkit-animation: sk-circleBounceDelay 1.2s infinite ease-in-out both;
animation: sk-circleBounceDelay 1.2s infinite ease-in-out both;
@ -68,36 +68,47 @@
-ms-transform: rotate(330deg);
transform: rotate(330deg); }
.sk-circle .sk-circle2:before {
background-color: #35b9ea;
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s; }
.sk-circle .sk-circle3:before {
background-color: #33b0df;
-webkit-animation-delay: -1s;
animation-delay: -1s; }
.sk-circle .sk-circle4:before {
background-color: #36bbed;
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s; }
.sk-circle .sk-circle5:before {
background-color: #46b9cc;
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s; }
.sk-circle .sk-circle6:before {
background-color: #4fbbbd;
-webkit-animation-delay: -0.7s;
animation-delay: -0.7s; }
.sk-circle .sk-circle7:before {
background-color: #51b9b5;
-webkit-animation-delay: -0.6s;
animation-delay: -0.6s; }
.sk-circle .sk-circle8:before {
background-color: #5fbca1;
-webkit-animation-delay: -0.5s;
animation-delay: -0.5s; }
.sk-circle .sk-circle9:before {
background-color: #5db99e;
-webkit-animation-delay: -0.4s;
animation-delay: -0.4s; }
.sk-circle .sk-circle10:before {
background-color: #5ebba0;
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s; }
.sk-circle .sk-circle11:before {
background-color: #5db99e;
-webkit-animation-delay: -0.2s;
animation-delay: -0.2s; }
.sk-circle .sk-circle12:before {
background-color: #5fbba0;
-webkit-animation-delay: -0.1s;
animation-delay: -0.1s; }

View File

@ -15,14 +15,11 @@
'disable': disable}" class="wrapper-text" (click)="setTyping(true)">
<span>
<label>
{{dataSource.selected?.accessId}}
{{dataSource.selected?.name}}
</label>
</span>
<div class="input-group">
<div>{{dataSource.selected?.name}}</div>
<button *ngIf="!disable" type="button" (click)="clear()" title="clear search" class="btn rounded remove">
<span class="glyphicon glyphicon-remove-sign" aria-hidden="true"></span>
</button>
<div>{{dataSource.selected?.accessId}}</div>
</div>
</div>
<div [ngClass]="{'hidden': dataSource.selected && !typing}">
@ -31,13 +28,12 @@
{{dataSource.selected?.name}}
</label>
</span>
<div class="input-group">
<input #inputTypeAhead class=" form-control input-text" [ngClass]="{'invalid': dataSource.length == null}" (blur)="typeaheadOnSelect({'item':dataSource.selected})" name="accessItem-{{index}}"
required #accessItemName="ngModel" [(ngModel)]="value" [typeahead]="dataSource" typeaheadOptionField="name" [typeaheadItemTemplate]="customItemTemplate"
(typeaheadOnSelect)="typeaheadOnSelect($event, index)" [typeaheadScrollable]="true" [typeaheadOptionsInScrollableView]="typeaheadOptionsInScrollableView"
[typeaheadMinLength]="typeaheadMinLength" [typeaheadWaitMs]="typeaheadWaitMs" (typeaheadLoading)="changeTypeaheadLoading($event)"
placeholder="{{displayError? placeHolderMessage: ''}}" [@validation]="validationValue">
placeholder="{{displayError? placeHolderMessage: ''}}" [@validation]="validationValue" >
<button *ngIf="!typeaheadLoading" type="button" title="search" class="btn rounded blue">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>

View File

@ -5,14 +5,14 @@
height: 47px;
& label {
margin-bottom: 0px;
padding-left: 12px;
padding: 0px 12px;
font-style: italic;
overflow: hidden;
}
&> div{
&> div {
border-bottom: 1px solid $light-grey;
margin-top:6px;
margin-top:3px;
padding-left: 12px;
min-width: 175px;
}
@ -21,7 +21,7 @@
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
padding-right: 35px;
margin-right: 35px;
}
}

View File

@ -103,7 +103,7 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
}).pipe(mergeMap((token: string) => this.getUsersAsObservable(token)));
this.accessIdsService.getAccessItemsInformation(this.value).subscribe(items => {
if (items.length > 0) {
this.dataSource.selected = items.find(item => item.accessId === this.value);
this.dataSource.selected = items.find(item => item.accessId.toLowerCase() === this.value.toLowerCase());
}
});
}
@ -139,12 +139,4 @@ export class TypeAheadComponent implements OnInit, ControlValueAccessor {
join(text: string, str: string) {
return text.toLocaleLowerCase().split(str).join(`<strong>${str}</strong>`);
}
clear() {
this.value = null;
this.innerValue = null;
this.dataSource.selected = null
this.onSelect.emit(this.dataSource.selected)
}
}