@masterteam/client-components 0.0.3 → 0.0.5
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 +540 -95
- package/fesm2022/masterteam-client-components-client-list.mjs.map +1 -1
- package/fesm2022/masterteam-client-components-escalation-runtime.mjs +164 -0
- package/fesm2022/masterteam-client-components-escalation-runtime.mjs.map +1 -0
- package/package.json +18 -12
- package/types/masterteam-client-components-client-list.d.ts +163 -29
- package/types/masterteam-client-components-escalation-runtime.d.ts +75 -0
|
@@ -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,55 @@ 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
|
+
lazyLoad = output();
|
|
339
|
+
table = computed(() => {
|
|
340
|
+
return this.state();
|
|
341
|
+
}, ...(ngDevMode ? [{ debugName: "table" }] : []));
|
|
342
|
+
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS$2}, minmax(0, 1fr))`;
|
|
343
|
+
slotGridSpan(span) {
|
|
344
|
+
return `span ${span} / span ${span}`;
|
|
345
|
+
}
|
|
346
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListTableView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
347
|
+
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 } }, 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 [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"] }] });
|
|
348
|
+
}
|
|
349
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListTableView, decorators: [{
|
|
350
|
+
type: Component,
|
|
351
|
+
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 [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" }]
|
|
352
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }] } });
|
|
353
|
+
|
|
354
|
+
class ClientListCardsView {
|
|
355
|
+
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
356
|
+
cardsState = computed(() => this.state(), ...(ngDevMode ? [{ debugName: "cardsState" }] : []));
|
|
357
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListCardsView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
358
|
+
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"] }] });
|
|
359
|
+
}
|
|
360
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListCardsView, decorators: [{
|
|
361
|
+
type: Component,
|
|
362
|
+
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" }]
|
|
363
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }] } });
|
|
364
|
+
|
|
365
|
+
const DEFAULT_GRID_COLUMNS$1 = 12;
|
|
366
|
+
class ClientListInformativeView {
|
|
367
|
+
state = input.required(...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
368
|
+
informativeState = computed(() => this.state(), ...(ngDevMode ? [{ debugName: "informativeState" }] : []));
|
|
369
|
+
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS$1}, minmax(0, 1fr))`;
|
|
370
|
+
slotGridSpan(span) {
|
|
371
|
+
return `span ${span} / span ${span}`;
|
|
372
|
+
}
|
|
373
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListInformativeView, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
374
|
+
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"] }] });
|
|
375
|
+
}
|
|
376
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientListInformativeView, decorators: [{
|
|
377
|
+
type: Component,
|
|
378
|
+
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" }]
|
|
379
|
+
}], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: true }] }] } });
|
|
380
|
+
|
|
381
|
+
const DEFAULT_AREA_TYPE = 'table';
|
|
147
382
|
const DEFAULT_MODE = 'auto';
|
|
383
|
+
const DEFAULT_TYPE = 'form';
|
|
148
384
|
const DEFAULT_SERVER_PAGE_SIZE = 50;
|
|
149
385
|
const LOCAL_PAGE_SIZE_SOURCE = 100000;
|
|
150
386
|
const DEFAULT_COLLAPSE_ICON = 'arrow.chevron-up';
|
|
@@ -158,101 +394,174 @@ class ClientList {
|
|
|
158
394
|
defaultTake = input(DEFAULT_SERVER_PAGE_SIZE, ...(ngDevMode ? [{ debugName: "defaultTake" }] : []));
|
|
159
395
|
loaded = output();
|
|
160
396
|
errored = output();
|
|
161
|
-
|
|
162
|
-
gridTemplateColumns = `repeat(${DEFAULT_GRID_COLUMNS}, minmax(0, 1fr))`;
|
|
397
|
+
items = this.state.items;
|
|
163
398
|
subscriptions = new Map();
|
|
164
399
|
inFlightRequestSignatures = new Map();
|
|
165
400
|
fulfilledRequestSignatures = new Map();
|
|
166
401
|
constructor() {
|
|
167
402
|
effect(() => {
|
|
168
403
|
const configs = this.configurations();
|
|
169
|
-
untracked(() => this.
|
|
404
|
+
untracked(() => this.configureItems(configs));
|
|
170
405
|
untracked(() => {
|
|
171
|
-
this.state.
|
|
172
|
-
this.
|
|
406
|
+
this.state.items().forEach((item) => {
|
|
407
|
+
this.loadItem(item);
|
|
173
408
|
});
|
|
174
409
|
});
|
|
175
410
|
});
|
|
176
411
|
}
|
|
177
|
-
onLazyLoad(
|
|
178
|
-
const
|
|
179
|
-
if (!
|
|
412
|
+
onLazyLoad(itemKey, event) {
|
|
413
|
+
const item = this.state.itemsByKey()[itemKey];
|
|
414
|
+
if (!item ||
|
|
415
|
+
item.type === 'informative' ||
|
|
416
|
+
item.areaType !== 'table' ||
|
|
417
|
+
!item.config.isPaginated) {
|
|
180
418
|
return;
|
|
181
|
-
|
|
419
|
+
}
|
|
420
|
+
const take = Number(event.pageSize ?? item.take);
|
|
182
421
|
const skip = Number(event.first ?? 0);
|
|
183
|
-
this.loadTable(
|
|
422
|
+
this.loadTable(item.key, item.config, skip, take);
|
|
184
423
|
}
|
|
185
|
-
reload(
|
|
186
|
-
if (
|
|
187
|
-
this.reloadByKey(
|
|
424
|
+
reload(itemKey) {
|
|
425
|
+
if (itemKey) {
|
|
426
|
+
this.reloadByKey(itemKey);
|
|
188
427
|
return;
|
|
189
428
|
}
|
|
190
|
-
this.
|
|
191
|
-
this.
|
|
429
|
+
this.items().forEach((item) => {
|
|
430
|
+
this.loadItem(item, true);
|
|
192
431
|
});
|
|
193
432
|
}
|
|
194
|
-
reloadByKey(
|
|
195
|
-
const
|
|
196
|
-
if (!
|
|
433
|
+
reloadByKey(itemKey) {
|
|
434
|
+
const item = this.state.itemsByKey()[itemKey];
|
|
435
|
+
if (!item)
|
|
197
436
|
return;
|
|
198
|
-
this.
|
|
437
|
+
this.loadItem(item, true);
|
|
199
438
|
}
|
|
200
439
|
toggleExpanded(key) {
|
|
201
440
|
this.state.toggleExpanded(key);
|
|
202
441
|
}
|
|
203
|
-
|
|
204
|
-
return `span ${span} / span ${span}`;
|
|
205
|
-
}
|
|
206
|
-
templateContext(table) {
|
|
442
|
+
templateContext(item) {
|
|
207
443
|
return {
|
|
208
|
-
$implicit:
|
|
209
|
-
table,
|
|
444
|
+
$implicit: item,
|
|
445
|
+
table: item,
|
|
210
446
|
};
|
|
211
447
|
}
|
|
448
|
+
defaultTitle(item) {
|
|
449
|
+
if (item.type === 'informative') {
|
|
450
|
+
return 'Informative Dashboard';
|
|
451
|
+
}
|
|
452
|
+
return item.areaType === 'cards' ? 'Cards' : 'Table';
|
|
453
|
+
}
|
|
212
454
|
ngOnDestroy() {
|
|
213
455
|
this.subscriptions.forEach((sub) => sub.unsubscribe());
|
|
214
456
|
this.subscriptions.clear();
|
|
215
457
|
}
|
|
216
|
-
|
|
217
|
-
const
|
|
458
|
+
configureItems(configs) {
|
|
459
|
+
const previousItems = this.state.itemsByKey();
|
|
218
460
|
const hasMultipleConfigs = (configs ?? []).length > 1;
|
|
219
461
|
const normalized = (configs ?? []).map((config, index) => {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
?
|
|
224
|
-
:
|
|
462
|
+
const type = this.resolveType(config.type);
|
|
463
|
+
const isInformative = type === 'informative';
|
|
464
|
+
const areaType = isInformative
|
|
465
|
+
? DEFAULT_AREA_TYPE
|
|
466
|
+
: this.resolveAreaType(config.areaType);
|
|
467
|
+
const mode = isInformative
|
|
468
|
+
? DEFAULT_MODE
|
|
469
|
+
: this.resolveMode(config.mode, config.columnKeys);
|
|
470
|
+
const isPaginated = !isInformative &&
|
|
471
|
+
areaType === 'table' &&
|
|
472
|
+
(config.isPaginated ?? true);
|
|
473
|
+
const take = !isInformative && areaType === 'table'
|
|
474
|
+
? isPaginated
|
|
475
|
+
? (config.take ?? this.defaultTake())
|
|
476
|
+
: LOCAL_PAGE_SIZE_SOURCE
|
|
477
|
+
: 0;
|
|
225
478
|
const collapseEnabled = (config.collapse?.enabled ?? true) && hasMultipleConfigs;
|
|
226
479
|
const layout = this.resolveLayout(config);
|
|
227
480
|
const key = config.key ??
|
|
228
481
|
`${config.levelId ?? 'x'}-${config.levelDataId ?? 'x'}-${config.moduleId ?? 'x'}-${index}`;
|
|
229
|
-
const
|
|
482
|
+
const existing = previousItems[key];
|
|
483
|
+
const normalizedConfig = this.toNormalizedConfig(config, type, areaType, mode, isPaginated, take, collapseEnabled, layout);
|
|
484
|
+
if (isInformative) {
|
|
485
|
+
return {
|
|
486
|
+
key,
|
|
487
|
+
config: normalizedConfig,
|
|
488
|
+
type: 'informative',
|
|
489
|
+
areaType: 'table',
|
|
490
|
+
loading: false,
|
|
491
|
+
error: null,
|
|
492
|
+
title: config.title?.trim() || '',
|
|
493
|
+
moduleKey: '',
|
|
494
|
+
totalCount: 0,
|
|
495
|
+
columns: [],
|
|
496
|
+
rows: [],
|
|
497
|
+
cards: [],
|
|
498
|
+
skip: 0,
|
|
499
|
+
take: 0,
|
|
500
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
501
|
+
dashboardData: existing?.dashboardData ?? null,
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
if (areaType === 'cards') {
|
|
505
|
+
return {
|
|
506
|
+
key,
|
|
507
|
+
config: normalizedConfig,
|
|
508
|
+
type: 'form',
|
|
509
|
+
areaType: 'cards',
|
|
510
|
+
loading: false,
|
|
511
|
+
error: null,
|
|
512
|
+
title: config.title?.trim() || '',
|
|
513
|
+
moduleKey: '',
|
|
514
|
+
totalCount: 0,
|
|
515
|
+
columns: [],
|
|
516
|
+
rows: [],
|
|
517
|
+
cards: [],
|
|
518
|
+
skip: 0,
|
|
519
|
+
take: 0,
|
|
520
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
521
|
+
dashboardData: null,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
230
524
|
return {
|
|
231
525
|
key,
|
|
232
|
-
config:
|
|
526
|
+
config: normalizedConfig,
|
|
527
|
+
type: 'form',
|
|
528
|
+
areaType: 'table',
|
|
233
529
|
loading: false,
|
|
234
530
|
error: null,
|
|
235
531
|
title: config.title?.trim() || '',
|
|
236
532
|
moduleKey: '',
|
|
533
|
+
totalCount: 0,
|
|
237
534
|
columns: [],
|
|
238
535
|
rows: [],
|
|
239
|
-
|
|
536
|
+
cards: [],
|
|
537
|
+
skip: existing?.areaType === 'table' ? existing.skip : 0,
|
|
240
538
|
take,
|
|
241
|
-
|
|
242
|
-
|
|
539
|
+
expanded: existing?.expanded ?? config.collapse?.expandedByDefault ?? true,
|
|
540
|
+
dashboardData: null,
|
|
243
541
|
};
|
|
244
542
|
});
|
|
245
543
|
this.state.setConfigs(normalized);
|
|
246
|
-
this.cleanupStaleResources(new Set(normalized.map((
|
|
544
|
+
this.cleanupStaleResources(new Set(normalized.map((item) => item.key)));
|
|
545
|
+
}
|
|
546
|
+
loadItem(item, force = false) {
|
|
547
|
+
if (item.type === 'informative') {
|
|
548
|
+
this.loadInformative(item.key, item.config, force);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (item.areaType === 'cards') {
|
|
552
|
+
this.loadCards(item.key, item.config, force);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
this.loadTable(item.key, item.config, item.skip, item.take, force);
|
|
247
556
|
}
|
|
248
557
|
loadTable(key, config, skip, take, force = false) {
|
|
249
558
|
if (!this.hasValidIdentifiers(config)) {
|
|
250
559
|
this.state.setLoading(key, false);
|
|
251
|
-
this.state.setError(key,
|
|
560
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
252
561
|
return;
|
|
253
562
|
}
|
|
254
|
-
const query = this.
|
|
255
|
-
const requestSignature = this.
|
|
563
|
+
const query = this.toTableQuery(config, skip, take);
|
|
564
|
+
const requestSignature = this.createTableRequestSignature(config, query);
|
|
256
565
|
if (force) {
|
|
257
566
|
this.inFlightRequestSignatures.delete(key);
|
|
258
567
|
this.fulfilledRequestSignatures.delete(key);
|
|
@@ -292,16 +601,117 @@ class ClientList {
|
|
|
292
601
|
});
|
|
293
602
|
this.subscriptions.set(key, sub);
|
|
294
603
|
}
|
|
604
|
+
loadCards(key, config, force = false) {
|
|
605
|
+
if (!this.hasValidIdentifiers(config)) {
|
|
606
|
+
this.state.setLoading(key, false);
|
|
607
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const requestSignature = this.createCardsRequestSignature(config);
|
|
611
|
+
if (force) {
|
|
612
|
+
this.inFlightRequestSignatures.delete(key);
|
|
613
|
+
this.fulfilledRequestSignatures.delete(key);
|
|
614
|
+
}
|
|
615
|
+
else if (this.inFlightRequestSignatures.get(key) === requestSignature ||
|
|
616
|
+
this.fulfilledRequestSignatures.get(key) === requestSignature) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
this.subscriptions.get(key)?.unsubscribe();
|
|
620
|
+
this.inFlightRequestSignatures.set(key, requestSignature);
|
|
621
|
+
this.state.setLoading(key, true);
|
|
622
|
+
this.state.setError(key, null);
|
|
623
|
+
const sub = this.api
|
|
624
|
+
.getCards(config.levelDataId, config.moduleId)
|
|
625
|
+
.subscribe({
|
|
626
|
+
next: (response) => {
|
|
627
|
+
if (response.data) {
|
|
628
|
+
this.state.setCardsResult(key, response.data, config);
|
|
629
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
630
|
+
this.loaded.emit(key);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
const message = response.message ?? 'Failed to load cards';
|
|
634
|
+
this.state.setError(key, message);
|
|
635
|
+
this.errored.emit({ key, message });
|
|
636
|
+
}
|
|
637
|
+
this.state.setLoading(key, false);
|
|
638
|
+
this.inFlightRequestSignatures.delete(key);
|
|
639
|
+
},
|
|
640
|
+
error: (error) => {
|
|
641
|
+
const message = error?.error?.message ?? error?.message ?? 'Failed to load cards';
|
|
642
|
+
this.state.setError(key, message);
|
|
643
|
+
this.state.setLoading(key, false);
|
|
644
|
+
this.inFlightRequestSignatures.delete(key);
|
|
645
|
+
this.errored.emit({ key, message });
|
|
646
|
+
},
|
|
647
|
+
});
|
|
648
|
+
this.subscriptions.set(key, sub);
|
|
649
|
+
}
|
|
650
|
+
loadInformative(key, config, force = false) {
|
|
651
|
+
if (!this.hasValidIdentifiers(config)) {
|
|
652
|
+
this.state.setLoading(key, false);
|
|
653
|
+
this.state.setError(key, this.getMissingIdentifiersMessage(config));
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const requestSignature = this.createInformativeRequestSignature(config);
|
|
657
|
+
if (force) {
|
|
658
|
+
this.inFlightRequestSignatures.delete(key);
|
|
659
|
+
this.fulfilledRequestSignatures.delete(key);
|
|
660
|
+
}
|
|
661
|
+
else if (this.inFlightRequestSignatures.get(key) === requestSignature ||
|
|
662
|
+
this.fulfilledRequestSignatures.get(key) === requestSignature) {
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
this.subscriptions.get(key)?.unsubscribe();
|
|
666
|
+
this.inFlightRequestSignatures.set(key, requestSignature);
|
|
667
|
+
this.state.setLoading(key, true);
|
|
668
|
+
this.state.setError(key, null);
|
|
669
|
+
const sub = this.api.getInformativeDashboard(config.moduleId).subscribe({
|
|
670
|
+
next: (response) => {
|
|
671
|
+
this.state.setInformativeResult(key, response.data ?? null, config);
|
|
672
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
673
|
+
this.loaded.emit(key);
|
|
674
|
+
this.state.setLoading(key, false);
|
|
675
|
+
this.inFlightRequestSignatures.delete(key);
|
|
676
|
+
},
|
|
677
|
+
error: (error) => {
|
|
678
|
+
if (error?.status === 404) {
|
|
679
|
+
this.state.setInformativeResult(key, null, config);
|
|
680
|
+
this.fulfilledRequestSignatures.set(key, requestSignature);
|
|
681
|
+
this.loaded.emit(key);
|
|
682
|
+
this.state.setLoading(key, false);
|
|
683
|
+
this.inFlightRequestSignatures.delete(key);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const message = error?.error?.message ??
|
|
687
|
+
error?.message ??
|
|
688
|
+
'Failed to load informative dashboard';
|
|
689
|
+
this.state.setError(key, message);
|
|
690
|
+
this.state.setLoading(key, false);
|
|
691
|
+
this.inFlightRequestSignatures.delete(key);
|
|
692
|
+
this.errored.emit({ key, message });
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
this.subscriptions.set(key, sub);
|
|
696
|
+
}
|
|
697
|
+
resolveAreaType(areaType) {
|
|
698
|
+
return areaType === 'cards' ? 'cards' : DEFAULT_AREA_TYPE;
|
|
699
|
+
}
|
|
700
|
+
resolveType(type) {
|
|
701
|
+
return type === 'informative' ? 'informative' : DEFAULT_TYPE;
|
|
702
|
+
}
|
|
295
703
|
resolveMode(mode, columnKeys) {
|
|
296
704
|
if (mode !== 'override')
|
|
297
705
|
return DEFAULT_MODE;
|
|
298
706
|
return (columnKeys ?? []).length > 0 ? 'override' : DEFAULT_MODE;
|
|
299
707
|
}
|
|
300
|
-
toNormalizedConfig(config, mode, isPaginated, take, collapseEnabled, layout) {
|
|
708
|
+
toNormalizedConfig(config, type, areaType, mode, isPaginated, take, collapseEnabled, layout) {
|
|
301
709
|
return {
|
|
302
710
|
levelId: config.levelId,
|
|
303
711
|
levelDataId: config.levelDataId,
|
|
304
712
|
moduleId: config.moduleId,
|
|
713
|
+
type,
|
|
714
|
+
areaType,
|
|
305
715
|
mode,
|
|
306
716
|
isPaginated,
|
|
307
717
|
take,
|
|
@@ -356,7 +766,7 @@ class ClientList {
|
|
|
356
766
|
}
|
|
357
767
|
}
|
|
358
768
|
}
|
|
359
|
-
|
|
769
|
+
toTableQuery(config, skip, take) {
|
|
360
770
|
return {
|
|
361
771
|
mode: config.mode,
|
|
362
772
|
columnKeys: config.mode === 'override' ? config.columnKeys : undefined,
|
|
@@ -364,8 +774,10 @@ class ClientList {
|
|
|
364
774
|
take: config.isPaginated ? take : LOCAL_PAGE_SIZE_SOURCE,
|
|
365
775
|
};
|
|
366
776
|
}
|
|
367
|
-
|
|
777
|
+
createTableRequestSignature(config, query) {
|
|
368
778
|
return [
|
|
779
|
+
config.type,
|
|
780
|
+
config.areaType,
|
|
369
781
|
config.levelId,
|
|
370
782
|
config.levelDataId,
|
|
371
783
|
config.moduleId,
|
|
@@ -375,20 +787,53 @@ class ClientList {
|
|
|
375
787
|
...(query.columnKeys ?? []),
|
|
376
788
|
].join('|');
|
|
377
789
|
}
|
|
790
|
+
createCardsRequestSignature(config) {
|
|
791
|
+
return [
|
|
792
|
+
config.type,
|
|
793
|
+
config.areaType,
|
|
794
|
+
config.levelDataId,
|
|
795
|
+
config.moduleId,
|
|
796
|
+
'card',
|
|
797
|
+
].join('|');
|
|
798
|
+
}
|
|
799
|
+
createInformativeRequestSignature(config) {
|
|
800
|
+
return [config.type, config.moduleId, 'dashboard'].join('|');
|
|
801
|
+
}
|
|
378
802
|
hasValidIdentifiers(config) {
|
|
803
|
+
if (config.type === 'informative') {
|
|
804
|
+
return Number.isFinite(config.moduleId) && config.moduleId > 0;
|
|
805
|
+
}
|
|
806
|
+
const hasLevelDataId = Number.isFinite(config.levelDataId) && config.levelDataId > 0;
|
|
807
|
+
const hasModuleId = Number.isFinite(config.moduleId) && config.moduleId > 0;
|
|
808
|
+
if (config.areaType === 'cards') {
|
|
809
|
+
return hasLevelDataId && hasModuleId;
|
|
810
|
+
}
|
|
379
811
|
return (Number.isFinite(config.levelId) &&
|
|
380
812
|
config.levelId > 0 &&
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
813
|
+
hasLevelDataId &&
|
|
814
|
+
hasModuleId);
|
|
815
|
+
}
|
|
816
|
+
getMissingIdentifiersMessage(config) {
|
|
817
|
+
if (config.type === 'informative') {
|
|
818
|
+
return 'Missing identifiers: moduleId is required';
|
|
819
|
+
}
|
|
820
|
+
if (config.areaType === 'cards') {
|
|
821
|
+
return 'Missing identifiers: levelDataId and moduleId are required';
|
|
822
|
+
}
|
|
823
|
+
return 'Missing identifiers: levelId, levelDataId and moduleId are required';
|
|
385
824
|
}
|
|
386
825
|
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 (
|
|
826
|
+
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 (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"], 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
827
|
}
|
|
389
828
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: ClientList, decorators: [{
|
|
390
829
|
type: Component,
|
|
391
|
-
args: [{ selector: 'mt-client-list', standalone: true, imports: [
|
|
830
|
+
args: [{ selector: 'mt-client-list', standalone: true, imports: [
|
|
831
|
+
CommonModule,
|
|
832
|
+
Button,
|
|
833
|
+
ClientListTableView,
|
|
834
|
+
ClientListCardsView,
|
|
835
|
+
ClientListInformativeView,
|
|
836
|
+
], 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 (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
837
|
}], 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
838
|
|
|
394
839
|
/**
|