@masterteam/client-components 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/masterteam-client-components-client-list.mjs +542 -95
- package/fesm2022/masterteam-client-components-client-list.mjs.map +1 -1
- package/fesm2022/masterteam-client-components-escalation-runtime.mjs +2 -2
- package/fesm2022/masterteam-client-components-escalation-runtime.mjs.map +1 -1
- package/package.json +4 -3
- package/types/masterteam-client-components-client-list.d.ts +166 -30
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, signal, computed, input, output, effect, untracked
|
|
2
|
+
import { inject, Injectable, signal, computed, input, output, Component, effect, untracked } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
4
|
import { CommonModule } from '@angular/common';
|
|
5
|
-
import { Table } from '@masterteam/components/table';
|
|
6
5
|
import { Button } from '@masterteam/components/button';
|
|
7
|
-
import * as i2 from 'primeng/skeleton';
|
|
8
|
-
import { SkeletonModule } from 'primeng/skeleton';
|
|
9
6
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
10
7
|
import { Card } from '@masterteam/components/card';
|
|
8
|
+
import { Table } from '@masterteam/components/table';
|
|
9
|
+
import * as i2 from 'primeng/skeleton';
|
|
10
|
+
import { SkeletonModule } from 'primeng/skeleton';
|
|
11
|
+
import { EntitiesPreview } from '@masterteam/components/entities';
|
|
12
|
+
import { DashboardViewer } from '@masterteam/dashboard-builder';
|
|
11
13
|
|
|
12
14
|
class ClientListApiService {
|
|
13
15
|
http = inject(HttpClient);
|
|
14
|
-
|
|
16
|
+
tablesBaseUrl = 'data/tables';
|
|
17
|
+
cardsBaseUrl = 'data/modules/cards';
|
|
18
|
+
informativeBaseUrl = 'Modules';
|
|
15
19
|
getRows(levelId, levelDataId, moduleId, query) {
|
|
16
|
-
const endpoint = `${this.
|
|
20
|
+
const endpoint = `${this.tablesBaseUrl}/level/${levelId}/level-data/${levelDataId}/module/${moduleId}/rows`;
|
|
17
21
|
let params = new HttpParams()
|
|
18
22
|
.set('mode', query.mode)
|
|
19
23
|
.set('skip', query.skip)
|
|
@@ -25,6 +29,18 @@ class ClientListApiService {
|
|
|
25
29
|
params,
|
|
26
30
|
});
|
|
27
31
|
}
|
|
32
|
+
getCards(levelDataId, moduleId) {
|
|
33
|
+
const params = new HttpParams()
|
|
34
|
+
.set('moduleId', moduleId)
|
|
35
|
+
.set('levelDataId', levelDataId)
|
|
36
|
+
.append('displayAreas', 'card');
|
|
37
|
+
return this.http.get(this.cardsBaseUrl, {
|
|
38
|
+
params,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
getInformativeDashboard(moduleId) {
|
|
42
|
+
return this.http.get(`${this.informativeBaseUrl}/${moduleId}/dashboard`);
|
|
43
|
+
}
|
|
28
44
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
29
45
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListApiService, providedIn: 'root' });
|
|
30
46
|
}
|
|
@@ -34,36 +50,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
34
50
|
}] });
|
|
35
51
|
|
|
36
52
|
class ClientListStateService {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
? a.config.levelDataId - b.config.levelDataId
|
|
40
|
-
: a.config.moduleId - b.config.moduleId), ...(ngDevMode ? [{ debugName: "
|
|
53
|
+
itemsByKey = signal({}, ...(ngDevMode ? [{ debugName: "itemsByKey" }] : []));
|
|
54
|
+
items = computed(() => Object.values(this.itemsByKey()).sort((a, b) => a.config.moduleId === b.config.moduleId
|
|
55
|
+
? (a.config.levelDataId ?? 0) - (b.config.levelDataId ?? 0)
|
|
56
|
+
: a.config.moduleId - b.config.moduleId), ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
41
57
|
setConfigs(configs) {
|
|
58
|
+
const currentItems = this.itemsByKey();
|
|
42
59
|
const next = {};
|
|
43
|
-
configs.forEach((
|
|
44
|
-
|
|
45
|
-
next[table.key] = {
|
|
46
|
-
...table,
|
|
47
|
-
loading: current?.loading ?? false,
|
|
48
|
-
error: current?.error ?? null,
|
|
49
|
-
title: current?.title ?? table.title,
|
|
50
|
-
moduleKey: current?.moduleKey ?? table.moduleKey,
|
|
51
|
-
columns: current?.columns ?? table.columns,
|
|
52
|
-
rows: current?.rows ?? table.rows,
|
|
53
|
-
skip: current?.skip ?? table.skip,
|
|
54
|
-
take: current?.take ?? table.take,
|
|
55
|
-
totalCount: current?.totalCount ?? table.totalCount,
|
|
56
|
-
expanded: current?.expanded ?? table.expanded,
|
|
57
|
-
};
|
|
60
|
+
configs.forEach((item) => {
|
|
61
|
+
next[item.key] = this.mergeItemState(item, currentItems[item.key]);
|
|
58
62
|
});
|
|
59
|
-
this.
|
|
63
|
+
this.itemsByKey.set(next);
|
|
60
64
|
}
|
|
61
65
|
setLoading(key, loading) {
|
|
62
|
-
const target = this.
|
|
66
|
+
const target = this.itemsByKey()[key];
|
|
63
67
|
if (!target)
|
|
64
68
|
return;
|
|
65
|
-
this.
|
|
66
|
-
...this.
|
|
69
|
+
this.itemsByKey.set({
|
|
70
|
+
...this.itemsByKey(),
|
|
67
71
|
[key]: {
|
|
68
72
|
...target,
|
|
69
73
|
loading,
|
|
@@ -71,11 +75,11 @@ class ClientListStateService {
|
|
|
71
75
|
});
|
|
72
76
|
}
|
|
73
77
|
setError(key, message) {
|
|
74
|
-
const target = this.
|
|
78
|
+
const target = this.itemsByKey()[key];
|
|
75
79
|
if (!target)
|
|
76
80
|
return;
|
|
77
|
-
this.
|
|
78
|
-
...this.
|
|
81
|
+
this.itemsByKey.set({
|
|
82
|
+
...this.itemsByKey(),
|
|
79
83
|
[key]: {
|
|
80
84
|
...target,
|
|
81
85
|
error: message,
|
|
@@ -83,23 +87,28 @@ class ClientListStateService {
|
|
|
83
87
|
});
|
|
84
88
|
}
|
|
85
89
|
setRowsResult(key, response, config, skip, take) {
|
|
86
|
-
const target = this.
|
|
87
|
-
if (!target
|
|
90
|
+
const target = this.itemsByKey()[key];
|
|
91
|
+
if (!target ||
|
|
92
|
+
target.type === 'informative' ||
|
|
93
|
+
target.areaType !== 'table') {
|
|
88
94
|
return;
|
|
89
|
-
|
|
90
|
-
const
|
|
95
|
+
}
|
|
96
|
+
const visibleColumns = this.getVisibleColumns(response.columns);
|
|
97
|
+
const columns = this.toColumnDefs(visibleColumns);
|
|
98
|
+
const rows = this.toDisplayRows(response.rows ?? [], visibleColumns);
|
|
91
99
|
const title = (config.title ?? '').trim() || response.moduleKey;
|
|
92
100
|
const totalCount = config.isPaginated === false
|
|
93
101
|
? rows.length
|
|
94
102
|
: (response.pagination?.totalCount ?? rows.length);
|
|
95
|
-
this.
|
|
96
|
-
...this.
|
|
103
|
+
this.itemsByKey.set({
|
|
104
|
+
...this.itemsByKey(),
|
|
97
105
|
[key]: {
|
|
98
106
|
...target,
|
|
99
107
|
title,
|
|
100
108
|
moduleKey: response.moduleKey ?? '',
|
|
101
109
|
columns,
|
|
102
110
|
rows,
|
|
111
|
+
cards: [],
|
|
103
112
|
skip,
|
|
104
113
|
take,
|
|
105
114
|
totalCount,
|
|
@@ -107,27 +116,206 @@ class ClientListStateService {
|
|
|
107
116
|
},
|
|
108
117
|
});
|
|
109
118
|
}
|
|
119
|
+
setCardsResult(key, response, config) {
|
|
120
|
+
const target = this.itemsByKey()[key];
|
|
121
|
+
if (!target ||
|
|
122
|
+
target.type === 'informative' ||
|
|
123
|
+
target.areaType !== 'cards') {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const cards = this.toCards(response);
|
|
127
|
+
const firstModule = response.details?.[0]?.module;
|
|
128
|
+
const moduleKey = firstModule?.key ?? target.moduleKey ?? '';
|
|
129
|
+
const title = (config.title ?? '').trim() ||
|
|
130
|
+
firstModule?.name ||
|
|
131
|
+
moduleKey ||
|
|
132
|
+
target.title;
|
|
133
|
+
this.itemsByKey.set({
|
|
134
|
+
...this.itemsByKey(),
|
|
135
|
+
[key]: {
|
|
136
|
+
...target,
|
|
137
|
+
title,
|
|
138
|
+
moduleKey,
|
|
139
|
+
columns: [],
|
|
140
|
+
rows: [],
|
|
141
|
+
cards,
|
|
142
|
+
skip: 0,
|
|
143
|
+
take: 0,
|
|
144
|
+
totalCount: cards.length,
|
|
145
|
+
error: null,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
setInformativeResult(key, response, config) {
|
|
150
|
+
const target = this.itemsByKey()[key];
|
|
151
|
+
if (!target || target.type !== 'informative')
|
|
152
|
+
return;
|
|
153
|
+
const moduleKey = target.moduleKey || `Module ${config.moduleId}`;
|
|
154
|
+
const title = (config.title ?? '').trim() || target.title || 'Informative Dashboard';
|
|
155
|
+
const dashboardData = response
|
|
156
|
+
? this.toDashboardData(response, title)
|
|
157
|
+
: null;
|
|
158
|
+
const chartsCount = dashboardData?.charts?.length ?? 0;
|
|
159
|
+
this.itemsByKey.set({
|
|
160
|
+
...this.itemsByKey(),
|
|
161
|
+
[key]: {
|
|
162
|
+
...target,
|
|
163
|
+
title,
|
|
164
|
+
moduleKey,
|
|
165
|
+
columns: [],
|
|
166
|
+
rows: [],
|
|
167
|
+
cards: [],
|
|
168
|
+
skip: 0,
|
|
169
|
+
take: 0,
|
|
170
|
+
totalCount: chartsCount,
|
|
171
|
+
dashboardData,
|
|
172
|
+
error: null,
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
110
176
|
toggleExpanded(key) {
|
|
111
|
-
const target = this.
|
|
177
|
+
const target = this.itemsByKey()[key];
|
|
112
178
|
if (!target)
|
|
113
179
|
return;
|
|
114
|
-
this.
|
|
115
|
-
...this.
|
|
180
|
+
this.itemsByKey.set({
|
|
181
|
+
...this.itemsByKey(),
|
|
116
182
|
[key]: {
|
|
117
183
|
...target,
|
|
118
184
|
expanded: !target.expanded,
|
|
119
185
|
},
|
|
120
186
|
});
|
|
121
187
|
}
|
|
122
|
-
|
|
188
|
+
mergeItemState(item, existing) {
|
|
189
|
+
if (!existing ||
|
|
190
|
+
existing.type !== item.type ||
|
|
191
|
+
existing.areaType !== item.areaType) {
|
|
192
|
+
return item;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
...item,
|
|
196
|
+
loading: existing.loading,
|
|
197
|
+
error: existing.error,
|
|
198
|
+
title: item.title || existing.title,
|
|
199
|
+
moduleKey: existing.moduleKey || item.moduleKey,
|
|
200
|
+
totalCount: existing.totalCount,
|
|
201
|
+
columns: existing.columns,
|
|
202
|
+
rows: existing.rows,
|
|
203
|
+
cards: existing.cards,
|
|
204
|
+
skip: existing.skip,
|
|
205
|
+
take: existing.take,
|
|
206
|
+
expanded: existing.expanded,
|
|
207
|
+
dashboardData: existing.dashboardData,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
getVisibleColumns(columns) {
|
|
123
211
|
return (columns ?? [])
|
|
124
212
|
.filter((column) => column.isVisible)
|
|
125
|
-
.sort((a, b) => a.order - b.order)
|
|
126
|
-
|
|
213
|
+
.sort((a, b) => a.order - b.order);
|
|
214
|
+
}
|
|
215
|
+
toColumnDefs(columns) {
|
|
216
|
+
return columns.map((column) => ({
|
|
217
|
+
...column,
|
|
127
218
|
key: column.columnKey,
|
|
128
|
-
label: this.toLabel(column.columnKey),
|
|
219
|
+
label: column.name || this.toLabel(column.columnKey),
|
|
220
|
+
runtimeType: column.type,
|
|
221
|
+
type: 'entity',
|
|
129
222
|
}));
|
|
130
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Enriches each flat API row so that every cell value becomes a
|
|
226
|
+
* RuntimeTableCell carrying both the original value and the full
|
|
227
|
+
* column metadata. The `Id` key is preserved as-is.
|
|
228
|
+
*/
|
|
229
|
+
toDisplayRows(apiRows, columns) {
|
|
230
|
+
return apiRows.map((row) => {
|
|
231
|
+
const displayRow = { Id: row['Id'] };
|
|
232
|
+
for (const col of columns) {
|
|
233
|
+
displayRow[col.columnKey] = this.toCell(row[col.columnKey], col);
|
|
234
|
+
}
|
|
235
|
+
return displayRow;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
toCell(value, column) {
|
|
239
|
+
return { ...column, value };
|
|
240
|
+
}
|
|
241
|
+
toCards(data) {
|
|
242
|
+
const details = data?.details ?? [];
|
|
243
|
+
if (details.length === 0) {
|
|
244
|
+
return [];
|
|
245
|
+
}
|
|
246
|
+
const configurationByKey = this.buildDisplayConfigurationLookup(data?.displayConfigurations ?? []);
|
|
247
|
+
return details.flatMap((detailsBlock) => (detailsBlock.data ?? []).map((card) => ({
|
|
248
|
+
...card,
|
|
249
|
+
module: card.module ?? detailsBlock.module,
|
|
250
|
+
entities: this.mapEntities(card.properties ?? [], configurationByKey),
|
|
251
|
+
})));
|
|
252
|
+
}
|
|
253
|
+
toDashboardData(data, title) {
|
|
254
|
+
const charts = (data.chartLinks ?? []).map((link) => {
|
|
255
|
+
const configuration = link.configuration ?? {};
|
|
256
|
+
return {
|
|
257
|
+
...configuration,
|
|
258
|
+
id: link.id,
|
|
259
|
+
chartComponentId: link.chartComponentId,
|
|
260
|
+
};
|
|
261
|
+
});
|
|
262
|
+
return {
|
|
263
|
+
page: {
|
|
264
|
+
id: data.moduleId,
|
|
265
|
+
name: { en: title, ar: title },
|
|
266
|
+
type: 'Dashboard',
|
|
267
|
+
dashboardConfig: {
|
|
268
|
+
ignoreQueryFilter: data.ignoreQueryFilter,
|
|
269
|
+
filters: data.filters,
|
|
270
|
+
versionNumber: data.versionNumber,
|
|
271
|
+
extraInfo: data.extraInfo,
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
charts,
|
|
275
|
+
dialogs: [],
|
|
276
|
+
filters: [],
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
buildDisplayConfigurationLookup(displayConfigurations) {
|
|
280
|
+
const configurationsByProperty = new Map();
|
|
281
|
+
for (const displayConfiguration of displayConfigurations) {
|
|
282
|
+
for (const propertyConfiguration of displayConfiguration.properties ??
|
|
283
|
+
[]) {
|
|
284
|
+
if (propertyConfiguration.areaKey !== 'card' ||
|
|
285
|
+
!propertyConfiguration.propertyKey) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
configurationsByProperty.set(propertyConfiguration.propertyKey.toLowerCase(), propertyConfiguration);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return configurationsByProperty;
|
|
292
|
+
}
|
|
293
|
+
mapEntities(properties, configurationByKey) {
|
|
294
|
+
return properties
|
|
295
|
+
.map((property, index) => {
|
|
296
|
+
const propertyConfiguration = this.getPropertyConfiguration(property, configurationByKey);
|
|
297
|
+
return {
|
|
298
|
+
...property,
|
|
299
|
+
rawValue: property.rawValue ?? undefined,
|
|
300
|
+
order: propertyConfiguration?.order ?? index + 1,
|
|
301
|
+
configuration: propertyConfiguration?.configuration ?? { size: 4 },
|
|
302
|
+
};
|
|
303
|
+
})
|
|
304
|
+
.sort((first, second) => (first.order ?? 0) - (second.order ?? 0));
|
|
305
|
+
}
|
|
306
|
+
getPropertyConfiguration(property, configurationByKey) {
|
|
307
|
+
const propertyKeys = [property.normalizedKey, property.key, property.name];
|
|
308
|
+
for (const propertyKey of propertyKeys) {
|
|
309
|
+
if (!propertyKey) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
const configuration = configurationByKey.get(propertyKey.toLowerCase());
|
|
313
|
+
if (configuration) {
|
|
314
|
+
return configuration;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
131
319
|
toLabel(key) {
|
|
132
320
|
return key
|
|
133
321
|
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
@@ -144,7 +332,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
144
332
|
type: Injectable
|
|
145
333
|
}] });
|
|
146
334
|
|
|
335
|
+
const DEFAULT_GRID_COLUMNS$2 = 12;
|
|
336
|
+
class ClientListTableView {
|
|
337
|
+
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
338
|
+
rowActions = input([], ...(ngDevMode ? [{ debugName: "rowActions" }] : []));
|
|
339
|
+
lazyLoad = output();
|
|
340
|
+
table = computed(() => {
|
|
341
|
+
return this.state();
|
|
342
|
+
}, ...(ngDevMode ? [{ debugName: "table" }] : []));
|
|
343
|
+
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS$2}, minmax(0, 1fr))`;
|
|
344
|
+
slotGridSpan(span) {
|
|
345
|
+
return `span ${span} / span ${span}`;
|
|
346
|
+
}
|
|
347
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListTableView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
348
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientListTableView, isStandalone: true, selector: "mt-client-list-table-view", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { lazyLoad: "lazyLoad" }, ngImport: i0, template: "<div class=\"grid gap-4\" [style.gridTemplateColumns]=\"gridTemplateColumns\">\r\n @if (table().config.contentStart) {\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.startSpan)\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"table().config.contentStart\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: table(),\r\n table: table(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.tableSpan)\">\r\n <mt-card>\r\n @if (table().loading && table().rows.length === 0) {\r\n <div class=\"flex flex-col gap-3 py-3\">\r\n <p-skeleton height=\"3rem\" />\r\n <p-skeleton height=\"3rem\" />\r\n <p-skeleton height=\"3rem\" />\r\n </div>\r\n } @else if (table().error) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n >\r\n {{ table().error }}\r\n </div>\r\n } @else {\r\n <mt-table\r\n [data]=\"table().rows\"\r\n [columns]=\"table().columns\"\r\n [rowActions]=\"rowActions()\"\r\n [loading]=\"table().loading\"\r\n [lazy]=\"table().config.isPaginated\"\r\n [lazyTotalRecords]=\"table().totalCount\"\r\n [pageSize]=\"table().config.isPaginated ? table().take : 10\"\r\n (lazyLoad)=\"lazyLoad.emit($event)\"\r\n />\r\n }\r\n </mt-card>\r\n </div>\r\n\r\n @if (table().config.contentEnd) {\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.endSpan)\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"table().config.contentEnd\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: table(),\r\n table: table(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Table, selector: "mt-table", inputs: ["filters", "data", "columns", "rowActions", "size", "showGridlines", "stripedRows", "selectableRows", "clickableRows", "generalSearch", "showFilters", "loading", "updating", "lazy", "lazyTotalRecords", "reorderableColumns", "reorderableRows", "dataKey", "exportable", "exportFilename", "tabs", "tabsOptionLabel", "tabsOptionValue", "activeTab", "actions", "paginatorPosition", "pageSize", "currentPage", "first", "filterTerm"], outputs: ["selectionChange", "cellChange", "lazyLoad", "columnReorder", "rowReorder", "rowClick", "filtersChange", "activeTabChange", "onTabChange", "pageSizeChange", "currentPageChange", "firstChange", "filterTermChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i2.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
349
|
+
}
|
|
350
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListTableView, decorators: [{
|
|
351
|
+
type: Component,
|
|
352
|
+
args: [{ selector: 'mt-client-list-table-view', standalone: true, imports: [CommonModule, Card, Table, SkeletonModule], template: "<div class=\"grid gap-4\" [style.gridTemplateColumns]=\"gridTemplateColumns\">\r\n @if (table().config.contentStart) {\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.startSpan)\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"table().config.contentStart\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: table(),\r\n table: table(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.tableSpan)\">\r\n <mt-card>\r\n @if (table().loading && table().rows.length === 0) {\r\n <div class=\"flex flex-col gap-3 py-3\">\r\n <p-skeleton height=\"3rem\" />\r\n <p-skeleton height=\"3rem\" />\r\n <p-skeleton height=\"3rem\" />\r\n </div>\r\n } @else if (table().error) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n >\r\n {{ table().error }}\r\n </div>\r\n } @else {\r\n <mt-table\r\n [data]=\"table().rows\"\r\n [columns]=\"table().columns\"\r\n [rowActions]=\"rowActions()\"\r\n [loading]=\"table().loading\"\r\n [lazy]=\"table().config.isPaginated\"\r\n [lazyTotalRecords]=\"table().totalCount\"\r\n [pageSize]=\"table().config.isPaginated ? table().take : 10\"\r\n (lazyLoad)=\"lazyLoad.emit($event)\"\r\n />\r\n }\r\n </mt-card>\r\n </div>\r\n\r\n @if (table().config.contentEnd) {\r\n <div [style.gridColumn]=\"slotGridSpan(table().config.layout.endSpan)\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"table().config.contentEnd\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: table(),\r\n table: table(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n" }]
|
|
353
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }] } });
|
|
354
|
+
|
|
355
|
+
class ClientListCardsView {
|
|
356
|
+
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
357
|
+
cardsState = computed(() => this.state(), ...(ngDevMode ? [{ debugName: "cardsState" }] : []));
|
|
358
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListCardsView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
359
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientListCardsView, isStandalone: true, selector: "mt-client-list-cards-view", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (cardsState().loading && cardsState().cards.length === 0) {\r\n <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"20rem\" borderRadius=\"1rem\" />\r\n }\r\n </div>\r\n} @else if (cardsState().error) {\r\n <div class=\"rounded-lg border border-red-200 bg-red-50 p-6 text-red-600\">\r\n {{ cardsState().error }}\r\n </div>\r\n} @else if (cardsState().cards.length === 0) {\r\n <div class=\"p-6 text-center text-gray-400\">No cards found.</div>\r\n} @else {\r\n <div class=\"grid grid-cols-1 gap-5 md:grid-cols-2 xl:grid-cols-3\">\r\n @for (card of cardsState().cards; track card.id) {\r\n <mt-card class=\"cursor-pointer p-3\">\r\n <ng-template #headless>\r\n <mt-entities-preview [entities]=\"card.entities\" />\r\n </ng-template>\r\n </mt-card>\r\n }\r\n </div>\r\n}\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: EntitiesPreview, selector: "mt-entities-preview", inputs: ["entities"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i2.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
360
|
+
}
|
|
361
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListCardsView, decorators: [{
|
|
362
|
+
type: Component,
|
|
363
|
+
args: [{ selector: 'mt-client-list-cards-view', standalone: true, imports: [CommonModule, Card, EntitiesPreview, SkeletonModule], template: "@if (cardsState().loading && cardsState().cards.length === 0) {\r\n <div class=\"grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3\">\r\n @for (i of [1, 2, 3, 4, 5, 6]; track i) {\r\n <p-skeleton height=\"20rem\" borderRadius=\"1rem\" />\r\n }\r\n </div>\r\n} @else if (cardsState().error) {\r\n <div class=\"rounded-lg border border-red-200 bg-red-50 p-6 text-red-600\">\r\n {{ cardsState().error }}\r\n </div>\r\n} @else if (cardsState().cards.length === 0) {\r\n <div class=\"p-6 text-center text-gray-400\">No cards found.</div>\r\n} @else {\r\n <div class=\"grid grid-cols-1 gap-5 md:grid-cols-2 xl:grid-cols-3\">\r\n @for (card of cardsState().cards; track card.id) {\r\n <mt-card class=\"cursor-pointer p-3\">\r\n <ng-template #headless>\r\n <mt-entities-preview [entities]=\"card.entities\" />\r\n </ng-template>\r\n </mt-card>\r\n }\r\n </div>\r\n}\r\n" }]
|
|
364
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }] } });
|
|
365
|
+
|
|
366
|
+
const DEFAULT_GRID_COLUMNS$1 = 12;
|
|
367
|
+
class ClientListInformativeView {
|
|
368
|
+
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
369
|
+
informativeState = computed(() => this.state(), ...(ngDevMode ? [{ debugName: "informativeState" }] : []));
|
|
370
|
+
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS$1}, minmax(0, 1fr))`;
|
|
371
|
+
slotGridSpan(span) {
|
|
372
|
+
return `span ${span} / span ${span}`;
|
|
373
|
+
}
|
|
374
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListInformativeView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
375
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientListInformativeView, isStandalone: true, selector: "mt-client-list-informative-view", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"grid gap-4\" [style.gridTemplateColumns]=\"gridTemplateColumns\">\r\n @if (informativeState().config.contentStart) {\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.startSpan)\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"informativeState().config.contentStart\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: informativeState(),\r\n table: informativeState(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.tableSpan)\r\n \"\r\n >\r\n <mt-card>\r\n @if (\r\n informativeState().loading &&\r\n !informativeState().dashboardData?.charts?.length\r\n ) {\r\n <div class=\"flex flex-col gap-3 py-3\">\r\n <p-skeleton height=\"6rem\" />\r\n <p-skeleton height=\"12rem\" />\r\n <p-skeleton height=\"12rem\" />\r\n </div>\r\n } @else if (informativeState().error) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n >\r\n {{ informativeState().error }}\r\n </div>\r\n } @else if (!informativeState().dashboardData?.charts?.length) {\r\n <div class=\"p-6 text-center text-gray-400\">\r\n No informative dashboard found.\r\n </div>\r\n } @else {\r\n <div class=\"min-h-[420px]\">\r\n <mt-dashboard-viewer\r\n [isPage]=\"false\"\r\n [showFilters]=\"false\"\r\n [dashboardData]=\"informativeState().dashboardData\"\r\n />\r\n </div>\r\n }\r\n </mt-card>\r\n </div>\r\n\r\n @if (informativeState().config.contentEnd) {\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.endSpan)\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"informativeState().config.contentEnd\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: informativeState(),\r\n table: informativeState(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: DashboardViewer, selector: "mt-dashboard-viewer", inputs: ["isPage", "pageTitle", "backButton", "pageId", "dashboardData", "chartsData", "dialogsData", "filtersData", "showFilters"], outputs: ["pageLoaded", "onBack", "chartClick"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i2.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }] });
|
|
376
|
+
}
|
|
377
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListInformativeView, decorators: [{
|
|
378
|
+
type: Component,
|
|
379
|
+
args: [{ selector: 'mt-client-list-informative-view', standalone: true, imports: [CommonModule, Card, DashboardViewer, SkeletonModule], template: "<div class=\"grid gap-4\" [style.gridTemplateColumns]=\"gridTemplateColumns\">\r\n @if (informativeState().config.contentStart) {\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.startSpan)\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"informativeState().config.contentStart\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: informativeState(),\r\n table: informativeState(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.tableSpan)\r\n \"\r\n >\r\n <mt-card>\r\n @if (\r\n informativeState().loading &&\r\n !informativeState().dashboardData?.charts?.length\r\n ) {\r\n <div class=\"flex flex-col gap-3 py-3\">\r\n <p-skeleton height=\"6rem\" />\r\n <p-skeleton height=\"12rem\" />\r\n <p-skeleton height=\"12rem\" />\r\n </div>\r\n } @else if (informativeState().error) {\r\n <div\r\n class=\"rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700\"\r\n >\r\n {{ informativeState().error }}\r\n </div>\r\n } @else if (!informativeState().dashboardData?.charts?.length) {\r\n <div class=\"p-6 text-center text-gray-400\">\r\n No informative dashboard found.\r\n </div>\r\n } @else {\r\n <div class=\"min-h-[420px]\">\r\n <mt-dashboard-viewer\r\n [isPage]=\"false\"\r\n [showFilters]=\"false\"\r\n [dashboardData]=\"informativeState().dashboardData\"\r\n />\r\n </div>\r\n }\r\n </mt-card>\r\n </div>\r\n\r\n @if (informativeState().config.contentEnd) {\r\n <div\r\n [style.gridColumn]=\"\r\n slotGridSpan(informativeState().config.layout.endSpan)\r\n \"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"informativeState().config.contentEnd\"\r\n [ngTemplateOutletContext]=\"{\r\n $implicit: informativeState(),\r\n table: informativeState(),\r\n }\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n" }]
|
|
380
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }] } });
|
|
381
|
+
|
|
382
|
+
const DEFAULT_AREA_TYPE = 'table';
|
|
147
383
|
const DEFAULT_MODE = 'auto';
|
|
384
|
+
const DEFAULT_TYPE = 'form';
|
|
148
385
|
const DEFAULT_SERVER_PAGE_SIZE = 50;
|
|
149
386
|
const LOCAL_PAGE_SIZE_SOURCE = 100000;
|
|
150
387
|
const DEFAULT_COLLAPSE_ICON = 'arrow.chevron-up';
|
|
@@ -158,101 +395,174 @@ class ClientList {
|
|
|
158
395
|
defaultTake = input(DEFAULT_SERVER_PAGE_SIZE, ...(ngDevMode ? [{ debugName: "defaultTake" }] : []));
|
|
159
396
|
loaded = output();
|
|
160
397
|
errored = output();
|
|
161
|
-
|
|
162
|
-
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS}, minmax(0, 1fr))`;
|
|
398
|
+
items = this.state.items;
|
|
163
399
|
subscriptions = new Map();
|
|
164
400
|
inFlightRequestSignatures = new Map();
|
|
165
401
|
fulfilledRequestSignatures = new Map();
|
|
166
402
|
constructor() {
|
|
167
403
|
effect(() => {
|
|
168
404
|
const configs = this.configurations();
|
|
169
|
-
untracked(() => this.
|
|
405
|
+
untracked(() => this.configureItems(configs));
|
|
170
406
|
untracked(() => {
|
|
171
|
-
this.state.
|
|
172
|
-
this.
|
|
407
|
+
this.state.items().forEach((item) => {
|
|
408
|
+
this.loadItem(item);
|
|
173
409
|
});
|
|
174
410
|
});
|
|
175
411
|
});
|
|
176
412
|
}
|
|
177
|
-
onLazyLoad(
|
|
178
|
-
const
|
|
179
|
-
if (!
|
|
413
|
+
onLazyLoad(itemKey, event) {
|
|
414
|
+
const item = this.state.itemsByKey()[itemKey];
|
|
415
|
+
if (!item ||
|
|
416
|
+
item.type === 'informative' ||
|
|
417
|
+
item.areaType !== 'table' ||
|
|
418
|
+
!item.config.isPaginated) {
|
|
180
419
|
return;
|
|
181
|
-
|
|
420
|
+
}
|
|
421
|
+
const take = Number(event.pageSize ?? item.take);
|
|
182
422
|
const skip = Number(event.first ?? 0);
|
|
183
|
-
this.loadTable(
|
|
423
|
+
this.loadTable(item.key, item.config, skip, take);
|
|
184
424
|
}
|
|
185
|
-
reload(
|
|
186
|
-
if (
|
|
187
|
-
this.reloadByKey(
|
|
425
|
+
reload(itemKey) {
|
|
426
|
+
if (itemKey) {
|
|
427
|
+
this.reloadByKey(itemKey);
|
|
188
428
|
return;
|
|
189
429
|
}
|
|
190
|
-
this.
|
|
191
|
-
this.
|
|
430
|
+
this.items().forEach((item) => {
|
|
431
|
+
this.loadItem(item, true);
|
|
192
432
|
});
|
|
193
433
|
}
|
|
194
|
-
reloadByKey(
|
|
195
|
-
const
|
|
196
|
-
if (!
|
|
434
|
+
reloadByKey(itemKey) {
|
|
435
|
+
const item = this.state.itemsByKey()[itemKey];
|
|
436
|
+
if (!item)
|
|
197
437
|
return;
|
|
198
|
-
this.
|
|
438
|
+
this.loadItem(item, true);
|
|
199
439
|
}
|
|
200
440
|
toggleExpanded(key) {
|
|
201
441
|
this.state.toggleExpanded(key);
|
|
202
442
|
}
|
|
203
|
-
|
|
204
|
-
return `span ${span} / span ${span}`;
|
|
205
|
-
}
|
|
206
|
-
templateContext(table) {
|
|
443
|
+
templateContext(item) {
|
|
207
444
|
return {
|
|
208
|
-
$implicit:
|
|
209
|
-
table,
|
|
445
|
+
$implicit: item,
|
|
446
|
+
table: item,
|
|
210
447
|
};
|
|
211
448
|
}
|
|
449
|
+
defaultTitle(item) {
|
|
450
|
+
if (item.type === 'informative') {
|
|
451
|
+
return 'Informative Dashboard';
|
|
452
|
+
}
|
|
453
|
+
return item.areaType === 'cards' ? 'Cards' : 'Table';
|
|
454
|
+
}
|
|
212
455
|
ngOnDestroy() {
|
|
213
456
|
this.subscriptions.forEach((sub) => sub.unsubscribe());
|
|
214
457
|
this.subscriptions.clear();
|
|
215
458
|
}
|
|
216
|
-
|
|
217
|
-
const
|
|
459
|
+
configureItems(configs) {
|
|
460
|
+
const previousItems = this.state.itemsByKey();
|
|
218
461
|
const hasMultipleConfigs = (configs ?? []).length > 1;
|
|
219
462
|
const normalized = (configs ?? []).map((config, index) => {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
?
|
|
224
|
-
:
|
|
463
|
+
const type = this.resolveType(config.type);
|
|
464
|
+
const isInformative = type === 'informative';
|
|
465
|
+
const areaType = isInformative
|
|
466
|
+
? DEFAULT_AREA_TYPE
|
|
467
|
+
: this.resolveAreaType(config.areaType);
|
|
468
|
+
const mode = isInformative
|
|
469
|
+
? DEFAULT_MODE
|
|
470
|
+
: this.resolveMode(config.mode, config.columnKeys);
|
|
471
|
+
const isPaginated = !isInformative &&
|
|
472
|
+
areaType === 'table' &&
|
|
473
|
+
(config.isPaginated ?? true);
|
|
474
|
+
const take = !isInformative && areaType === 'table'
|
|
475
|
+
? isPaginated
|
|
476
|
+
? (config.take ?? this.defaultTake())
|
|
477
|
+
: LOCAL_PAGE_SIZE_SOURCE
|
|
478
|
+
: 0;
|
|
225
479
|
const collapseEnabled = (config.collapse?.enabled ?? true) && hasMultipleConfigs;
|
|
226
480
|
const layout = this.resolveLayout(config);
|
|
227
481
|
const key = config.key ??
|
|
228
482
|
`${config.levelId ?? 'x'}-${config.levelDataId ?? 'x'}-${config.moduleId ?? 'x'}-${index}`;
|
|
229
|
-
const
|
|
483
|
+
const existing = previousItems[key];
|
|
484
|
+
const normalizedConfig = this.toNormalizedConfig(config, type, areaType, mode, isPaginated, take, collapseEnabled, layout);
|
|
485
|
+
if (isInformative) {
|
|
486
|
+
return {
|
|
487
|
+
key,
|
|
488
|
+
config: normalizedConfig,
|
|
489
|
+
type: 'informative',
|
|
490
|
+
areaType: 'table',
|
|
491
|
+
loading: false,
|
|
492
|
+
error: null,
|
|
493
|
+
title: config.title?.trim() || '',
|
|
494
|
+
moduleKey: '',
|
|
495
|
+
totalCount: 0,
|
|
496
|
+
columns: [],
|
|
497
|
+
rows: [],
|
|
498
|
+
cards: [],
|
|
499
|
+
skip: 0,
|
|
500
|
+
take: 0,
|
|
501
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
502
|
+
dashboardData: existing?.dashboardData ?? null,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
if (areaType === 'cards') {
|
|
506
|
+
return {
|
|
507
|
+
key,
|
|
508
|
+
config: normalizedConfig,
|
|
509
|
+
type: 'form',
|
|
510
|
+
areaType: 'cards',
|
|
511
|
+
loading: false,
|
|
512
|
+
error: null,
|
|
513
|
+
title: config.title?.trim() || '',
|
|
514
|
+
moduleKey: '',
|
|
515
|
+
totalCount: 0,
|
|
516
|
+
columns: [],
|
|
517
|
+
rows: [],
|
|
518
|
+
cards: [],
|
|
519
|
+
skip: 0,
|
|
520
|
+
take: 0,
|
|
521
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
522
|
+
dashboardData: null,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
230
525
|
return {
|
|
231
526
|
key,
|
|
232
|
-
config:
|
|
527
|
+
config: normalizedConfig,
|
|
528
|
+
type: 'form',
|
|
529
|
+
areaType: 'table',
|
|
233
530
|
loading: false,
|
|
234
531
|
error: null,
|
|
235
532
|
title: config.title?.trim() || '',
|
|
236
533
|
moduleKey: '',
|
|
534
|
+
totalCount: 0,
|
|
237
535
|
columns: [],
|
|
238
536
|
rows: [],
|
|
239
|
-
|
|
537
|
+
cards: [],
|
|
538
|
+
skip: existing?.areaType === 'table' ? existing.skip : 0,
|
|
240
539
|
take,
|
|
241
|
-
|
|
242
|
-
|
|
540
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
541
|
+
dashboardData: null,
|
|
243
542
|
};
|
|
244
543
|
});
|
|
245
544
|
this.state.setConfigs(normalized);
|
|
246
|
-
this.cleanupStaleResources(new Set(normalized.map((
|
|
545
|
+
this.cleanupStaleResources(new Set(normalized.map((item) => item.key)));
|
|
546
|
+
}
|
|
547
|
+
loadItem(item, force = false) {
|
|
548
|
+
if (item.type === 'informative') {
|
|
549
|
+
this.loadInformative(item.key, item.config, force);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
if (item.areaType === 'cards') {
|
|
553
|
+
this.loadCards(item.key, item.config, force);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
this.loadTable(item.key, item.config, item.skip, item.take, force);
|
|
247
557
|
}
|
|
248
558
|
loadTable(key, config, skip, take, force = false) {
|
|
249
559
|
if (!this.hasValidIdentifiers(config)) {
|
|
250
560
|
this.state.setLoading(key, false);
|
|
251
|
-
this.state.setError(key,
|
|
561
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
252
562
|
return;
|
|
253
563
|
}
|
|
254
|
-
const query = this.
|
|
255
|
-
const requestSignature = this.
|
|
564
|
+
const query = this.toTableQuery(config, skip, take);
|
|
565
|
+
const requestSignature = this.createTableRequestSignature(config, query);
|
|
256
566
|
if (force) {
|
|
257
567
|
this.inFlightRequestSignatures.delete(key);
|
|
258
568
|
this.fulfilledRequestSignatures.delete(key);
|
|
@@ -292,16 +602,117 @@ class ClientList {
|
|
|
292
602
|
});
|
|
293
603
|
this.subscriptions.set(key, sub);
|
|
294
604
|
}
|
|
605
|
+
loadCards(key, config, force = false) {
|
|
606
|
+
if (!this.hasValidIdentifiers(config)) {
|
|
607
|
+
this.state.setLoading(key, false);
|
|
608
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const requestSignature = this.createCardsRequestSignature(config);
|
|
612
|
+
if (force) {
|
|
613
|
+
this.inFlightRequestSignatures.delete(key);
|
|
614
|
+
this.fulfilledRequestSignatures.delete(key);
|
|
615
|
+
}
|
|
616
|
+
else if (this.inFlightRequestSignatures.get(key) === requestSignature ||
|
|
617
|
+
this.fulfilledRequestSignatures.get(key) === requestSignature) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
this.subscriptions.get(key)?.unsubscribe();
|
|
621
|
+
this.inFlightRequestSignatures.set(key, requestSignature);
|
|
622
|
+
this.state.setLoading(key, true);
|
|
623
|
+
this.state.setError(key, null);
|
|
624
|
+
const sub = this.api
|
|
625
|
+
.getCards(config.levelDataId, config.moduleId)
|
|
626
|
+
.subscribe({
|
|
627
|
+
next: (response) => {
|
|
628
|
+
if (response.data) {
|
|
629
|
+
this.state.setCardsResult(key, response.data, config);
|
|
630
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
631
|
+
this.loaded.emit(key);
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
const message = response.message ?? 'Failed to load cards';
|
|
635
|
+
this.state.setError(key, message);
|
|
636
|
+
this.errored.emit({ key, message });
|
|
637
|
+
}
|
|
638
|
+
this.state.setLoading(key, false);
|
|
639
|
+
this.inFlightRequestSignatures.delete(key);
|
|
640
|
+
},
|
|
641
|
+
error: (error) => {
|
|
642
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to load cards';
|
|
643
|
+
this.state.setError(key, message);
|
|
644
|
+
this.state.setLoading(key, false);
|
|
645
|
+
this.inFlightRequestSignatures.delete(key);
|
|
646
|
+
this.errored.emit({ key, message });
|
|
647
|
+
},
|
|
648
|
+
});
|
|
649
|
+
this.subscriptions.set(key, sub);
|
|
650
|
+
}
|
|
651
|
+
loadInformative(key, config, force = false) {
|
|
652
|
+
if (!this.hasValidIdentifiers(config)) {
|
|
653
|
+
this.state.setLoading(key, false);
|
|
654
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
const requestSignature = this.createInformativeRequestSignature(config);
|
|
658
|
+
if (force) {
|
|
659
|
+
this.inFlightRequestSignatures.delete(key);
|
|
660
|
+
this.fulfilledRequestSignatures.delete(key);
|
|
661
|
+
}
|
|
662
|
+
else if (this.inFlightRequestSignatures.get(key) === requestSignature ||
|
|
663
|
+
this.fulfilledRequestSignatures.get(key) === requestSignature) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
this.subscriptions.get(key)?.unsubscribe();
|
|
667
|
+
this.inFlightRequestSignatures.set(key, requestSignature);
|
|
668
|
+
this.state.setLoading(key, true);
|
|
669
|
+
this.state.setError(key, null);
|
|
670
|
+
const sub = this.api.getInformativeDashboard(config.moduleId).subscribe({
|
|
671
|
+
next: (response) => {
|
|
672
|
+
this.state.setInformativeResult(key, response.data ?? null, config);
|
|
673
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
674
|
+
this.loaded.emit(key);
|
|
675
|
+
this.state.setLoading(key, false);
|
|
676
|
+
this.inFlightRequestSignatures.delete(key);
|
|
677
|
+
},
|
|
678
|
+
error: (error) => {
|
|
679
|
+
if (error?.status === 404) {
|
|
680
|
+
this.state.setInformativeResult(key, null, config);
|
|
681
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
682
|
+
this.loaded.emit(key);
|
|
683
|
+
this.state.setLoading(key, false);
|
|
684
|
+
this.inFlightRequestSignatures.delete(key);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const message = error?.error?.message ??
|
|
688
|
+
error?.message ??
|
|
689
|
+
'Failed to load informative dashboard';
|
|
690
|
+
this.state.setError(key, message);
|
|
691
|
+
this.state.setLoading(key, false);
|
|
692
|
+
this.inFlightRequestSignatures.delete(key);
|
|
693
|
+
this.errored.emit({ key, message });
|
|
694
|
+
},
|
|
695
|
+
});
|
|
696
|
+
this.subscriptions.set(key, sub);
|
|
697
|
+
}
|
|
698
|
+
resolveAreaType(areaType) {
|
|
699
|
+
return areaType === 'cards' ? 'cards' : DEFAULT_AREA_TYPE;
|
|
700
|
+
}
|
|
701
|
+
resolveType(type) {
|
|
702
|
+
return type === 'informative' ? 'informative' : DEFAULT_TYPE;
|
|
703
|
+
}
|
|
295
704
|
resolveMode(mode, columnKeys) {
|
|
296
705
|
if (mode !== 'override')
|
|
297
706
|
return DEFAULT_MODE;
|
|
298
707
|
return (columnKeys ?? []).length > 0 ? 'override' : DEFAULT_MODE;
|
|
299
708
|
}
|
|
300
|
-
toNormalizedConfig(config, mode, isPaginated, take, collapseEnabled, layout) {
|
|
709
|
+
toNormalizedConfig(config, type, areaType, mode, isPaginated, take, collapseEnabled, layout) {
|
|
301
710
|
return {
|
|
302
711
|
levelId: config.levelId,
|
|
303
712
|
levelDataId: config.levelDataId,
|
|
304
713
|
moduleId: config.moduleId,
|
|
714
|
+
type,
|
|
715
|
+
areaType,
|
|
305
716
|
mode,
|
|
306
717
|
isPaginated,
|
|
307
718
|
take,
|
|
@@ -311,6 +722,7 @@ class ClientList {
|
|
|
311
722
|
headerEnd: config.headerEnd,
|
|
312
723
|
contentStart: config.contentStart,
|
|
313
724
|
contentEnd: config.contentEnd,
|
|
725
|
+
rowActions: config.rowActions ?? [],
|
|
314
726
|
collapse: {
|
|
315
727
|
enabled: collapseEnabled,
|
|
316
728
|
expandedByDefault: config.collapse?.expandedByDefault ?? true,
|
|
@@ -356,7 +768,7 @@ class ClientList {
|
|
|
356
768
|
}
|
|
357
769
|
}
|
|
358
770
|
}
|
|
359
|
-
|
|
771
|
+
toTableQuery(config, skip, take) {
|
|
360
772
|
return {
|
|
361
773
|
mode: config.mode,
|
|
362
774
|
columnKeys: config.mode === 'override' ? config.columnKeys : undefined,
|
|
@@ -364,8 +776,10 @@ class ClientList {
|
|
|
364
776
|
take: config.isPaginated ? take : LOCAL_PAGE_SIZE_SOURCE,
|
|
365
777
|
};
|
|
366
778
|
}
|
|
367
|
-
|
|
779
|
+
createTableRequestSignature(config, query) {
|
|
368
780
|
return [
|
|
781
|
+
config.type,
|
|
782
|
+
config.areaType,
|
|
369
783
|
config.levelId,
|
|
370
784
|
config.levelDataId,
|
|
371
785
|
config.moduleId,
|
|
@@ -375,20 +789,53 @@ class ClientList {
|
|
|
375
789
|
...(query.columnKeys ?? []),
|
|
376
790
|
].join('|');
|
|
377
791
|
}
|
|
792
|
+
createCardsRequestSignature(config) {
|
|
793
|
+
return [
|
|
794
|
+
config.type,
|
|
795
|
+
config.areaType,
|
|
796
|
+
config.levelDataId,
|
|
797
|
+
config.moduleId,
|
|
798
|
+
'card',
|
|
799
|
+
].join('|');
|
|
800
|
+
}
|
|
801
|
+
createInformativeRequestSignature(config) {
|
|
802
|
+
return [config.type, config.moduleId, 'dashboard'].join('|');
|
|
803
|
+
}
|
|
378
804
|
hasValidIdentifiers(config) {
|
|
805
|
+
if (config.type === 'informative') {
|
|
806
|
+
return Number.isFinite(config.moduleId) && config.moduleId > 0;
|
|
807
|
+
}
|
|
808
|
+
const hasLevelDataId = Number.isFinite(config.levelDataId) && config.levelDataId > 0;
|
|
809
|
+
const hasModuleId = Number.isFinite(config.moduleId) && config.moduleId > 0;
|
|
810
|
+
if (config.areaType === 'cards') {
|
|
811
|
+
return hasLevelDataId && hasModuleId;
|
|
812
|
+
}
|
|
379
813
|
return (Number.isFinite(config.levelId) &&
|
|
380
814
|
config.levelId > 0 &&
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
815
|
+
hasLevelDataId &&
|
|
816
|
+
hasModuleId);
|
|
817
|
+
}
|
|
818
|
+
getMissingIdentifiersMessage(config) {
|
|
819
|
+
if (config.type === 'informative') {
|
|
820
|
+
return 'Missing identifiers: moduleId is required';
|
|
821
|
+
}
|
|
822
|
+
if (config.areaType === 'cards') {
|
|
823
|
+
return 'Missing identifiers: levelDataId and moduleId are required';
|
|
824
|
+
}
|
|
825
|
+
return 'Missing identifiers: levelId, levelDataId and moduleId are required';
|
|
385
826
|
}
|
|
386
827
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientList, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
387
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientList, isStandalone: true, selector: "mt-client-list", inputs: { configurations: { classPropertyName: "configurations", publicName: "configurations", isSignal: true, isRequired: true, transformFunction: null }, defaultTake: { classPropertyName: "defaultTake", publicName: "defaultTake", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", errored: "errored" }, providers: [ClientListStateService], ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\r\n @for (
|
|
828
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: ClientList, isStandalone: true, selector: "mt-client-list", inputs: { configurations: { classPropertyName: "configurations", publicName: "configurations", isSignal: true, isRequired: true, transformFunction: null }, defaultTake: { classPropertyName: "defaultTake", publicName: "defaultTake", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loaded: "loaded", errored: "errored" }, providers: [ClientListStateService], ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\r\n @for (item of items(); track item.key) {\r\n <section class=\"flex flex-col gap-4\">\r\n <div class=\"flex w-full items-center gap-2\">\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (item.config.collapse.enabled) {\r\n <mt-button\r\n variant=\"text\"\r\n severity=\"secondary\"\r\n [icon]=\"\r\n item.expanded\r\n ? item.config.collapse.collapseIcon\r\n : item.config.collapse.expandIcon\r\n \"\r\n (onClick)=\"toggleExpanded(item.key)\"\r\n />\r\n }\r\n <h3 class=\"m-0 text-lg font-bold\">\r\n {{ item.title || item.moduleKey || defaultTitle(item) }}\r\n </h3>\r\n @if (item.config.headerStart) {\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"item.config.headerStart\"\r\n [ngTemplateOutletContext]=\"templateContext(item)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n @if (item.config.headerEnd) {\r\n <div class=\"ml-auto flex shrink-0 items-center gap-2\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"item.config.headerEnd\"\r\n [ngTemplateOutletContext]=\"templateContext(item)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (item.expanded || !item.config.collapse.enabled) {\r\n @if (item.type === \"informative\") {\r\n <mt-client-list-informative-view [state]=\"item\" />\r\n } @else if (item.areaType === \"table\") {\r\n <mt-client-list-table-view\r\n [state]=\"item\"\r\n [rowActions]=\"item.config.rowActions\"\r\n (lazyLoad)=\"onLazyLoad(item.key, $event)\"\r\n />\r\n } @else {\r\n <mt-client-list-cards-view [state]=\"item\" />\r\n }\r\n }\r\n </section>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ClientListTableView, selector: "mt-client-list-table-view", inputs: ["state", "rowActions"], outputs: ["lazyLoad"] }, { kind: "component", type: ClientListCardsView, selector: "mt-client-list-cards-view", inputs: ["state"] }, { kind: "component", type: ClientListInformativeView, selector: "mt-client-list-informative-view", inputs: ["state"] }] });
|
|
388
829
|
}
|
|
389
830
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientList, decorators: [{
|
|
390
831
|
type: Component,
|
|
391
|
-
args: [{ selector: 'mt-client-list', standalone: true, imports: [
|
|
832
|
+
args: [{ selector: 'mt-client-list', standalone: true, imports: [
|
|
833
|
+
CommonModule,
|
|
834
|
+
Button,
|
|
835
|
+
ClientListTableView,
|
|
836
|
+
ClientListCardsView,
|
|
837
|
+
ClientListInformativeView,
|
|
838
|
+
], providers: [ClientListStateService], template: "<div class=\"flex flex-col gap-4\">\r\n @for (item of items(); track item.key) {\r\n <section class=\"flex flex-col gap-4\">\r\n <div class=\"flex w-full items-center gap-2\">\r\n <div class=\"flex min-w-0 flex-1 items-center gap-2\">\r\n @if (item.config.collapse.enabled) {\r\n <mt-button\r\n variant=\"text\"\r\n severity=\"secondary\"\r\n [icon]=\"\r\n item.expanded\r\n ? item.config.collapse.collapseIcon\r\n : item.config.collapse.expandIcon\r\n \"\r\n (onClick)=\"toggleExpanded(item.key)\"\r\n />\r\n }\r\n <h3 class=\"m-0 text-lg font-bold\">\r\n {{ item.title || item.moduleKey || defaultTitle(item) }}\r\n </h3>\r\n @if (item.config.headerStart) {\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"item.config.headerStart\"\r\n [ngTemplateOutletContext]=\"templateContext(item)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n @if (item.config.headerEnd) {\r\n <div class=\"ml-auto flex shrink-0 items-center gap-2\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"item.config.headerEnd\"\r\n [ngTemplateOutletContext]=\"templateContext(item)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (item.expanded || !item.config.collapse.enabled) {\r\n @if (item.type === \"informative\") {\r\n <mt-client-list-informative-view [state]=\"item\" />\r\n } @else if (item.areaType === \"table\") {\r\n <mt-client-list-table-view\r\n [state]=\"item\"\r\n [rowActions]=\"item.config.rowActions\"\r\n (lazyLoad)=\"onLazyLoad(item.key, $event)\"\r\n />\r\n } @else {\r\n <mt-client-list-cards-view [state]=\"item\" />\r\n }\r\n }\r\n </section>\r\n }\r\n</div>\r\n" }]
|
|
392
839
|
}], ctorParameters: () => [], propDecorators: { configurations: [{ type: i0.Input, args: [{ isSignal: true, alias: "configurations", required: true }] }], defaultTake: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultTake", required: false }] }], loaded: [{ type: i0.Output, args: ["loaded"] }], errored: [{ type: i0.Output, args: ["errored"] }] } });
|
|
393
840
|
|
|
394
841
|
/**
|