@mintplayer/ng-spark 22.1.0 → 22.3.0
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/mintplayer-ng-spark-client-operations.mjs +69 -4
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +111 -0
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-models.mjs +112 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +2 -2
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +211 -54
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +2 -2
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +88 -46
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/package.json +5 -1
- package/types/mintplayer-ng-spark-client-operations.d.ts +30 -4
- package/types/mintplayer-ng-spark-grid.d.ts +63 -0
- package/types/mintplayer-ng-spark-models.d.ts +56 -2
- package/types/mintplayer-ng-spark-po-detail.d.ts +112 -3
- package/types/mintplayer-ng-spark-query-list.d.ts +37 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DestroyRef, input, output, signal, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { inject, DestroyRef, input, output, signal, effect, untracked, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
4
|
import * as i1 from '@angular/common';
|
|
5
5
|
import { CommonModule, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';
|
|
@@ -15,11 +15,12 @@ import { BsGridComponent, BsGridRowDirective, BsGridColumnDirective } from '@min
|
|
|
15
15
|
import { BsInputGroupComponent } from '@mintplayer/ng-bootstrap/input-group';
|
|
16
16
|
import { BsPriorityNavComponent, BsPriorityNavItemDirective } from '@mintplayer/ng-bootstrap/priority-nav';
|
|
17
17
|
import { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';
|
|
18
|
+
import { filterQueryActions, selectionModeFor, parseSelectionRule } from '@mintplayer/ng-spark/models';
|
|
19
|
+
import { SparkQueryRefreshService } from '@mintplayer/ng-spark/client-operations';
|
|
18
20
|
import { SparkService, SparkStreamingService, SparkLanguageService } from '@mintplayer/ng-spark/services';
|
|
19
21
|
import { ResolveTranslationPipe, TranslateKeyPipe, AttributeValuePipe, ReferenceChipsPipe } from '@mintplayer/ng-spark/pipes';
|
|
20
22
|
import { SparkIconComponent } from '@mintplayer/ng-spark/icon';
|
|
21
|
-
import {
|
|
22
|
-
import { hasShowedOnFlag, ShowedOn } from '@mintplayer/ng-spark/models';
|
|
23
|
+
import { SparkGridRenderers, initialGridSettings, isVirtualScrollingQuery, visibleGridAttributes } from '@mintplayer/ng-spark/grid';
|
|
23
24
|
|
|
24
25
|
class SparkQueryListComponent {
|
|
25
26
|
route = inject(ActivatedRoute);
|
|
@@ -27,7 +28,7 @@ class SparkQueryListComponent {
|
|
|
27
28
|
sparkService = inject(SparkService);
|
|
28
29
|
streamingService = inject(SparkStreamingService);
|
|
29
30
|
lang = inject(SparkLanguageService);
|
|
30
|
-
|
|
31
|
+
gridRenderers = inject(SparkGridRenderers);
|
|
31
32
|
destroyRef = inject(DestroyRef);
|
|
32
33
|
extraActionsTemplate = input(null, /* @ts-ignore */
|
|
33
34
|
...(ngDevMode ? [{ debugName: "extraActionsTemplate" }] : /* istanbul ignore next */ []));
|
|
@@ -72,8 +73,25 @@ class SparkQueryListComponent {
|
|
|
72
73
|
}), /* @ts-ignore */
|
|
73
74
|
...(ngDevMode ? [{ debugName: "settings" }] : /* istanbul ignore next */ []));
|
|
74
75
|
constructor() {
|
|
75
|
-
this
|
|
76
|
+
// The handler is async and this is a subscribe, so a rejection lands nowhere:
|
|
77
|
+
// the metadata load would reject, entityType() would stay null, and the template
|
|
78
|
+
// would render a spinner FOREVER -- while this component has had an errorMessage
|
|
79
|
+
// surface all along that only the fetch path ever reached. Catch it here.
|
|
80
|
+
this.route.paramMap.pipe(takeUntilDestroyed()).subscribe(params => {
|
|
81
|
+
this.onParamsChange(params).catch((e) => this.reportLoadFailure(e));
|
|
82
|
+
});
|
|
76
83
|
this.destroyRef.onDestroy(() => this.disconnectStreaming());
|
|
84
|
+
// Server-issued refreshQuery. Its own effect, skipping the first run, so it drives the
|
|
85
|
+
// cheap data refresh and never re-resolves metadata (which would reset page and sort).
|
|
86
|
+
let firstRefreshTick = true;
|
|
87
|
+
effect(() => {
|
|
88
|
+
this.queryRefresh.tokenFor(this.query()?.alias || this.query()?.id);
|
|
89
|
+
if (firstRefreshTick) {
|
|
90
|
+
firstRefreshTick = false;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
untracked(() => this.reload());
|
|
94
|
+
});
|
|
77
95
|
}
|
|
78
96
|
async onParamsChange(params) {
|
|
79
97
|
// Reset prior-route state so we render the spinner (not stale rows from
|
|
@@ -83,6 +101,15 @@ class SparkQueryListComponent {
|
|
|
83
101
|
this.resultCount.set(null);
|
|
84
102
|
this.allItems.set([]);
|
|
85
103
|
this.streamItems.set([]);
|
|
104
|
+
this.errorMessage.set(null);
|
|
105
|
+
// Reset the permission-derived state too. Without this, navigating A -> B where
|
|
106
|
+
// B's load fails leaves A's buttons and A's canRead/canCreate on screen.
|
|
107
|
+
this.canRead.set(false);
|
|
108
|
+
this.canCreate.set(false);
|
|
109
|
+
this.customActions.set([]);
|
|
110
|
+
// Ids from the previous query are meaningless against the next one, and would be POSTed
|
|
111
|
+
// as though they belonged to it.
|
|
112
|
+
this.selection.set([]);
|
|
86
113
|
this.disconnectStreaming();
|
|
87
114
|
const queryId = params.get('queryId');
|
|
88
115
|
const typeParam = params.get('type');
|
|
@@ -121,15 +148,7 @@ class SparkQueryListComponent {
|
|
|
121
148
|
if (resolvedEntityType) {
|
|
122
149
|
this.entityType.set(resolvedEntityType);
|
|
123
150
|
this.allEntityTypes.set(resolvedEntityTypes);
|
|
124
|
-
|
|
125
|
-
property: sc.property,
|
|
126
|
-
direction: sc.direction === 'desc' ? 'descending' : 'ascending'
|
|
127
|
-
}));
|
|
128
|
-
this.settings.set(new DatatableSettings({
|
|
129
|
-
perPage: { values: [10, 25, 50], selected: 10 },
|
|
130
|
-
page: { values: [1], selected: 1 },
|
|
131
|
-
sortColumns: initialSortColumns
|
|
132
|
-
}));
|
|
151
|
+
this.settings.set(initialGridSettings(resolvedQuery));
|
|
133
152
|
if (resolvedQuery?.isStreamingQuery) {
|
|
134
153
|
// Streaming: WebSocket feeds allItems; the datatable binds [data]="streamItems()".
|
|
135
154
|
this.connectStreaming(resolvedQuery.id);
|
|
@@ -147,9 +166,22 @@ class SparkQueryListComponent {
|
|
|
147
166
|
]);
|
|
148
167
|
this.canRead.set(permissions.canRead);
|
|
149
168
|
this.canCreate.set(permissions.canCreate);
|
|
150
|
-
|
|
169
|
+
// 'query', not 'list'. The server model and docs/guide-custom-actions.md have
|
|
170
|
+
// always documented "detail" | "query" | "both"; this filter tested for a value
|
|
171
|
+
// nothing emits, so an action authored per the documentation rendered NOWHERE.
|
|
172
|
+
this.customActions.set(filterQueryActions(actions));
|
|
151
173
|
}
|
|
152
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* A load failure has to render, not just be swallowed: a denied query answers 404
|
|
177
|
+
* (audit M-3, so existence is not leaked), which is indistinguishable from a missing
|
|
178
|
+
* one -- hence a deliberately generic message rather than a guess at which it was.
|
|
179
|
+
*/
|
|
180
|
+
reportLoadFailure(err) {
|
|
181
|
+
this.errorMessage.set(err?.status === 404
|
|
182
|
+
? (this.lang.t('spark.query.unavailable') || 'This list is not available.')
|
|
183
|
+
: (err?.error?.error || err?.message || 'An unexpected error occurred'));
|
|
184
|
+
}
|
|
153
185
|
async onCustomAction(action) {
|
|
154
186
|
if (action.confirmationMessageKey) {
|
|
155
187
|
const message = this.lang.t(action.confirmationMessageKey) || 'Are you sure?';
|
|
@@ -157,10 +189,10 @@ class SparkQueryListComponent {
|
|
|
157
189
|
return;
|
|
158
190
|
}
|
|
159
191
|
try {
|
|
160
|
-
await this.sparkService.executeCustomAction(this.entityType().id, action.name);
|
|
192
|
+
await this.sparkService.executeCustomAction(this.entityType().id, action.name, undefined, this.selection());
|
|
161
193
|
this.customActionExecuted.emit({ action });
|
|
162
194
|
if (action.refreshOnCompleted) {
|
|
163
|
-
this.
|
|
195
|
+
this.reload();
|
|
164
196
|
}
|
|
165
197
|
}
|
|
166
198
|
catch (e) {
|
|
@@ -234,8 +266,14 @@ class SparkQueryListComponent {
|
|
|
234
266
|
return { data: [], totalRecords: 0, totalPages: 1, perPage: req.perPage, page: req.page };
|
|
235
267
|
});
|
|
236
268
|
}
|
|
237
|
-
/**
|
|
238
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Force a refetch (e.g. after a custom action) without changing page/sort.
|
|
271
|
+
*
|
|
272
|
+
* Public so a host can drive it, and named to match
|
|
273
|
+
* `SparkSubQueryComponent.reload()` — the two grids had drifted into having the
|
|
274
|
+
* same mechanism under different names, one of them unreachable.
|
|
275
|
+
*/
|
|
276
|
+
reload() {
|
|
239
277
|
if (this.isStreaming()) {
|
|
240
278
|
this.applyFilter();
|
|
241
279
|
return;
|
|
@@ -269,38 +307,42 @@ class SparkQueryListComponent {
|
|
|
269
307
|
this.searchTerm = '';
|
|
270
308
|
this.onSearchChange();
|
|
271
309
|
}
|
|
272
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Whether the first column links to a detail page.
|
|
312
|
+
*
|
|
313
|
+
* Declared by the query, because the framework cannot derive it: `Database.*` rows
|
|
314
|
+
* are always real documents, but a `Custom.*` query may return loadable documents
|
|
315
|
+
* (Fleet's Stolen_Cars) or rows fabricated in memory (StreamItems). Absent means
|
|
316
|
+
* navigable -- defaulting Custom.* to false would strip the working links off every
|
|
317
|
+
* custom query that does return documents.
|
|
318
|
+
*/
|
|
319
|
+
/**
|
|
320
|
+
* Rows the user has ticked. Lives here rather than in the datatable so the action bar can
|
|
321
|
+
* read it, and MUST be cleared whenever the source changes — otherwise route A's selection
|
|
322
|
+
* is POSTed as ids of route B's type.
|
|
323
|
+
*/
|
|
324
|
+
selection = signal([], /* @ts-ignore */
|
|
325
|
+
...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
|
|
326
|
+
queryRefresh = inject(SparkQueryRefreshService);
|
|
327
|
+
/** 'none' unless an action is selection-gated, so unaffected grids gain no checkbox column. */
|
|
328
|
+
selectionMode = computed(() => selectionModeFor(this.customActions()), /* @ts-ignore */
|
|
329
|
+
...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
|
|
330
|
+
/** Whether an action's selection rule is satisfied right now. The server checks it again. */
|
|
331
|
+
isActionEnabled(action) {
|
|
332
|
+
return parseSelectionRule(action.selectionRule)(this.selection().length);
|
|
333
|
+
}
|
|
334
|
+
isVirtualScrolling = computed(() => isVirtualScrollingQuery(this.query()), /* @ts-ignore */
|
|
273
335
|
...(ngDevMode ? [{ debugName: "isVirtualScrolling" }] : /* istanbul ignore next */ []));
|
|
274
|
-
visibleAttributes = computed(() =>
|
|
275
|
-
return this.entityType()?.attributes
|
|
276
|
-
.filter(a => a.isVisible && hasShowedOnFlag(a.showedOn, ShowedOn.Query))
|
|
277
|
-
.sort((a, b) => a.order - b.order) || [];
|
|
278
|
-
}, /* @ts-ignore */
|
|
336
|
+
visibleAttributes = computed(() => visibleGridAttributes(this.entityType()), /* @ts-ignore */
|
|
279
337
|
...(ngDevMode ? [{ debugName: "visibleAttributes" }] : /* istanbul ignore next */ []));
|
|
280
338
|
getColumnRendererComponent(attr) {
|
|
281
|
-
|
|
282
|
-
return null;
|
|
283
|
-
return this.rendererRegistry.find(r => r.name === attr.renderer)?.columnComponent ?? null;
|
|
339
|
+
return this.gridRenderers.columnComponentFor(attr);
|
|
284
340
|
}
|
|
285
341
|
getColumnRendererInputs(component, item, attr) {
|
|
286
|
-
|
|
287
|
-
return withDeclaredInputs(component, {
|
|
288
|
-
value: rendererValue(itemAttr),
|
|
289
|
-
attribute: attr,
|
|
290
|
-
options: attr.rendererOptions,
|
|
291
|
-
item,
|
|
292
|
-
});
|
|
342
|
+
return this.gridRenderers.columnInputsFor(component, item, attr);
|
|
293
343
|
}
|
|
294
344
|
async loadLookupReferenceOptions() {
|
|
295
|
-
|
|
296
|
-
if (lookupAttrs.length === 0)
|
|
297
|
-
return;
|
|
298
|
-
const lookupNames = [...new Set(lookupAttrs.map(a => a.lookupReferenceType))];
|
|
299
|
-
const entries = await Promise.all(lookupNames.map(async (name) => {
|
|
300
|
-
const result = await this.sparkService.getLookupReference(name);
|
|
301
|
-
return [name, result];
|
|
302
|
-
}));
|
|
303
|
-
this.lookupReferenceOptions.set(entries.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}));
|
|
345
|
+
this.lookupReferenceOptions.set(await this.gridRenderers.loadLookupOptions(this.visibleAttributes()));
|
|
304
346
|
}
|
|
305
347
|
onCreate() {
|
|
306
348
|
this.createClicked.emit();
|
|
@@ -388,13 +430,13 @@ class SparkQueryListComponent {
|
|
|
388
430
|
this.resultCount.set(items.length);
|
|
389
431
|
}
|
|
390
432
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkQueryListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
391
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: SparkQueryListComponent, isStandalone: true, selector: "spark-query-list", inputs: { extraActionsTemplate: { classPropertyName: "extraActionsTemplate", publicName: "extraActionsTemplate", isSignal: true, isRequired: false, transformFunction: null }, showCustomActions: { classPropertyName: "showCustomActions", publicName: "showCustomActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClicked: "rowClicked", createClicked: "createClicked", customActionExecuted: "customActionExecuted" }, host: { properties: { "class.virtual-scrolling": "isVirtualScrolling()" } }, ngImport: i0, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n </ng-container>\n </bs-datatable>\n } @else {\n <bs-datatable class=\"flex-grow-1\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [fetch]=\"fetchFn()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n </ng-container>\n </bs-datatable>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n\n<ng-template #cellContent let-item let-attr=\"attr\">\n @if (getColumnRendererComponent(attr); as rendererType) {\n <ng-container *ngComponentOutlet=\"rendererType; inputs: getColumnRendererInputs(rendererType, item, attr)\"></ng-container>\n } @else if (attr.dataType === 'boolean') {\n <input type=\"checkbox\"\n [checked]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) === true\"\n [indeterminate]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) == null\"\n disabled\n onclick=\"return false;\">\n } @else if (attr.dataType === 'color') {\n @let colorVal = (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes());\n @if (colorVal) {\n <span class=\"d-inline-block align-middle border rounded\" [style.background-color]=\"colorVal\" style=\"width: 1.5em; height: 1.5em;\"></span>\n }\n } @else if (attr.dataType === 'Reference' && attr.isArray) {\n <span class=\"d-inline-flex flex-wrap gap-1\">\n @for (chip of (attr.name | referenceChips:item); track chip.id) {\n <span class=\"badge rounded-pill border bg-body-secondary text-body px-3 py-2\">{{ chip.label }}</span>\n }\n </span>\n } @else {\n {{ (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) }}\n }\n</ng-template>\n", styles: [".spark-actionbar{position:sticky;top:0;z-index:400;background-color:var(--bs-tertiary-bg);border-bottom:1px solid var(--bs-border-color);margin-bottom:1rem}.spark-actionbar .btn{border-radius:0}:host{display:flex;flex-direction:column;flex:1;min-height:0}:host.virtual-scrolling{margin:0 -1.5rem -1.5rem}:host.virtual-scrolling ::ng-deep bs-datatable{display:flex;flex-direction:column;min-height:0;--mp-datatable-virtual-max-height: 100%}:host.virtual-scrolling ::ng-deep bs-datatable mp-datatable{flex:1 1 auto;min-height:0}tr:hover{background-color:#0000000d}td input[type=checkbox]:disabled{opacity:1;pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: BsAlertComponent, selector: "bs-alert", inputs: ["type", "announce", "isVisible"], outputs: ["isVisibleChange", "afterOpenedOrClosed"] }, { kind: "component", type: BsDatatableComponent, selector: "bs-datatable", inputs: ["columns", "data", "fetch", "settings", "selectionMode", "selectable", "selection", "rowKey", "resizableColumns", "pagination", "virtualScroll", "itemSize", "virtualBuffer", "isResponsive", "compareWith", "tree", "idKey", "childCountKey", "treeIndent", "expandedIds", "selectionStrategy"], outputs: ["settingsChange", "selectionChange", "rowClick", "rowDblClick", "rowContextMenu", "expandedIdsChange", "rowExpand", "rowCollapse"] }, { kind: "directive", type: BsDatatableColumnDirective, selector: "[bsDatatableColumn]", inputs: ["bsDatatableColumn", "bsDatatableColumnSortable"] }, { kind: "directive", type: BsRowTemplateDirective, selector: "[bsRowTemplate]" }, { kind: "component", type: BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "component", type: BsGridComponent, selector: "bs-grid", inputs: ["stopFullWidthAt"] }, { kind: "directive", type: BsGridRowDirective, selector: "[bsRow]" }, { kind: "directive", type: BsGridColumnDirective, selector: "[xxs],[xs],[sm],[md],[lg],[xl],[xxl]", inputs: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"] }, { kind: "component", type: BsInputGroupComponent, selector: "bs-input-group", inputs: ["size"] }, { kind: "component", type: BsPriorityNavComponent, selector: "bs-priority-nav", inputs: ["moreLabel", "moreLabelTemplate", "collapseAt", "overflowFrom", "hideEmptyMore", "ariaLabel"], outputs: ["overflowChange"] }, { kind: "directive", type: BsPriorityNavItemDirective, selector: "[bsPriorityNavItem]", inputs: ["bsPriorityNavItem", "bsPriorityNavItemHideBelow"] }, { kind: "component", type: BsSpinnerComponent, selector: "bs-spinner", inputs: ["type", "color"] }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }, { kind: "pipe", type: AttributeValuePipe, name: "attributeValue" }, { kind: "pipe", type: ReferenceChipsPipe, name: "referenceChips" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
433
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: SparkQueryListComponent, isStandalone: true, selector: "spark-query-list", inputs: { extraActionsTemplate: { classPropertyName: "extraActionsTemplate", publicName: "extraActionsTemplate", isSignal: true, isRequired: false, transformFunction: null }, showCustomActions: { classPropertyName: "showCustomActions", publicName: "showCustomActions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClicked: "rowClicked", createClicked: "createClicked", customActionExecuted: "customActionExecuted" }, host: { properties: { "class.virtual-scrolling": "isVirtualScrolling()" } }, ngImport: i0, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <!-- Disabled, not hidden: hiding makes the affordance undiscoverable and reflows the\n priority nav on every selection change. The server enforces the same rule. -->\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\"\n [disabled]=\"!isActionEnabled(action)\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n } @else {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [fetch]=\"fetchFn()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n }\n } @else if (errorMessage(); as err) {\n <!-- The metadata load failed. This used to be unreachable: the rejection was\n swallowed by an async subscribe handler, so the spinner below span forever. -->\n <bs-alert [type]=\"colors.danger\" class=\"m-3 d-block\">\n {{ err }}\n </bs-alert>\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n\n<!--\n One row template for both the streaming and the paged datatable. These were two\n byte-identical copies in the same file, which is how the first column's link came to\n need fixing in three places instead of one.\n-->\n<ng-template #rowCells let-item>\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n <!-- `canRead()` is the whole gate, and it is the rights model: `Query` without\n `Read` lists the rows and withholds the link. Withhold `Read` for a query\n whose rows no detail page can load \u2014 a Custom.* query that fabricates rows\n in memory, say. Note cellContent renders INSIDE this anchor, so a custom\n renderer cannot suppress the link \u2014 it would nest a second one. -->\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n</ng-template>\n\n<ng-template #cellContent let-item let-attr=\"attr\">\n @if (getColumnRendererComponent(attr); as rendererType) {\n <ng-container *ngComponentOutlet=\"rendererType; inputs: getColumnRendererInputs(rendererType, item, attr)\"></ng-container>\n } @else if (attr.dataType === 'boolean') {\n <input type=\"checkbox\"\n [checked]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) === true\"\n [indeterminate]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) == null\"\n disabled\n onclick=\"return false;\">\n } @else if (attr.dataType === 'color') {\n @let colorVal = (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes());\n @if (colorVal) {\n <span class=\"d-inline-block align-middle border rounded\" [style.background-color]=\"colorVal\" style=\"width: 1.5em; height: 1.5em;\"></span>\n }\n } @else if (attr.dataType === 'Reference' && attr.isArray) {\n <span class=\"d-inline-flex flex-wrap gap-1\">\n @for (chip of (attr.name | referenceChips:item); track chip.id) {\n <span class=\"badge rounded-pill border bg-body-secondary text-body px-3 py-2\">{{ chip.label }}</span>\n }\n </span>\n } @else {\n {{ (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) }}\n }\n</ng-template>\n", styles: [".spark-actionbar{position:sticky;top:0;z-index:400;background-color:var(--bs-tertiary-bg);border-bottom:1px solid var(--bs-border-color);margin-bottom:1rem}.spark-actionbar .btn{border-radius:0}:host{display:flex;flex-direction:column;flex:1;min-height:0}:host.virtual-scrolling{margin:0 -1.5rem -1.5rem}:host.virtual-scrolling ::ng-deep bs-datatable{display:flex;flex-direction:column;min-height:0;--mp-datatable-virtual-max-height: 100%}:host.virtual-scrolling ::ng-deep bs-datatable mp-datatable{flex:1 1 auto;min-height:0}tr:hover{background-color:#0000000d}td input[type=checkbox]:disabled{opacity:1;pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: BsAlertComponent, selector: "bs-alert", inputs: ["type", "announce", "isVisible"], outputs: ["isVisibleChange", "afterOpenedOrClosed"] }, { kind: "component", type: BsDatatableComponent, selector: "bs-datatable", inputs: ["columns", "data", "fetch", "settings", "selectionMode", "selectable", "selection", "rowKey", "resizableColumns", "pagination", "virtualScroll", "itemSize", "virtualBuffer", "isResponsive", "compareWith", "tree", "idKey", "childCountKey", "treeIndent", "expandedIds", "selectionStrategy"], outputs: ["settingsChange", "selectionChange", "rowClick", "rowDblClick", "rowContextMenu", "expandedIdsChange", "rowExpand", "rowCollapse"] }, { kind: "directive", type: BsDatatableColumnDirective, selector: "[bsDatatableColumn]", inputs: ["bsDatatableColumn", "bsDatatableColumnSortable"] }, { kind: "directive", type: BsRowTemplateDirective, selector: "[bsRowTemplate]" }, { kind: "component", type: BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "component", type: BsGridComponent, selector: "bs-grid", inputs: ["stopFullWidthAt"] }, { kind: "directive", type: BsGridRowDirective, selector: "[bsRow]" }, { kind: "directive", type: BsGridColumnDirective, selector: "[xxs],[xs],[sm],[md],[lg],[xl],[xxl]", inputs: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"] }, { kind: "component", type: BsInputGroupComponent, selector: "bs-input-group", inputs: ["size"] }, { kind: "component", type: BsPriorityNavComponent, selector: "bs-priority-nav", inputs: ["moreLabel", "moreLabelTemplate", "collapseAt", "overflowFrom", "hideEmptyMore", "ariaLabel"], outputs: ["overflowChange"] }, { kind: "directive", type: BsPriorityNavItemDirective, selector: "[bsPriorityNavItem]", inputs: ["bsPriorityNavItem", "bsPriorityNavItemHideBelow"] }, { kind: "component", type: BsSpinnerComponent, selector: "bs-spinner", inputs: ["type", "color"] }, { kind: "component", type: SparkIconComponent, selector: "spark-icon", inputs: ["name"] }, { kind: "pipe", type: ResolveTranslationPipe, name: "resolveTranslation" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }, { kind: "pipe", type: AttributeValuePipe, name: "attributeValue" }, { kind: "pipe", type: ReferenceChipsPipe, name: "referenceChips" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
392
434
|
}
|
|
393
435
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: SparkQueryListComponent, decorators: [{
|
|
394
436
|
type: Component,
|
|
395
437
|
args: [{ selector: 'spark-query-list', imports: [CommonModule, NgTemplateOutlet, NgComponentOutlet, FormsModule, RouterModule, BsAlertComponent, BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, BsFormComponent, BsFormControlDirective, BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsInputGroupComponent, BsPriorityNavComponent, BsPriorityNavItemDirective, BsSpinnerComponent, SparkIconComponent, ResolveTranslationPipe, TranslateKeyPipe, AttributeValuePipe, ReferenceChipsPipe], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
396
438
|
'[class.virtual-scrolling]': 'isVirtualScrolling()'
|
|
397
|
-
}, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n
|
|
439
|
+
}, template: "<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <!-- Disabled, not hidden: hiding makes the affordance undiscoverable and reflows the\n priority nav on every selection change. The server enforces the same rule. -->\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\"\n [disabled]=\"!isActionEnabled(action)\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n } @else {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [fetch]=\"fetchFn()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n }\n } @else if (errorMessage(); as err) {\n <!-- The metadata load failed. This used to be unreachable: the rejection was\n swallowed by an async subscribe handler, so the spinner below span forever. -->\n <bs-alert [type]=\"colors.danger\" class=\"m-3 d-block\">\n {{ err }}\n </bs-alert>\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n\n<!--\n One row template for both the streaming and the paged datatable. These were two\n byte-identical copies in the same file, which is how the first column's link came to\n need fixing in three places instead of one.\n-->\n<ng-template #rowCells let-item>\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n <!-- `canRead()` is the whole gate, and it is the rights model: `Query` without\n `Read` lists the rows and withholds the link. Withhold `Read` for a query\n whose rows no detail page can load \u2014 a Custom.* query that fabricates rows\n in memory, say. Note cellContent renders INSIDE this anchor, so a custom\n renderer cannot suppress the link \u2014 it would nest a second one. -->\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n</ng-template>\n\n<ng-template #cellContent let-item let-attr=\"attr\">\n @if (getColumnRendererComponent(attr); as rendererType) {\n <ng-container *ngComponentOutlet=\"rendererType; inputs: getColumnRendererInputs(rendererType, item, attr)\"></ng-container>\n } @else if (attr.dataType === 'boolean') {\n <input type=\"checkbox\"\n [checked]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) === true\"\n [indeterminate]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) == null\"\n disabled\n onclick=\"return false;\">\n } @else if (attr.dataType === 'color') {\n @let colorVal = (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes());\n @if (colorVal) {\n <span class=\"d-inline-block align-middle border rounded\" [style.background-color]=\"colorVal\" style=\"width: 1.5em; height: 1.5em;\"></span>\n }\n } @else if (attr.dataType === 'Reference' && attr.isArray) {\n <span class=\"d-inline-flex flex-wrap gap-1\">\n @for (chip of (attr.name | referenceChips:item); track chip.id) {\n <span class=\"badge rounded-pill border bg-body-secondary text-body px-3 py-2\">{{ chip.label }}</span>\n }\n </span>\n } @else {\n {{ (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) }}\n }\n</ng-template>\n", styles: [".spark-actionbar{position:sticky;top:0;z-index:400;background-color:var(--bs-tertiary-bg);border-bottom:1px solid var(--bs-border-color);margin-bottom:1rem}.spark-actionbar .btn{border-radius:0}:host{display:flex;flex-direction:column;flex:1;min-height:0}:host.virtual-scrolling{margin:0 -1.5rem -1.5rem}:host.virtual-scrolling ::ng-deep bs-datatable{display:flex;flex-direction:column;min-height:0;--mp-datatable-virtual-max-height: 100%}:host.virtual-scrolling ::ng-deep bs-datatable mp-datatable{flex:1 1 auto;min-height:0}tr:hover{background-color:#0000000d}td input[type=checkbox]:disabled{opacity:1;pointer-events:none}\n"] }]
|
|
398
440
|
}], ctorParameters: () => [], propDecorators: { extraActionsTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraActionsTemplate", required: false }] }], showCustomActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCustomActions", required: false }] }], rowClicked: [{ type: i0.Output, args: ["rowClicked"] }], createClicked: [{ type: i0.Output, args: ["createClicked"] }], customActionExecuted: [{ type: i0.Output, args: ["customActionExecuted"] }] } });
|
|
399
441
|
|
|
400
442
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mintplayer-ng-spark-query-list.mjs","sources":["../../query-list/src/spark-query-list.component.ts","../../query-list/src/spark-query-list.component.html","../../query-list/mintplayer-ng-spark-query-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, DestroyRef, inject, input, output, signal, TemplateRef, Type } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subscription } from 'rxjs';\nimport { CommonModule, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute, Router, RouterModule } from '@angular/router';\nimport { Color } from '@mintplayer/ng-bootstrap';\nimport { BsAlertComponent } from '@mintplayer/ng-bootstrap/alert';\nimport { BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, DatatableSettings, type BsDatatableFetch } from '@mintplayer/ng-bootstrap/datatable';\nimport { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';\nimport { BsGridComponent, BsGridRowDirective, BsGridColumnDirective } from '@mintplayer/ng-bootstrap/grid';\nimport { BsInputGroupComponent } from '@mintplayer/ng-bootstrap/input-group';\nimport { BsPriorityNavComponent, BsPriorityNavItemDirective } from '@mintplayer/ng-bootstrap/priority-nav';\nimport { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { SortColumn } from '@mintplayer/pagination';\nimport { SparkService, SparkStreamingService, SparkLanguageService } from '@mintplayer/ng-spark/services';\nimport {\n TranslateKeyPipe,\n ResolveTranslationPipe,\n AttributeValuePipe,\n ReferenceChipsPipe,\n} from '@mintplayer/ng-spark/pipes';\nimport { SparkIconComponent } from '@mintplayer/ng-spark/icon';\nimport { SPARK_ATTRIBUTE_RENDERERS, rendererValue, withDeclaredInputs } from '@mintplayer/ng-spark/renderers';\nimport {\n CustomActionDefinition,\n StreamingMessage,\n EntityType,\n EntityAttributeDefinition,\n LookupReference,\n PersistentObject,\n SparkQuery,\n ShowedOn,\n hasShowedOnFlag,\n} from '@mintplayer/ng-spark/models';\n\n@Component({\n selector: 'spark-query-list',\n imports: [CommonModule, NgTemplateOutlet, NgComponentOutlet, FormsModule, RouterModule, BsAlertComponent, BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, BsFormComponent, BsFormControlDirective, BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsInputGroupComponent, BsPriorityNavComponent, BsPriorityNavItemDirective, BsSpinnerComponent, SparkIconComponent, ResolveTranslationPipe, TranslateKeyPipe, AttributeValuePipe, ReferenceChipsPipe],\n templateUrl: './spark-query-list.component.html',\n styleUrl: './spark-query-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.virtual-scrolling]': 'isVirtualScrolling()'\n }\n})\nexport class SparkQueryListComponent {\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly sparkService = inject(SparkService);\n private readonly streamingService = inject(SparkStreamingService);\n protected readonly lang = inject(SparkLanguageService);\n private readonly rendererRegistry = inject(SPARK_ATTRIBUTE_RENDERERS);\n private readonly destroyRef = inject(DestroyRef);\n\n extraActionsTemplate = input<TemplateRef<void> | null>(null);\n showCustomActions = input(true);\n\n rowClicked = output<PersistentObject>();\n createClicked = output<void>();\n customActionExecuted = output<{ action: CustomActionDefinition }>();\n\n colors = Color;\n errorMessage = signal<string | null>(null);\n query = signal<SparkQuery | null>(null);\n entityType = signal<EntityType | null>(null);\n allEntityTypes = signal<EntityType[]>([]);\n lookupReferenceOptions = signal<Record<string, LookupReference>>({});\n resultCount = signal<number | null>(null);\n searchTerm: string = '';\n canRead = signal(false);\n canCreate = signal(false);\n customActions = signal<CustomActionDefinition[]>([]);\n isStreaming = signal(false);\n private streamingSub: Subscription | null = null;\n private allItems = signal<PersistentObject[]>([]);\n streamItems = signal<PersistentObject[]>([]);\n fetchFn = signal<BsDatatableFetch<PersistentObject> | null>(null);\n settings = signal(new DatatableSettings({\n perPage: { values: [10, 25, 50], selected: 10 },\n page: { values: [1], selected: 1 },\n sortColumns: []\n }));\n\n constructor() {\n this.route.paramMap.pipe(takeUntilDestroyed()).subscribe(params => this.onParamsChange(params));\n this.destroyRef.onDestroy(() => this.disconnectStreaming());\n }\n\n private async onParamsChange(params: any): Promise<void> {\n // Reset prior-route state so we render the spinner (not stale rows from\n // the previous query) while the new query/entityType resolve.\n this.entityType.set(null);\n this.fetchFn.set(null);\n this.resultCount.set(null);\n this.allItems.set([]);\n this.streamItems.set([]);\n this.disconnectStreaming();\n\n const queryId = params.get('queryId');\n const typeParam = params.get('type');\n\n let resolvedQuery: SparkQuery | null = null;\n let resolvedEntityType: EntityType | null = null;\n let resolvedEntityTypes: EntityType[] = [];\n\n if (queryId) {\n resolvedQuery = await this.sparkService.getQuery(queryId);\n if (resolvedQuery) {\n const result = await this.resolveEntityTypeForQuery(resolvedQuery);\n resolvedEntityType = result.entityType;\n resolvedEntityTypes = result.entityTypes;\n }\n } else if (typeParam) {\n resolvedEntityTypes = await this.sparkService.getEntityTypes();\n resolvedEntityType = resolvedEntityTypes.find(t =>\n t.id === typeParam || t.alias === typeParam\n ) || null;\n\n if (resolvedEntityType) {\n const queries = await this.sparkService.getQueries();\n const singularName = resolvedEntityType.name;\n resolvedQuery = queries.find(q => {\n // Match by explicit entityType\n if (q.entityType === singularName) return true;\n // Match by source name\n const sourceName = this.extractSourceName(q.source);\n const sourceSingular = this.singularize(sourceName);\n return sourceName === singularName ||\n sourceSingular === singularName ||\n sourceName === singularName + 's';\n }) || null;\n }\n }\n\n if (resolvedQuery) this.query.set(resolvedQuery);\n\n if (resolvedEntityType) {\n this.entityType.set(resolvedEntityType);\n this.allEntityTypes.set(resolvedEntityTypes);\n\n const initialSortColumns: SortColumn[] = (resolvedQuery?.sortColumns || []).map(sc => ({\n property: sc.property,\n direction: sc.direction === 'desc' ? 'descending' as const : 'ascending' as const\n }));\n\n this.settings.set(new DatatableSettings({\n perPage: { values: [10, 25, 50], selected: 10 },\n page: { values: [1], selected: 1 },\n sortColumns: initialSortColumns\n }));\n\n if (resolvedQuery?.isStreamingQuery) {\n // Streaming: WebSocket feeds allItems; the datatable binds [data]=\"streamItems()\".\n this.connectStreaming(resolvedQuery.id);\n } else if (resolvedQuery) {\n // Non-streaming: the datatable drives paging/sorting via [(settings)] and calls\n // fetchFn per page. Virtual scrolling is just the [virtualScroll] template flag —\n // the datatable front-loads all pages from fetchFn when virtual.\n this.fetchFn.set(this.makeFetch(resolvedQuery));\n }\n\n this.loadLookupReferenceOptions();\n const [permissions, actions] = await Promise.all([\n this.sparkService.getPermissions(resolvedEntityType.id),\n this.sparkService.getCustomActions(resolvedEntityType.id),\n ]);\n this.canRead.set(permissions.canRead);\n this.canCreate.set(permissions.canCreate);\n this.customActions.set(actions.filter(a => a.showedOn === 'list' || a.showedOn === 'both'));\n }\n }\n\n async onCustomAction(action: CustomActionDefinition): Promise<void> {\n if (action.confirmationMessageKey) {\n const message = this.lang.t(action.confirmationMessageKey) || 'Are you sure?';\n if (!confirm(message)) return;\n }\n try {\n await this.sparkService.executeCustomAction(this.entityType()!.id, action.name);\n this.customActionExecuted.emit({ action });\n if (action.refreshOnCompleted) {\n this.refresh();\n }\n } catch (e) {\n const err = e as HttpErrorResponse;\n this.errorMessage.set(err.error?.error || err.message || 'Action failed');\n }\n }\n\n private async resolveEntityTypeForQuery(query: SparkQuery): Promise<{ entityType: EntityType | null; entityTypes: EntityType[] }> {\n const entityTypes = await this.sparkService.getEntityTypes();\n\n // If entityType is explicitly set on the query, use it directly\n if (query.entityType) {\n const type = entityTypes.find(t =>\n t.name === query.entityType || t.alias === query.entityType?.toLowerCase()\n );\n return { entityType: type || null, entityTypes };\n }\n\n // For Database.X sources, extract the property name and try to match\n const sourceName = this.extractSourceName(query.source);\n const singularName = this.singularize(sourceName);\n const type = entityTypes.find(t =>\n t.name === sourceName ||\n t.name === singularName ||\n t.clrType.endsWith(singularName)\n );\n return { entityType: type || null, entityTypes };\n }\n\n private extractSourceName(source: string): string {\n const dotIndex = source.indexOf('.');\n return dotIndex >= 0 ? source.substring(dotIndex + 1) : source;\n }\n\n private singularize(plural: string): string {\n const irregulars: { [key: string]: string } = {\n 'People': 'Person',\n 'Children': 'Child',\n 'Men': 'Men',\n 'Women': 'Woman'\n };\n if (irregulars[plural]) return irregulars[plural];\n\n if (plural.endsWith('ies')) {\n return plural.slice(0, -3) + 'y';\n }\n if (plural.endsWith('es')) {\n return plural.slice(0, -2);\n }\n if (plural.endsWith('s')) {\n return plural.slice(0, -1);\n }\n return plural;\n }\n\n /**\n * Builds the server-side fetch callback the datatable invokes per page/sort.\n * Reads `searchTerm` live, so a settings change (or a new fetchFn identity)\n * refetches with the current search term.\n */\n private makeFetch(query: SparkQuery): BsDatatableFetch<PersistentObject> {\n return (req) => this.sparkService.executeQuery(query.id, {\n sortColumns: req.sortColumns,\n skip: (req.page - 1) * req.perPage,\n take: req.perPage,\n search: this.searchTerm || undefined,\n }).then(r => {\n this.errorMessage.set(null);\n this.resultCount.set(r.totalRecords);\n return {\n data: r.data,\n totalRecords: r.totalRecords,\n totalPages: Math.ceil(r.totalRecords / req.perPage) || 1,\n perPage: req.perPage,\n page: req.page,\n };\n }).catch((e: any) => {\n this.errorMessage.set(e.error?.error || e.message || 'An unexpected error occurred');\n this.resultCount.set(0);\n return { data: [], totalRecords: 0, totalPages: 1, perPage: req.perPage, page: req.page };\n });\n }\n\n /** Force a refetch (e.g. after a custom action) without changing page/sort. */\n private refresh(): void {\n if (this.isStreaming()) {\n this.applyFilter();\n return;\n }\n const q = this.query();\n if (q) this.fetchFn.set(this.makeFetch(q));\n }\n\n onSearchChange(): void {\n if (this.isStreaming()) {\n this.applyFilter();\n return;\n }\n // Reset to page 1 for the new search.\n const s = this.settings();\n this.settings.set(new DatatableSettings({\n perPage: { values: s.perPage.values, selected: s.perPage.selected },\n page: { values: [1], selected: 1 },\n sortColumns: s.sortColumns,\n }));\n // Re-assign the fetch callback so the datatable refetches even when\n // page/perPage/sort are unchanged. ng-bootstrap 22.4's web component dedupes\n // reloads by {sortColumns, perPage, page}; setting a new fetch identity resets\n // that key (set fetch → _lastReloadKey = null) and forces the reload. makeFetch\n // reads searchTerm live (mirrors refresh()).\n const q = this.query();\n if (q) this.fetchFn.set(this.makeFetch(q));\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.onSearchChange();\n }\n\n isVirtualScrolling = computed(() => this.query()?.renderMode === 'VirtualScrolling');\n\n visibleAttributes = computed(() => {\n return this.entityType()?.attributes\n .filter(a => a.isVisible && hasShowedOnFlag(a.showedOn, ShowedOn.Query))\n .sort((a, b) => a.order - b.order) || [];\n });\n\n getColumnRendererComponent(attr: EntityAttributeDefinition): Type<any> | null {\n if (!attr.renderer) return null;\n return this.rendererRegistry.find(r => r.name === attr.renderer)?.columnComponent ?? null;\n }\n\n getColumnRendererInputs(component: Type<any>, item: PersistentObject, attr: EntityAttributeDefinition): Record<string, any> {\n const itemAttr = item.attributes.find(a => a.name === attr.name);\n return withDeclaredInputs(component, {\n value: rendererValue(itemAttr),\n attribute: attr,\n options: attr.rendererOptions,\n item,\n });\n }\n\n private async loadLookupReferenceOptions(): Promise<void> {\n const lookupAttrs = this.visibleAttributes().filter(a => a.lookupReferenceType);\n if (lookupAttrs.length === 0) return;\n\n const lookupNames = [...new Set(lookupAttrs.map(a => a.lookupReferenceType!))];\n const entries = await Promise.all(\n lookupNames.map(async name => {\n const result = await this.sparkService.getLookupReference(name);\n return [name, result] as const;\n })\n );\n this.lookupReferenceOptions.set(entries.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {} as Record<string, LookupReference>));\n }\n\n onCreate(): void {\n this.createClicked.emit();\n const et = this.entityType();\n if (et) {\n this.router.navigate(['/po', et.alias || et.id, 'new']);\n }\n }\n\n private connectStreaming(queryId: string): void {\n this.disconnectStreaming();\n this.isStreaming.set(true);\n\n this.streamingSub = this.streamingService.connectToStreamingQuery(queryId).subscribe({\n next: (message) => this.handleStreamingMessage(message),\n error: (err) => {\n this.errorMessage.set(err?.message || 'Streaming connection failed');\n this.isStreaming.set(false);\n },\n complete: () => {\n this.isStreaming.set(false);\n }\n });\n }\n\n private disconnectStreaming(): void {\n if (this.streamingSub) {\n this.streamingSub.unsubscribe();\n this.streamingSub = null;\n }\n this.isStreaming.set(false);\n }\n\n private handleStreamingMessage(message: StreamingMessage): void {\n switch (message.type) {\n case 'snapshot':\n this.errorMessage.set(null);\n this.allItems.set(message.data);\n this.applyFilter();\n break;\n\n case 'patch':\n if (message.updated.length > 0) {\n const currentItems = this.allItems();\n const updatedItems = currentItems.map(item => {\n const patch = message.updated.find(u => u.id === item.id);\n if (!patch) return item;\n\n // Clone the item and update only changed attribute values\n const updatedAttributes = item.attributes.map(attr => {\n if (attr.name in patch.attributes) {\n return { ...attr, value: patch.attributes[attr.name] };\n }\n return attr;\n });\n\n return { ...item, attributes: updatedAttributes };\n });\n\n this.allItems.set(updatedItems);\n this.applyFilter();\n }\n break;\n\n case 'error':\n this.errorMessage.set(message.message);\n break;\n }\n }\n\n private applyFilter(): void {\n let items = this.allItems();\n\n // Apply search filter\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n items = items.filter(item =>\n item.attributes.some(a => String(a.value ?? '').toLowerCase().includes(term))\n );\n }\n\n // Apply sorting (client-side for the streaming snapshot; the datatable in\n // [data] mode also auto-sorts on header clicks).\n const sortCols = this.settings().sortColumns;\n if (sortCols.length > 0) {\n items = [...items].sort((a, b) => {\n for (const col of sortCols) {\n const aVal = a.attributes.find(attr => attr.name === col.property)?.value ?? '';\n const bVal = b.attributes.find(attr => attr.name === col.property)?.value ?? '';\n const cmp = String(aVal).localeCompare(String(bVal));\n if (cmp !== 0) return col.direction === 'descending' ? -cmp : cmp;\n }\n return 0;\n });\n }\n\n this.streamItems.set(items);\n this.resultCount.set(items.length);\n }\n}\n","<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n </ng-container>\n </bs-datatable>\n } @else {\n <bs-datatable class=\"flex-grow-1\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [fetch]=\"fetchFn()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n </ng-container>\n </bs-datatable>\n }\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n\n<ng-template #cellContent let-item let-attr=\"attr\">\n @if (getColumnRendererComponent(attr); as rendererType) {\n <ng-container *ngComponentOutlet=\"rendererType; inputs: getColumnRendererInputs(rendererType, item, attr)\"></ng-container>\n } @else if (attr.dataType === 'boolean') {\n <input type=\"checkbox\"\n [checked]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) === true\"\n [indeterminate]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) == null\"\n disabled\n onclick=\"return false;\">\n } @else if (attr.dataType === 'color') {\n @let colorVal = (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes());\n @if (colorVal) {\n <span class=\"d-inline-block align-middle border rounded\" [style.background-color]=\"colorVal\" style=\"width: 1.5em; height: 1.5em;\"></span>\n }\n } @else if (attr.dataType === 'Reference' && attr.isArray) {\n <span class=\"d-inline-flex flex-wrap gap-1\">\n @for (chip of (attr.name | referenceChips:item); track chip.id) {\n <span class=\"badge rounded-pill border bg-body-secondary text-body px-3 py-2\">{{ chip.label }}</span>\n }\n </span>\n } @else {\n {{ (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) }}\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mintplayer-ng-spark-query-list.mjs","sources":["../../query-list/src/spark-query-list.component.ts","../../query-list/src/spark-query-list.component.html","../../query-list/mintplayer-ng-spark-query-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, DestroyRef, effect, inject, input, output, signal, TemplateRef, Type, untracked } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { Subscription } from 'rxjs';\nimport { CommonModule, NgTemplateOutlet, NgComponentOutlet } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { ActivatedRoute, Router, RouterModule } from '@angular/router';\nimport { Color } from '@mintplayer/ng-bootstrap';\nimport { BsAlertComponent } from '@mintplayer/ng-bootstrap/alert';\nimport { BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, DatatableSettings, type BsDatatableFetch } from '@mintplayer/ng-bootstrap/datatable';\nimport { BsFormComponent, BsFormControlDirective } from '@mintplayer/ng-bootstrap/form';\nimport { BsGridComponent, BsGridRowDirective, BsGridColumnDirective } from '@mintplayer/ng-bootstrap/grid';\nimport { BsInputGroupComponent } from '@mintplayer/ng-bootstrap/input-group';\nimport { BsPriorityNavComponent, BsPriorityNavItemDirective } from '@mintplayer/ng-bootstrap/priority-nav';\nimport { BsSpinnerComponent } from '@mintplayer/ng-bootstrap/spinner';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { filterQueryActions, parseSelectionRule, selectionModeFor } from '@mintplayer/ng-spark/models';\nimport { SparkQueryRefreshService } from '@mintplayer/ng-spark/client-operations';\nimport { SortColumn } from '@mintplayer/pagination';\nimport { SparkService, SparkStreamingService, SparkLanguageService } from '@mintplayer/ng-spark/services';\nimport {\n TranslateKeyPipe,\n ResolveTranslationPipe,\n AttributeValuePipe,\n ReferenceChipsPipe,\n} from '@mintplayer/ng-spark/pipes';\nimport { SparkIconComponent } from '@mintplayer/ng-spark/icon';\nimport { SparkGridRenderers, initialGridSettings, isVirtualScrollingQuery, visibleGridAttributes } from '@mintplayer/ng-spark/grid';\nimport {\n CustomActionDefinition,\n StreamingMessage,\n EntityType,\n EntityAttributeDefinition,\n LookupReference,\n PersistentObject,\n SparkQuery,\n ShowedOn,\n hasShowedOnFlag,\n} from '@mintplayer/ng-spark/models';\n\n@Component({\n selector: 'spark-query-list',\n imports: [CommonModule, NgTemplateOutlet, NgComponentOutlet, FormsModule, RouterModule, BsAlertComponent, BsDatatableComponent, BsDatatableColumnDirective, BsRowTemplateDirective, BsFormComponent, BsFormControlDirective, BsGridComponent, BsGridRowDirective, BsGridColumnDirective, BsInputGroupComponent, BsPriorityNavComponent, BsPriorityNavItemDirective, BsSpinnerComponent, SparkIconComponent, ResolveTranslationPipe, TranslateKeyPipe, AttributeValuePipe, ReferenceChipsPipe],\n templateUrl: './spark-query-list.component.html',\n styleUrl: './spark-query-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.virtual-scrolling]': 'isVirtualScrolling()'\n }\n})\nexport class SparkQueryListComponent {\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n private readonly sparkService = inject(SparkService);\n private readonly streamingService = inject(SparkStreamingService);\n protected readonly lang = inject(SparkLanguageService);\n private readonly gridRenderers = inject(SparkGridRenderers);\n private readonly destroyRef = inject(DestroyRef);\n\n extraActionsTemplate = input<TemplateRef<void> | null>(null);\n showCustomActions = input(true);\n\n rowClicked = output<PersistentObject>();\n createClicked = output<void>();\n customActionExecuted = output<{ action: CustomActionDefinition }>();\n\n colors = Color;\n errorMessage = signal<string | null>(null);\n query = signal<SparkQuery | null>(null);\n entityType = signal<EntityType | null>(null);\n allEntityTypes = signal<EntityType[]>([]);\n lookupReferenceOptions = signal<Record<string, LookupReference>>({});\n resultCount = signal<number | null>(null);\n searchTerm: string = '';\n canRead = signal(false);\n canCreate = signal(false);\n customActions = signal<CustomActionDefinition[]>([]);\n isStreaming = signal(false);\n private streamingSub: Subscription | null = null;\n private allItems = signal<PersistentObject[]>([]);\n streamItems = signal<PersistentObject[]>([]);\n fetchFn = signal<BsDatatableFetch<PersistentObject> | null>(null);\n settings = signal(new DatatableSettings({\n perPage: { values: [10, 25, 50], selected: 10 },\n page: { values: [1], selected: 1 },\n sortColumns: []\n }));\n\n constructor() {\n // The handler is async and this is a subscribe, so a rejection lands nowhere:\n // the metadata load would reject, entityType() would stay null, and the template\n // would render a spinner FOREVER -- while this component has had an errorMessage\n // surface all along that only the fetch path ever reached. Catch it here.\n this.route.paramMap.pipe(takeUntilDestroyed()).subscribe(params => {\n this.onParamsChange(params).catch((e: unknown) => this.reportLoadFailure(e as HttpErrorResponse));\n });\n this.destroyRef.onDestroy(() => this.disconnectStreaming());\n\n // Server-issued refreshQuery. Its own effect, skipping the first run, so it drives the\n // cheap data refresh and never re-resolves metadata (which would reset page and sort).\n let firstRefreshTick = true;\n effect(() => {\n this.queryRefresh.tokenFor(this.query()?.alias || this.query()?.id);\n if (firstRefreshTick) { firstRefreshTick = false; return; }\n untracked(() => this.reload());\n });\n }\n\n private async onParamsChange(params: any): Promise<void> {\n // Reset prior-route state so we render the spinner (not stale rows from\n // the previous query) while the new query/entityType resolve.\n this.entityType.set(null);\n this.fetchFn.set(null);\n this.resultCount.set(null);\n this.allItems.set([]);\n this.streamItems.set([]);\n this.errorMessage.set(null);\n // Reset the permission-derived state too. Without this, navigating A -> B where\n // B's load fails leaves A's buttons and A's canRead/canCreate on screen.\n this.canRead.set(false);\n this.canCreate.set(false);\n this.customActions.set([]);\n // Ids from the previous query are meaningless against the next one, and would be POSTed\n // as though they belonged to it.\n this.selection.set([]);\n this.disconnectStreaming();\n\n const queryId = params.get('queryId');\n const typeParam = params.get('type');\n\n let resolvedQuery: SparkQuery | null = null;\n let resolvedEntityType: EntityType | null = null;\n let resolvedEntityTypes: EntityType[] = [];\n\n if (queryId) {\n resolvedQuery = await this.sparkService.getQuery(queryId);\n if (resolvedQuery) {\n const result = await this.resolveEntityTypeForQuery(resolvedQuery);\n resolvedEntityType = result.entityType;\n resolvedEntityTypes = result.entityTypes;\n }\n } else if (typeParam) {\n resolvedEntityTypes = await this.sparkService.getEntityTypes();\n resolvedEntityType = resolvedEntityTypes.find(t =>\n t.id === typeParam || t.alias === typeParam\n ) || null;\n\n if (resolvedEntityType) {\n const queries = await this.sparkService.getQueries();\n const singularName = resolvedEntityType.name;\n resolvedQuery = queries.find(q => {\n // Match by explicit entityType\n if (q.entityType === singularName) return true;\n // Match by source name\n const sourceName = this.extractSourceName(q.source);\n const sourceSingular = this.singularize(sourceName);\n return sourceName === singularName ||\n sourceSingular === singularName ||\n sourceName === singularName + 's';\n }) || null;\n }\n }\n\n if (resolvedQuery) this.query.set(resolvedQuery);\n\n if (resolvedEntityType) {\n this.entityType.set(resolvedEntityType);\n this.allEntityTypes.set(resolvedEntityTypes);\n\n this.settings.set(initialGridSettings(resolvedQuery));\n\n if (resolvedQuery?.isStreamingQuery) {\n // Streaming: WebSocket feeds allItems; the datatable binds [data]=\"streamItems()\".\n this.connectStreaming(resolvedQuery.id);\n } else if (resolvedQuery) {\n // Non-streaming: the datatable drives paging/sorting via [(settings)] and calls\n // fetchFn per page. Virtual scrolling is just the [virtualScroll] template flag —\n // the datatable front-loads all pages from fetchFn when virtual.\n this.fetchFn.set(this.makeFetch(resolvedQuery));\n }\n\n this.loadLookupReferenceOptions();\n const [permissions, actions] = await Promise.all([\n this.sparkService.getPermissions(resolvedEntityType.id),\n this.sparkService.getCustomActions(resolvedEntityType.id),\n ]);\n this.canRead.set(permissions.canRead);\n this.canCreate.set(permissions.canCreate);\n // 'query', not 'list'. The server model and docs/guide-custom-actions.md have\n // always documented \"detail\" | \"query\" | \"both\"; this filter tested for a value\n // nothing emits, so an action authored per the documentation rendered NOWHERE.\n this.customActions.set(filterQueryActions(actions));\n }\n }\n\n /**\n * A load failure has to render, not just be swallowed: a denied query answers 404\n * (audit M-3, so existence is not leaked), which is indistinguishable from a missing\n * one -- hence a deliberately generic message rather than a guess at which it was.\n */\n private reportLoadFailure(err: HttpErrorResponse): void {\n this.errorMessage.set(\n err?.status === 404\n ? (this.lang.t('spark.query.unavailable') || 'This list is not available.')\n : (err?.error?.error || err?.message || 'An unexpected error occurred'));\n }\n\n async onCustomAction(action: CustomActionDefinition): Promise<void> {\n if (action.confirmationMessageKey) {\n const message = this.lang.t(action.confirmationMessageKey) || 'Are you sure?';\n if (!confirm(message)) return;\n }\n try {\n await this.sparkService.executeCustomAction(this.entityType()!.id, action.name, undefined, this.selection());\n this.customActionExecuted.emit({ action });\n if (action.refreshOnCompleted) {\n this.reload();\n }\n } catch (e) {\n const err = e as HttpErrorResponse;\n this.errorMessage.set(err.error?.error || err.message || 'Action failed');\n }\n }\n\n private async resolveEntityTypeForQuery(query: SparkQuery): Promise<{ entityType: EntityType | null; entityTypes: EntityType[] }> {\n const entityTypes = await this.sparkService.getEntityTypes();\n\n // If entityType is explicitly set on the query, use it directly\n if (query.entityType) {\n const type = entityTypes.find(t =>\n t.name === query.entityType || t.alias === query.entityType?.toLowerCase()\n );\n return { entityType: type || null, entityTypes };\n }\n\n // For Database.X sources, extract the property name and try to match\n const sourceName = this.extractSourceName(query.source);\n const singularName = this.singularize(sourceName);\n const type = entityTypes.find(t =>\n t.name === sourceName ||\n t.name === singularName ||\n t.clrType.endsWith(singularName)\n );\n return { entityType: type || null, entityTypes };\n }\n\n private extractSourceName(source: string): string {\n const dotIndex = source.indexOf('.');\n return dotIndex >= 0 ? source.substring(dotIndex + 1) : source;\n }\n\n private singularize(plural: string): string {\n const irregulars: { [key: string]: string } = {\n 'People': 'Person',\n 'Children': 'Child',\n 'Men': 'Men',\n 'Women': 'Woman'\n };\n if (irregulars[plural]) return irregulars[plural];\n\n if (plural.endsWith('ies')) {\n return plural.slice(0, -3) + 'y';\n }\n if (plural.endsWith('es')) {\n return plural.slice(0, -2);\n }\n if (plural.endsWith('s')) {\n return plural.slice(0, -1);\n }\n return plural;\n }\n\n /**\n * Builds the server-side fetch callback the datatable invokes per page/sort.\n * Reads `searchTerm` live, so a settings change (or a new fetchFn identity)\n * refetches with the current search term.\n */\n private makeFetch(query: SparkQuery): BsDatatableFetch<PersistentObject> {\n return (req) => this.sparkService.executeQuery(query.id, {\n sortColumns: req.sortColumns,\n skip: (req.page - 1) * req.perPage,\n take: req.perPage,\n search: this.searchTerm || undefined,\n }).then(r => {\n this.errorMessage.set(null);\n this.resultCount.set(r.totalRecords);\n return {\n data: r.data,\n totalRecords: r.totalRecords,\n totalPages: Math.ceil(r.totalRecords / req.perPage) || 1,\n perPage: req.perPage,\n page: req.page,\n };\n }).catch((e: any) => {\n this.errorMessage.set(e.error?.error || e.message || 'An unexpected error occurred');\n this.resultCount.set(0);\n return { data: [], totalRecords: 0, totalPages: 1, perPage: req.perPage, page: req.page };\n });\n }\n\n /**\n * Force a refetch (e.g. after a custom action) without changing page/sort.\n *\n * Public so a host can drive it, and named to match\n * `SparkSubQueryComponent.reload()` — the two grids had drifted into having the\n * same mechanism under different names, one of them unreachable.\n */\n reload(): void {\n if (this.isStreaming()) {\n this.applyFilter();\n return;\n }\n const q = this.query();\n if (q) this.fetchFn.set(this.makeFetch(q));\n }\n\n onSearchChange(): void {\n if (this.isStreaming()) {\n this.applyFilter();\n return;\n }\n // Reset to page 1 for the new search.\n const s = this.settings();\n this.settings.set(new DatatableSettings({\n perPage: { values: s.perPage.values, selected: s.perPage.selected },\n page: { values: [1], selected: 1 },\n sortColumns: s.sortColumns,\n }));\n // Re-assign the fetch callback so the datatable refetches even when\n // page/perPage/sort are unchanged. ng-bootstrap 22.4's web component dedupes\n // reloads by {sortColumns, perPage, page}; setting a new fetch identity resets\n // that key (set fetch → _lastReloadKey = null) and forces the reload. makeFetch\n // reads searchTerm live (mirrors refresh()).\n const q = this.query();\n if (q) this.fetchFn.set(this.makeFetch(q));\n }\n\n clearSearch(): void {\n this.searchTerm = '';\n this.onSearchChange();\n }\n\n /**\n * Whether the first column links to a detail page.\n *\n * Declared by the query, because the framework cannot derive it: `Database.*` rows\n * are always real documents, but a `Custom.*` query may return loadable documents\n * (Fleet's Stolen_Cars) or rows fabricated in memory (StreamItems). Absent means\n * navigable -- defaulting Custom.* to false would strip the working links off every\n * custom query that does return documents.\n */\n /**\n * Rows the user has ticked. Lives here rather than in the datatable so the action bar can\n * read it, and MUST be cleared whenever the source changes — otherwise route A's selection\n * is POSTed as ids of route B's type.\n */\n selection = signal<PersistentObject[]>([]);\n\n private readonly queryRefresh = inject(SparkQueryRefreshService);\n\n /** 'none' unless an action is selection-gated, so unaffected grids gain no checkbox column. */\n selectionMode = computed(() => selectionModeFor(this.customActions()));\n\n /** Whether an action's selection rule is satisfied right now. The server checks it again. */\n isActionEnabled(action: CustomActionDefinition): boolean {\n return parseSelectionRule(action.selectionRule)(this.selection().length);\n }\n\n isVirtualScrolling = computed(() => isVirtualScrollingQuery(this.query()));\n\n visibleAttributes = computed(() => visibleGridAttributes(this.entityType()));\n\n getColumnRendererComponent(attr: EntityAttributeDefinition): Type<any> | null {\n return this.gridRenderers.columnComponentFor(attr);\n }\n\n getColumnRendererInputs(component: Type<any>, item: PersistentObject, attr: EntityAttributeDefinition): Record<string, any> {\n return this.gridRenderers.columnInputsFor(component, item, attr);\n }\n\n private async loadLookupReferenceOptions(): Promise<void> {\n this.lookupReferenceOptions.set(await this.gridRenderers.loadLookupOptions(this.visibleAttributes()));\n }\n\n onCreate(): void {\n this.createClicked.emit();\n const et = this.entityType();\n if (et) {\n this.router.navigate(['/po', et.alias || et.id, 'new']);\n }\n }\n\n private connectStreaming(queryId: string): void {\n this.disconnectStreaming();\n this.isStreaming.set(true);\n\n this.streamingSub = this.streamingService.connectToStreamingQuery(queryId).subscribe({\n next: (message) => this.handleStreamingMessage(message),\n error: (err) => {\n this.errorMessage.set(err?.message || 'Streaming connection failed');\n this.isStreaming.set(false);\n },\n complete: () => {\n this.isStreaming.set(false);\n }\n });\n }\n\n private disconnectStreaming(): void {\n if (this.streamingSub) {\n this.streamingSub.unsubscribe();\n this.streamingSub = null;\n }\n this.isStreaming.set(false);\n }\n\n private handleStreamingMessage(message: StreamingMessage): void {\n switch (message.type) {\n case 'snapshot':\n this.errorMessage.set(null);\n this.allItems.set(message.data);\n this.applyFilter();\n break;\n\n case 'patch':\n if (message.updated.length > 0) {\n const currentItems = this.allItems();\n const updatedItems = currentItems.map(item => {\n const patch = message.updated.find(u => u.id === item.id);\n if (!patch) return item;\n\n // Clone the item and update only changed attribute values\n const updatedAttributes = item.attributes.map(attr => {\n if (attr.name in patch.attributes) {\n return { ...attr, value: patch.attributes[attr.name] };\n }\n return attr;\n });\n\n return { ...item, attributes: updatedAttributes };\n });\n\n this.allItems.set(updatedItems);\n this.applyFilter();\n }\n break;\n\n case 'error':\n this.errorMessage.set(message.message);\n break;\n }\n }\n\n private applyFilter(): void {\n let items = this.allItems();\n\n // Apply search filter\n if (this.searchTerm) {\n const term = this.searchTerm.toLowerCase();\n items = items.filter(item =>\n item.attributes.some(a => String(a.value ?? '').toLowerCase().includes(term))\n );\n }\n\n // Apply sorting (client-side for the streaming snapshot; the datatable in\n // [data] mode also auto-sorts on header clicks).\n const sortCols = this.settings().sortColumns;\n if (sortCols.length > 0) {\n items = [...items].sort((a, b) => {\n for (const col of sortCols) {\n const aVal = a.attributes.find(attr => attr.name === col.property)?.value ?? '';\n const bVal = b.attributes.find(attr => attr.name === col.property)?.value ?? '';\n const cmp = String(aVal).localeCompare(String(bVal));\n if (cmp !== 0) return col.direction === 'descending' ? -cmp : cmp;\n }\n return 0;\n });\n }\n\n this.streamItems.set(items);\n this.resultCount.set(items.length);\n }\n}\n","<div class=\"d-flex flex-column h-100\">\n <div class=\"spark-actionbar py-2 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\" [class.px-3]=\"!isVirtualScrolling()\">\n <bs-priority-nav [moreLabel]=\"lang.t('common.more')\" [collapseAt]=\"'sm'\">\n @if (canCreate()) {\n <button *bsPriorityNavItem=\"1\" class=\"btn btn-primary\" (click)=\"onCreate()\">\n <spark-icon name=\"plus-lg\" /> {{ 'common.new' | t }}\n </button>\n }\n @if (showCustomActions()) {\n @for (action of customActions(); track action.name) {\n <!-- Disabled, not hidden: hiding makes the affordance undiscoverable and reflows the\n priority nav on every selection change. The server enforces the same rule. -->\n <button *bsPriorityNavItem=\"10 + action.offset\" class=\"btn btn-outline-primary\"\n [disabled]=\"!isActionEnabled(action)\" (click)=\"onCustomAction(action)\">\n {{ action.displayName | resolveTranslation }}\n </button>\n }\n }\n @if (extraActionsTemplate(); as extraActionsTpl) {\n <ng-container *bsPriorityNavItem=\"50\">\n <ng-container *ngTemplateOutlet=\"extraActionsTpl\"></ng-container>\n </ng-container>\n }\n </bs-priority-nav>\n </div>\n <h2 class=\"mb-4 flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n {{ (query()?.description | resolveTranslation) || query()?.name || ('common.loading' | t) }}\n @if (isStreaming()) {\n <span class=\"badge bg-success ms-2\" style=\"font-size: 0.5em; vertical-align: middle;\">LIVE</span>\n }\n </h2>\n\n @if (entityType()) {\n <!-- Search box -->\n <div class=\"flex-shrink-0\" [class.px-4]=\"isVirtualScrolling()\">\n <bs-form>\n <bs-grid>\n <div bsRow class=\"mb-3\">\n <div [md]=\"4\">\n <bs-input-group>\n <span class=\"input-group-text\">\n <spark-icon name=\"search\" />\n </span>\n <input\n type=\"text\"\n [placeholder]=\"'common.search' | t\"\n [(ngModel)]=\"searchTerm\"\n (ngModelChange)=\"onSearchChange()\">\n @if (searchTerm) {\n <button\n type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"clearSearch()\">\n <spark-icon name=\"x-lg\" />\n </button>\n }\n </bs-input-group>\n </div>\n <div [md]=\"8\" class=\"text-end\">\n @if (searchTerm && resultCount() !== null) {\n <span class=\"text-muted\">\n {{ resultCount() }} {{ resultCount() === 1 ? ('common.resultFound' | t) : ('common.resultsFound' | t) }}\n </span>\n }\n </div>\n </div>\n </bs-grid>\n </bs-form>\n\n @if (errorMessage(); as err) {\n <bs-alert [type]=\"colors.danger\" class=\"mb-3\">\n {{ err }}\n </bs-alert>\n }\n </div>\n\n @if (isStreaming()) {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [data]=\"streamItems()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n } @else {\n <bs-datatable class=\"flex-grow-1\"\n [selectionMode]=\"selectionMode()\"\n [(selection)]=\"selection\"\n [virtualScroll]=\"isVirtualScrolling()\"\n [itemSize]=\"40\"\n [isResponsive]=\"isVirtualScrolling()\"\n [fetch]=\"fetchFn()\"\n [(settings)]=\"settings\">\n @for (attr of visibleAttributes(); track attr.id) {\n <div *bsDatatableColumn=\"attr.name; sortable: true\">\n {{ (attr.label | resolveTranslation) || attr.name }}\n </div>\n }\n\n <ng-container *bsRowTemplate=\"let item\">\n <ng-container *ngTemplateOutlet=\"rowCells; context: { $implicit: item }\"></ng-container>\n </ng-container>\n </bs-datatable>\n }\n } @else if (errorMessage(); as err) {\n <!-- The metadata load failed. This used to be unreachable: the rejection was\n swallowed by an async subscribe handler, so the spinner below span forever. -->\n <bs-alert [type]=\"colors.danger\" class=\"m-3 d-block\">\n {{ err }}\n </bs-alert>\n } @else {\n <div class=\"text-center p-5\">\n <bs-spinner />\n </div>\n }\n</div>\n\n<!--\n One row template for both the streaming and the paged datatable. These were two\n byte-identical copies in the same file, which is how the first column's link came to\n need fixing in three places instead of one.\n-->\n<ng-template #rowCells let-item>\n @let row = $any(item);\n @for (attr of visibleAttributes(); track attr.id; let first = $first) {\n <td>\n @if (row) {\n <!-- `canRead()` is the whole gate, and it is the rights model: `Query` without\n `Read` lists the rows and withholds the link. Withhold `Read` for a query\n whose rows no detail page can load — a Custom.* query that fabricates rows\n in memory, say. Note cellContent renders INSIDE this anchor, so a custom\n renderer cannot suppress the link — it would nest a second one. -->\n @if (first && canRead()) {\n <a [routerLink]=\"['/po', entityType()!.alias || entityType()!.id, row.id]\" (click)=\"rowClicked.emit(row)\">\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n </a>\n } @else {\n <ng-container *ngTemplateOutlet=\"cellContent; context: { $implicit: row, attr: attr }\"></ng-container>\n }\n } @else {\n \n }\n </td>\n }\n</ng-template>\n\n<ng-template #cellContent let-item let-attr=\"attr\">\n @if (getColumnRendererComponent(attr); as rendererType) {\n <ng-container *ngComponentOutlet=\"rendererType; inputs: getColumnRendererInputs(rendererType, item, attr)\"></ng-container>\n } @else if (attr.dataType === 'boolean') {\n <input type=\"checkbox\"\n [checked]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) === true\"\n [indeterminate]=\"(attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) == null\"\n disabled\n onclick=\"return false;\">\n } @else if (attr.dataType === 'color') {\n @let colorVal = (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes());\n @if (colorVal) {\n <span class=\"d-inline-block align-middle border rounded\" [style.background-color]=\"colorVal\" style=\"width: 1.5em; height: 1.5em;\"></span>\n }\n } @else if (attr.dataType === 'Reference' && attr.isArray) {\n <span class=\"d-inline-flex flex-wrap gap-1\">\n @for (chip of (attr.name | referenceChips:item); track chip.id) {\n <span class=\"badge rounded-pill border bg-body-secondary text-body px-3 py-2\">{{ chip.label }}</span>\n }\n </span>\n } @else {\n {{ (attr.name | attributeValue:item:entityType():lookupReferenceOptions():allEntityTypes()) }}\n }\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mintplayer/ng-spark",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "22.
|
|
4
|
+
"version": "22.3.0",
|
|
5
5
|
"description": "Angular component library for MintPlayer.Spark CRUD applications",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
"types": "./types/mintplayer-ng-spark-client-operations.d.ts",
|
|
34
34
|
"default": "./fesm2022/mintplayer-ng-spark-client-operations.mjs"
|
|
35
35
|
},
|
|
36
|
+
"./grid": {
|
|
37
|
+
"types": "./types/mintplayer-ng-spark-grid.d.ts",
|
|
38
|
+
"default": "./fesm2022/mintplayer-ng-spark-grid.mjs"
|
|
39
|
+
},
|
|
36
40
|
"./icon": {
|
|
37
41
|
"types": "./types/mintplayer-ng-spark-icon.d.ts",
|
|
38
42
|
"default": "./fesm2022/mintplayer-ng-spark-icon.mjs"
|