diff --git a/lib/process-services-cloud/src/lib/models/filter-counters-cloud.model.ts b/lib/process-services-cloud/src/lib/models/filter-counters-cloud.model.ts index 5a6a4e4882..bca1c9f8c8 100644 --- a/lib/process-services-cloud/src/lib/models/filter-counters-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/models/filter-counters-cloud.model.ts @@ -15,9 +15,6 @@ * limitations under the License. */ -/** - * Entity types accepted by the `POST /query/v1/count` endpoint. - */ export const FilterCounterEntityType = { TASK: 'TASK', PROCESS_INSTANCE: 'PROCESS_INSTANCE' @@ -31,7 +28,6 @@ export interface FilterCountersQuerySort { isProcessVariable: boolean; } -/** A single query of the batched count request, holding the criteria of one filter. */ export interface FilterCountersQuery { /** Identifies the query, so its counter can be read back from the response. */ requestId: string; @@ -41,28 +37,19 @@ export interface FilterCountersQuery { [criteria: string]: unknown; } -/** - * Payload of the batched count request, one entry per counter to be resolved. - */ export type FilterCountersRequest = { [entityType in FilterCounterEntityType]?: FilterCountersQuery[]; }; -/** Shape of a task or process filter the counters are resolved for. Its key is the `requestId`. */ export interface FilterCounterCandidate { - key?: string | null; + key: string; showCounter?: boolean; } -/** - * Counts returned by the batched count request, keyed by entity type and then by `requestId`. - * e.g. `{ TASK: { 'my-tasks': 5 }, PROCESS_INSTANCE: { 'running-processes': 5 } }` - */ export type FilterCounters = { [entityType in FilterCounterEntityType]?: { [requestId: string]: number }; }; -/** Counters of the filters of one entity type, keyed by filter key. */ export interface FilterCountersResult { [filterKey: string]: number; } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters/process-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters/process-filters-cloud.component.ts index c457e7a46a..e0e74ba1cb 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters/process-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters/process-filters-cloud.component.ts @@ -133,7 +133,6 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges { } }); - /* Read along with the filters, not once they arrive, so both components share one request. */ this.loadFilterCounters(appName, filters$); } @@ -141,11 +140,7 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges { * Initialize counter collection for filters */ initFilterCounters(): void { - this.filters.forEach((filter) => { - if (filter.key) { - this.counters[filter.key] = 0; - } - }); + this.filters.forEach((filter) => (this.counters[filter.key] = 0)); } /** @@ -283,7 +278,6 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges { private loadFilterCounters(appName: string, filters$: Observable): void { this.countersSubscription?.unsubscribe(); - /* Counters are keyed by filter key, so they are applied once the filters are known. */ this.countersSubscription = combineLatest([ filters$.pipe(catchError(() => EMPTY)), this.filterCountersCloudService.getFilterCounters(appName, FilterCounterEntityType.PROCESS_INSTANCE) @@ -293,21 +287,16 @@ export class ProcessFiltersCloudComponent implements OnInit, OnChanges { } private applyFilterCounters(counters: FilterCountersResult): void { - this.filters.forEach((filter) => { - /* A filter without a key holds no request id. */ - const filterKey = filter?.showCounter ? filter.key : undefined; - if (!filterKey) { - return; - } + this.filters + .filter((filter) => filter?.showCounter) + .forEach((filter) => { + const counter = counters[filter.key]; + if (counter === undefined) { + return; + } - const counter = counters[filterKey]; - /* A filter the request left out keeps the counter it holds, rather than showing a wrong one. */ - if (counter === undefined) { - return; - } - - this.checkIfFilterValuesHasBeenUpdated(filterKey, counter); - this.counters = { ...this.counters, [filterKey]: counter }; - }); + this.checkIfFilterValuesHasBeenUpdated(filter.key, counter); + this.counters = { ...this.counters, [filter.key]: counter }; + }); } } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts index 3435fe4c35..6afe9dd6d2 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/models/process-filter-cloud.model.ts @@ -25,7 +25,7 @@ import { ProcessVariableFilterModel } from '../../../models/process-variable-fil export class ProcessFilterCloudModel { id: string; name: string | null; - key: string | null; + key: string; icon: string | null; index: number | null; appName: string | null; @@ -79,7 +79,7 @@ export class ProcessFilterCloudModel { this.id = obj.id || Math.random().toString(36).substring(2, 9); this.name = obj.name || null; - this.key = obj.key || null; + this.key = obj.key; this.environmentId = obj.environmentId || null; this.showCounter = obj.showCounter || false; this.icon = obj.icon || null; diff --git a/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.spec.ts index 1ab400ce65..812f08bf0a 100644 --- a/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.spec.ts +++ b/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.spec.ts @@ -88,7 +88,6 @@ describe('FilterCountersCloudService', () => { const counters = (entityType: FilterCounterEntityType, appName = 'mock-app') => firstValueFrom(service.getFilterCounters(appName, entityType)); const taskCounters = (appName = 'mock-app') => counters(FilterCounterEntityType.TASK, appName); const processCounters = (appName = 'mock-app') => counters(FilterCounterEntityType.PROCESS_INSTANCE, appName); - /** As read when both filter components are on screen. */ const bothCounters = (appName = 'mock-app') => firstValueFrom( combineLatest([ @@ -114,7 +113,6 @@ describe('FilterCountersCloudService', () => { taskEvents$ = new Subject(); processEvents$ = new Subject(); makeGQLQuerySpy = spyOn(notificationCloudService, 'makeGQLQuery'); - /* Every entity type holds its own subscription. */ makeGQLQuerySpy.and.callFake((_appName: string, query: string) => (query.includes('TASK_CREATED') ? taskEvents$ : processEvents$).asObservable() ); @@ -146,7 +144,6 @@ describe('FilterCountersCloudService', () => { }); it('should share the filters with the batched count request', async () => { - /* The filter component holds its subscription while the counters are resolved. */ const subscription = service.getTaskFilters('mock-app').subscribe(); await taskCounters(); subscription.unsubscribe(); @@ -232,13 +229,6 @@ describe('FilterCountersCloudService', () => { expect(countRequestIds(FilterCounterEntityType.TASK)).toEqual(['queued-tasks']); }); - it('should leave out a filter without a key, since it holds no request id', async () => { - getProcessFiltersSpy.and.returnValue(of([processFilter({ key: null, status: 'RUNNING', showCounter: true })])); - - expect(await processCounters()).toEqual({}); - expect(postSpy).not.toHaveBeenCalled(); - }); - it('should resolve the counters of an entity type when the filters of the other one fail to load', async () => { getProcessFiltersSpy.and.returnValue(throwError(() => new Error('filters failed'))); @@ -330,7 +320,6 @@ describe('FilterCountersCloudService', () => { service.getFilterCounters('mock-app', FilterCounterEntityType.TASK).subscribe(); tick(0); - /* Opened again, so the first subscription was closed rather than left behind. */ expect(makeGQLQuerySpy).toHaveBeenCalledTimes(2); })); @@ -348,11 +337,9 @@ describe('FilterCountersCloudService', () => { })); it('should release the filters subscription once nothing reads them', fakeAsync(() => { - /* `TaskFilterCloudService.filters$` never completes, so a subscription left behind would be held. */ const filters$ = new BehaviorSubject(taskFiltersMock); getTaskListFiltersSpy.and.returnValue(filters$.asObservable()); - /* As the filter component does: the filters are held while the counters are read. */ const subscriptions = [ service.getTaskFilters('mock-app').subscribe(), service.getFilterCounters('mock-app', FilterCounterEntityType.TASK).subscribe() diff --git a/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.ts b/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.ts index 39e9311e1c..82e212c697 100644 --- a/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/services/filter-counters-cloud.service.ts @@ -47,7 +47,6 @@ interface EngineEventsData { engineEvents?: TaskCloudEngineEvent[]; } -/** One subscription per entity type, so an app showing one of them is not notified of the other. */ const ENGINE_EVENTS_SUBSCRIPTION_QUERIES: Record = { [FilterCounterEntityType.TASK]: ` subscription { @@ -264,7 +263,6 @@ export class FilterCountersCloudService extends BaseCloudService { this.recountTrigger(appName).next(); } - // The filters of an entity type that fails to load are left out, so the other one is still counted. private getFiltersForCounters(appName: string): Observable { const activeEntityTypes = this.activeEntityTypes(appName); @@ -305,7 +303,6 @@ export class FilterCountersCloudService extends BaseCloudService { return this.getFiltersForCounters(appName).pipe( take(1), switchMap((filters) => this.fetchFilterCounters(appName, this.buildRequest(filters))), - /* A failed count leaves the counters as they are, rather than breaking the stream. */ catchError(() => of({})) ); } @@ -314,7 +311,6 @@ export class FilterCountersCloudService extends BaseCloudService { return merge( /* Reads landing in the same task are merged, so both filter components share one request. */ merge(of(undefined), this.recountTrigger(appName)).pipe(debounceTime(0, asapScheduler)), - /* One debounce over every entity type, so a batch of events also results in one request. */ this.eventRecountTrigger(appName).pipe(debounceTime(this.notificationDebounceTime)) ); } @@ -364,12 +360,12 @@ export class FilterCountersCloudService extends BaseCloudService { buildQuery: (filter: T) => Omit ): FilterCountersQuery[] { return (filters ?? []) - .filter((filter) => filter?.showCounter && this.isCounterBatched(filter)) + .filter((filter) => filter?.showCounter) .map((filter) => { try { - return { ...buildQuery(filter), requestId: filter.key as string }; + return { ...buildQuery(filter), requestId: filter.key }; } catch { - /* A malformed filter is left without a counter, so the others still hold one. */ + /* Left without a counter, so the other filters still hold theirs. */ return undefined; } }) @@ -385,9 +381,4 @@ export class FilterCountersCloudService extends BaseCloudService { return this.post(queryUrl, request).pipe(map((counters) => counters || {})); } - - // A filter without a key holds no `requestId` its counter could be keyed by. - private isCounterBatched(filter: FilterCounterCandidate): boolean { - return !!filter?.key; - } } diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters/service-task-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters/service-task-filters-cloud.component.ts index 5f9f2a7268..fc9e9eae28 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters/service-task-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/service-task-filters/service-task-filters-cloud.component.ts @@ -108,7 +108,7 @@ export class ServiceTaskFiltersCloudComponent extends BaseTaskFiltersCloudCompon this.filters.find( (filter, index) => paramFilter.index === index || - paramFilter.key === filter.key || + (!!paramFilter.key && paramFilter.key === filter.key) || paramFilter.id === filter.id || (paramFilter.name && paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase()) ); // fallback to preserve the previous behavior diff --git a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters/task-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters/task-filters-cloud.component.ts index f1c2389acb..a5b9fac8c6 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters/task-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/components/task-filters/task-filters-cloud.component.ts @@ -118,7 +118,6 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp } }); - /* Read along with the filters, not once they arrive, so both components share one request. */ this.loadFilterCounters(appName, filters$); } @@ -170,7 +169,7 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp this.filters.find( (filter, index) => paramFilter.index === index || - paramFilter.key === filter.key || + (!!paramFilter.key && paramFilter.key === filter.key) || paramFilter.id === filter.id || (paramFilter.name && paramFilter.name.toLocaleLowerCase() === this.translationService.instant(filter.name).toLocaleLowerCase()) ); // fallback to preserve the previous behavior @@ -241,7 +240,6 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp private loadFilterCounters(appName: string, filters$: Observable): void { this.countersSubscription?.unsubscribe(); - /* Counters are keyed by filter key, so they are applied once the filters are known. */ this.countersSubscription = combineLatest([ filters$.pipe(catchError(() => of([]))), this.filterCountersCloudService.getFilterCounters(appName, FilterCounterEntityType.TASK) @@ -251,22 +249,17 @@ export class TaskFiltersCloudComponent extends BaseTaskFiltersCloudComponent imp } private applyFilterCounters(counters: FilterCountersResult): void { - this.filters.forEach((filter) => { - /* A filter without a key holds no request id. */ - const filterKey = filter?.showCounter ? filter.key : undefined; - if (!filterKey) { - return; - } + this.filters + .filter((filter) => filter?.showCounter) + .forEach((filter) => { + const counter = counters[filter.key]; + if (counter === undefined) { + return; + } - const counter = counters[filterKey]; - /* A filter the request left out keeps the counter it holds, rather than showing a wrong one. */ - if (counter === undefined) { - return; - } - - this.checkIfFilterValuesHasBeenUpdated(filterKey, counter); - this.counters = { ...this.counters, [filterKey]: counter }; - }); + this.checkIfFilterValuesHasBeenUpdated(filter.key, counter); + this.counters = { ...this.counters, [filter.key]: counter }; + }); } /** diff --git a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts index 44ecfe8950..15799ab433 100644 --- a/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts +++ b/lib/process-services-cloud/src/lib/task/task-filters/models/filter-cloud.model.ts @@ -84,7 +84,7 @@ export class TaskFilterCloudModel { if (obj) { this.id = obj.id || Math.random().toString(36).substr(2, 9); this.name = obj.name || null; - this.key = obj.key || null; + this.key = obj.key; this.environmentId = obj.environmentId || null; this.icon = obj.icon || null; this.index = obj.index || null;