[ACA-4259] Task filter counter notifications (#6607)

* [ACA-4259] Task Filter Counter Notifications

* Improve Apollo connection for multiple apps

* Improve Notification Cloud Service

* Rebase branch

* Rebase branch

* Add peer dependencies

* Rebase

* Remove apollo-angular-link-http

* Fix linting

* Rebase branch

* Fix package lock

* Push package lock
This commit is contained in:
davidcanonieto
2021-02-16 15:27:38 +01:00
committed by GitHub
parent 7996f70b26
commit cf0c95b3d1
23 changed files with 688 additions and 57 deletions

View File

@@ -46,7 +46,7 @@
</ng-template>
<p class="adf-notification-history-menu-message"
*ngFor="let message of notification.messages"
mat-line>{{ message }}</p>
mat-line [matTooltip]="message" matTooltipShowDelay="1000">{{ message }}</p>
<p class="adf-notification-history-menu-date"
mat-line> {{notification.datetime | adfTimeAgo}} </p>
</mat-list-item>

View File

@@ -21,8 +21,11 @@
"@alfresco/js-api": "4.2.0",
"@alfresco/adf-core": "4.2.0",
"@alfresco/adf-content-services": "4.2.0",
"@apollo/client": "^3.3.7",
"@ngx-translate/core": ">=13.0.0",
"moment": ">=2.22.2"
"apollo-angular": "^2.2.0",
"moment": ">=2.22.2",
"subscriptions-transport-ws": "^0.9.18"
},
"keywords": [
"process-services-cloud",

View File

@@ -0,0 +1,23 @@
/*!
* @license
* Copyright 2019 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 { TaskDetailsCloudModel } from '../task/start-task/models/task-details-cloud.model';
export interface TaskCloudEngineEvent {
eventType: string;
entity: TaskDetailsCloudModel;
}

View File

@@ -0,0 +1,72 @@
/*!
* @license
* Copyright 2019 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 { TestBed, async } from '@angular/core/testing';
import { setupTestBed } from '@alfresco/adf-core';
import { ProcessServiceCloudTestingModule } from '../testing/process-service-cloud.testing.module';
import { TranslateModule } from '@ngx-translate/core';
import { NotificationCloudService } from './notification-cloud.service';
import { Apollo } from 'apollo-angular';
describe('NotificationCloudService', () => {
let service: NotificationCloudService;
let apollo: Apollo;
const queryMock = `
subscription {
engineEvents(eventType: [
MY_EVENT
]) {
eventType
entity
}
}
`;
setupTestBed({
imports: [
TranslateModule.forRoot(),
ProcessServiceCloudTestingModule
]
});
beforeEach(async(() => {
service = TestBed.inject(NotificationCloudService);
apollo = TestBed.inject(Apollo);
}));
it('should not create more than one websocket per app if it was already created', () => {
const apolloCreateSpy = spyOn(apollo, 'create');
const apolloSubscribeSpy = spyOn(apollo, 'subscribe');
service.makeGQLQuery('myAppName', queryMock);
expect(service.appsListening.length).toBe(1);
expect(service.appsListening[0]).toBe('myAppName');
service.makeGQLQuery('myAppName', queryMock);
expect(service.appsListening.length).toBe(1);
expect(service.appsListening[0]).toBe('myAppName');
service.makeGQLQuery('myAppName2', queryMock);
expect(service.appsListening.length).toBe(2);
expect(service.appsListening[0]).toBe('myAppName');
expect(service.appsListening[1]).toBe('myAppName2');
expect(apolloCreateSpy).toHaveBeenCalledTimes(2);
expect(apolloSubscribeSpy).toHaveBeenCalledTimes(3);
});
});

View File

@@ -0,0 +1,85 @@
/*!
* @license
* Copyright 2019 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 { Apollo } from 'apollo-angular';
import { HttpLink } from 'apollo-angular/http';
import { split, gql, InMemoryCache } from '@apollo/client/core';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import { Injectable } from '@angular/core';
import { StorageService, AppConfigService, AlfrescoApiService } from '@alfresco/adf-core';
import { BaseCloudService } from './base-cloud.service';
@Injectable({
providedIn: 'root'
})
export class NotificationCloudService extends BaseCloudService {
appsListening = [];
constructor(apiService: AlfrescoApiService,
appConfigService: AppConfigService,
public apollo: Apollo,
private http: HttpLink,
private storageService: StorageService) {
super(apiService, appConfigService);
}
private getUrlDomain(appName: string) {
return this.getBasePath(appName).split('://')[1];
}
initNotificationsForApp(appName: string) {
if (!this.appsListening.includes(appName)) {
this.appsListening.push(appName);
const httpLink = this.http.create({
uri: `${this.getBasePath(appName)}/notifications/graphql`
});
const webSocketLink = new WebSocketLink({
uri: `wss://${this.getUrlDomain(appName)}/notifications/ws/graphql`,
options: {
reconnect: true,
lazy: true,
connectionParams: {
kaInterval: 2000,
'X-Authorization': 'Bearer ' + this.storageService.getItem('access_token')
}
}
});
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
},
webSocketLink,
httpLink
);
this.apollo.create(<any> {
link,
cache: new InMemoryCache({})
});
}
}
makeGQLQuery(appName: string, gqlQuery: string) {
this.initNotificationsForApp(appName);
return this.apollo.subscribe({ query : gql(gqlQuery) });
}
}

View File

@@ -18,5 +18,6 @@
export * from './user-preference-cloud.service';
export * from './local-preference-cloud.service';
export * from './cloud-token.service';
export * from './notification-cloud.service';
export * from './preference-cloud.interface';
export * from './form-fields.interfaces';

View File

@@ -1,16 +1,25 @@
<ng-container *ngIf="filters$ | async as filterList; else loading">
<div *ngFor="let filter of filterList" class="adf-task-filters__entry">
<div *ngFor="let filter of filterList"
class="adf-task-filters__entry">
<button (click)="onFilterClick(filter)"
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
mat-button
[class.adf-active]="currentFilter === filter"
class="adf-filter-action-button adf-full-width" fxLayout="row" fxLayoutAlign="space-between center">
<adf-icon data-automation-id="adf-filter-icon" *ngIf="showIcons" [value]="filter.icon"></adf-icon>
<span data-automation-id="adf-filter-label" class="adf-filter-action-button__label">{{ filter.name | translate }}</span>
[attr.aria-label]="filter.name | translate"
[id]="filter.id"
[attr.data-automation-id]="filter.key + '_filter'"
mat-button
[class.adf-active]="currentFilter === filter"
class="adf-filter-action-button adf-full-width"
fxLayout="row"
fxLayoutAlign="space-between center">
<adf-icon data-automation-id="adf-filter-icon"
*ngIf="showIcons"
[value]="filter.icon"></adf-icon>
<span data-automation-id="adf-filter-label"
class="adf-filter-action-button__label">{{ filter.name | translate }}</span>
</button>
<span *ngIf="counters$[filter.key]" class="adf-filter-action-button__counter">
<span *ngIf="counters$[filter.key]"
[attr.data-automation-id]="filter.key + '_filter-counter'"
class="adf-filter-action-button__counter"
[class.adf-active]=wasFilterUpdated(filter.key)>
{{ counters$[filter.key] | async }}
</span>
</div>

View File

@@ -1,5 +1,7 @@
@mixin adf-cloud-task-filters-theme($theme) {
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$background: map-get($theme, background);
.adf {
&-task-filters__entry {
@@ -7,7 +9,6 @@
padding: 12px 0 !important;
height: 24px;
width: 100%;
cursor: pointer;
font-size: 14px !important;
font-weight: bold;
opacity: 1;
@@ -20,6 +21,7 @@
.adf-filter-action-button {
opacity: 0.54;
padding: 16px;
cursor: pointer;
.adf-filter-action-button__label {
padding-left: 20px;
@@ -29,13 +31,26 @@
.adf-filter-action-button__counter {
opacity: 0.54;
padding-left: 10px;
padding-top: 6px;
margin-left: 10px;
margin-top: 6px;
&.adf-active {
margin-left: 8px;
margin-top: 5px;
padding: 0 5px;
border-radius: 15px;
background-color: mat-color($accent);
color: mat-color($mat-grey, 50);
font-size: smaller;
}
}
&:hover {
color: mat-color($primary);
.adf-filter-action-button__counter, .adf-filter-action-button {
.adf-filter-action-button__counter,
.adf-filter-action-button {
opacity: 1;
}
}

View File

@@ -46,6 +46,7 @@ export abstract class BaseTaskFiltersCloudComponent implements OnDestroy {
error: EventEmitter<any> = new EventEmitter<any>();
counters$: {[key: string]: Observable<number>} = {};
updatedCounters: string[] = [];
protected onDestroy$ = new Subject<boolean>();
@@ -53,4 +54,21 @@ export abstract class BaseTaskFiltersCloudComponent implements OnDestroy {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
wasFilterUpdated(filterKey: string): boolean {
return this.updatedCounters.includes(filterKey);
}
addToUpdatedCounters(filterKey: string) {
if (!this.updatedCounters.includes(filterKey)) {
this.updatedCounters.push(filterKey);
}
}
resetFilterCounter(filterKey: string) {
const filterIndex = this.updatedCounters.indexOf(filterKey);
if (filterIndex > -1) {
this.updatedCounters.splice(filterIndex, 1);
}
}
}

View File

@@ -26,7 +26,7 @@ import { TaskFiltersCloudComponent } from './task-filters-cloud.component';
import { By } from '@angular/platform-browser';
import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module';
import { TaskFiltersCloudModule } from '../task-filters-cloud.module';
import { fakeGlobalFilter } from '../mock/task-filters-cloud.mock';
import { fakeGlobalFilter, taskNotifications } from '../mock/task-filters-cloud.mock';
import { TranslateModule } from '@ngx-translate/core';
describe('TaskFiltersCloudComponent', () => {
@@ -34,7 +34,7 @@ describe('TaskFiltersCloudComponent', () => {
let taskFilterService: TaskFilterCloudService;
const fakeGlobalFilterObservable =
new Observable(function(observer) {
new Observable(function (observer) {
observer.next(fakeGlobalFilter);
observer.complete();
});
@@ -69,12 +69,13 @@ describe('TaskFiltersCloudComponent', () => {
taskFilterService = TestBed.inject(TaskFilterCloudService);
spyOn(taskFilterService, 'getTaskFilterCounter').and.returnValue(of(11));
spyOn(taskFilterService, 'getTaskNotificationSubscription').and.returnValue(of(taskNotifications));
});
it('should attach specific icon for each filter if hasIcon is true', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
const change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({'appName': change});
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
component.showIcons = true;
fixture.whenStable().then(() => {
@@ -93,7 +94,7 @@ describe('TaskFiltersCloudComponent', () => {
component.showIcons = false;
const change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({'appName': change});
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
fixture.whenStable().then(() => {
@@ -107,7 +108,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should display the filters', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
const change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({'appName': change});
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
component.showIcons = true;
fixture.whenStable().then(() => {
@@ -126,7 +127,7 @@ describe('TaskFiltersCloudComponent', () => {
const appName = 'my-app-1';
const change = new SimpleChange(null, appName, true);
component.ngOnChanges({'appName': change});
component.ngOnChanges({ 'appName': change });
component.error.subscribe((err) => {
expect(err).toBeDefined();
@@ -368,7 +369,7 @@ describe('TaskFiltersCloudComponent', () => {
it('should display filter counter if property set to true', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
const change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({'appName': change});
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
component.showIcons = true;
fixture.whenStable().then(() => {
@@ -379,4 +380,44 @@ describe('TaskFiltersCloudComponent', () => {
expect(filterCounters[0].nativeElement.innerText).toContain('11');
});
}));
it('should update filter counter when notification received', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
const change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
component.showIcons = true;
fixture.whenStable().then(() => {
fixture.detectChanges();
const updatedFilterCounters = fixture.debugElement.queryAll(By.css('span.adf-active'));
expect(updatedFilterCounters.length).toBe(1);
expect(Object.keys(component.counters$).length).toBe(1);
expect(component.counters$['fake-involved-tasks']).toBeDefined();
});
}));
it('should reset filter counter notification when filter is selected', async(() => {
spyOn(taskFilterService, 'getTaskListFilters').and.returnValue(fakeGlobalFilterObservable);
let change = new SimpleChange(undefined, 'my-app-1', true);
component.ngOnChanges({ 'appName': change });
fixture.detectChanges();
component.showIcons = true;
fixture.whenStable().then(() => {
fixture.detectChanges();
let updatedFilterCounters = fixture.debugElement.queryAll(By.css('span.adf-active'));
expect(updatedFilterCounters.length).toBe(1);
component.filters = fakeGlobalFilter;
component.currentFilter = null;
change = new SimpleChange(null, { key: fakeGlobalFilter[0].key }, true);
component.ngOnChanges({ 'filterParam': change });
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
updatedFilterCounters = fixture.debugElement.queryAll(By.css('span.adf-active'));
expect(updatedFilterCounters.length).toBe(0);
});
});
}));
});

View File

@@ -20,8 +20,10 @@ import { Observable } from 'rxjs';
import { TaskFilterCloudService } from '../services/task-filter-cloud.service';
import { TaskFilterCloudModel, FilterParamsModel } from '../models/filter-cloud.model';
import { TranslationService } from '@alfresco/adf-core';
import { takeUntil } from 'rxjs/operators';
import { map, takeUntil } from 'rxjs/operators';
import { BaseTaskFiltersCloudComponent } from './base-task-filters-cloud.component';
import { TaskDetailsCloudModel } from '../../start-task/models/task-details-cloud.model';
import { TaskCloudEngineEvent } from '../../../models/engine-event-cloud.model';
@Component({
selector: 'adf-cloud-task-filters',
@@ -37,10 +39,13 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
@Output()
filterClicked = new EventEmitter<TaskFilterCloudModel>();
/** Emitted when filter counters are updated. */
@Output()
filterCounterUpdated: EventEmitter<TaskCloudEngineEvent[]> = new EventEmitter<TaskCloudEngineEvent[]>();
filters$: Observable<TaskFilterCloudModel[]>;
filters: TaskFilterCloudModel[] = [];
currentFilter: TaskFilterCloudModel;
counters = {};
constructor(private taskFilterCloudService: TaskFilterCloudService,
private translationService: TranslationService) {
@@ -48,6 +53,7 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
}
ngOnInit() {
this.initFilterCounterNotifications();
this.getFilters(this.appName);
}
@@ -89,6 +95,30 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
});
}
initFilterCounterNotifications() {
this.taskFilterCloudService.getTaskNotificationSubscription(this.appName)
.subscribe((result: TaskCloudEngineEvent[]) => {
result.map((taskEvent: TaskCloudEngineEvent) => {
this.updateFilterCounter(taskEvent.entity);
});
this.filterCounterUpdated.emit(result);
});
}
updateFilterCounter(filterNotification: TaskDetailsCloudModel) {
this.filters.map((filter) => {
if (this.isFilterPresent(filter, filterNotification)) {
this.counters$[filter.key] = this.counters$[filter.key].pipe(map((counter) => counter + 1));
this.addToUpdatedCounters(filter.key);
}
});
}
isFilterPresent(filter: TaskFilterCloudModel, filterNotification: TaskDetailsCloudModel): boolean {
return filter.status === filterNotification.status
&& filter.assignee === filterNotification.assignee;
}
public selectFilter(paramFilter: FilterParamsModel) {
if (paramFilter) {
this.currentFilter = this.filters.find((filter, index) =>
@@ -104,7 +134,10 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp
public selectFilterAndEmit(newParamFilter: FilterParamsModel) {
if (newParamFilter) {
this.selectFilter(newParamFilter);
this.filterSelected.emit(this.currentFilter);
if (this.currentFilter) {
this.resetFilterCounter(this.currentFilter.key);
this.filterSelected.emit(this.currentFilter);
}
} else {
this.currentFilter = undefined;
}

View File

@@ -15,6 +15,7 @@
* limitations under the License.
*/
import { assignedTaskDetailsCloudMock } from '../../task-header/mocks/task-details-cloud.mock';
import { TaskFilterCloudModel, ServiceTaskFilterCloudModel } from '../models/filter-cloud.model';
export const fakeGlobalFilter = [
@@ -23,8 +24,8 @@ export const fakeGlobalFilter = [
key: 'fake-involved-tasks',
icon: 'adjust',
id: '10',
status: 'open',
assignee: 'fake-involved',
status: 'ASSIGNED',
assignee: 'AssignedTaskUser',
showCounter: true
}),
new TaskFilterCloudModel({
@@ -273,3 +274,16 @@ export const fakeTaskCloudFilters = [
order: 'DESC'
}
];
export const taskNotifications = [
{
eventType: 'TASK_ASSIGNED',
entity: assignedTaskDetailsCloudMock
}
];
export const taskCloudEngineEventsMock = {
data: {
engineEvents: taskNotifications
}
};

View File

@@ -33,15 +33,19 @@ import {
fakePreferenceWithNoTaskFilterPreference,
fakeTaskCloudFilters,
fakeTaskCloudPreferenceList,
fakeTaskFilter
fakeTaskFilter,
taskCloudEngineEventsMock
} from '../mock/task-filters-cloud.mock';
import { UserPreferenceCloudService } from '../../../services/user-preference-cloud.service';
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TaskFilterCloudModel } from '../models/filter-cloud.model';
import { NotificationCloudService } from '../../../services/notification-cloud.service';
import { TaskCloudEngineEvent } from './../../../models/engine-event-cloud.model';
describe('TaskFilterCloudService', () => {
let service: TaskFilterCloudService;
let notificationCloudService: NotificationCloudService;
let getPreferencesSpy: jasmine.Spy;
let getPreferenceByKeySpy: jasmine.Spy;
@@ -53,7 +57,7 @@ describe('TaskFilterCloudService', () => {
setupTestBed({
imports: [
HttpClientTestingModule
HttpClientTestingModule
],
providers: [
{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: UserPreferenceCloudService },
@@ -64,6 +68,7 @@ describe('TaskFilterCloudService', () => {
beforeEach(() => {
service = TestBed.inject(TaskFilterCloudService);
notificationCloudService = TestBed.inject(NotificationCloudService);
const preferenceCloudService = service.preferenceService;
createPreferenceSpy = spyOn(preferenceCloudService, 'createPreference').and.returnValue(of(fakeTaskCloudFilters));
@@ -229,6 +234,17 @@ describe('TaskFilterCloudService', () => {
expect(service.isDefaultFilter(defaultFilterName)).toBe(true);
expect(service.isDefaultFilter(fakeFilterName)).toBe(false);
});
it('should return engine event task subscription', (done) => {
spyOn(notificationCloudService, 'makeGQLQuery').and.returnValue(of(taskCloudEngineEventsMock));
service.getTaskNotificationSubscription('myAppName').subscribe((res: TaskCloudEngineEvent[]) => {
expect(res.length).toBe(1);
expect(res[0].eventType).toBe('TASK_ASSIGNED');
expect(res[0].entity.name).toBe('This is a new task');
done();
});
});
});
describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService', () => {
@@ -240,9 +256,7 @@ describe('Inject [LocalPreferenceCloudService] into the TaskFilterCloudService',
const identityUserMock = { username: 'fakeusername', firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' };
setupTestBed({
imports: [
HttpClientTestingModule
],
imports: [ HttpClientTestingModule ],
providers: [
{ provide: TASK_FILTERS_SERVICE_TOKEN, useClass: LocalPreferenceCloudService }
]

View File

@@ -24,6 +24,24 @@ import { BaseCloudService } from '../../../services/base-cloud.service';
import { PreferenceCloudServiceInterface } from '../../../services/preference-cloud.interface';
import { TASK_FILTERS_SERVICE_TOKEN } from '../../../services/cloud-token.service';
import { TaskCloudNodePaging } from '../../task-list/models/task-cloud.model';
import { NotificationCloudService } from '../../../services/notification-cloud.service';
import { TaskCloudEngineEvent } from '../../../models/engine-event-cloud.model';
const TASK_EVENT_SUBSCRIPTION_QUERY = `
subscription {
engineEvents(eventType: [
TASK_COMPLETED
TASK_ASSIGNED
TASK_ACTIVATED
TASK_SUSPENDED
TASK_CANCELLED
TASK_UPDATED
]) {
eventType
entity
}
}
`;
@Injectable({
providedIn: 'root'
@@ -37,7 +55,8 @@ export class TaskFilterCloudService extends BaseCloudService {
@Inject(TASK_FILTERS_SERVICE_TOKEN)
public preferenceService: PreferenceCloudServiceInterface,
apiService: AlfrescoApiService,
appConfigService: AppConfigService) {
appConfigService: AppConfigService,
private notificationCloudService: NotificationCloudService) {
super(apiService, appConfigService);
this.filtersSubject = new BehaviorSubject([]);
this.filters$ = this.filtersSubject.asObservable();
@@ -315,4 +334,9 @@ export class TaskFilterCloudService extends BaseCloudService {
})
];
}
getTaskNotificationSubscription(appName: string): Observable<TaskCloudEngineEvent[]> {
return this.notificationCloudService.makeGQLQuery(appName, TASK_EVENT_SUBSCRIPTION_QUERY)
.pipe(map((events: any) => events.data.engineEvents));
}
}

View File

@@ -21,7 +21,7 @@ export const fakeTaskDetailsCloud = {
'appVersion': '',
'id': '68d54a8f',
'assignee': 'Phil Woods',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': 1545048055900,
'dueDate': 1545091200000,

View File

@@ -46,7 +46,7 @@ export const assignedTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': '68d54a8f-01f3-11e9-8e36-0a58646002ad',
'assignee': 'AssignedTaskUser',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(),
@@ -70,7 +70,7 @@ export const createdTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': '68d54a8f-01f3-11e9-8e36-0a58646002ad',
'assignee': 'CreatedTaskUser',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),
@@ -94,7 +94,7 @@ export const emptyOwnerTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': '68d54a8f-01f3-11e9-8e36-0a58646002ad',
'assignee': 'AssignedTaskUser',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),
@@ -118,7 +118,7 @@ export const createdStateTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': 'mock-task-id',
'assignee': '',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),
@@ -142,7 +142,7 @@ export const completedTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': 'mock-task-id',
'assignee': 'CompletedTaskAssignee',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),
@@ -166,7 +166,7 @@ export const cancelledTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': 'mock-task-id',
'assignee': 'CancelledTaskAssignee',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),
@@ -190,7 +190,7 @@ export const suspendedTaskDetailsCloudMock: TaskDetailsCloudModel = {
'appVersion': 1,
'id': 'mock-task-id',
'assignee': 'SuspendedTaskAssignee',
'name': 'This is a new task ',
'name': 'This is a new task',
'description': 'This is the description ',
'createdDate': new Date(1545048055900),
'dueDate': new Date(1545091200000),

View File

@@ -29,3 +29,4 @@ export * from './lib/pipes/process-services-cloud-pipe.module';
export * from './lib/models/process-definition-cloud.model';
export * from './lib/models/date-cloud-filter.model';
export * from './lib/models/application-version.model';
export * from './lib/models/engine-event-cloud.model';

View File

@@ -29,7 +29,7 @@
"@alfresco/adf-core": ["./core/"],
"@alfresco/adf-insights": ["./analytics"]
},
"lib": ["es2018", "esnext.array", "dom"],
"lib": ["es2018", "esnext.array", "esnext.asynciterable", "dom"],
"suppressImplicitAnyIndexErrors": true
},
"exclude": [