@mintplayer/ng-spark 22.23.0 → 22.24.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/README.md +181 -0
- package/fesm2022/mintplayer-ng-spark-attribute-description.mjs +100 -47
- package/fesm2022/mintplayer-ng-spark-attribute-description.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +308 -329
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-column-filter.mjs +175 -135
- package/fesm2022/mintplayer-ng-spark-column-filter.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +2259 -1119
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-history.mjs +611 -0
- package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-icon.mjs +64 -27
- package/fesm2022/mintplayer-ng-spark-icon.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs +366 -762
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-moderation.mjs +1212 -0
- package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-panels.mjs +52 -0
- package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +1122 -765
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +273 -169
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +786 -410
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +292 -284
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +2187 -1225
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +516 -303
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +17 -55
- package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +216 -177
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-routes.mjs +24 -28
- package/fesm2022/mintplayer-ng-spark-routes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +625 -640
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-shell.mjs +1013 -397
- package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-soft-delete.mjs +294 -0
- package/fesm2022/mintplayer-ng-spark-soft-delete.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark.mjs +13 -50
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +17 -1
- package/types/mintplayer-ng-spark-attribute-description.d.ts +25 -18
- package/types/mintplayer-ng-spark-client-operations.d.ts +133 -160
- package/types/mintplayer-ng-spark-column-filter.d.ts +73 -55
- package/types/mintplayer-ng-spark-grid.d.ts +885 -448
- package/types/mintplayer-ng-spark-history.d.ts +223 -0
- package/types/mintplayer-ng-spark-icon.d.ts +15 -13
- package/types/mintplayer-ng-spark-models.d.ts +624 -573
- package/types/mintplayer-ng-spark-moderation.d.ts +402 -0
- package/types/mintplayer-ng-spark-panels.d.ts +108 -0
- package/types/mintplayer-ng-spark-pipes.d.ts +120 -149
- package/types/mintplayer-ng-spark-po-create.d.ts +46 -37
- package/types/mintplayer-ng-spark-po-detail.d.ts +177 -117
- package/types/mintplayer-ng-spark-po-edit.d.ts +64 -65
- package/types/mintplayer-ng-spark-po-form.d.ts +507 -371
- package/types/mintplayer-ng-spark-query-list.d.ts +118 -82
- package/types/mintplayer-ng-spark-renderers.d.ts +79 -85
- package/types/mintplayer-ng-spark-retry-action-modal.d.ts +31 -34
- package/types/mintplayer-ng-spark-routes.d.ts +7 -11
- package/types/mintplayer-ng-spark-services.d.ts +377 -261
- package/types/mintplayer-ng-spark-shell.d.ts +209 -128
- package/types/mintplayer-ng-spark-soft-delete.d.ts +90 -0
- package/types/mintplayer-ng-spark.d.ts +7 -12
|
@@ -1,647 +1,632 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import { HttpClient, withInterceptors } from
|
|
4
|
-
import {
|
|
5
|
-
import { currentLanguage, filterQueryActions } from
|
|
6
|
-
import { SPARK_CONFIG } from
|
|
7
|
-
import { SparkClientOperationDispatcher } from
|
|
8
|
-
import { DomSanitizer } from
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
// conversation and not the component's lifetime, and two unrelated conversations do not add up.
|
|
422
|
-
if ((body.retryResults?.length ?? 0) >= SparkService.MAX_RETRY_DEPTH) {
|
|
423
|
-
throw new Error(`Gave up after answering ${SparkService.MAX_RETRY_DEPTH} retry prompts; the last was step ` +
|
|
424
|
-
`${retryOp.step} ("${retryOp.title}"). A hook that raises a retry without checking ` +
|
|
425
|
-
`Retry.Result first will do this — it re-raises on every resubmission.`);
|
|
426
|
-
}
|
|
427
|
-
const payload = {
|
|
428
|
-
type: 'retry-action',
|
|
429
|
-
step: retryOp.step,
|
|
430
|
-
title: retryOp.title,
|
|
431
|
-
options: retryOp.options,
|
|
432
|
-
defaultOption: retryOp.defaultOption ?? undefined,
|
|
433
|
-
persistentObject: retryOp.persistentObject ?? undefined,
|
|
434
|
-
message: retryOp.message ?? undefined,
|
|
435
|
-
};
|
|
436
|
-
const result = await this.retryActionService.show(payload);
|
|
437
|
-
if (result.option === 'Cancel' && !payload.options.includes('Cancel'))
|
|
438
|
-
throw error;
|
|
439
|
-
body.retryResults = [...(body.retryResults || []), result];
|
|
440
|
-
return retryFn();
|
|
441
|
-
}
|
|
442
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
443
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, providedIn: 'root' });
|
|
444
|
-
}
|
|
445
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkService, decorators: [{
|
|
446
|
-
type: Injectable,
|
|
447
|
-
args: [{ providedIn: 'root' }]
|
|
448
|
-
}] });
|
|
449
|
-
|
|
450
|
-
/** Built-in SVG icons used by ng-spark library templates. */
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { Injectable, NgZone, PLATFORM_ID, inject, signal } from "@angular/core";
|
|
3
|
+
import { HttpClient, withInterceptors } from "@angular/common/http";
|
|
4
|
+
import { Observable, firstValueFrom } from "rxjs";
|
|
5
|
+
import { currentLanguage, filterQueryActions } from "@mintplayer/ng-spark/models";
|
|
6
|
+
import { SPARK_CONFIG } from "@mintplayer/ng-spark";
|
|
7
|
+
import { SparkClientOperationDispatcher } from "@mintplayer/ng-spark/client-operations";
|
|
8
|
+
import { DomSanitizer } from "@angular/platform-browser";
|
|
9
|
+
import { DOCUMENT, isPlatformBrowser } from "@angular/common";
|
|
10
|
+
import { Router } from "@angular/router";
|
|
11
|
+
var RetryActionService = class RetryActionService {
|
|
12
|
+
resolveRetry = null;
|
|
13
|
+
payload = signal(null, ...ngDevMode ? [{ debugName: "payload" }] : /* istanbul ignore next */ []);
|
|
14
|
+
show(payload) {
|
|
15
|
+
this.payload.set(payload);
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
this.resolveRetry = resolve;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
respond(result) {
|
|
21
|
+
this.payload.set(null);
|
|
22
|
+
this.resolveRetry?.(result);
|
|
23
|
+
this.resolveRetry = null;
|
|
24
|
+
}
|
|
25
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
26
|
+
minVersion: "12.0.0",
|
|
27
|
+
version: "22.2.0",
|
|
28
|
+
ngImport: i0,
|
|
29
|
+
type: RetryActionService,
|
|
30
|
+
deps: [],
|
|
31
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
32
|
+
});
|
|
33
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
34
|
+
minVersion: "12.0.0",
|
|
35
|
+
version: "22.2.0",
|
|
36
|
+
ngImport: i0,
|
|
37
|
+
type: RetryActionService,
|
|
38
|
+
providedIn: "root"
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
42
|
+
minVersion: "12.0.0",
|
|
43
|
+
version: "22.2.0",
|
|
44
|
+
ngImport: i0,
|
|
45
|
+
type: RetryActionService,
|
|
46
|
+
decorators: [{
|
|
47
|
+
type: Injectable,
|
|
48
|
+
args: [{ providedIn: "root" }]
|
|
49
|
+
}]
|
|
50
|
+
});
|
|
51
|
+
var SparkLanguageService = class SparkLanguageService {
|
|
52
|
+
http = inject(HttpClient);
|
|
53
|
+
config = inject(SPARK_CONFIG, { optional: true });
|
|
54
|
+
baseUrl = this.config?.baseUrl ?? "/spark";
|
|
55
|
+
currentLang = signal("en", ...ngDevMode ? [{ debugName: "currentLang" }] : /* istanbul ignore next */ []);
|
|
56
|
+
translationsMap = signal({}, ...ngDevMode ? [{ debugName: "translationsMap" }] : /* istanbul ignore next */ []);
|
|
57
|
+
language = this.currentLang.asReadonly();
|
|
58
|
+
languages = signal({}, ...ngDevMode ? [{ debugName: "languages" }] : /* istanbul ignore next */ []);
|
|
59
|
+
constructor() {
|
|
60
|
+
this.loadCulture();
|
|
61
|
+
this.loadTranslations();
|
|
62
|
+
}
|
|
63
|
+
async loadCulture() {
|
|
64
|
+
const config = await firstValueFrom(this.http.get(`${this.baseUrl}/culture`));
|
|
65
|
+
this.languages.set(config.languages);
|
|
66
|
+
const lang = localStorage.getItem("spark-lang") ?? config.defaultLanguage;
|
|
67
|
+
this.currentLang.set(lang);
|
|
68
|
+
currentLanguage.set(lang);
|
|
69
|
+
}
|
|
70
|
+
async loadTranslations() {
|
|
71
|
+
const t = await firstValueFrom(this.http.get(`${this.baseUrl}/translations`));
|
|
72
|
+
this.translationsMap.set(t);
|
|
73
|
+
}
|
|
74
|
+
setLanguage(lang) {
|
|
75
|
+
this.currentLang.set(lang);
|
|
76
|
+
currentLanguage.set(lang);
|
|
77
|
+
localStorage.setItem("spark-lang", lang);
|
|
78
|
+
}
|
|
79
|
+
resolve(ts) {
|
|
80
|
+
if (!ts) return "";
|
|
81
|
+
return ts[this.currentLang()] ?? ts["en"] ?? Object.values(ts)[0] ?? "";
|
|
82
|
+
}
|
|
83
|
+
t(key) {
|
|
84
|
+
const ts = this.translationsMap()[key];
|
|
85
|
+
return this.resolve(ts) || key;
|
|
86
|
+
}
|
|
87
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
88
|
+
minVersion: "12.0.0",
|
|
89
|
+
version: "22.2.0",
|
|
90
|
+
ngImport: i0,
|
|
91
|
+
type: SparkLanguageService,
|
|
92
|
+
deps: [],
|
|
93
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
94
|
+
});
|
|
95
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
96
|
+
minVersion: "12.0.0",
|
|
97
|
+
version: "22.2.0",
|
|
98
|
+
ngImport: i0,
|
|
99
|
+
type: SparkLanguageService,
|
|
100
|
+
providedIn: "root"
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
104
|
+
minVersion: "12.0.0",
|
|
105
|
+
version: "22.2.0",
|
|
106
|
+
ngImport: i0,
|
|
107
|
+
type: SparkLanguageService,
|
|
108
|
+
decorators: [{
|
|
109
|
+
type: Injectable,
|
|
110
|
+
args: [{ providedIn: "root" }]
|
|
111
|
+
}],
|
|
112
|
+
ctorParameters: () => []
|
|
113
|
+
});
|
|
114
|
+
var SparkStreamingService = class SparkStreamingService {
|
|
115
|
+
config = inject(SPARK_CONFIG, { optional: true });
|
|
116
|
+
baseUrl = this.config?.baseUrl ?? "/spark";
|
|
117
|
+
ngZone = inject(NgZone);
|
|
118
|
+
connectToStreamingQuery(queryId) {
|
|
119
|
+
return new Observable((subscriber) => {
|
|
120
|
+
let ws = null;
|
|
121
|
+
let retryCount = 0;
|
|
122
|
+
let retryTimeout = null;
|
|
123
|
+
let closed = false;
|
|
124
|
+
const maxRetries = 10;
|
|
125
|
+
const maxDelay = 3e4;
|
|
126
|
+
const connect = () => {
|
|
127
|
+
if (closed) return;
|
|
128
|
+
const url = this.buildWebSocketUrl(queryId);
|
|
129
|
+
ws = new WebSocket(url);
|
|
130
|
+
ws.onopen = () => {
|
|
131
|
+
retryCount = 0;
|
|
132
|
+
};
|
|
133
|
+
ws.onmessage = (event) => {
|
|
134
|
+
try {
|
|
135
|
+
const message = JSON.parse(event.data);
|
|
136
|
+
this.ngZone.run(() => subscriber.next(message));
|
|
137
|
+
} catch {}
|
|
138
|
+
};
|
|
139
|
+
ws.onerror = () => {};
|
|
140
|
+
ws.onclose = (event) => {
|
|
141
|
+
if (closed) return;
|
|
142
|
+
if (event.code === 1e3) {
|
|
143
|
+
this.ngZone.run(() => subscriber.complete());
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (retryCount < maxRetries) {
|
|
147
|
+
const delay = Math.min(1e3 * Math.pow(2, retryCount), maxDelay);
|
|
148
|
+
retryCount++;
|
|
149
|
+
retryTimeout = setTimeout(() => connect(), delay);
|
|
150
|
+
} else this.ngZone.run(() => subscriber.error(/* @__PURE__ */ new Error("WebSocket connection failed after maximum retries")));
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
connect();
|
|
154
|
+
return () => {
|
|
155
|
+
closed = true;
|
|
156
|
+
if (retryTimeout) clearTimeout(retryTimeout);
|
|
157
|
+
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) ws.close(1e3, "Client unsubscribed");
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
buildWebSocketUrl(queryId) {
|
|
162
|
+
const encodedId = encodeURIComponent(queryId);
|
|
163
|
+
const path = `${this.baseUrl}/queries/${encodedId}/stream`;
|
|
164
|
+
if (this.baseUrl.startsWith("http://")) return path.replace(/^http:\/\//, "ws://");
|
|
165
|
+
if (this.baseUrl.startsWith("https://")) return path.replace(/^https:\/\//, "wss://");
|
|
166
|
+
return `${window.location.protocol === "https:" ? "wss:" : "ws:"}//${window.location.host}${path}`;
|
|
167
|
+
}
|
|
168
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
169
|
+
minVersion: "12.0.0",
|
|
170
|
+
version: "22.2.0",
|
|
171
|
+
ngImport: i0,
|
|
172
|
+
type: SparkStreamingService,
|
|
173
|
+
deps: [],
|
|
174
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
175
|
+
});
|
|
176
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
177
|
+
minVersion: "12.0.0",
|
|
178
|
+
version: "22.2.0",
|
|
179
|
+
ngImport: i0,
|
|
180
|
+
type: SparkStreamingService,
|
|
181
|
+
providedIn: "root"
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
185
|
+
minVersion: "12.0.0",
|
|
186
|
+
version: "22.2.0",
|
|
187
|
+
ngImport: i0,
|
|
188
|
+
type: SparkStreamingService,
|
|
189
|
+
decorators: [{
|
|
190
|
+
type: Injectable,
|
|
191
|
+
args: [{ providedIn: "root" }]
|
|
192
|
+
}]
|
|
193
|
+
});
|
|
194
|
+
var SparkService = class SparkService {
|
|
195
|
+
config = inject(SPARK_CONFIG, { optional: true });
|
|
196
|
+
baseUrl = this.config?.baseUrl ?? "/spark";
|
|
197
|
+
http = inject(HttpClient);
|
|
198
|
+
retryActionService = inject(RetryActionService);
|
|
199
|
+
static MAX_RETRY_DEPTH = 16;
|
|
200
|
+
dispatcher = inject(SparkClientOperationDispatcher);
|
|
201
|
+
async getEntityTypes() {
|
|
202
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/types`));
|
|
203
|
+
}
|
|
204
|
+
async getEntityType(id) {
|
|
205
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/types/${encodeURIComponent(id)}`));
|
|
206
|
+
}
|
|
207
|
+
async getEntityTypeByClrType(clrType) {
|
|
208
|
+
return (await this.getEntityTypes()).find((t) => t.clrType === clrType);
|
|
209
|
+
}
|
|
210
|
+
async getPermissions(entityTypeId) {
|
|
211
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/permissions/${encodeURIComponent(entityTypeId)}`));
|
|
212
|
+
}
|
|
213
|
+
#queryCatalogue;
|
|
214
|
+
async getQueries() {
|
|
215
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/queries`));
|
|
216
|
+
}
|
|
217
|
+
async getQuery(id) {
|
|
218
|
+
return firstValueFrom(this.http.post(`${this.baseUrl}/queries/get`, { queryId: id }));
|
|
219
|
+
}
|
|
220
|
+
async getQueryByName(name) {
|
|
221
|
+
this.#queryCatalogue ??= this.getQueries();
|
|
222
|
+
return (await this.#queryCatalogue).find((q) => q.name === name);
|
|
223
|
+
}
|
|
224
|
+
async executeQuery(queryId, options) {
|
|
225
|
+
return this.sendRead(`${this.baseUrl}/queries/execute`, {
|
|
226
|
+
queryId,
|
|
227
|
+
sortColumns: options?.sortColumns?.length ? options.sortColumns.map((c) => ({
|
|
228
|
+
property: c.property,
|
|
229
|
+
direction: c.direction === "descending" ? "desc" : "asc"
|
|
230
|
+
})) : void 0,
|
|
231
|
+
parentId: options?.parentId,
|
|
232
|
+
parentType: options?.parentType,
|
|
233
|
+
skip: options?.skip,
|
|
234
|
+
take: options?.take,
|
|
235
|
+
search: options?.search,
|
|
236
|
+
columns: options?.columns?.length ? options.columns : void 0,
|
|
237
|
+
deleted: options?.deleted,
|
|
238
|
+
parentDeleted: options?.parentDeleted
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
async getDistinctValues(queryId, column, options) {
|
|
242
|
+
return this.sendRead(`${this.baseUrl}/queries/distinct-values`, {
|
|
243
|
+
queryId,
|
|
244
|
+
column,
|
|
245
|
+
search: options?.search || void 0,
|
|
246
|
+
querySearch: options?.querySearch || void 0,
|
|
247
|
+
columns: options?.columns?.length ? options.columns : void 0,
|
|
248
|
+
deleted: options?.deleted,
|
|
249
|
+
parentId: options?.parentId,
|
|
250
|
+
parentType: options?.parentType,
|
|
251
|
+
parentDeleted: options?.parentDeleted
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
async executeQueryByName(queryName, options) {
|
|
255
|
+
const query = await this.getQueryByName(queryName);
|
|
256
|
+
if (!query) return {
|
|
257
|
+
columns: [],
|
|
258
|
+
items: [],
|
|
259
|
+
totalItems: 0,
|
|
260
|
+
skip: 0,
|
|
261
|
+
take: options?.take ?? 50
|
|
262
|
+
};
|
|
263
|
+
return this.executeQuery(query.id, options);
|
|
264
|
+
}
|
|
265
|
+
async getProgramUnits() {
|
|
266
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/program-units`));
|
|
267
|
+
}
|
|
268
|
+
async get(type, id, options) {
|
|
269
|
+
return this.sendRead(`${this.baseUrl}/po/load`, {
|
|
270
|
+
objectTypeId: type,
|
|
271
|
+
id,
|
|
272
|
+
deleted: options?.deleted
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async create(type, data) {
|
|
276
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/create`, {
|
|
277
|
+
objectTypeId: type,
|
|
278
|
+
persistentObject: data
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async update(type, id, data) {
|
|
282
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/update`, {
|
|
283
|
+
objectTypeId: type,
|
|
284
|
+
id,
|
|
285
|
+
persistentObject: data
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
async refresh(type, data, triggeredBy) {
|
|
289
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/refresh`, {
|
|
290
|
+
objectTypeId: type,
|
|
291
|
+
persistentObject: data,
|
|
292
|
+
triggeredBy
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
async newObject(type, options) {
|
|
296
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/new`, {
|
|
297
|
+
objectTypeId: type,
|
|
298
|
+
...options ?? {}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
async deleteRow(type, options) {
|
|
302
|
+
await this.postWithEnvelope(`${this.baseUrl}/po/delete-row`, {
|
|
303
|
+
objectTypeId: type,
|
|
304
|
+
...options
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
async delete(type, id) {
|
|
308
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/delete`, {
|
|
309
|
+
objectTypeId: type,
|
|
310
|
+
id
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
async deleteMany(type, ids, options) {
|
|
314
|
+
return this.postWithEnvelope(`${this.baseUrl}/po/delete-many`, {
|
|
315
|
+
objectTypeId: type,
|
|
316
|
+
ids,
|
|
317
|
+
...options ?? {}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
async getCustomActions(objectTypeId) {
|
|
321
|
+
return firstValueFrom(this.http.post(`${this.baseUrl}/actions/list`, { objectTypeId }));
|
|
322
|
+
}
|
|
323
|
+
async executeCustomAction(objectTypeId, actionName, parent, selectedItemIds, queryParent, queryId) {
|
|
324
|
+
const body = {
|
|
325
|
+
objectTypeId,
|
|
326
|
+
actionName,
|
|
327
|
+
parent,
|
|
328
|
+
selectedItemIds,
|
|
329
|
+
parentId: queryParent?.id,
|
|
330
|
+
parentType: queryParent?.type,
|
|
331
|
+
queryId
|
|
332
|
+
};
|
|
333
|
+
return await this.postWithEnvelope(`${this.baseUrl}/actions/execute`, body) ?? void 0;
|
|
334
|
+
}
|
|
335
|
+
async getLookupReferences() {
|
|
336
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/lookupref`));
|
|
337
|
+
}
|
|
338
|
+
async getLookupReference(name) {
|
|
339
|
+
return firstValueFrom(this.http.get(`${this.baseUrl}/lookupref/${encodeURIComponent(name)}`));
|
|
340
|
+
}
|
|
341
|
+
async addLookupReferenceValue(name, value) {
|
|
342
|
+
return firstValueFrom(this.http.post(`${this.baseUrl}/lookupref/${encodeURIComponent(name)}`, value));
|
|
343
|
+
}
|
|
344
|
+
async updateLookupReferenceValue(name, key, value) {
|
|
345
|
+
return firstValueFrom(this.http.put(`${this.baseUrl}/lookupref/${encodeURIComponent(name)}/${encodeURIComponent(key)}`, value));
|
|
346
|
+
}
|
|
347
|
+
async deleteLookupReferenceValue(name, key) {
|
|
348
|
+
return firstValueFrom(this.http.delete(`${this.baseUrl}/lookupref/${encodeURIComponent(name)}/${encodeURIComponent(key)}`));
|
|
349
|
+
}
|
|
350
|
+
postEnvelope(path, body) {
|
|
351
|
+
return this.postWithEnvelope(`${this.baseUrl}${path}`, body);
|
|
352
|
+
}
|
|
353
|
+
postWithEnvelope(url, body) {
|
|
354
|
+
return this.sendWithEnvelope(() => firstValueFrom(this.http.post(url, body)), body, () => this.postWithEnvelope(url, body));
|
|
355
|
+
}
|
|
356
|
+
async sendRead(url, body) {
|
|
357
|
+
try {
|
|
358
|
+
return await firstValueFrom(this.http.post(url, body));
|
|
359
|
+
} catch (error) {
|
|
360
|
+
return this.handleEnvelopeRetryError(error, () => this.sendRead(url, body), body);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
async sendWithEnvelope(send, body, retryFn) {
|
|
364
|
+
try {
|
|
365
|
+
const envelope = await send();
|
|
366
|
+
if (envelope?.operations?.length) this.dispatcher.dispatch(envelope.operations);
|
|
367
|
+
return envelope?.result;
|
|
368
|
+
} catch (error) {
|
|
369
|
+
return this.handleEnvelopeRetryError(error, retryFn, body);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async handleEnvelopeRetryError(error, retryFn, body) {
|
|
373
|
+
if (error.status !== 449) throw error;
|
|
374
|
+
const envelope = error.error;
|
|
375
|
+
if (!envelope?.operations?.length) throw error;
|
|
376
|
+
const nonRetry = envelope.operations.filter((o) => o.type !== "retry");
|
|
377
|
+
if (nonRetry.length) this.dispatcher.dispatch(nonRetry);
|
|
378
|
+
const retryOp = envelope.operations.find((o) => o.type === "retry");
|
|
379
|
+
if (!retryOp) throw error;
|
|
380
|
+
if ((body.retryResults?.length ?? 0) >= SparkService.MAX_RETRY_DEPTH) throw new Error(`Gave up after answering ${SparkService.MAX_RETRY_DEPTH} retry prompts; the last was step ${retryOp.step} ("${retryOp.title}"). A hook that raises a retry without checking Retry.Result first will do this — it re-raises on every resubmission.`);
|
|
381
|
+
const payload = {
|
|
382
|
+
type: "retry-action",
|
|
383
|
+
step: retryOp.step,
|
|
384
|
+
title: retryOp.title,
|
|
385
|
+
options: retryOp.options,
|
|
386
|
+
defaultOption: retryOp.defaultOption ?? void 0,
|
|
387
|
+
persistentObject: retryOp.persistentObject ?? void 0,
|
|
388
|
+
message: retryOp.message ?? void 0
|
|
389
|
+
};
|
|
390
|
+
const result = await this.retryActionService.show(payload);
|
|
391
|
+
if (result.option === "Cancel" && !payload.options.includes("Cancel")) throw error;
|
|
392
|
+
body.retryResults = [...body.retryResults || [], result];
|
|
393
|
+
return retryFn();
|
|
394
|
+
}
|
|
395
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
396
|
+
minVersion: "12.0.0",
|
|
397
|
+
version: "22.2.0",
|
|
398
|
+
ngImport: i0,
|
|
399
|
+
type: SparkService,
|
|
400
|
+
deps: [],
|
|
401
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
402
|
+
});
|
|
403
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
404
|
+
minVersion: "12.0.0",
|
|
405
|
+
version: "22.2.0",
|
|
406
|
+
ngImport: i0,
|
|
407
|
+
type: SparkService,
|
|
408
|
+
providedIn: "root"
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
412
|
+
minVersion: "12.0.0",
|
|
413
|
+
version: "22.2.0",
|
|
414
|
+
ngImport: i0,
|
|
415
|
+
type: SparkService,
|
|
416
|
+
decorators: [{
|
|
417
|
+
type: Injectable,
|
|
418
|
+
args: [{ providedIn: "root" }]
|
|
419
|
+
}]
|
|
420
|
+
});
|
|
451
421
|
const SPARK_BUILT_IN_ICONS = {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
422
|
+
"three-dots-vertical": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-three-dots-vertical\" viewBox=\"0 0 16 16\"><path d=\"M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0\"/></svg>",
|
|
423
|
+
"x-circle": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-x-circle\" viewBox=\"0 0 16 16\"><path d=\"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16\"/><path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/></svg>",
|
|
424
|
+
"arrow-left": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-arrow-left\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8\"/></svg>",
|
|
425
|
+
"pencil": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-pencil\" viewBox=\"0 0 16 16\"><path d=\"M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325\"/></svg>",
|
|
426
|
+
"plus": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-plus\" viewBox=\"0 0 16 16\"><path d=\"M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4\"/></svg>",
|
|
427
|
+
"plus-lg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-plus-lg\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2\"/></svg>",
|
|
428
|
+
"search": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-search\" viewBox=\"0 0 16 16\"><path d=\"M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0\"/></svg>",
|
|
429
|
+
"trash": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-trash\" viewBox=\"0 0 16 16\"><path d=\"M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z\"/><path d=\"M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z\"/></svg>",
|
|
430
|
+
"x-lg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-x-lg\" viewBox=\"0 0 16 16\"><path d=\"M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z\"/></svg>"
|
|
459
431
|
};
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
432
|
+
var SparkIconRegistry = class SparkIconRegistry {
|
|
433
|
+
sanitizer = inject(DomSanitizer);
|
|
434
|
+
icons = /* @__PURE__ */ new Map();
|
|
435
|
+
constructor() {
|
|
436
|
+
for (const [name, svg] of Object.entries(SPARK_BUILT_IN_ICONS)) this.icons.set(name, this.sanitizer.bypassSecurityTrustHtml(svg));
|
|
437
|
+
}
|
|
438
|
+
register(name, svg) {
|
|
439
|
+
this.icons.set(name, svg);
|
|
440
|
+
}
|
|
441
|
+
get(name) {
|
|
442
|
+
return this.icons.get(name);
|
|
443
|
+
}
|
|
444
|
+
has(name) {
|
|
445
|
+
return this.icons.has(name);
|
|
446
|
+
}
|
|
447
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
448
|
+
minVersion: "12.0.0",
|
|
449
|
+
version: "22.2.0",
|
|
450
|
+
ngImport: i0,
|
|
451
|
+
type: SparkIconRegistry,
|
|
452
|
+
deps: [],
|
|
453
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
454
|
+
});
|
|
455
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
456
|
+
minVersion: "12.0.0",
|
|
457
|
+
version: "22.2.0",
|
|
458
|
+
ngImport: i0,
|
|
459
|
+
type: SparkIconRegistry,
|
|
460
|
+
providedIn: "root"
|
|
461
|
+
});
|
|
462
|
+
};
|
|
463
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
464
|
+
minVersion: "12.0.0",
|
|
465
|
+
version: "22.2.0",
|
|
466
|
+
ngImport: i0,
|
|
467
|
+
type: SparkIconRegistry,
|
|
468
|
+
decorators: [{
|
|
469
|
+
type: Injectable,
|
|
470
|
+
args: [{ providedIn: "root" }]
|
|
471
|
+
}],
|
|
472
|
+
ctorParameters: () => []
|
|
473
|
+
});
|
|
474
|
+
var SparkQueryActionsService = class SparkQueryActionsService {
|
|
475
|
+
sparkService = inject(SparkService);
|
|
476
|
+
async actionsFor(queryIdOrAlias) {
|
|
477
|
+
const context = await this.contextFor(queryIdOrAlias);
|
|
478
|
+
if (!context) return [];
|
|
479
|
+
return filterQueryActions(await this.sparkService.getCustomActions(context.entityType.id));
|
|
480
|
+
}
|
|
481
|
+
async execute(queryIdOrAlias, actionName, options) {
|
|
482
|
+
const context = await this.contextFor(queryIdOrAlias);
|
|
483
|
+
if (!context) throw new Error(`Cannot execute '${actionName}': query '${queryIdOrAlias}' resolves to no entity type, so there is nothing to execute it against.`);
|
|
484
|
+
await this.sparkService.executeCustomAction(context.entityType.id, actionName, options?.parent, options?.selectedItemIds, options?.queryParent, context.query.id);
|
|
485
|
+
}
|
|
486
|
+
async contextFor(queryIdOrAlias) {
|
|
487
|
+
const [query, entityTypes] = await Promise.all([this.sparkService.getQuery(queryIdOrAlias), this.sparkService.getEntityTypes()]);
|
|
488
|
+
if (!query) return null;
|
|
489
|
+
const entityType = entityTypes.find((t) => t.name === query.entityType) ?? entityTypes.find((t) => t.id === query.entityType);
|
|
490
|
+
return entityType ? {
|
|
491
|
+
query,
|
|
492
|
+
entityType
|
|
493
|
+
} : null;
|
|
494
|
+
}
|
|
495
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
496
|
+
minVersion: "12.0.0",
|
|
497
|
+
version: "22.2.0",
|
|
498
|
+
ngImport: i0,
|
|
499
|
+
type: SparkQueryActionsService,
|
|
500
|
+
deps: [],
|
|
501
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
502
|
+
});
|
|
503
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
504
|
+
minVersion: "12.0.0",
|
|
505
|
+
version: "22.2.0",
|
|
506
|
+
ngImport: i0,
|
|
507
|
+
type: SparkQueryActionsService,
|
|
508
|
+
providedIn: "root"
|
|
509
|
+
});
|
|
510
|
+
};
|
|
511
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
512
|
+
minVersion: "12.0.0",
|
|
513
|
+
version: "22.2.0",
|
|
514
|
+
ngImport: i0,
|
|
515
|
+
type: SparkQueryActionsService,
|
|
516
|
+
decorators: [{
|
|
517
|
+
type: Injectable,
|
|
518
|
+
args: [{ providedIn: "root" }]
|
|
519
|
+
}]
|
|
520
|
+
});
|
|
521
|
+
const SPARK_TIMEZONE_HEADER = "X-Spark-Timezone";
|
|
522
|
+
const SPARK_TIMEZONE_COOKIE = "spark-timezone";
|
|
523
|
+
const COOKIE_MAX_AGE_SECONDS = 31536e3;
|
|
524
|
+
const ZONE_ID_SHAPE = /^[A-Za-z][A-Za-z0-9_+\-]*(\/[A-Za-z0-9_+\-]+){0,2}$/;
|
|
525
|
+
function resolveBrowserTimeZone() {
|
|
526
|
+
try {
|
|
527
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
|
|
528
|
+
} catch {
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
504
531
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
* A query's custom actions, reachable **without the grid that usually renders them**.
|
|
512
|
-
*
|
|
513
|
-
* ## Why this exists
|
|
514
|
-
*
|
|
515
|
-
* A query's actions were only ever obtainable by rendering `<spark-query-grid>`, which loads the
|
|
516
|
-
* query, resolves its entity type, fetches the actions and filters them to the ones marked for a
|
|
517
|
-
* query surface — all privately. A page that wanted the same buttons somewhere else (a toolbar
|
|
518
|
-
* above the card, the shell's topbar) had three bad options: duplicate the four-step resolution
|
|
519
|
-
* and let it drift, reach into the grid's internals, or put the button in the wrong place.
|
|
520
|
-
*
|
|
521
|
-
* This exposes the resolution itself. The grid keeps rendering the default placement; a host that
|
|
522
|
-
* wants a different one asks here and renders its own control.
|
|
523
|
-
*
|
|
524
|
-
* ## What it does not do
|
|
525
|
-
*
|
|
526
|
-
* It does not authorize. `/spark/actions/{type}` returns only the actions this caller may see —
|
|
527
|
-
* the server filters against `security.json`, and executing re-checks — so nothing here is a gate,
|
|
528
|
-
* and a host must not treat "the list came back empty" as anything other than a display fact.
|
|
529
|
-
*
|
|
530
|
-
* It also does not cache. Actions depend on the caller, and a memo keyed by type id would survive
|
|
531
|
-
* a sign-out.
|
|
532
|
-
*/
|
|
533
|
-
class SparkQueryActionsService {
|
|
534
|
-
sparkService = inject(SparkService);
|
|
535
|
-
/**
|
|
536
|
-
* The custom actions of the query named by id or alias, already filtered to those that belong on
|
|
537
|
-
* a query surface.
|
|
538
|
-
*
|
|
539
|
-
* Returns an empty list — rather than throwing — when the query resolves to no entity type,
|
|
540
|
-
* because a caller rendering a toolbar wants "no buttons", not a broken page.
|
|
541
|
-
*/
|
|
542
|
-
async actionsFor(queryIdOrAlias) {
|
|
543
|
-
const context = await this.contextFor(queryIdOrAlias);
|
|
544
|
-
if (!context)
|
|
545
|
-
return [];
|
|
546
|
-
// filterQueryActions, not a local predicate: the grid uses it too, and the `showedOn` values
|
|
547
|
-
// are exactly the kind of thing a second copy gets subtly wrong — both grids once tested for
|
|
548
|
-
// "list", a value nothing emits, and every correctly authored action rendered nowhere.
|
|
549
|
-
return filterQueryActions(await this.sparkService.getCustomActions(context.entityType.id));
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Runs one of those actions. `selectedItemIds` are row ids, exactly as the grid posts them —
|
|
553
|
-
* the server re-materializes each one through the same load path a detail page uses, so an id
|
|
554
|
-
* from anywhere is treated as caller input rather than as a verified row.
|
|
555
|
-
*/
|
|
556
|
-
async execute(queryIdOrAlias, actionName, options) {
|
|
557
|
-
const context = await this.contextFor(queryIdOrAlias);
|
|
558
|
-
if (!context) {
|
|
559
|
-
throw new Error(`Cannot execute '${actionName}': query '${queryIdOrAlias}' resolves to no entity type, so there ` +
|
|
560
|
-
`is nothing to execute it against.`);
|
|
561
|
-
}
|
|
562
|
-
await this.sparkService.executeCustomAction(context.entityType.id, actionName, options?.parent, options?.selectedItemIds, options?.queryParent, context.query.id);
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* The query and the entity type its rows are mapped against — the two-step resolution both
|
|
566
|
-
* methods need, kept in one place so they cannot disagree about which type an action runs on.
|
|
567
|
-
*/
|
|
568
|
-
async contextFor(queryIdOrAlias) {
|
|
569
|
-
const [query, entityTypes] = await Promise.all([
|
|
570
|
-
this.sparkService.getQuery(queryIdOrAlias),
|
|
571
|
-
this.sparkService.getEntityTypes(),
|
|
572
|
-
]);
|
|
573
|
-
if (!query)
|
|
574
|
-
return null;
|
|
575
|
-
const entityType = entityTypes.find(t => t.name === query.entityType)
|
|
576
|
-
?? entityTypes.find(t => t.id === query.entityType);
|
|
577
|
-
return entityType ? { query, entityType } : null;
|
|
578
|
-
}
|
|
579
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkQueryActionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
580
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SparkQueryActionsService, providedIn: 'root' });
|
|
532
|
+
function readCookie(cookies, name) {
|
|
533
|
+
for (const part of cookies.split(";")) {
|
|
534
|
+
const eq = part.indexOf("=");
|
|
535
|
+
if (eq > 0 && part.slice(0, eq).trim() === name) return part.slice(eq + 1).trim();
|
|
536
|
+
}
|
|
537
|
+
return null;
|
|
581
538
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* The header carrying the viewer's IANA timezone id, e.g. `Europe/Brussels`.
|
|
589
|
-
* Must stay in lockstep with `RequestTimeZoneResolver.HeaderName` on the server.
|
|
590
|
-
*/
|
|
591
|
-
const SPARK_TIMEZONE_HEADER = 'X-Spark-Timezone';
|
|
592
|
-
/**
|
|
593
|
-
* Returns the browser's IANA zone id, or `null` when the environment cannot name one.
|
|
594
|
-
*
|
|
595
|
-
* An id is deliberately sent rather than a numeric offset: an offset is only valid at one instant,
|
|
596
|
-
* so a server asked to render "next Tuesday at 09:00" from an offset captured today gets it wrong
|
|
597
|
-
* across a DST boundary. A zone id carries the rules, not one sample of them.
|
|
598
|
-
*/
|
|
599
|
-
function resolveBrowserTimeZone() {
|
|
600
|
-
try {
|
|
601
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
|
|
602
|
-
}
|
|
603
|
-
catch {
|
|
604
|
-
return null;
|
|
605
|
-
}
|
|
539
|
+
function writeTimezoneCookie(doc, name, zone) {
|
|
540
|
+
if (readCookie(doc.cookie, name) === zone) return;
|
|
541
|
+
const secure = doc.location?.protocol === "https:" ? "; Secure" : "";
|
|
542
|
+
doc.cookie = `${name}=${zone}; Path=/; Max-Age=${COOKIE_MAX_AGE_SECONDS}; SameSite=Lax${secure}`;
|
|
606
543
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
return next(req);
|
|
622
|
-
}
|
|
623
|
-
catch {
|
|
624
|
-
return next(req);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
const zone = resolveBrowserTimeZone();
|
|
628
|
-
if (!zone)
|
|
629
|
-
return next(req);
|
|
630
|
-
return next(req.clone({ setHeaders: { [SPARK_TIMEZONE_HEADER]: zone } }));
|
|
631
|
-
};
|
|
632
|
-
/**
|
|
633
|
-
* `provideHttpClient(...withSparkTimezone())` — registers {@link sparkTimezoneInterceptor}.
|
|
634
|
-
*
|
|
635
|
-
* Spreadable alongside `withSparkAuth()`:
|
|
636
|
-
* `provideHttpClient(...withSparkAuth(), ...withSparkTimezone())`.
|
|
637
|
-
*/
|
|
638
|
-
function withSparkTimezone() {
|
|
639
|
-
return [withInterceptors([sparkTimezoneInterceptor])];
|
|
544
|
+
function createSparkTimezoneInterceptor(options = {}) {
|
|
545
|
+
const cookieName = options.cookieName === void 0 ? SPARK_TIMEZONE_COOKIE : options.cookieName;
|
|
546
|
+
return (req, next) => {
|
|
547
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID))) return next(req);
|
|
548
|
+
const zone = resolveBrowserTimeZone();
|
|
549
|
+
if (!zone) return next(req);
|
|
550
|
+
if (cookieName && ZONE_ID_SHAPE.test(zone)) writeTimezoneCookie(inject(DOCUMENT), cookieName, zone);
|
|
551
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(req.url)) try {
|
|
552
|
+
if (new URL(req.url).origin !== window.location.origin) return next(req);
|
|
553
|
+
} catch {
|
|
554
|
+
return next(req);
|
|
555
|
+
}
|
|
556
|
+
return next(req.clone({ setHeaders: { [SPARK_TIMEZONE_HEADER]: zone } }));
|
|
557
|
+
};
|
|
640
558
|
}
|
|
559
|
+
const sparkTimezoneInterceptor = createSparkTimezoneInterceptor();
|
|
560
|
+
function withSparkTimezone(options) {
|
|
561
|
+
return [withInterceptors([options ? createSparkTimezoneInterceptor(options) : sparkTimezoneInterceptor])];
|
|
562
|
+
}
|
|
563
|
+
const SPARK_RETURN_URL_STATE_KEY = "sparkReturnUrl";
|
|
564
|
+
var SparkReturnNavigationService = class SparkReturnNavigationService {
|
|
565
|
+
router = inject(Router);
|
|
566
|
+
spark = inject(SparkService);
|
|
567
|
+
stateForRowLink() {
|
|
568
|
+
return { [SPARK_RETURN_URL_STATE_KEY]: this.router.url };
|
|
569
|
+
}
|
|
570
|
+
recordedReturnUrl() {
|
|
571
|
+
const url = (typeof history !== "undefined" ? history.state : null)?.[SPARK_RETURN_URL_STATE_KEY];
|
|
572
|
+
return typeof url === "string" && url.startsWith("/") && !url.startsWith("//") ? url : null;
|
|
573
|
+
}
|
|
574
|
+
async returnToList(entityTypeName, options) {
|
|
575
|
+
const recorded = this.recordedReturnUrl();
|
|
576
|
+
if (recorded) {
|
|
577
|
+
await this.router.navigateByUrl(recorded, { replaceUrl: true });
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
const route = entityTypeName ? await this.listRouteFor(entityTypeName) : null;
|
|
581
|
+
if (route) {
|
|
582
|
+
await this.router.navigate(route, {
|
|
583
|
+
replaceUrl: true,
|
|
584
|
+
...options?.deletedView ? { queryParams: { deleted: "only" } } : {}
|
|
585
|
+
});
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
await this.router.navigate(["/"], { replaceUrl: true });
|
|
589
|
+
}
|
|
590
|
+
async listRouteFor(entityTypeName) {
|
|
591
|
+
let queries;
|
|
592
|
+
try {
|
|
593
|
+
queries = (await this.spark.getQueries()).filter((q) => q.entityType === entityTypeName);
|
|
594
|
+
} catch {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
if (!queries.length) return null;
|
|
598
|
+
try {
|
|
599
|
+
const units = (await this.spark.getProgramUnits()).programUnitGroups.flatMap((g) => g.programUnits).filter((u) => u.type === "query").sort((a, b) => a.order - b.order);
|
|
600
|
+
for (const unit of units) if (queries.some((q) => q.id === unit.queryId || !!unit.alias && q.alias === unit.alias)) return ["/query", unit.alias || unit.queryId];
|
|
601
|
+
} catch {}
|
|
602
|
+
return ["/query", queries[0].alias || queries[0].id];
|
|
603
|
+
}
|
|
604
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
605
|
+
minVersion: "12.0.0",
|
|
606
|
+
version: "22.2.0",
|
|
607
|
+
ngImport: i0,
|
|
608
|
+
type: SparkReturnNavigationService,
|
|
609
|
+
deps: [],
|
|
610
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
611
|
+
});
|
|
612
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({
|
|
613
|
+
minVersion: "12.0.0",
|
|
614
|
+
version: "22.2.0",
|
|
615
|
+
ngImport: i0,
|
|
616
|
+
type: SparkReturnNavigationService,
|
|
617
|
+
providedIn: "root"
|
|
618
|
+
});
|
|
619
|
+
};
|
|
620
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
621
|
+
minVersion: "12.0.0",
|
|
622
|
+
version: "22.2.0",
|
|
623
|
+
ngImport: i0,
|
|
624
|
+
type: SparkReturnNavigationService,
|
|
625
|
+
decorators: [{
|
|
626
|
+
type: Injectable,
|
|
627
|
+
args: [{ providedIn: "root" }]
|
|
628
|
+
}]
|
|
629
|
+
});
|
|
630
|
+
export { RetryActionService, SPARK_RETURN_URL_STATE_KEY, SPARK_TIMEZONE_COOKIE, SPARK_TIMEZONE_HEADER, SparkIconRegistry, SparkLanguageService, SparkQueryActionsService, SparkReturnNavigationService, SparkService, SparkStreamingService, createSparkTimezoneInterceptor, resolveBrowserTimeZone, sparkTimezoneInterceptor, withSparkTimezone };
|
|
641
631
|
|
|
642
|
-
|
|
643
|
-
* Generated bundle index. Do not edit.
|
|
644
|
-
*/
|
|
645
|
-
|
|
646
|
-
export { RetryActionService, SPARK_TIMEZONE_HEADER, SparkIconRegistry, SparkLanguageService, SparkQueryActionsService, SparkService, SparkStreamingService, resolveBrowserTimeZone, sparkTimezoneInterceptor, withSparkTimezone };
|
|
647
|
-
//# sourceMappingURL=mintplayer-ng-spark-services.mjs.map
|
|
632
|
+
//# sourceMappingURL=mintplayer-ng-spark-services.mjs.map
|