diff --git a/src/app/applications/components/table.component.html b/src/app/applications/components/table.component.html index 21d0fd4bf..f0db90e2d 100644 --- a/src/app/applications/components/table.component.html +++ b/src/app/applications/components/table.component.html @@ -1,3 +1,3 @@ - \ No newline at end of file diff --git a/src/app/applications/components/table.component.spec.ts b/src/app/applications/components/table.component.spec.ts index 738edf54a..b74e70fca 100644 --- a/src/app/applications/components/table.component.spec.ts +++ b/src/app/applications/components/table.component.spec.ts @@ -213,7 +213,7 @@ describe('TasksTableComponent', () => { }); it('should get data', () => { - expect(component.data).toEqual(mockApplicationsDataService.data); + expect(component.data()).toEqual(mockApplicationsDataService.data); }); it('should get total', () => { diff --git a/src/app/applications/components/table.component.ts b/src/app/applications/components/table.component.ts index 0be1d8777..10b36cb9b 100644 --- a/src/app/applications/components/table.component.ts +++ b/src/app/applications/components/table.component.ts @@ -46,6 +46,7 @@ export class ApplicationsTableComponent extends AbstractTaskByStatusTableCompone ]; ngOnInit(): void { + this.initTableDataService(); this.initStatuses(); } diff --git a/src/app/applications/index.component.html b/src/app/applications/index.component.html index 63c0a6ae0..33d861f3b 100644 --- a/src/app/applications/index.component.html +++ b/src/app/applications/index.component.html @@ -6,7 +6,7 @@ { describe('initialisation', () => { it('should load data from the cache', () => { - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { name: 'application1', @@ -95,7 +95,7 @@ describe('ApplicationDataService', () => { }); it('should set the total cached data', () => { - expect(service.total).toEqual(cachedApplications.total); + expect(service.total()).toEqual(cachedApplications.total); }); }); @@ -107,12 +107,12 @@ describe('ApplicationDataService', () => { it('should update the total', () => { service.refresh$.next(); - expect(service.total).toEqual(applications.total); + expect(service.total()).toEqual(applications.total); }); it('should update the data', () => { service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { name: 'application1', @@ -162,7 +162,7 @@ describe('ApplicationDataService', () => { const emptyApplications = { applications: undefined, total: 0 } as unknown as ListApplicationsResponse; mockApplicationsGrpcService.list$.mockReturnValueOnce(of(emptyApplications)); service.refresh$.next(); - expect(service.data).toEqual([]); + expect(service.data()).toEqual([]); }); it('should catch errors', () => { @@ -207,7 +207,7 @@ describe('ApplicationDataService', () => { }); it('should load correctly', () => { - expect(service.loading).toBeFalsy(); + expect(service.loading()).toBeFalsy(); }); describe('Applying filters', () => { @@ -281,7 +281,7 @@ describe('ApplicationDataService', () => { it('should apply the filters correctly when transforming the data', () => { service.filters = filters; service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { name: 'application1', diff --git a/src/app/dashboard/components/lines/applications-line.component.html b/src/app/dashboard/components/lines/applications-line.component.html index b5d0f79db..a4b26d040 100644 --- a/src/app/dashboard/components/lines/applications-line.component.html +++ b/src/app/dashboard/components/lines/applications-line.component.html @@ -1,7 +1,7 @@ diff --git a/src/app/partitions/components/table.component.ts b/src/app/partitions/components/table.component.ts index 005621e59..a39e62491 100644 --- a/src/app/partitions/components/table.component.ts +++ b/src/app/partitions/components/table.component.ts @@ -28,6 +28,7 @@ export class PartitionsTableComponent extends AbstractTaskByStatusTableComponent table: TableTasksByStatus = 'partitions'; ngOnInit(): void { + this.initTableDataService(); this.initStatuses(); } diff --git a/src/app/partitions/index.component.html b/src/app/partitions/index.component.html index c2ace5d0f..dd69db783 100644 --- a/src/app/partitions/index.component.html +++ b/src/app/partitions/index.component.html @@ -6,7 +6,7 @@ { describe('initialisation', () => { it('should load data from the cache', () => { - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'partition1', @@ -99,7 +99,7 @@ describe('PartitionsDataService', () => { }); it('should set the total cached data', () => { - expect(service.total).toEqual(cachedPartitions.total); + expect(service.total()).toEqual(cachedPartitions.total); }); }); @@ -111,12 +111,12 @@ describe('PartitionsDataService', () => { it('should update the total', () => { service.refresh$.next(); - expect(service.total).toEqual(partitions.total); + expect(service.total()).toEqual(partitions.total); }); it('should update the data', () => { service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'partition1', @@ -157,7 +157,7 @@ describe('PartitionsDataService', () => { const partitions = { partitions: undefined, total: 0} as unknown as ListPartitionsResponse; mockPartitionsGrpcService.list$.mockReturnValueOnce(of(partitions)); service.refresh$.next(); - expect(service.data).toEqual([]); + expect(service.data()).toEqual([]); }); it('should catch errors', () => { @@ -202,7 +202,7 @@ describe('PartitionsDataService', () => { }); it('should load correctly', () => { - expect(service.loading).toBeFalsy(); + expect(service.loading()).toBeFalsy(); }); describe('Applying filters', () => { @@ -234,7 +234,7 @@ describe('PartitionsDataService', () => { it('should apply the filters correctly when transforming the data', () => { service.filters = filters; service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'partition1', diff --git a/src/app/results/components/table.component.html b/src/app/results/components/table.component.html index 05f197934..0867fc5f8 100644 --- a/src/app/results/components/table.component.html +++ b/src/app/results/components/table.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/results/components/table.component.spec.ts b/src/app/results/components/table.component.spec.ts index 17495389f..afefa4732 100644 --- a/src/app/results/components/table.component.spec.ts +++ b/src/app/results/components/table.component.spec.ts @@ -112,7 +112,7 @@ describe('TasksTableComponent', () => { }); it('should get data', () => { - expect(component.data).toEqual(mockResultsDataService.data); + expect(component.data()).toEqual(mockResultsDataService.data); }); it('should get total', () => { diff --git a/src/app/results/components/table.component.ts b/src/app/results/components/table.component.ts index cc9fb1520..46fec411e 100644 --- a/src/app/results/components/table.component.ts +++ b/src/app/results/components/table.component.ts @@ -1,5 +1,5 @@ import { ResultRawEnumField } from '@aneoconsultingfr/armonik.api.angular'; -import { Component, inject } from '@angular/core'; +import { Component, OnInit, inject } from '@angular/core'; import { AbstractTableComponent } from '@app/types/components/table'; import { ArmonikData } from '@app/types/data'; import { TableComponent } from '@components/table/table.component'; @@ -20,10 +20,14 @@ import { ResultRaw } from '../types'; TableComponent, ] }) -export class ResultsTableComponent extends AbstractTableComponent { +export class ResultsTableComponent extends AbstractTableComponent implements OnInit { readonly tableDataService = inject(ResultsDataService); readonly statusesService = inject(ResultsStatusesService); + ngOnInit(): void { + this.initTableDataService(); + } + isDataRawEqual(value: ResultRaw, entry: ResultRaw): boolean { return value.resultId === entry.resultId; } diff --git a/src/app/results/index.component.html b/src/app/results/index.component.html index 658c38b5d..c928b5511 100644 --- a/src/app/results/index.component.html +++ b/src/app/results/index.component.html @@ -6,7 +6,7 @@ { describe('initialisation', () => { it('should load data from the cache', () => { - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { resultId: 'result1' @@ -77,7 +77,7 @@ describe('ResultsDataService', () => { }); it('should set the total cached data', () => { - expect(service.total).toEqual(cachedResults.total); + expect(service.total()).toEqual(cachedResults.total); }); }); @@ -89,12 +89,12 @@ describe('ResultsDataService', () => { it('should update the total', () => { service.refresh$.next(); - expect(service.total).toEqual(results.total); + expect(service.total()).toEqual(results.total); }); it('should update the data', () => { service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { resultId: 'result1' @@ -117,7 +117,7 @@ describe('ResultsDataService', () => { const emptyResults = { results: undefined, total: 0 } as unknown as ListResultsResponse; mockResultsGrpcService.list$.mockReturnValueOnce(of(emptyResults)); service.refresh$.next(); - expect(service.data).toEqual([]); + expect(service.data()).toEqual([]); }); it('should catch errors', () => { @@ -162,6 +162,6 @@ describe('ResultsDataService', () => { }); it('should load correctly', () => { - expect(service.loading).toBeFalsy(); + expect(service.loading()).toBeFalsy(); }); }); \ No newline at end of file diff --git a/src/app/sessions/components/table.component.html b/src/app/sessions/components/table.component.html index 6784db80d..b2f394052 100644 --- a/src/app/sessions/components/table.component.html +++ b/src/app/sessions/components/table.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/sessions/components/table.component.spec.ts b/src/app/sessions/components/table.component.spec.ts index b5fee52c5..aea6394ed 100644 --- a/src/app/sessions/components/table.component.spec.ts +++ b/src/app/sessions/components/table.component.spec.ts @@ -338,7 +338,7 @@ describe('SessionsTableComponent', () => { }); it('should get data', () => { - expect(component.data).toEqual(mockSessionsDataService.data); + expect(component.data()).toEqual(mockSessionsDataService.data); }); it('should get total', () => { diff --git a/src/app/sessions/components/table.component.ts b/src/app/sessions/components/table.component.ts index 41b026855..b30913cd8 100644 --- a/src/app/sessions/components/table.component.ts +++ b/src/app/sessions/components/table.component.ts @@ -122,6 +122,7 @@ export class SessionsTableComponent extends AbstractTaskByStatusTableComponent { const map2 = new Map(); map1.set('sessionId', {'0-root-1-0': 'session1'}); map2.set('sessionId', {'0-root-1-0': 'session2'}); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { sessionId: 'session1' @@ -119,7 +119,7 @@ describe('SessionsDataService', () => { }); it('should set the total cached data', () => { - expect(service.total).toEqual(cachedSessions.total); + expect(service.total()).toEqual(cachedSessions.total); }); }); @@ -131,7 +131,7 @@ describe('SessionsDataService', () => { it('should update the total', () => { service.refresh$.next(); - expect(service.total).toEqual(sessions.total); + expect(service.total()).toEqual(sessions.total); }); it('should update the data', () => { @@ -190,7 +190,7 @@ describe('SessionsDataService', () => { map2.set('sessionId', {'0-root-1-0': 'session2'}); map3.set('sessionId', {'0-root-1-0': 'session3'}); service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { sessionId: 'session1' @@ -264,7 +264,7 @@ describe('SessionsDataService', () => { const sessions = { sessions: undefined, total: 0} as unknown as ListSessionsResponse; mockSessionsGrpcService.list$.mockReturnValueOnce(of(sessions)); service.refresh$.next(); - expect(service.data).toEqual([]); + expect(service.data()).toEqual([]); }); it('should catch errors', () => { @@ -309,7 +309,7 @@ describe('SessionsDataService', () => { }); it('should load correctly', () => { - expect(service.loading).toBeFalsy(); + expect(service.loading()).toBeFalsy(); }); describe('computing duration', () => { @@ -319,7 +319,7 @@ describe('SessionsDataService', () => { it('should compute the duration for each session', () => { service.refresh$.next(); - expect(service.data.map((session) => ({sessionId: session.raw.sessionId, duration: session.raw.duration}))).toEqual([ + expect(service.data().map((session) => ({sessionId: session.raw.sessionId, duration: session.raw.duration}))).toEqual([ { sessionId: 'session1', duration: { @@ -364,7 +364,7 @@ describe('SessionsDataService', () => { direction: 'asc', }; service.refresh$.next(); - expect(service.data.map(session => session.raw.sessionId)).toEqual(['session1', 'session2', 'session3']); + expect(service.data().map(session => session.raw.sessionId)).toEqual(['session1', 'session2', 'session3']); }); it('should sort in a descending order', () => { @@ -374,7 +374,46 @@ describe('SessionsDataService', () => { direction: 'desc', }; service.refresh$.next(); - expect(service.data.map(session => session.raw.sessionId)).toEqual(['session3', 'session2', 'session1']); + expect(service.data().map(session => session.raw.sessionId)).toEqual(['session3', 'session2', 'session1']); + }); + + it('should append the filters to existing ones if they do not contain a CREATED_AT field', () => { + const dateFilter: Filter = { + field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_CREATED_AT, + for: 'root', + operator: FilterDateOperator.FILTER_DATE_OPERATOR_AFTER, + value: 1 + }; + const stringFilter: Filter = { + field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_CLIENT_SUBMISSION, + for: 'root', + operator: FilterStringOperator.FILTER_STRING_OPERATOR_CONTAINS, + value: 1 + }; + const arrayFilter: Filter = + { + field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_OPTIONS, + for: 'root', + operator: FilterArrayOperator.FILTER_ARRAY_OPERATOR_NOT_CONTAINS, + value: 1 + }; + jest.useFakeTimers().setSystemTime(new Date('1970-01-01')); + const date = new Date(); + date.setDate(date.getDate() - 3); + const appliedFilter: Filter = { + field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_CREATED_AT, + for: 'root', + operator: FilterDateOperator.FILTER_DATE_OPERATOR_AFTER_OR_EQUAL, + value: Math.floor(date.getTime()/1000) + }; + service.options = { pageIndex: 0, pageSize: 0, sort: { active: 'duration', direction: 'asc'}}; + service.isDurationDisplayed = true; + service.filters = [[arrayFilter, stringFilter], [dateFilter]]; + service.refresh$.next(); + expect(mockSessionsGrpcService.list$).toHaveBeenCalledWith( + { pageIndex: 0, pageSize: 0, sort: { active: 'createdAt', direction: 'asc'}}, + [[arrayFilter, stringFilter, appliedFilter], [dateFilter]] + ); }); }); diff --git a/src/app/sessions/services/sessions-data.service.ts b/src/app/sessions/services/sessions-data.service.ts index 783786508..df89c0cdf 100644 --- a/src/app/sessions/services/sessions-data.service.ts +++ b/src/app/sessions/services/sessions-data.service.ts @@ -31,7 +31,7 @@ export class SessionsDataService extends AbstractTableDataService { - const filters = super.preparefilters(); - if(this.isDurationDisplayed && this.options.sort.active === 'duration' && this.filtersHaveNoCreatedAt()) { + const filtersOr = super.preparefilters(); + if(this.isDurationDisplayed && this.options.sort.active === 'duration') { const date = new Date(); date.setDate(date.getDate() - 3); - filters.push([{ + const filter: Filter = { field: SessionRawEnumField.SESSION_RAW_ENUM_FIELD_CREATED_AT, for: 'root', operator: FilterDateOperator.FILTER_DATE_OPERATOR_AFTER_OR_EQUAL, value: Math.floor(date.getTime()/1000) - }]); + }; + if (filtersOr.length !== 0) { + filtersOr.forEach(filtersAnd => { + if (filtersAnd.find(filter => filter.field === SessionRawEnumField.SESSION_RAW_ENUM_FIELD_CREATED_AT) === undefined) { + filtersAnd.push(filter); + } + }); + } else { + filtersOr.push([filter]); + } } - return filters; + return filtersOr; } createNewLine(entry: SessionRaw): SessionData { @@ -220,11 +229,10 @@ export class SessionsDataService extends AbstractTableDataService diff --git a/src/app/tasks/components/table.component.spec.ts b/src/app/tasks/components/table.component.spec.ts index 6c96cb185..0ff5103d5 100644 --- a/src/app/tasks/components/table.component.spec.ts +++ b/src/app/tasks/components/table.component.spec.ts @@ -272,7 +272,7 @@ describe('TasksTableComponent', () => { }); it('should get data', () => { - expect(component.data).toEqual(mockTasksDataService.data); + expect(component.data()).toEqual(mockTasksDataService.data); }); it('should get total', () => { diff --git a/src/app/tasks/components/table.component.ts b/src/app/tasks/components/table.component.ts index 54632d0fb..0af17419a 100644 --- a/src/app/tasks/components/table.component.ts +++ b/src/app/tasks/components/table.component.ts @@ -1,6 +1,6 @@ import { TaskOptionEnumField, TaskSummaryEnumField} from '@aneoconsultingfr/armonik.api.angular'; import { Clipboard, } from '@angular/cdk/clipboard'; -import { Component, EventEmitter, Input, Output, inject } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, inject } from '@angular/core'; import { Router} from '@angular/router'; import { AbstractTableComponent } from '@app/types/components/table'; import { Scope } from '@app/types/config'; @@ -23,7 +23,7 @@ import { TaskOptions, TaskSummary } from '../types'; TableComponent ] }) -export class TasksTableComponent extends AbstractTableComponent { +export class TasksTableComponent extends AbstractTableComponent implements OnInit { scope: Scope = 'tasks'; @Input({ required: false }) set serviceIcon(entry: string | null) { @@ -112,6 +112,10 @@ export class TasksTableComponent extends AbstractTableComponent { describe('initialisation', () => { it('should load data from the cache', () => { - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'task1' @@ -84,7 +84,7 @@ describe('TasksDataService', () => { }); it('should set the total cached data', () => { - expect(service.total).toEqual(cachedTasks.total); + expect(service.total()).toEqual(cachedTasks.total); }); }); @@ -96,12 +96,12 @@ describe('TasksDataService', () => { it('should update the total', () => { service.refresh$.next(); - expect(service.total).toEqual(tasks.total); + expect(service.total()).toEqual(tasks.total); }); it('should update the data', () => { service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'task1' @@ -133,7 +133,7 @@ describe('TasksDataService', () => { const emptyTasks = { tasks: undefined, total: 0 } as unknown as ListTasksResponse; mockTasksGrpcService.list$.mockReturnValueOnce(of(emptyTasks)); service.refresh$.next(); - expect(service.data).toEqual([]); + expect(service.data()).toEqual([]); }); it('should catch errors', () => { @@ -178,7 +178,7 @@ describe('TasksDataService', () => { }); it('should load correctly', () => { - expect(service.loading).toBeFalsy(); + expect(service.loading()).toBeFalsy(); }); describe('Applying filters', () => { @@ -222,7 +222,7 @@ describe('TasksDataService', () => { it('should apply the filters correctly when transforming the data', () => { service.filters = filters; service.refresh$.next(); - expect(service.data).toEqual([ + expect(service.data()).toEqual([ { raw: { id: 'task1' diff --git a/src/app/types/components/dashboard-line-table.ts b/src/app/types/components/dashboard-line-table.ts index 211c3c15c..4ea85a281 100644 --- a/src/app/types/components/dashboard-line-table.ts +++ b/src/app/types/components/dashboard-line-table.ts @@ -144,15 +144,6 @@ export abstract class DashboardLineTableComponent = this.dialog.open(EditNameLineDialogComponent, { data: { diff --git a/src/app/types/components/table.ts b/src/app/types/components/table.ts index 9503cc80e..12959502b 100644 --- a/src/app/types/components/table.ts +++ b/src/app/types/components/table.ts @@ -1,5 +1,5 @@ import { SelectionModel } from '@angular/cdk/collections'; -import { Component, EventEmitter, Input, Output, inject } from '@angular/core'; +import { Component, EventEmitter, Input, Output, Signal, inject } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ManageGroupsDialogData, ManageGroupsDialogResult, TasksStatusesGroup } from '@app/dashboard/types'; import { TaskOptions } from '@app/tasks/types'; @@ -8,7 +8,8 @@ import { NotificationService } from '@services/notification.service'; import { TableTasksByStatus, TasksByStatusService } from '@services/tasks-by-status.service'; import { TableColumn } from '../column.type'; import { ArmonikData, ColumnKey, DataRaw } from '../data'; -import { FiltersEnums, FiltersOptionsEnums } from '../filters'; +import { FiltersEnums, FiltersOptionsEnums, FiltersOr } from '../filters'; +import { ListOptions } from '../options'; import { AbstractTableDataService } from '../services/table-data.service'; export interface SelectableTable { @@ -24,43 +25,34 @@ export interface SelectableTable { }) export abstract class AbstractTableComponent { @Input({ required: true }) set displayedColumns(columns: TableColumn[]) { - this._displayedColumns = columns; - this._columnKeys = columns.map(column => column.key); + this.columns = columns; + this.columnKeys = columns.map(column => column.key); } @Input() lockColumns = false; @Output() columnUpdate = new EventEmitter[]>(); @Output() optionsUpdate = new EventEmitter(); - private _displayedColumns: TableColumn[] = []; - private _columnKeys: ColumnKey[]; + columns: TableColumn[] = []; + columnKeys: ColumnKey[]; - get data() { - return this.tableDataService.data; - } - - get total() { - return this.tableDataService.total; - } - - get options() { - return this.tableDataService.options; - } + data: Signal[]>; - get filters() { - return this.tableDataService.filters; - } + total: Signal; - get columnKeys() { - return this._columnKeys; - } + options: ListOptions; - get displayedColumns() { - return this._displayedColumns; - } + filters: FiltersOr; readonly notificationService = inject(NotificationService); abstract readonly tableDataService: AbstractTableDataService; + protected initTableDataService() { + this.data = this.tableDataService.data; + this.total = this.tableDataService.total; + this.options = this.tableDataService.options; + this.filters = this.tableDataService.filters; + } + onDrop(columnsKeys: ColumnKey[]) { this.columnUpdate.emit(columnsKeys); } diff --git a/src/app/types/services/table-data.service.ts b/src/app/types/services/table-data.service.ts index 969c46561..9b3cca2a2 100644 --- a/src/app/types/services/table-data.service.ts +++ b/src/app/types/services/table-data.service.ts @@ -1,4 +1,4 @@ -import { Injectable, WritableSignal, inject, signal } from '@angular/core'; +import { Injectable, inject, signal } from '@angular/core'; import { TaskOptions } from '@app/tasks/types'; import { ArmonikData, DataRaw, GrpcResponse } from '@app/types/data'; import { FiltersEnums, FiltersOptionsEnums, FiltersOr } from '@app/types/filters'; @@ -23,44 +23,15 @@ export abstract class AbstractTableDataService(); - private readonly _loading = signal(false); - private readonly _data: WritableSignal[]> = signal([]); - private readonly _total = signal(0); + readonly loading = signal(false); + readonly total = signal(0); + readonly data = signal[]>([]); filters: FiltersOr = []; options: ListOptions; abstract scope: Scope; - protected set data(entries: T[]) { - this._data.set(entries.map(entry => this.createNewLine(entry))); - } - - protected set loading(value: boolean) { - this._loading.set(value); - } - - /** - * Handle the loading state of the table. - */ - get loading(): boolean { - return this._loading(); - } - - /** - * The current loaded data. - */ - get data(): ArmonikData[] { - return this._data(); - } - - /** - * Total number of this data stored in the database. - */ - get total(): number { - return this._total(); - } - constructor() { this.loadFromCache(); this.subscribeToGrpcList(); @@ -73,9 +44,9 @@ export abstract class AbstractTableDataService { - this._loading.set(true); + this.loading.set(true); const options = this.prepareOptions(); const filters = this.preparefilters(); @@ -102,7 +73,7 @@ export abstract class AbstractTableDataService { - this._total.set(entries?.total ?? 0); + this.total.set(entries?.total ?? 0); if (entries) { this.cacheService.save(this.scope, entries); return this.computeGrpcData(entries) ?? []; @@ -111,7 +82,6 @@ export abstract class AbstractTableDataService { this.handleData(entries); - this._loading.set(false); }); } @@ -134,7 +104,8 @@ export abstract class AbstractTableDataService this.createNewLine(entry))); + this.loading.set(false); } /**