mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-12 17:04:57 +00:00
[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:
parent
7996f70b26
commit
cf0c95b3d1
@ -214,6 +214,11 @@
|
||||
"STORE": "Store",
|
||||
"RESTORE": "Restore"
|
||||
},
|
||||
"NOTIFICATIONS": {
|
||||
"TASK_ASSIGNED": "{{taskName}} task has been assigned to {{assignee}}",
|
||||
"PROCESS_STARTED": "{{processName}} process has been started",
|
||||
"TASK_UPDATED": "{{taskName}} task details has been updated"
|
||||
},
|
||||
"FORM-LOADING": {
|
||||
"FORM_DATA": "Form Data",
|
||||
"FORM_DATA_MESSAGE": "Enter values to populate the form",
|
||||
|
@ -17,6 +17,23 @@
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { CloudLayoutService } from './services/cloud-layout.service';
|
||||
import { NotificationModel, NotificationService } from '@alfresco/adf-core';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { NotificationCloudService } from '@alfresco/adf-process-services-cloud';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
const SUBSCRIPTION_QUERY = `
|
||||
subscription {
|
||||
engineEvents(eventType: [
|
||||
PROCESS_STARTED
|
||||
TASK_ASSIGNED
|
||||
TASK_UPDATED
|
||||
]) {
|
||||
eventType
|
||||
entity
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@Component({
|
||||
selector: 'app-cloud-layout',
|
||||
@ -31,13 +48,26 @@ export class CloudLayoutComponent implements OnInit {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private cloudLayoutService: CloudLayoutService
|
||||
private cloudLayoutService: CloudLayoutService,
|
||||
private notificationCloudService: NotificationCloudService,
|
||||
private notificationService: NotificationService,
|
||||
private translateService: TranslateService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
let root: string = '';
|
||||
this.route.params.subscribe((params) => {
|
||||
this.appName = params.appName;
|
||||
this.notificationCloudService.makeGQLQuery(
|
||||
this.appName, SUBSCRIPTION_QUERY
|
||||
)
|
||||
.pipe(map((events: any) => events.data.engineEvents))
|
||||
.subscribe((result) => {
|
||||
result.map((engineEvent) => {
|
||||
this.notifyEvent(engineEvent);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (this.route.snapshot && this.route.snapshot.firstChild) {
|
||||
@ -62,4 +92,37 @@ export class CloudLayoutComponent implements OnInit {
|
||||
onStartProcess() {
|
||||
this.router.navigate([`/cloud/${this.appName}/start-process/`]);
|
||||
}
|
||||
|
||||
notifyEvent(engineEvent) {
|
||||
let message;
|
||||
switch (engineEvent.eventType) {
|
||||
case 'TASK_ASSIGNED':
|
||||
message = this.translateService.instant('NOTIFICATIONS.TASK_ASSIGNED',
|
||||
{ taskName: engineEvent.entity.name || '', assignee: engineEvent.entity.assignee });
|
||||
this.pushNotification(engineEvent, message);
|
||||
break;
|
||||
case 'PROCESS_STARTED':
|
||||
message = this.translateService.instant('NOTIFICATIONS.PROCESS_STARTED',
|
||||
{ processName: engineEvent.entity.name });
|
||||
this.pushNotification(engineEvent, message);
|
||||
break;
|
||||
case 'TASK_UPDATED':
|
||||
message = this.translateService.instant('NOTIFICATIONS.TASK_UPDATED',
|
||||
{ taskName: engineEvent.entity.name || '' });
|
||||
this.pushNotification(engineEvent, message);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
pushNotification(engineEvent: any, message: string) {
|
||||
const notification = {
|
||||
messages: [message],
|
||||
icon: 'info',
|
||||
datetime: new Date(),
|
||||
initiator: { displayName: engineEvent.entity.initiator || 'System' }
|
||||
} as NotificationModel;
|
||||
|
||||
this.notificationService.pushToNotificationHistory(notification);
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
});
|
||||
});
|
@ -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) });
|
||||
}
|
||||
}
|
@ -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';
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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 }
|
||||
]
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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';
|
||||
|
@ -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": [
|
||||
|
232
package-lock.json
generated
232
package-lock.json
generated
@ -1411,6 +1411,38 @@
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@apollo/client": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.3.10.tgz",
|
||||
"integrity": "sha512-OL5y8q5evSbvsqMAHKZJgfgB/MS9PLGF7f0MtHEkGGCDvmcmA81lsjYwk0xpDm/3XdnrYp/duN2tYUu2LnpJmw==",
|
||||
"requires": {
|
||||
"@graphql-typed-document-node/core": "^3.0.0",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"@wry/context": "^0.5.2",
|
||||
"@wry/equality": "^0.3.0",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"graphql-tag": "^2.12.0",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"optimism": "^0.14.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"symbol-observable": "^2.0.0",
|
||||
"ts-invariant": "^0.6.0",
|
||||
"tslib": "^1.10.0",
|
||||
"zen-observable": "^0.8.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"symbol-observable": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz",
|
||||
"integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA=="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
||||
@ -2936,6 +2968,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@graphql-typed-document-node/core": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.0.tgz",
|
||||
"integrity": "sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg=="
|
||||
},
|
||||
"@istanbuljs/schema": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
|
||||
@ -5862,6 +5899,11 @@
|
||||
"integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/ungap__global-this": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ungap__global-this/-/ungap__global-this-0.3.1.tgz",
|
||||
"integrity": "sha512-+/DsiV4CxXl6ZWefwHZDXSe1Slitz21tom38qPCaG0DYCS1NnDPIQDTKcmQ/tvK/edJUKkmuIDBJbmKDiB0r/g=="
|
||||
},
|
||||
"@types/unist": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
|
||||
@ -5902,6 +5944,16 @@
|
||||
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/zen-observable": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz",
|
||||
"integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg=="
|
||||
},
|
||||
"@ungap/global-this": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/global-this/-/global-this-0.4.4.tgz",
|
||||
"integrity": "sha512-mHkm6FvepJECMNthFuIgpAEFmPOk71UyXuIxYfjytvFTnSDBIz7jmViO+LfHI/AjrazWije0PnSP3+/NlwzqtA=="
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
|
||||
@ -6077,6 +6129,51 @@
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
"@wry/context": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@wry/context/-/context-0.5.4.tgz",
|
||||
"integrity": "sha512-/pktJKHUXDr4D6TJqWgudOPJW2Z+Nb+bqk40jufA3uTkLbnCRKdJPiYDIa/c7mfcPH8Hr6O8zjCERpg5Sq04Zg==",
|
||||
"requires": {
|
||||
"tslib": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@wry/equality": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.3.2.tgz",
|
||||
"integrity": "sha512-yi0VRqw+ygqM/WVZUze5meAhe2evOHBFXqK8onNVdNNB+Tyn8/07FZpeDklECBHeT9KN9DY2JpCVGNQY6RCRDg==",
|
||||
"requires": {
|
||||
"tslib": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@wry/trie": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.2.2.tgz",
|
||||
"integrity": "sha512-OxqBB39x6MfHaa2HpMiRMfhuUnQTddD32Ko020eBeJXq87ivX6xnSSnzKHVbA21p7iqBASz8n/07b6W5wW1BVQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@xtuc/ieee754": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
|
||||
@ -6370,6 +6467,16 @@
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"apollo-angular": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/apollo-angular/-/apollo-angular-2.2.0.tgz",
|
||||
"integrity": "sha512-/38ynj2gMJ1M/JlSDB6vv1fGYJy7WDukJn/3wQnoOYay5ZeU0rsAJdBaSZQiOPxqAJgVoGfU787/aXjIC1PWZg==",
|
||||
"requires": {
|
||||
"extract-files": "^9.0.0",
|
||||
"semver": "^7.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"app-root-path": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz",
|
||||
@ -6645,8 +6752,7 @@
|
||||
"async-limiter": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
@ -6852,8 +6958,7 @@
|
||||
"backo2": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
||||
},
|
||||
"bail": {
|
||||
"version": "1.0.5",
|
||||
@ -11579,8 +11684,7 @@
|
||||
"extract-files": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/extract-files/-/extract-files-9.0.0.tgz",
|
||||
"integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ=="
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
@ -11628,8 +11732,7 @@
|
||||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
@ -12820,6 +12923,21 @@
|
||||
"form-data": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"graphql-tag": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.1.tgz",
|
||||
"integrity": "sha512-LPewEE1vzGkHnCO8zdOGogKsHHBdtpGyihow1UuMwp6RnZa0lAS7NcbvltLOuo4pi5diQCPASAXZkQq44ffixA==",
|
||||
"requires": {
|
||||
"tslib": "^1.14.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"graphviz": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/graphviz/-/graphviz-0.0.8.tgz",
|
||||
@ -13076,6 +13194,14 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"homedir-polyfill": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
|
||||
@ -14537,6 +14663,11 @@
|
||||
"integrity": "sha512-O62gD5ADMUGtJoOoM9U6LQ7i4byPXUNoHJ6mqsmkQJcom331ZJGDApWgDESWyBMEHEJRjtHozgIiTzYo9RU4UA==",
|
||||
"dev": true
|
||||
},
|
||||
"iterall": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
|
||||
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
|
||||
},
|
||||
"jake": {
|
||||
"version": "10.8.2",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
|
||||
@ -14899,8 +15030,7 @@
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.0.0",
|
||||
@ -16439,7 +16569,6 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
@ -18531,8 +18660,7 @@
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
@ -18775,6 +18903,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"optimism": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/optimism/-/optimism-0.14.0.tgz",
|
||||
"integrity": "sha512-ygbNt8n4DOCVpkwiLF+IrKKeNHOjtr9aXLWGP9HNJGoblSGsnVbJLstcH6/nE9Xy5ZQtlkSioFQNnthmENW6FQ==",
|
||||
"requires": {
|
||||
"@wry/context": "^0.5.2",
|
||||
"@wry/trie": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"optimize-css-assets-webpack-plugin": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz",
|
||||
@ -20483,6 +20620,16 @@
|
||||
"sisteransi": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||
@ -21386,6 +21533,11 @@
|
||||
"strip-json-comments": "~2.0.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
@ -25494,6 +25646,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"subscriptions-transport-ws": {
|
||||
"version": "0.9.18",
|
||||
"resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz",
|
||||
"integrity": "sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA==",
|
||||
"requires": {
|
||||
"backo2": "^1.0.2",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"iterall": "^1.2.1",
|
||||
"symbol-observable": "^1.0.4",
|
||||
"ws": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eventemitter3": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
|
||||
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
|
||||
"integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sugarss": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
|
||||
@ -26200,6 +26384,23 @@
|
||||
"glob": "^7.1.2"
|
||||
}
|
||||
},
|
||||
"ts-invariant": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.6.0.tgz",
|
||||
"integrity": "sha512-caoafsfgb8QxdrKzFfjKt627m4i8KTtfAiji0DYJfWI4A/S9ORNNpzYuD9br64kyKFgxn9UNaLLbSupam84mCA==",
|
||||
"requires": {
|
||||
"@types/ungap__global-this": "^0.3.1",
|
||||
"@ungap/global-this": "^0.4.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ts-loader": {
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz",
|
||||
@ -29053,6 +29254,11 @@
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"zen-observable": {
|
||||
"version": "0.8.15",
|
||||
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz",
|
||||
"integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="
|
||||
},
|
||||
"zone.js": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
|
||||
|
@ -84,10 +84,12 @@
|
||||
"@angular/platform-browser": "^10.0.4",
|
||||
"@angular/platform-browser-dynamic": "^10.0.4",
|
||||
"@angular/router": "^10.0.4",
|
||||
"@apollo/client": "^3.3.7",
|
||||
"@mat-datetimepicker/core": "^5.1.1",
|
||||
"@mat-datetimepicker/moment": "^5.1.1",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"adf-tslint-rules": "0.0.7",
|
||||
"apollo-angular": "^2.2.0",
|
||||
"chart.js": "2.9.4",
|
||||
"classlist.js": "1.1.20150312",
|
||||
"custom-event-polyfill": "^1.0.7",
|
||||
@ -101,6 +103,7 @@
|
||||
"raphael": "2.3.0",
|
||||
"rxjs": "^6.6.3",
|
||||
"snyk": "^1.452.0",
|
||||
"subscriptions-transport-ws": "^0.9.18",
|
||||
"tslib": "^2.0.3",
|
||||
"zone.js": "~0.10.2"
|
||||
},
|
||||
|
@ -25,6 +25,7 @@
|
||||
"lib": [
|
||||
"es2018",
|
||||
"esnext.array",
|
||||
"esnext.asynciterable",
|
||||
"dom"
|
||||
],
|
||||
"paths": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user