@mintplayer/ng-spark 22.31.0 → 22.33.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 +101 -1
- package/fesm2022/mintplayer-ng-spark-attribute-description.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-account.mjs +18 -18
- package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs +16 -8
- package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-auth-confirm-email.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-core.mjs +6 -6
- package/fesm2022/mintplayer-ng-spark-auth-external-login.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-login.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-register.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +24 -24
- package/fesm2022/mintplayer-ng-spark-column-filter.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-contributions.mjs +9 -9
- package/fesm2022/mintplayer-ng-spark-grid.mjs +220 -49
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-history.mjs +9 -9
- package/fesm2022/mintplayer-ng-spark-icon.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-identity-provider-connected-applications.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-identity-provider-core.mjs +9 -9
- package/fesm2022/mintplayer-ng-spark-identity-provider-developers.mjs +6 -6
- package/fesm2022/mintplayer-ng-spark-identity-provider-management.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-models.mjs +44 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-moderation.mjs +21 -21
- package/fesm2022/mintplayer-ng-spark-notifications.mjs +687 -0
- package/fesm2022/mintplayer-ng-spark-notifications.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-organizations-accept.mjs +179 -0
- package/fesm2022/mintplayer-ng-spark-organizations-accept.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-organizations.mjs +202 -0
- package/fesm2022/mintplayer-ng-spark-organizations.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +125 -85
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +90 -26
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +84 -12
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +9 -9
- package/fesm2022/mintplayer-ng-spark-pwa.mjs +74 -6
- package/fesm2022/mintplayer-ng-spark-pwa.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +10 -109
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-score-renderers.mjs +801 -0
- package/fesm2022/mintplayer-ng-spark-score-renderers.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-services.mjs +424 -72
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-share-page.mjs +334 -0
- package/fesm2022/mintplayer-ng-spark-share-page.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-share.mjs +10 -0
- package/fesm2022/mintplayer-ng-spark-share.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-shell.mjs +38 -36
- package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-soft-delete.mjs +9 -9
- package/package.json +25 -1
- package/types/mintplayer-ng-spark-grid.d.ts +77 -26
- package/types/mintplayer-ng-spark-models.d.ts +150 -17
- package/types/mintplayer-ng-spark-notifications.d.ts +188 -0
- package/types/mintplayer-ng-spark-organizations-accept.d.ts +40 -0
- package/types/mintplayer-ng-spark-organizations.d.ts +72 -0
- package/types/mintplayer-ng-spark-pipes.d.ts +10 -0
- package/types/mintplayer-ng-spark-po-detail.d.ts +26 -0
- package/types/mintplayer-ng-spark-po-edit.d.ts +37 -0
- package/types/mintplayer-ng-spark-pwa.d.ts +48 -2
- package/types/mintplayer-ng-spark-query-list.d.ts +8 -23
- package/types/mintplayer-ng-spark-score-renderers.d.ts +340 -0
- package/types/mintplayer-ng-spark-services.d.ts +146 -6
- package/types/mintplayer-ng-spark-share-page.d.ts +67 -0
- package/types/mintplayer-ng-spark-share.d.ts +26 -0
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.33.0",
|
|
5
5
|
"description": "Angular component library for MintPlayer.Spark CRUD applications",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -160,6 +160,18 @@
|
|
|
160
160
|
"types": "./types/mintplayer-ng-spark-moderation.d.ts",
|
|
161
161
|
"default": "./fesm2022/mintplayer-ng-spark-moderation.mjs"
|
|
162
162
|
},
|
|
163
|
+
"./notifications": {
|
|
164
|
+
"types": "./types/mintplayer-ng-spark-notifications.d.ts",
|
|
165
|
+
"default": "./fesm2022/mintplayer-ng-spark-notifications.mjs"
|
|
166
|
+
},
|
|
167
|
+
"./organizations": {
|
|
168
|
+
"types": "./types/mintplayer-ng-spark-organizations.d.ts",
|
|
169
|
+
"default": "./fesm2022/mintplayer-ng-spark-organizations.mjs"
|
|
170
|
+
},
|
|
171
|
+
"./organizations/accept": {
|
|
172
|
+
"types": "./types/mintplayer-ng-spark-organizations-accept.d.ts",
|
|
173
|
+
"default": "./fesm2022/mintplayer-ng-spark-organizations-accept.mjs"
|
|
174
|
+
},
|
|
163
175
|
"./panels": {
|
|
164
176
|
"types": "./types/mintplayer-ng-spark-panels.d.ts",
|
|
165
177
|
"default": "./fesm2022/mintplayer-ng-spark-panels.mjs"
|
|
@@ -204,10 +216,22 @@
|
|
|
204
216
|
"types": "./types/mintplayer-ng-spark-routes.d.ts",
|
|
205
217
|
"default": "./fesm2022/mintplayer-ng-spark-routes.mjs"
|
|
206
218
|
},
|
|
219
|
+
"./score-renderers": {
|
|
220
|
+
"types": "./types/mintplayer-ng-spark-score-renderers.d.ts",
|
|
221
|
+
"default": "./fesm2022/mintplayer-ng-spark-score-renderers.mjs"
|
|
222
|
+
},
|
|
207
223
|
"./services": {
|
|
208
224
|
"types": "./types/mintplayer-ng-spark-services.d.ts",
|
|
209
225
|
"default": "./fesm2022/mintplayer-ng-spark-services.mjs"
|
|
210
226
|
},
|
|
227
|
+
"./share": {
|
|
228
|
+
"types": "./types/mintplayer-ng-spark-share.d.ts",
|
|
229
|
+
"default": "./fesm2022/mintplayer-ng-spark-share.mjs"
|
|
230
|
+
},
|
|
231
|
+
"./share/page": {
|
|
232
|
+
"types": "./types/mintplayer-ng-spark-share-page.d.ts",
|
|
233
|
+
"default": "./fesm2022/mintplayer-ng-spark-share-page.mjs"
|
|
234
|
+
},
|
|
211
235
|
"./shell": {
|
|
212
236
|
"types": "./types/mintplayer-ng-spark-shell.d.ts",
|
|
213
237
|
"default": "./fesm2022/mintplayer-ng-spark-shell.mjs"
|
|
@@ -219,23 +219,22 @@ export declare function sparkActionClass(definition: CustomActionDefinition, siz
|
|
|
219
219
|
* The one Spark grid: a `<bs-datatable>` rendering a query or a sub-query.
|
|
220
220
|
*
|
|
221
221
|
* This replaces two components that were the same grid written twice — and, counting
|
|
222
|
-
* `spark-query-list`'s streaming and paged branches, the `<bs-datatable>` element itself
|
|
223
|
-
* three times. The duplication had already produced four user-visible bugs, each fixed on
|
|
224
|
-
* side and not the other: `[indeterminate]` on null booleans, permission state surviving a failed
|
|
222
|
+
* `spark-query-list`'s former streaming and paged branches, the `<bs-datatable>` element itself
|
|
223
|
+
* written three times. The duplication had already produced four user-visible bugs, each fixed on
|
|
224
|
+
* one side and not the other: `[indeterminate]` on null booleans, permission state surviving a failed
|
|
225
225
|
* reload, a swallowed fetch failure, and virtual-scroll sizing. `SparkGridRenderers` was
|
|
226
226
|
* extracted to stop that and could only take the stateless helpers with it; this takes the rest.
|
|
227
227
|
*
|
|
228
|
-
* ##
|
|
228
|
+
* ## Where the rows come from
|
|
229
229
|
*
|
|
230
|
-
* `
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* - unbound `data` — the grid fetches for itself, paging and sorting server-side;
|
|
230
|
+
* - unbound `data` — the grid fetches for itself, paging and sorting server-side: over HTTP, or over
|
|
231
|
+
* `/spark/live` when the grid is live (see {@link live});
|
|
234
232
|
* - bound `data` — the grid renders what it is given and never fetches.
|
|
235
233
|
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
234
|
+
* This is the line `bs-datatable` itself draws: `[data]` and `[fetch]` are mutually exclusive, and
|
|
235
|
+
* binding both makes `[fetch]` win silently. Live rides on `[fetch]`, so server-side paging, sort,
|
|
236
|
+
* search and filters work the same live or not; every embedded grid, sub-query and card follows a live
|
|
237
|
+
* query, not only the query page.
|
|
239
238
|
*
|
|
240
239
|
* ## Reading its state
|
|
241
240
|
*
|
|
@@ -246,6 +245,7 @@ export declare function sparkActionClass(definition: CustomActionDefinition, siz
|
|
|
246
245
|
*/
|
|
247
246
|
export declare class SparkQueryGridComponent {
|
|
248
247
|
private readonly sparkService;
|
|
248
|
+
private readonly liveService;
|
|
249
249
|
private readonly gridRenderers;
|
|
250
250
|
private readonly queryRefresh;
|
|
251
251
|
private readonly injector;
|
|
@@ -282,11 +282,31 @@ export declare class SparkQueryGridComponent {
|
|
|
282
282
|
/**
|
|
283
283
|
* Rows supplied from outside. When bound, the grid renders these and runs no fetch.
|
|
284
284
|
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
285
|
+
* `null` — the default — means "fetch for yourself"; an empty array means "you have been given no
|
|
286
|
+
* rows", which is a different statement and renders an empty grid rather than triggering a load.
|
|
287
|
+
* Bound rows are never live.
|
|
288
288
|
*/
|
|
289
289
|
data: import("@angular/core").InputSignal<QueryResultItem[] | null>;
|
|
290
|
+
/**
|
|
291
|
+
* Whether this grid follows its query over `/spark/live` (X4): `undefined` — the default — follows the
|
|
292
|
+
* query's own `live` flag; `true`/`false` overrides it (`[live]="false"` on a dashboard tile).
|
|
293
|
+
*
|
|
294
|
+
* Live, the grid's current request (page, sort, search, column filters, parent, deleted modes — exactly
|
|
295
|
+
* the `/execute` body) is ONE server subscription, sent again as an `update` on every page, sort, search
|
|
296
|
+
* or filter change, and every pushed page is rendered as it arrives: rows that change, appear or leave.
|
|
297
|
+
* A subscription `error` clears the rows and shows the message; it is not retried (see {@link isLive}).
|
|
298
|
+
* A virtual-scrolling query is never live: its blocks are separate pages fetched as the user scrolls, and
|
|
299
|
+
* one subscription follows one page.
|
|
300
|
+
*/
|
|
301
|
+
live: import("@angular/core").InputSignal<boolean | undefined>;
|
|
302
|
+
/**
|
|
303
|
+
* The live subscription ended with an error for the query loaded now. Reset by a new load; a live grid
|
|
304
|
+
* does not resubscribe by itself after an error (the answer would not change).
|
|
305
|
+
*/
|
|
306
|
+
private readonly liveFailed;
|
|
307
|
+
/** Whether rows arrive over `/spark/live` right now: the query page shows its LIVE badge from this. */
|
|
308
|
+
readonly isLive: import("@angular/core").Signal<boolean>;
|
|
309
|
+
private liveWanted;
|
|
290
310
|
/**
|
|
291
311
|
* Server-side search term, passed through to the query.
|
|
292
312
|
*
|
|
@@ -539,10 +559,9 @@ export declare class SparkQueryGridComponent {
|
|
|
539
559
|
deleteRows(rows: QueryResultItem[], definition?: CustomActionDefinition): Promise<void>;
|
|
540
560
|
isVirtualScrolling: import("@angular/core").Signal<boolean>;
|
|
541
561
|
/**
|
|
542
|
-
* Columns as sent with the most recent fetched page.
|
|
562
|
+
* Columns as sent with the most recent fetched (or pushed) page.
|
|
543
563
|
*
|
|
544
|
-
* A host binding `data`
|
|
545
|
-
* snapshot carries them once, exactly as a paged result does.
|
|
564
|
+
* A host binding `data` supplies its own via the `columns` input instead.
|
|
546
565
|
*/
|
|
547
566
|
private readonly fetchedColumns;
|
|
548
567
|
/**
|
|
@@ -557,15 +576,7 @@ export declare class SparkQueryGridComponent {
|
|
|
557
576
|
* each string names comes from `bsDatatableColumnLabel` in the template. See `sparkDatatableLabels`.
|
|
558
577
|
*/
|
|
559
578
|
datatableLabels: import("@angular/core").Signal<import("@mintplayer/ng-spark/services").SparkDatatableLabels>;
|
|
560
|
-
/**
|
|
561
|
-
* True when rows do not come from this component's own fetch.
|
|
562
|
-
*
|
|
563
|
-
* Either because the host bound `data`, or because the query streams — a streaming query's rows
|
|
564
|
-
* arrive over a socket and `/execute` is not a way to get them. The grid recognises the second
|
|
565
|
-
* case itself rather than waiting to be told, because it resolves the query before the host can
|
|
566
|
-
* see it: left to `data` alone, every streaming grid would fire one pointless fetch on mount,
|
|
567
|
-
* before the host had anything to bind.
|
|
568
|
-
*/
|
|
579
|
+
/** True when rows do not come from this component's own fetch: the host bound `data`. */
|
|
569
580
|
hasExternalData: import("@angular/core").Signal<boolean>;
|
|
570
581
|
/**
|
|
571
582
|
* Whether an action can run right now: its selection rule is satisfied, and the client method it
|
|
@@ -578,6 +589,22 @@ export declare class SparkQueryGridComponent {
|
|
|
578
589
|
*/
|
|
579
590
|
actionUnavailableReason(action: CustomActionDefinition): string | null;
|
|
580
591
|
constructor();
|
|
592
|
+
/** The live subscription of the query loaded now, while the grid is live. */
|
|
593
|
+
private liveSession;
|
|
594
|
+
private disposeLive;
|
|
595
|
+
/**
|
|
596
|
+
* A pushed page: re-fetch through the datatable, which lands in the live fetch and is served from
|
|
597
|
+
* memory. Through `reload()` rather than a new `[fetch]` identity, so page, sort and scroll stay.
|
|
598
|
+
*/
|
|
599
|
+
private onLivePush;
|
|
600
|
+
/**
|
|
601
|
+
* A live subscription error (defect 4): clear the rows — a stale page must never stay up looking current
|
|
602
|
+
* — and say why. Not retried: `unavailable` (unknown, forbidden, not live, missing parent — one answer),
|
|
603
|
+
* `invalid`, `limit` and `failed` would answer the same again, and a socket-level failure (4429, a
|
|
604
|
+
* repeated 4401) is the socket's to surface. No HTTP fallback either: `unavailable` is the same answer
|
|
605
|
+
* `/execute` gives as a 404, and an app stream's rows exist only on the socket.
|
|
606
|
+
*/
|
|
607
|
+
private onLiveError;
|
|
581
608
|
/**
|
|
582
609
|
* Re-run the query, keeping the current page, sort and scroll position.
|
|
583
610
|
*
|
|
@@ -689,7 +716,26 @@ export declare class SparkQueryGridComponent {
|
|
|
689
716
|
* rendered correctly as a page. Both grids are this one now, so there is one answer.
|
|
690
717
|
*/
|
|
691
718
|
private resolveEntityType;
|
|
719
|
+
/** The datatable's `[fetch]`: over `/spark/live` when the grid is live (see {@link live}), else HTTP. */
|
|
692
720
|
private makeFetch;
|
|
721
|
+
/**
|
|
722
|
+
* The `/execute` body for one datatable request — the same for HTTP and live. Read at call time, so
|
|
723
|
+
* what forces a refetch is the fetch identity `reload()` creates, not the value captured when the
|
|
724
|
+
* closure was built.
|
|
725
|
+
*/
|
|
726
|
+
private requestFor;
|
|
727
|
+
/**
|
|
728
|
+
* One page as the datatable takes it, recording what the chrome reads off a result: count, columns,
|
|
729
|
+
* the result's withheld actions, the ids on screen.
|
|
730
|
+
*/
|
|
731
|
+
private toPage;
|
|
732
|
+
/**
|
|
733
|
+
* Live: the request goes to this grid's {@link LiveGridSession} — subscribed on the first fetch, sent as
|
|
734
|
+
* an `update` when it changes, answered from the latest push when it does not. After an error every fetch
|
|
735
|
+
* is an empty page and the error stays shown.
|
|
736
|
+
*/
|
|
737
|
+
private makeLiveFetch;
|
|
738
|
+
private makeHttpFetch;
|
|
693
739
|
private loadLookupReferenceOptions;
|
|
694
740
|
/**
|
|
695
741
|
* The underlying value a custom renderer receives, which is not the printable one.
|
|
@@ -730,6 +776,11 @@ export declare class SparkQueryGridComponent {
|
|
|
730
776
|
"required": false;
|
|
731
777
|
"isSignal": true;
|
|
732
778
|
};
|
|
779
|
+
"live": {
|
|
780
|
+
"alias": "live";
|
|
781
|
+
"required": false;
|
|
782
|
+
"isSignal": true;
|
|
783
|
+
};
|
|
733
784
|
"search": {
|
|
734
785
|
"alias": "search";
|
|
735
786
|
"required": false;
|
|
@@ -341,6 +341,12 @@ export interface EntityType {
|
|
|
341
341
|
*/
|
|
342
342
|
canRead?: boolean;
|
|
343
343
|
alias?: string;
|
|
344
|
+
/**
|
|
345
|
+
* Whether an object of this type is followed over `/spark/live` (X4): `spark-po-detail` replaces the
|
|
346
|
+
* shown object when it changes and shows the unavailable state when it is deleted, and `spark-po-edit`
|
|
347
|
+
* adopts a newer version (or offers a merge when the form is dirty). Opt-in per type.
|
|
348
|
+
*/
|
|
349
|
+
live?: boolean;
|
|
344
350
|
/**
|
|
345
351
|
* Breadcrumb template: literal text plus `{AttributeName}` placeholders. A scalar placeholder
|
|
346
352
|
* renders its value; a reference placeholder renders the referenced entity's breadcrumb.
|
|
@@ -409,8 +415,12 @@ export interface SparkQuery {
|
|
|
409
415
|
indexName?: string;
|
|
410
416
|
/** Optional entity type name (e.g., "Person"). When set, used for entity type resolution. */
|
|
411
417
|
entityType?: string;
|
|
412
|
-
/**
|
|
413
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Whether grids showing this query follow it over `/spark/live` (X4): the page re-renders when a row in
|
|
420
|
+
* it changes, appears or disappears, with server-side paging, sort, search and filters intact. Opt-in
|
|
421
|
+
* per query; a grid's `[live]` input overrides it. See `docs/guide-live-updates.md`.
|
|
422
|
+
*/
|
|
423
|
+
live?: boolean;
|
|
414
424
|
/**
|
|
415
425
|
* Whether the grid offers row selection (#460, D17). Absent is `'auto'`: derived from the offered
|
|
416
426
|
* actions. A sub-query entry on the parent's type may override it.
|
|
@@ -734,30 +744,153 @@ export interface EntityPermissions {
|
|
|
734
744
|
canRevertContribution?: boolean;
|
|
735
745
|
}
|
|
736
746
|
/**
|
|
737
|
-
* The
|
|
747
|
+
* The live-updates protocol (`/spark/live`, X4), as `docs/guide-live-updates.md` "The protocol" fixes it.
|
|
738
748
|
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
749
|
+
* One WebSocket per browser tab carries every subscription; one JSON object per text frame. Subscriptions
|
|
750
|
+
* are reads only: mutations stay on HTTP.
|
|
741
751
|
*/
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
data: QueryResultItem[];
|
|
746
|
-
}
|
|
747
|
-
export interface StreamingPatchItem {
|
|
752
|
+
/** A subscription to one persistent object: exactly the body of `POST /spark/po/load`. */
|
|
753
|
+
export interface LivePoRequest {
|
|
754
|
+
objectTypeId: string;
|
|
748
755
|
id: string;
|
|
749
|
-
|
|
750
|
-
|
|
756
|
+
deleted?: SparkDeletedFilter | null;
|
|
757
|
+
}
|
|
758
|
+
/** A sort column as `/spark/queries/execute` takes it. */
|
|
759
|
+
export interface LiveSortColumn {
|
|
760
|
+
property: string;
|
|
761
|
+
direction: 'asc' | 'desc';
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* A subscription to one page of a query: exactly the body of `POST /spark/queries/execute`
|
|
765
|
+
* (`retryResults` is ignored by the server — a push cannot prompt).
|
|
766
|
+
*/
|
|
767
|
+
export interface LiveQueryRequest {
|
|
768
|
+
queryId: string;
|
|
769
|
+
skip?: number | null;
|
|
770
|
+
take?: number | null;
|
|
771
|
+
sortColumns?: LiveSortColumn[] | null;
|
|
772
|
+
search?: string | null;
|
|
773
|
+
columns?: QueryColumnFilter[] | null;
|
|
774
|
+
parentId?: string | null;
|
|
775
|
+
parentType?: string | null;
|
|
776
|
+
deleted?: SparkDeletedFilter | null;
|
|
777
|
+
parentDeleted?: SparkDeletedFilter | null;
|
|
778
|
+
}
|
|
779
|
+
export interface LiveSubscribePoOp {
|
|
780
|
+
op: 'subscribe';
|
|
781
|
+
sub: string;
|
|
782
|
+
po: LivePoRequest;
|
|
783
|
+
}
|
|
784
|
+
export interface LiveSubscribeQueryOp {
|
|
785
|
+
op: 'subscribe';
|
|
786
|
+
sub: string;
|
|
787
|
+
query: LiveQueryRequest;
|
|
788
|
+
}
|
|
789
|
+
/** The same query subscription with a new page, sort, search or filters; the server keeps the sub. */
|
|
790
|
+
export interface LiveUpdateOp {
|
|
791
|
+
op: 'update';
|
|
792
|
+
sub: string;
|
|
793
|
+
query: LiveQueryRequest;
|
|
794
|
+
}
|
|
795
|
+
export interface LiveUnsubscribeOp {
|
|
796
|
+
op: 'unsubscribe';
|
|
797
|
+
sub: string;
|
|
751
798
|
}
|
|
752
|
-
export
|
|
799
|
+
export type LiveClientOp = LiveSubscribePoOp | LiveSubscribeQueryOp | LiveUpdateOp | LiveUnsubscribeOp;
|
|
800
|
+
/** `error` codes. Every one ends its subscription; the socket stays open. */
|
|
801
|
+
export type LiveErrorCode = 'unavailable' | 'invalid' | 'limit' | 'failed';
|
|
802
|
+
/** The changes to a held persistent object: top-level fields (`null` = removed) and whole attributes, by `name`. */
|
|
803
|
+
export interface LivePoPatch {
|
|
804
|
+
set?: Record<string, unknown>;
|
|
805
|
+
attributes?: PersistentObjectAttribute[];
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* The changes to a held query page. Apply: index the held rows by `id`; drop `remove`; replace or add each
|
|
809
|
+
* `upsert`; the rows are `order` mapped through the index when present, otherwise the held order minus the
|
|
810
|
+
* removed rows; then assign `set` (`totalItems`, `skip`, `take`, `disabledActions`, `typeHints`, …).
|
|
811
|
+
*/
|
|
812
|
+
export interface LiveQueryPatch {
|
|
813
|
+
upsert?: QueryResultItem[];
|
|
814
|
+
remove?: string[];
|
|
815
|
+
order?: string[];
|
|
816
|
+
set?: Record<string, unknown>;
|
|
817
|
+
}
|
|
818
|
+
/** The first state of an object, or one whose set or order of attributes changed. Replace. */
|
|
819
|
+
export interface LivePoFrame {
|
|
820
|
+
type: 'po';
|
|
821
|
+
sub: string;
|
|
822
|
+
po: PersistentObject;
|
|
823
|
+
}
|
|
824
|
+
export interface LivePoPatchFrame {
|
|
825
|
+
type: 'poPatch';
|
|
826
|
+
sub: string;
|
|
827
|
+
patch: LivePoPatch;
|
|
828
|
+
}
|
|
829
|
+
/** Deleted or no longer readable (one answer). The subscription has ended. */
|
|
830
|
+
export interface LiveGoneFrame {
|
|
831
|
+
type: 'gone';
|
|
832
|
+
sub: string;
|
|
833
|
+
}
|
|
834
|
+
/** The first page, a page whose columns changed, or a change a patch would not make smaller. Replace. */
|
|
835
|
+
export interface LiveResultFrame {
|
|
836
|
+
type: 'result';
|
|
837
|
+
sub: string;
|
|
838
|
+
result: QueryResult;
|
|
839
|
+
}
|
|
840
|
+
export interface LivePatchFrame {
|
|
753
841
|
type: 'patch';
|
|
754
|
-
|
|
842
|
+
sub: string;
|
|
843
|
+
patch: LiveQueryPatch;
|
|
755
844
|
}
|
|
756
|
-
|
|
845
|
+
/** The subscription has ended. Without `sub` it answers an unparseable frame. */
|
|
846
|
+
export interface LiveErrorFrame {
|
|
757
847
|
type: 'error';
|
|
848
|
+
sub?: string;
|
|
849
|
+
code: LiveErrorCode;
|
|
758
850
|
message: string;
|
|
759
851
|
}
|
|
760
|
-
|
|
852
|
+
/** Heartbeat. Nothing to answer. */
|
|
853
|
+
export interface LivePingFrame {
|
|
854
|
+
type: 'ping';
|
|
855
|
+
}
|
|
856
|
+
export type LiveServerFrame = LivePoFrame | LivePoPatchFrame | LiveGoneFrame | LiveResultFrame | LivePatchFrame | LiveErrorFrame | LivePingFrame;
|
|
857
|
+
/** Close codes with a meaning of their own; any other code is reconnected with backoff. */
|
|
858
|
+
export declare const LIVE_CLOSE_REAUTHENTICATE = 4401;
|
|
859
|
+
export declare const LIVE_CLOSE_TOO_MANY_SOCKETS = 4429;
|
|
860
|
+
export declare const LIVE_CLOSE_MESSAGE_TOO_LARGE = 1009;
|
|
861
|
+
/**
|
|
862
|
+
* Why a watcher's subscription ended, beyond the server's own {@link LiveErrorCode}s — the socket-level
|
|
863
|
+
* failures the client surfaces instead of retrying:
|
|
864
|
+
* - `tooManySockets`: closed with 4429; not reconnected until a new watcher asks.
|
|
865
|
+
* - `unauthenticated`: closed with 4401 again within seconds of reconnecting for a 4401.
|
|
866
|
+
* - `messageTooLarge`: closed with 1009, a client bug; not retried blindly.
|
|
867
|
+
*/
|
|
868
|
+
export type LiveFailureCode = LiveErrorCode | 'tooManySockets' | 'unauthenticated' | 'messageTooLarge';
|
|
869
|
+
export interface LiveErrorEvent {
|
|
870
|
+
type: 'error';
|
|
871
|
+
code: LiveFailureCode;
|
|
872
|
+
message: string;
|
|
873
|
+
}
|
|
874
|
+
/** `po`: the object with every patch applied. `gone` and `error` end the stream (it completes after them). */
|
|
875
|
+
export type LivePoEvent = {
|
|
876
|
+
type: 'po';
|
|
877
|
+
po: PersistentObject;
|
|
878
|
+
} | {
|
|
879
|
+
type: 'gone';
|
|
880
|
+
} | LiveErrorEvent;
|
|
881
|
+
/** `result`: the page with every patch applied. `error` ends the stream (it completes after it). */
|
|
882
|
+
export type LiveQueryEvent = {
|
|
883
|
+
type: 'result';
|
|
884
|
+
result: QueryResult;
|
|
885
|
+
} | LiveErrorEvent;
|
|
886
|
+
/**
|
|
887
|
+
* Applies a `patch` frame to a held page, exactly as the protocol says. A new id in `upsert` that `order`
|
|
888
|
+
* does not place (the server always sends `order` when membership changes, so this is defensive) is
|
|
889
|
+
* appended rather than dropped.
|
|
890
|
+
*/
|
|
891
|
+
export declare function applyLiveQueryPatch(held: QueryResult, patch: LiveQueryPatch): QueryResult;
|
|
892
|
+
/** Applies a `poPatch` frame to a held object: `set` assigned, changed attributes replaced by `name`. */
|
|
893
|
+
export declare function applyLivePoPatch(held: PersistentObject, patch: LivePoPatch): PersistentObject;
|
|
761
894
|
/**
|
|
762
895
|
* Conversions between the wire format for a timestamp and what an `<input type="datetime-local">`
|
|
763
896
|
* or `<input type="date">` will accept.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { InjectionToken, Provider, Signal } from "@angular/core";
|
|
3
|
+
import { QueryResultItem } from "@mintplayer/ng-spark/models";
|
|
4
|
+
import { ConnectedPosition } from "@angular/cdk/overlay";
|
|
5
|
+
import { Color } from "@mintplayer/ng-bootstrap";
|
|
6
|
+
/** The `Notification` entity type of `MintPlayer.Spark.Notifications` (`App_Data/Model/Notification.json`). */
|
|
7
|
+
export declare const SPARK_NOTIFICATION_TYPE_ID = "411e3be6-5da0-5d84-bc21-001888fafc6d";
|
|
8
|
+
/** `MyNotifications` (alias `notifications`): the caller's notifications, newest first. Live. */
|
|
9
|
+
export declare const SPARK_MY_NOTIFICATIONS_QUERY_ID = "7123c201-9aed-50f9-9d9a-ede2491af7f9";
|
|
10
|
+
/** `UnreadNotifications` (alias `unread-notifications`): the caller's unread ones. Live. */
|
|
11
|
+
export declare const SPARK_UNREAD_NOTIFICATIONS_QUERY_ID = "a205d3e5-ff6e-5260-ac9e-e5c6b16644c9";
|
|
12
|
+
/** One notification as the bell lists it: a row of `MyNotifications`. */
|
|
13
|
+
export interface SparkNotification {
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
body: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* The link, when the row carries it. `Url` is a detail-only attribute in the shipped model, so a row
|
|
19
|
+
* usually does not, and {@link SparkNotificationsService.open} loads it from the object instead.
|
|
20
|
+
*/
|
|
21
|
+
url: string | null;
|
|
22
|
+
isRead: boolean;
|
|
23
|
+
createdAt: Date | null;
|
|
24
|
+
}
|
|
25
|
+
/** A query row of `MyNotifications` as a {@link SparkNotification}. */
|
|
26
|
+
export declare function toSparkNotification(item: QueryResultItem): SparkNotification;
|
|
27
|
+
/** Options of the notification bell and service. */
|
|
28
|
+
export interface SparkNotificationsOptions {
|
|
29
|
+
/** How many of the latest notifications the bell lists. Default 8. */
|
|
30
|
+
recentCount: number;
|
|
31
|
+
/** Where "All notifications" goes: a router link. Default `['/query', 'notifications']` (the `MyNotifications` alias). */
|
|
32
|
+
listLink: string | readonly unknown[];
|
|
33
|
+
}
|
|
34
|
+
export declare const SPARK_NOTIFICATIONS_OPTIONS: InjectionToken<SparkNotificationsOptions>;
|
|
35
|
+
/** Overrides {@link SparkNotificationsOptions}; anything left out keeps its default. */
|
|
36
|
+
export declare function provideSparkNotifications(options?: Partial<SparkNotificationsOptions>): Provider;
|
|
37
|
+
/** The browser's Notification API, as far as push needs it. */
|
|
38
|
+
export interface SparkNotificationPermissions {
|
|
39
|
+
readonly permission: NotificationPermission;
|
|
40
|
+
requestPermission(): Promise<NotificationPermission>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* What the browser offers for Web Push: the Notification API, or `null` when there is no Notification,
|
|
44
|
+
* no `PushManager` or no service worker. That is the case in Safari on iPhone and iPad until the app is
|
|
45
|
+
* added to the Home Screen, so `null` reads as "install the app first". Replaceable for tests.
|
|
46
|
+
*/
|
|
47
|
+
export declare const SPARK_PUSH_PERMISSIONS: InjectionToken<SparkNotificationPermissions | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Web Push on this device: `unsupported` (no service worker, no PushManager or no Notification API:
|
|
50
|
+
* an iPhone/iPad needs the app on its Home Screen), `denied` (blocked in the browser's settings),
|
|
51
|
+
* `off` or `on`.
|
|
52
|
+
*/
|
|
53
|
+
export type SparkPushState = 'unsupported' | 'denied' | 'off' | 'on';
|
|
54
|
+
/**
|
|
55
|
+
* The client of `MintPlayer.Spark.Notifications` (`docs/seo_analyzer_PRD.md` X10, D20, D30).
|
|
56
|
+
*
|
|
57
|
+
* - **In-app**: {@link unreadCount} and {@link recent} follow the live queries `UnreadNotifications`
|
|
58
|
+
* (one row, for its `totalItems`) and `MyNotifications` (the latest few) over the ONE `/spark/live`
|
|
59
|
+
* socket of {@link SparkLiveService}. Nothing polls and there is no second channel: a new, read or
|
|
60
|
+
* deleted notification arrives as a patch. The subscriptions start again whenever `SPARK_AUTH_STATE`
|
|
61
|
+
* changes (sign-in, sign-out), so a page opened before signing in still counts afterwards.
|
|
62
|
+
* - **Web Push**: {@link enablePush} / {@link disablePush} subscribe this device through Angular's
|
|
63
|
+
* `SwPush` and register it at `/spark/notifications/push/*`. It needs `provideSparkServiceWorker()`
|
|
64
|
+
* (or `provideServiceWorker`) with the worker enabled; without it {@link pushState} is `unsupported`.
|
|
65
|
+
*/
|
|
66
|
+
export declare class SparkNotificationsService {
|
|
67
|
+
private readonly http;
|
|
68
|
+
private readonly live;
|
|
69
|
+
private readonly spark;
|
|
70
|
+
private readonly router;
|
|
71
|
+
private readonly location;
|
|
72
|
+
private readonly document;
|
|
73
|
+
private readonly swPush;
|
|
74
|
+
private readonly permissions;
|
|
75
|
+
private readonly options;
|
|
76
|
+
private readonly baseUrl;
|
|
77
|
+
private readonly browser;
|
|
78
|
+
private readonly unread;
|
|
79
|
+
private readonly latest;
|
|
80
|
+
/** Unread notifications of the signed-in user; 0 until the first result and while signed out. */
|
|
81
|
+
readonly unreadCount: Signal<number>;
|
|
82
|
+
/** The latest notifications (read or not), newest first; empty until the first result. */
|
|
83
|
+
readonly recent: Signal<SparkNotification[]>;
|
|
84
|
+
/** Whether {@link recent} holds a result yet. */
|
|
85
|
+
readonly loaded: Signal<boolean>;
|
|
86
|
+
/** Whether this browser can receive Web Push here at all (see {@link SparkPushState}). */
|
|
87
|
+
readonly pushSupported: boolean;
|
|
88
|
+
private readonly permission;
|
|
89
|
+
private readonly subscribed;
|
|
90
|
+
private readonly configured;
|
|
91
|
+
private readonly busy;
|
|
92
|
+
private publicKey;
|
|
93
|
+
/** Web Push on this device. */
|
|
94
|
+
readonly pushState: Signal<SparkPushState>;
|
|
95
|
+
/**
|
|
96
|
+
* Whether the server sends Web Push (`GET /spark/notifications/push/key` answered a key): `null` while
|
|
97
|
+
* unknown, `false` when Web Push is not configured or nobody is signed in. Offer no push UI unless `true`.
|
|
98
|
+
*/
|
|
99
|
+
readonly pushConfigured: Signal<boolean | null>;
|
|
100
|
+
/** True while {@link enablePush} or {@link disablePush} runs. */
|
|
101
|
+
readonly pushBusy: Signal<boolean>;
|
|
102
|
+
constructor();
|
|
103
|
+
/**
|
|
104
|
+
* Marks notifications read: the given ids, or every unread one of the caller when `ids` is omitted.
|
|
105
|
+
* Resolves to how many changed. The live queries then deliver the new state; nothing is set locally.
|
|
106
|
+
*/
|
|
107
|
+
markRead(ids?: readonly string[]): Promise<number>;
|
|
108
|
+
/**
|
|
109
|
+
* Opens a notification: marks it read when it is not, then follows its link, in-app through the router
|
|
110
|
+
* for a URL on this origin, as a page load for another `http(s)` URL. A row without its `Url` (a
|
|
111
|
+
* detail-only attribute in the shipped model) is loaded once for it.
|
|
112
|
+
*/
|
|
113
|
+
open(notification: SparkNotification): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Turns Web Push on for this device. Call it straight from a click handler: the permission prompt is
|
|
116
|
+
* requested before anything is awaited, because Safari only grants it to a user gesture. Resolves to
|
|
117
|
+
* whether the device is now subscribed; a refusal, a missing key or a subscription the server rejects
|
|
118
|
+
* (400: a push service outside its allow-list) is `false`.
|
|
119
|
+
*/
|
|
120
|
+
enablePush(): Promise<boolean>;
|
|
121
|
+
/** Turns Web Push off for this device: the server forgets it, then the browser unsubscribes. */
|
|
122
|
+
disablePush(): Promise<void>;
|
|
123
|
+
private follow;
|
|
124
|
+
private loadPublicKey;
|
|
125
|
+
private loadUrl;
|
|
126
|
+
private navigate;
|
|
127
|
+
/** A full page load (overridden in specs: jsdom cannot navigate). */
|
|
128
|
+
protected assign(href: string): void;
|
|
129
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkNotificationsService, never>;
|
|
130
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<any>;
|
|
131
|
+
}
|
|
132
|
+
/** English fallbacks of `notifications.spa.*`, shown until the server's translations arrive. */
|
|
133
|
+
export declare const SPARK_NOTIFICATION_TEXTS: Record<string, string>;
|
|
134
|
+
/**
|
|
135
|
+
* The Web Push opt-in for this device, on its own (an account or settings page); the notification bell
|
|
136
|
+
* shows the same control. Renders nothing unless the server sends Web Push. Otherwise: a button to turn
|
|
137
|
+
* it on or off, or why it cannot be (blocked in the browser, or a browser without push: on iPhone and
|
|
138
|
+
* iPad the app must be on the Home Screen first).
|
|
139
|
+
*/
|
|
140
|
+
export declare class SparkPushToggleComponent {
|
|
141
|
+
protected readonly notifications: SparkNotificationsService;
|
|
142
|
+
private readonly language;
|
|
143
|
+
protected t(key: string): string;
|
|
144
|
+
/** Synchronous up to the permission prompt: this is the click handler the prompt needs. */
|
|
145
|
+
protected enable(): void;
|
|
146
|
+
protected disable(): void;
|
|
147
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkPushToggleComponent, never>;
|
|
148
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SparkPushToggleComponent, "spark-push-toggle", never, {}, {}, never, never, true, never>;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The notification bell for an app's top bar (`docs/seo_analyzer_PRD.md` X10): the unread count as a
|
|
152
|
+
* badge, live; a menu with the latest notifications (title, message, relative time), "Mark all as read",
|
|
153
|
+
* a link to the full list and, where this browser can receive it, the Web Push opt-in. Choosing a
|
|
154
|
+
* notification marks it read and follows its link.
|
|
155
|
+
*/
|
|
156
|
+
export declare class SparkNotificationBellComponent {
|
|
157
|
+
protected readonly notifications: SparkNotificationsService;
|
|
158
|
+
private readonly language;
|
|
159
|
+
private readonly options;
|
|
160
|
+
protected readonly colors: typeof Color;
|
|
161
|
+
/** Where "All notifications" goes. Default: `provideSparkNotifications({ listLink })`, else the `notifications` query page. */
|
|
162
|
+
readonly allLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
|
|
163
|
+
readonly open: import("@angular/core").WritableSignal<boolean>;
|
|
164
|
+
protected readonly listLink: import("@angular/core").Signal<string | readonly unknown[]>;
|
|
165
|
+
protected readonly countText: import("@angular/core").Signal<string>;
|
|
166
|
+
protected readonly ariaLabel: import("@angular/core").Signal<string>;
|
|
167
|
+
readonly positions: ConnectedPosition[];
|
|
168
|
+
protected t(key: string): string;
|
|
169
|
+
protected when(notification: SparkNotification): string;
|
|
170
|
+
close(): void;
|
|
171
|
+
/** A click outside closes the menu, except on the bell itself, whose own handler toggles it. */
|
|
172
|
+
onOutsideClick(event: MouseEvent, toggle: HTMLElement): void;
|
|
173
|
+
choose(notification: SparkNotification): Promise<void>;
|
|
174
|
+
markAllRead(): Promise<void>;
|
|
175
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkNotificationBellComponent, never>;
|
|
176
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SparkNotificationBellComponent, "spark-notification-bell", never, {
|
|
177
|
+
"allLink": {
|
|
178
|
+
"alias": "allLink";
|
|
179
|
+
"required": false;
|
|
180
|
+
"isSignal": true;
|
|
181
|
+
};
|
|
182
|
+
}, {}, never, never, true, never>;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* `date` relative to `now` in `language` ("5 minutes ago", "il y a 5 minutes", "5 minuten geleden"),
|
|
186
|
+
* through `Intl.RelativeTimeFormat`; "now" under a minute. Empty for a missing date.
|
|
187
|
+
*/
|
|
188
|
+
export declare function sparkRelativeTime(date: Date | null | undefined, now: number, language: string): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Color } from "@mintplayer/ng-bootstrap";
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/** What `POST /spark/organizations/accept` answers. */
|
|
4
|
+
export interface SparkOrganizationAcceptance {
|
|
5
|
+
accepted: boolean;
|
|
6
|
+
organizationId: string | null;
|
|
7
|
+
organization: string | null;
|
|
8
|
+
problem: string | null;
|
|
9
|
+
/** Which refusal: `invalid` (any unknown, used or expired link) or `otherAddress` (D43). */
|
|
10
|
+
reason?: 'invalid' | 'otherAddress' | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The target of a mailed organization invitation or join request
|
|
14
|
+
* (`/organizations/accept/:token?id=<invitationId>`, `docs/seo_analyzer_PRD.md` D18). Accepting is an
|
|
15
|
+
* explicit click, never a side effect of opening the link (mail scanners open links). An invitation
|
|
16
|
+
* makes the signed-in account a member; a join request lets its requester in and needs an Owner or
|
|
17
|
+
* Admin. Every failure reads the same, except a valid invitation opened by an account that does not own
|
|
18
|
+
* the invited address (D43): the page says so, so the user can sign in with the right account.
|
|
19
|
+
*/
|
|
20
|
+
export declare class SparkAcceptOrganizationInvitationComponent {
|
|
21
|
+
private readonly http;
|
|
22
|
+
private readonly route;
|
|
23
|
+
private readonly translations;
|
|
24
|
+
protected readonly colors: typeof Color;
|
|
25
|
+
private readonly token;
|
|
26
|
+
private readonly invitationId;
|
|
27
|
+
/** A link without both values cannot be an invitation. */
|
|
28
|
+
protected readonly valid: boolean;
|
|
29
|
+
readonly busy: import("@angular/core").WritableSignal<boolean>;
|
|
30
|
+
readonly failed: import("@angular/core").WritableSignal<boolean>;
|
|
31
|
+
/** The refusal to show: a translation key under `organizations.spa`. */
|
|
32
|
+
readonly reason: import("@angular/core").WritableSignal<"invalid" | "otherAddress">;
|
|
33
|
+
/** The organization joined, once accepted. */
|
|
34
|
+
readonly joined: import("@angular/core").WritableSignal<SparkOrganizationAcceptance | null>;
|
|
35
|
+
/** The page's texts: `organizations.spa.*` in the organizations library's `translations.json`. */
|
|
36
|
+
protected t(key: string): string;
|
|
37
|
+
accept(): Promise<void>;
|
|
38
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkAcceptOrganizationInvitationComponent, never>;
|
|
39
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SparkAcceptOrganizationInvitationComponent, "spark-accept-organization-invitation", never, {}, {}, never, never, true, never>;
|
|
40
|
+
}
|