[ADF-2452] Task Standalone component (#3084)

* Add a new standalone component to show when there is no form attached to a task.
This commit is contained in:
camorra-skk
2018-03-20 17:53:19 +05:30
committed by Eugenio Romano
parent c578529b15
commit afb91cf062
11 changed files with 344 additions and 21 deletions

View File

@@ -38,16 +38,18 @@
(formLoaded)='onFormLoaded($event)'
(error)='onFormError($event)'
(executeOutcome)='onFormExecuteOutcome($event)'>
<div empty-form><h3 class="adf-task-title">Please select a Task</h3></div>
</adf-form>
<adf-task-standalone *ngIf="!hasFormKey()"
[taskName]= "taskDetails.name"
[isCompleted]="isCompletedTask()"
[hasCompletePermission]="isCompleteButtonEnabled()"
[hideCancelButton]="true"
(complete)="onComplete()">
</adf-task-standalone>
</div>
<div *ngIf="!isAssigned()" id="claim-message-id">
{{ 'ADF_TASK_LIST.DETAILS.MESSAGES.CLAIM' | translate }}
</div>
<button mat-raised-button class="activiti-task-details__action-button"
*ngIf="isCompleteButtonVisible()" (click)="onComplete()">
{{ 'ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE' | translate }}
</button>
</div>
<div class="adf-task-details-core-sidebar">
<adf-info-drawer *ngIf="showHeaderContent" title="{{ 'ADF_TASK_LIST.DETAILS.LABELS.INFO_DRAWER_TITLE' | translate }}" class="adf-task-details-core-sidebar-drawer">

View File

@@ -52,7 +52,6 @@ describe('TaskDetailsComponent', () => {
let completeTaskSpy: jasmine.Spy;
let logService: LogService;
let commentProcessService: CommentProcessService;
let authService: AuthenticationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
@@ -85,7 +84,6 @@ describe('TaskDetailsComponent', () => {
service = fixture.debugElement.injector.get(TaskListService);
formService = fixture.debugElement.injector.get(FormService);
commentProcessService = TestBed.get(CommentProcessService);
authService = TestBed.get(AuthenticationService);
getTaskDetailsSpy = spyOn(service, 'getTaskDetails').and.returnValue(Observable.of(taskDetailsMock));
spyOn(formService, 'getTaskForm').and.returnValue(Observable.of(taskFormMock));
@@ -149,27 +147,21 @@ describe('TaskDetailsComponent', () => {
});
}));
it('should display complete button when task without form is assigned to current user', async(() => {
spyOn(authService, 'getBpmUsername').and.returnValue(taskDetailsMock.assignee.email);
taskDetailsMock.formKey = undefined;
it('should display task standalone component when the task does not have an associated form', async(() => {
component.taskId = '123';
fixture.detectChanges();
fixture.whenStable().then(() => {
const completeBtn = fixture.nativeElement.querySelector('button');
expect(completeBtn).toBeDefined();
expect(completeBtn.disabled).toBeFalsy();
expect(completeBtn.innerText).toBe('ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE');
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('adf-task-standalone'))).not.toBeNull();
});
}));
it('should not display complete button when task without form is not assigned to current user', async(() => {
spyOn(authService, 'getBpmUsername').and.returnValue('');
it('should not display task standalone component when the task have an associated form', async(() => {
component.taskId = '123';
taskDetailsMock.formKey = undefined;
fixture.detectChanges();
fixture.whenStable().then(() => {
const completeBtn = fixture.nativeElement.querySelector('.activiti-task-details__action-button');
expect(completeBtn).toBeNull();
fixture.detectChanges();
expect(fixture.debugElement.query(By.css('adf-task-standalone'))).not.toBeNull();
});
}));

View File

@@ -0,0 +1,24 @@
<mat-card class="adf-message-card">
<mat-card-content>
<div class="adf-no-form-message-container">
<div class="adf-no-form-message-list">
<div *ngIf="!isCompleted; else completedMessage" class="adf-no-form-message">
<span id="adf-no-form-message">{{'ADF_TASK_LIST.STANDALONE_TASK.NO_FORM_MESSAGE' | translate}}</span>
</div>
<ng-template #completedMessage>
<div id="adf-completed-form-message" class="adf-no-form-message">
<p>{{'ADF_TASK_LIST.STANDALONE_TASK.COMPLETE_TASK_MESSAGE' | translate : {taskName : taskName} }}</p>
</div>
<div class="adf-no-form-submessage">
{{'ADF_TASK_LIST.STANDALONE_TASK.COMPLETE_TASK_SUB_MESSAGE' | translate}}
</div>
</ng-template>
</div>
</div>
</mat-card-content>
<mat-card-actions class="adf-no-form-mat-card-actions">
<button mat-button *ngIf="hasCancelButton()" id="adf-no-form-cancel-button" (click)="onCancelButtonClick()">{{ 'ADF_TASK_LIST.START_TASK.FORM.ACTION.CANCEL' | translate }}</button>
<button mat-button *ngIf="hasCompleteButton()" id="adf-no-form-complete-button" color="primary" (click)="onCompleteButtonClick()">{{ 'ADF_TASK_LIST.DETAILS.BUTTON.COMPLETE' | translate }}</button>
</mat-card-actions>
</mat-card>

View File

@@ -0,0 +1,53 @@
@mixin adf-task-standalone-component-theme($theme) {
$config: mat-typography-config();
$background: map-get($theme, background);
.adf {
&-message-card {
width: 60%;
box-sizing: border-box;
margin: 16px auto;
.mat-card-actions {
border-top: solid 1px mat-color($background, status-bar);
}
}
&-no-form-message-container {
height:256px;
width: 100%;
display: table;
}
&-no-form-message-list {
display: table-cell;
vertical-align: middle;
text-align: center !important;
}
&-no-form-message {
padding-bottom: 10px;
font-size: mat-font-size($config, display-1);
line-height: 36px;
letter-spacing: -1.3px;
opacity: .54;
margin: auto;
width: fit-content !important;
}
&-no-form-submessage {
font-size: mat-font-size($config, subheading-2);
opacity: .54;
margin: auto;
width: fit-content !important;
}
&-no-form-mat-card-actions {
text-align: right;
& .mat-button {
text-transform: uppercase;
border-radius: 5px;
}
& .mat-button-wrapper {
opacity: 0.54;
font-size: mat-font-size($config, button);
font-weight: bold;
}
}
}
}

View File

@@ -0,0 +1,139 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TaskStandaloneComponent } from './task-standalone.component';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {
MatButtonModule,
MatCardModule
} from '@angular/material';
describe('TaskStandaloneComponent', () => {
let component: TaskStandaloneComponent;
let fixture: ComponentFixture<TaskStandaloneComponent>;
let element: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
TaskStandaloneComponent
],
imports: [
MatButtonModule,
MatCardModule
]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(TaskStandaloneComponent);
component = fixture.componentInstance;
element = fixture.nativeElement;
fixture.detectChanges();
});
}));
it('should show Completed message if isCompleted is true', async(() => {
component.isCompleted = true;
fixture.detectChanges();
const completedFormElement = fixture.debugElement.nativeElement.querySelector('#adf-completed-form-message');
const completedFormSubElement = fixture.debugElement.nativeElement.querySelector('.adf-no-form-submessage');
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(element.querySelector('#adf-no-form-message')).toBeNull();
expect(completedFormElement).toBeDefined();
expect(completedFormElement.innerText.trim()).toBe('ADF_TASK_LIST.STANDALONE_TASK.COMPLETE_TASK_MESSAGE');
expect(completedFormSubElement).toBeDefined();
expect(completedFormSubElement.innerText).toBe('ADF_TASK_LIST.STANDALONE_TASK.COMPLETE_TASK_SUB_MESSAGE');
expect(element.querySelector('.adf-no-form-mat-card-actions')).toBeDefined();
});
}));
it('should show No form message if isCompleted is false', async(() => {
component.isCompleted = false;
fixture.detectChanges();
const noformElement = fixture.debugElement.nativeElement.querySelector('#adf-no-form-message');
fixture.whenStable().then(() => {
expect(noformElement).toBeDefined();
expect(noformElement.innerText).toBe('ADF_TASK_LIST.STANDALONE_TASK.NO_FORM_MESSAGE');
expect(element.querySelector('#adf-completed-form-message')).toBeNull();
expect(element.querySelector('.adf-no-form-submessage')).toBeNull();
});
}));
it('should hide Cancel button by default', async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#adf-no-form-cancel-button')).toBeNull();
});
}));
it('should emit cancel event if clicked on Cancel Button ', async(() => {
component.hideCancelButton = false;
component.isCompleted = false;
fixture.detectChanges();
fixture.whenStable().then(() => {
const emitSpy = spyOn(component.cancel, 'emit');
const el = fixture.nativeElement.querySelector('#adf-no-form-cancel-button');
el.click();
expect(emitSpy).toHaveBeenCalled();
});
}));
it('should hide Cancel button if hideCancelButton is true', async(() => {
component.hideCancelButton = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#adf-no-form-cancel-button')).toBeNull();
});
}));
it('should hide Cancel button if isCompleted is true', async(() => {
component.isCompleted = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#adf-no-form-cancel-button')).toBeNull();
});
}));
it('should emit complete event if clicked on Complete Button', async(() => {
component.hasCompletePermission = true;
component.isCompleted = false;
fixture.detectChanges();
fixture.whenStable().then(() => {
const emitSpy = spyOn(component.complete, 'emit');
expect(element.querySelector('#adf-no-form-complete-button')).toBeDefined();
const el = fixture.nativeElement.querySelector('#adf-no-form-complete-button');
el.click();
expect(emitSpy).toHaveBeenCalled();
});
}));
it('should hide Complete button if isCompleted is true', async(() => {
component.isCompleted = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#adf-no-form-complete-button')).toBeNull();
});
}));
it('should hide Complete button if hasCompletePermission is false', async(() => {
component.hasCompletePermission = false;
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('#adf-no-form-complete-button')).toBeNull();
});
}));
});

View File

@@ -0,0 +1,64 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'adf-task-standalone',
templateUrl: './task-standalone.component.html',
styleUrls: ['./task-standalone.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class TaskStandaloneComponent {
@Input()
taskName: string;
@Input()
isCompleted: boolean = false;
@Input()
hasCompletePermission: boolean = true;
@Input()
hideCancelButton: boolean = true;
@Output()
cancel: EventEmitter<void> = new EventEmitter<void>();
@Output()
complete: EventEmitter<void> = new EventEmitter<void>();
constructor() { }
onCancelButtonClick(): void {
this.cancel.emit();
}
onCompleteButtonClick(): void {
this.complete.emit();
}
hasCompleteButton(): boolean {
return this.hasCompletePermission && !this.isCompleted;
}
hasCancelButton(): boolean {
return !this.hideCancelButton && !this.isCompleted;
}
}