@mintplayer/ng-spark 22.11.0 → 22.13.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 +113 -5
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +40 -3
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +79 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +110 -4
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +23 -5
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mintplayer-ng-spark-client-operations.d.ts +86 -6
- package/types/mintplayer-ng-spark-grid.d.ts +23 -0
- package/types/mintplayer-ng-spark-models.d.ts +32 -0
- package/types/mintplayer-ng-spark-pipes.d.ts +38 -2
- package/types/mintplayer-ng-spark-po-detail.d.ts +33 -0
- package/types/mintplayer-ng-spark-services.d.ts +21 -1
|
@@ -26,6 +26,15 @@ interface RefreshAttributeOperation {
|
|
|
26
26
|
id: string;
|
|
27
27
|
attributeName: string;
|
|
28
28
|
value?: unknown;
|
|
29
|
+
/**
|
|
30
|
+
* Nested rows of an `AsDetail` attribute. A loaded AsDetail attribute carries its rows in
|
|
31
|
+
* `object` / `objects` and leaves `value` null, so a patch limited to `value` could never
|
|
32
|
+
* refresh a detail grid -- it always sent null, and a null over a null repaints nothing.
|
|
33
|
+
*
|
|
34
|
+
* An empty `objects` array means the grid is now empty, and is distinct from omitting it.
|
|
35
|
+
*/
|
|
36
|
+
object?: unknown;
|
|
37
|
+
objects?: unknown[];
|
|
29
38
|
}
|
|
30
39
|
interface RefreshQueryOperation {
|
|
31
40
|
type: 'refreshQuery';
|
|
@@ -157,13 +166,21 @@ declare class SparkToastContainerComponent {
|
|
|
157
166
|
}
|
|
158
167
|
|
|
159
168
|
/**
|
|
160
|
-
* Registers the built-in client-operation handlers: `notify
|
|
161
|
-
* Apps add this once in their bootstrap providers.
|
|
169
|
+
* Registers the built-in client-operation handlers: `notify`, `refreshQuery`,
|
|
170
|
+
* `refreshAttribute` and `navigate`. Apps add this once in their bootstrap providers.
|
|
162
171
|
*
|
|
163
172
|
* Unregistered operation types are dropped SILENTLY by the dispatcher, which is why
|
|
164
173
|
* `refreshQuery` did nothing at all for as long as it went unhandled — the server emitted
|
|
165
|
-
* it, nothing listened, and no error said so.
|
|
166
|
-
*
|
|
174
|
+
* it, nothing listened, and no error said so.
|
|
175
|
+
*
|
|
176
|
+
* That happened twice more before anyone noticed. `refreshAttribute` and `navigate` were both
|
|
177
|
+
* declared wire types with no handler anywhere in the repository: every
|
|
178
|
+
* `IClientAccessor.RefreshAttribute` and `Navigate` call in every Spark application was
|
|
179
|
+
* computed, serialised, sent and discarded. Both are registered below. The remaining gap is
|
|
180
|
+
* `disableAction`, registered purely to log so that it stays visible rather than invisible.
|
|
181
|
+
*
|
|
182
|
+
* The lesson worth keeping: a wire type in `operations.ts` is not a feature. Adding one without
|
|
183
|
+
* a handler here produces a server API that appears to work and does nothing.
|
|
167
184
|
*
|
|
168
185
|
* To register custom operation types alongside the built-ins, add additional
|
|
169
186
|
* `multi: true` providers using <see cref="SPARK_CLIENT_OPERATION_HANDLERS" />.
|
|
@@ -201,5 +218,68 @@ declare class SparkQueryRefreshService {
|
|
|
201
218
|
static ɵprov: i0.ɵɵInjectableDeclaration<SparkQueryRefreshService>;
|
|
202
219
|
}
|
|
203
220
|
|
|
204
|
-
|
|
205
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Carries a server-issued `refreshAttribute` to whichever detail page is showing that object.
|
|
223
|
+
*
|
|
224
|
+
* The same broadcast shape as {@link SparkQueryRefreshService}, and for the same reason: detail
|
|
225
|
+
* pages come and go behind `@if` and lazy routes, and nothing in ng-spark holds a component
|
|
226
|
+
* reference. A page reads {@link tokenFor} in an effect and applies {@link patchesFor} when it
|
|
227
|
+
* changes.
|
|
228
|
+
*
|
|
229
|
+
* Until this existed the operation was declared on the wire and handled by nobody: the server
|
|
230
|
+
* computed the new values, serialised them, sent them, and the dispatcher dropped them silently
|
|
231
|
+
* because unknown types are ignored. `IClientAccessor.RefreshAttribute` was inert in every Spark
|
|
232
|
+
* application. It is what made the Coverage home page's Resync button look dead — it recomputed
|
|
233
|
+
* the account and repository counts correctly on every click and none of them ever arrived.
|
|
234
|
+
*
|
|
235
|
+
* The operation carries the new value, so this is a patch and not a re-fetch: no round trip, and
|
|
236
|
+
* no dependence on an index that may still be stale from the write that triggered it.
|
|
237
|
+
*/
|
|
238
|
+
/**
|
|
239
|
+
* The parts of an attribute a server patch may carry.
|
|
240
|
+
*
|
|
241
|
+
* Three fields rather than one value because a loaded attribute does not keep every shape in
|
|
242
|
+
* `value`: an `AsDetail` attribute puts its nested rows in `object` / `objects` and leaves
|
|
243
|
+
* `value` null. A patch limited to `value` was therefore incapable of refreshing a detail grid,
|
|
244
|
+
* and did so silently -- see {@link SparkAttributeRefreshService}.
|
|
245
|
+
*
|
|
246
|
+
* Only the keys the server sent are present, and each is applied on its own. An `objects: []`
|
|
247
|
+
* means the grid is now empty, which is why emptiness has to be distinguishable from absence.
|
|
248
|
+
*/
|
|
249
|
+
interface SparkAttributePatch {
|
|
250
|
+
value?: unknown;
|
|
251
|
+
object?: unknown;
|
|
252
|
+
objects?: unknown[];
|
|
253
|
+
}
|
|
254
|
+
declare class SparkAttributeRefreshService {
|
|
255
|
+
private readonly tokens;
|
|
256
|
+
private readonly patches;
|
|
257
|
+
/**
|
|
258
|
+
* Objects are keyed by type AND id: the same id can exist under two types, and a detail page
|
|
259
|
+
* only ever wants the attributes meant for the object it is showing.
|
|
260
|
+
*/
|
|
261
|
+
private static keyFor;
|
|
262
|
+
/** Bumped every time the server patches an attribute of this object. */
|
|
263
|
+
tokenFor(objectTypeId: string | undefined | null, id: string | undefined | null): number;
|
|
264
|
+
/**
|
|
265
|
+
* The newest value the server sent for each patched attribute of this object.
|
|
266
|
+
*
|
|
267
|
+
* Cumulative rather than drained on read: a detail page that mounts after the operation arrived
|
|
268
|
+
* still sees the value, and two pages showing the same object both get it. Values are overwritten
|
|
269
|
+
* by later patches, so this holds one entry per attribute, not a history.
|
|
270
|
+
*/
|
|
271
|
+
patchesFor(objectTypeId: string | undefined | null, id: string | undefined | null): Record<string, SparkAttributePatch>;
|
|
272
|
+
/**
|
|
273
|
+
* Record a new value for one attribute and wake whoever is showing the object.
|
|
274
|
+
*
|
|
275
|
+
* Callers patching several attributes for one user action should do so in one synchronous run:
|
|
276
|
+
* the signals coalesce within a tick into a single effect run, and patches split across an await
|
|
277
|
+
* become one run each.
|
|
278
|
+
*/
|
|
279
|
+
request(objectTypeId: string, id: string, attributeName: string, patch: SparkAttributePatch): void;
|
|
280
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkAttributeRefreshService, never>;
|
|
281
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SparkAttributeRefreshService>;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export { NotificationKind, SPARK_CLIENT_OPERATION_HANDLERS, SparkAttributeRefreshService, SparkClientOperationDispatcher, SparkNotificationService, SparkQueryRefreshService, SparkToastContainerComponent, provideSparkClientOperations };
|
|
285
|
+
export type { ClientOperation, ClientOperationEnvelope, ClientOperationHandler, ClientOperationHandlerRegistration, DisableActionOperation, DisableTarget, NavigateOperation, NotifyOperation, RefreshAttributeOperation, RefreshQueryOperation, RetryOperation, SparkAttributePatch, SparkToast };
|
|
@@ -308,6 +308,19 @@ declare class SparkQueryGridComponent {
|
|
|
308
308
|
canCreate: _angular_core.WritableSignal<boolean>;
|
|
309
309
|
resultCount: _angular_core.WritableSignal<number | null>;
|
|
310
310
|
customActions: _angular_core.WritableSignal<CustomActionDefinition[]>;
|
|
311
|
+
/** Names the server withheld for this RESULT; see QueryResult.disabledActions. */
|
|
312
|
+
private readonly disabledActions;
|
|
313
|
+
/**
|
|
314
|
+
* The actions actually offered for this result.
|
|
315
|
+
*
|
|
316
|
+
* The catalogue at `/spark/actions/{objectTypeId}` is per TYPE and is never told what an
|
|
317
|
+
* execution returned, so an action that applies to only some results cannot be filtered there.
|
|
318
|
+
* A custom query withholds what does not apply via `CustomQueryArgs.DisableActions(...)`, and
|
|
319
|
+
* the answer arrives on the result.
|
|
320
|
+
*
|
|
321
|
+
* An affordance, not a permission -- the action handler still refuses on its own terms.
|
|
322
|
+
*/
|
|
323
|
+
visibleCustomActions: _angular_core.Signal<CustomActionDefinition[]>;
|
|
311
324
|
fetchFn: _angular_core.WritableSignal<BsDatatableFetch<QueryResultItem> | null>;
|
|
312
325
|
/**
|
|
313
326
|
* Why the component renders its own failure instead of only reporting one.
|
|
@@ -534,6 +547,16 @@ declare class SparkGridCellComponent {
|
|
|
534
547
|
protected readonly rendererInputs: _angular_core.Signal<Record<string, any>>;
|
|
535
548
|
/** Null and undefined are distinct from `false` here — see the template. */
|
|
536
549
|
protected readonly isUnsetBoolean: _angular_core.Signal<boolean>;
|
|
550
|
+
/**
|
|
551
|
+
* {@link display} when it really is a `Date`, and `null` otherwise.
|
|
552
|
+
*
|
|
553
|
+
* Angular's `DatePipe` does not degrade on a non-date: it **throws**
|
|
554
|
+
* `NG02100: InvalidPipeArgument`, which would take down the whole cell. Both cell pipes
|
|
555
|
+
* deliberately fall back to the raw text for an unparseable date rather than hiding the stored
|
|
556
|
+
* value, so that text reaches this component and must not be piped. A template cannot express
|
|
557
|
+
* `instanceof`, hence the computed.
|
|
558
|
+
*/
|
|
559
|
+
protected readonly dateValue: _angular_core.Signal<Date | null>;
|
|
537
560
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkGridCellComponent, never>;
|
|
538
561
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkGridCellComponent, "spark-grid-cell", never, { "column": { "alias": "column"; "required": true; "isSignal": true; }; "display": { "alias": "display"; "required": false; "isSignal": true; }; "rendererValue": { "alias": "rendererValue"; "required": false; "isSignal": true; }; "item": { "alias": "item"; "required": false; "isSignal": true; }; "chips": { "alias": "chips"; "required": false; "isSignal": true; }; "link": { "alias": "link"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
539
562
|
}
|
|
@@ -56,6 +56,19 @@ interface PersistentObject {
|
|
|
56
56
|
attributes: PersistentObjectAttribute[];
|
|
57
57
|
/** Per-row edit/delete affordances; undefined = fall back to type-level permissions. */
|
|
58
58
|
can?: PersistentObjectPermissions;
|
|
59
|
+
/**
|
|
60
|
+
* Custom actions withheld for THIS object, by name. Absent or empty means every action the
|
|
61
|
+
* caller has the right to is offered.
|
|
62
|
+
*
|
|
63
|
+
* The action catalogue at `/spark/actions/{objectTypeId}` is per TYPE -- it is never told which
|
|
64
|
+
* row is open -- so an action that applies to only some rows cannot be filtered there. The
|
|
65
|
+
* entity actions hook decides while it has the entity in hand, and the answer arrives here.
|
|
66
|
+
*
|
|
67
|
+
* An affordance, not a permission: the action endpoint is still reachable and its handler still
|
|
68
|
+
* refuses on its own terms. What this prevents is offering a destructive action where it cannot
|
|
69
|
+
* apply.
|
|
70
|
+
*/
|
|
71
|
+
disabledActions?: string[];
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
interface PersistentObjectAttribute {
|
|
@@ -199,6 +212,14 @@ interface EntityType {
|
|
|
199
212
|
* query. Types are data from the wire, not a promise about it.
|
|
200
213
|
*/
|
|
201
214
|
clrType?: string;
|
|
215
|
+
/**
|
|
216
|
+
* Whether this caller may OPEN one of these, as opposed to list them.
|
|
217
|
+
*
|
|
218
|
+
* The catalogue is gated on Query, so its presence here means "you may list this type" and says
|
|
219
|
+
* nothing about opening one. A reference must not render as a link when this is false: it used
|
|
220
|
+
* to, and the click refused on arrival.
|
|
221
|
+
*/
|
|
222
|
+
canRead?: boolean;
|
|
202
223
|
alias?: string;
|
|
203
224
|
/**
|
|
204
225
|
* Breadcrumb template: literal text plus `{AttributeName}` placeholders. A scalar placeholder
|
|
@@ -256,6 +277,17 @@ interface QueryResult {
|
|
|
256
277
|
skip: number;
|
|
257
278
|
take: number;
|
|
258
279
|
typeHints?: Record<string, string>;
|
|
280
|
+
/**
|
|
281
|
+
* Custom actions withheld for THIS result, by name. Absent or empty means every action the
|
|
282
|
+
* caller has the right to is offered.
|
|
283
|
+
*
|
|
284
|
+
* The mirror of `PersistentObject.disabledActions`, set server-side via
|
|
285
|
+
* `CustomQueryArgs.DisableActions(...)`. The action catalogue is per type and is never told what
|
|
286
|
+
* an execution returned, so this is where a per-result answer travels.
|
|
287
|
+
*
|
|
288
|
+
* An affordance, not a permission -- the action handler still refuses on its own terms.
|
|
289
|
+
*/
|
|
290
|
+
disabledActions?: string[];
|
|
259
291
|
}
|
|
260
292
|
/**
|
|
261
293
|
* The subset of column metadata a cell needs in order to render.
|
|
@@ -96,8 +96,44 @@ declare class AsDetailColumnsPipe implements PipeTransform {
|
|
|
96
96
|
static ɵpipe: i0.ɵɵPipeDeclaration<AsDetailColumnsPipe, "asDetailColumns", true>;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/** What a cell can resolve to: the column's own type, or `null` when it has no value. */
|
|
100
|
+
type AsDetailCellValue = string | number | boolean | Date | null;
|
|
101
|
+
/**
|
|
102
|
+
* The value of one cell in an `AsDetail` table, **typed by the column's `dataType`** rather than
|
|
103
|
+
* flattened to a string.
|
|
104
|
+
*
|
|
105
|
+
* <p>
|
|
106
|
+
* This used to end in `return String(value)` for everything, and declare `: string`. That is fine
|
|
107
|
+
* for a cell which is only interpolated, and wrong for one whose consumer inspects it —
|
|
108
|
+
* `spark-grid-cell` branches on the column type and binds `[checked]="display() === true"` and
|
|
109
|
+
* `[indeterminate]="display() == null"` for a boolean, so it needs the value and not a rendering
|
|
110
|
+
* of it.
|
|
111
|
+
* </p>
|
|
112
|
+
* <p>
|
|
113
|
+
* The visible symptom was a detail page showing unticked checkboxes for rows whose edit form showed
|
|
114
|
+
* them ticked — the edit form reads `attribute.objects` directly, so it never went through here. All
|
|
115
|
+
* three states of a `bool?` were affected, and one of them silently:
|
|
116
|
+
* </p>
|
|
117
|
+
* <ul>
|
|
118
|
+
* <li><b>true</b> — `'true' === true` is false, so it rendered <b>unchecked</b>;</li>
|
|
119
|
+
* <li><b>null</b> — became `''`, and `'' == null` is false, so it rendered unchecked <b>and
|
|
120
|
+
* determinate</b>, i.e. claiming to be false;</li>
|
|
121
|
+
* <li><b>false</b> — `'false'` is not `=== true`, so it rendered correctly <b>by accident</b>.</li>
|
|
122
|
+
* </ul>
|
|
123
|
+
* <p>
|
|
124
|
+
* Types that stay strings do so deliberately, not by omission. `color`, `image` and `url` are bound
|
|
125
|
+
* into a style, an `src` and an `href`, so a string is what they need. `Reference` and `AsDetail`
|
|
126
|
+
* resolve to a breadcrumb, which is a label rather than a value.
|
|
127
|
+
* </p>
|
|
128
|
+
* <p>
|
|
129
|
+
* `date` and `datetime` return a real `Date`. They arrive as ISO strings, and the cell used to
|
|
130
|
+
* print that string verbatim — `2026-09-07T13:25:57.3119825Z` in a table column. Returning the
|
|
131
|
+
* parsed value lets `spark-grid-cell` format it in one place for both grids; an unparseable value
|
|
132
|
+
* falls back to its text, because showing what is there beats showing `Invalid Date`.
|
|
133
|
+
* </p>
|
|
134
|
+
*/
|
|
99
135
|
declare class AsDetailCellValuePipe implements PipeTransform {
|
|
100
|
-
transform(row: Record<string, any>, parentAttr: EntityAttributeDefinition, col: EntityAttributeDefinition, asDetailRefOptions: Record<string, Record<string, QueryResultItem[]>>):
|
|
136
|
+
transform(row: Record<string, any>, parentAttr: EntityAttributeDefinition, col: EntityAttributeDefinition, asDetailRefOptions: Record<string, Record<string, QueryResultItem[]>>): AsDetailCellValue;
|
|
101
137
|
static ɵfac: i0.ɵɵFactoryDeclaration<AsDetailCellValuePipe, never>;
|
|
102
138
|
static ɵpipe: i0.ɵɵPipeDeclaration<AsDetailCellValuePipe, "asDetailCellValue", true>;
|
|
103
139
|
}
|
|
@@ -200,4 +236,4 @@ declare class QueryReferenceChipsPipe implements PipeTransform {
|
|
|
200
236
|
}
|
|
201
237
|
|
|
202
238
|
export { ArrayValuePipe, AsDetailCellValuePipe, AsDetailColumnsPipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AttributeValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, ErrorForAttributePipe, IconNamePipe, InlineRefOptionsPipe, InputTypePipe, LookupDisplayTypePipe, LookupDisplayValuePipe, LookupOptionsPipe, QueryCellValuePipe, QueryReferenceChipsPipe, RawAttributeValuePipe, ReferenceAttrValuePipe, ReferenceChipsPipe, ReferenceDisplayValuePipe, ReferenceLinkRoutePipe, ResolveTranslationPipe, RouterLinkPipe, TranslateKeyPipe };
|
|
203
|
-
export type { ReferenceChip };
|
|
239
|
+
export type { AsDetailCellValue, ReferenceChip };
|
|
@@ -9,6 +9,7 @@ declare class SparkPoDetailComponent {
|
|
|
9
9
|
private readonly router;
|
|
10
10
|
private readonly sparkService;
|
|
11
11
|
private readonly queryRefresh;
|
|
12
|
+
private readonly attributeRefresh;
|
|
12
13
|
protected readonly lang: SparkLanguageService;
|
|
13
14
|
private readonly rendererRegistry;
|
|
14
15
|
showCustomActions: _angular_core.InputSignal<boolean>;
|
|
@@ -51,7 +52,29 @@ declare class SparkPoDetailComponent {
|
|
|
51
52
|
canEdit: _angular_core.WritableSignal<boolean>;
|
|
52
53
|
canDelete: _angular_core.WritableSignal<boolean>;
|
|
53
54
|
customActions: _angular_core.WritableSignal<CustomActionDefinition[]>;
|
|
55
|
+
/**
|
|
56
|
+
* The actions actually offered for the object on screen.
|
|
57
|
+
*
|
|
58
|
+
* The catalogue at `/spark/actions/{objectTypeId}` is per TYPE -- the server is never told which
|
|
59
|
+
* row is open -- so an action that applies to only some rows cannot be filtered there. The
|
|
60
|
+
* entity's actions hook decides while it has the entity in hand and withholds what does not
|
|
61
|
+
* apply, and the object arrives carrying that answer.
|
|
62
|
+
*
|
|
63
|
+
* An affordance, not a permission: the endpoint stays reachable and the action handler still
|
|
64
|
+
* refuses on its own terms. What this prevents is offering a destructive action where it cannot
|
|
65
|
+
* possibly apply -- Coverage showed an irreversible red "Delete data" button on every repository
|
|
66
|
+
* page, healthy ones included, and only admitted it would refuse after the confirmation prompt.
|
|
67
|
+
*/
|
|
68
|
+
visibleCustomActions: _angular_core.Signal<CustomActionDefinition[]>;
|
|
54
69
|
constructor();
|
|
70
|
+
/**
|
|
71
|
+
* Applies patched attribute values in place, without a re-fetch.
|
|
72
|
+
*
|
|
73
|
+
* The operation carries the value the server computed after its own write, so this is both
|
|
74
|
+
* cheaper and more correct than re-reading: a re-read goes through a RavenDB index that may
|
|
75
|
+
* still be stale from the very write that produced the patch, and would show the old value.
|
|
76
|
+
*/
|
|
77
|
+
private applyAttributePatches;
|
|
55
78
|
private onParamsChange;
|
|
56
79
|
visibleAttributes: _angular_core.Signal<EntityAttributeDefinition[]>;
|
|
57
80
|
private static readonly DEFAULT_TAB;
|
|
@@ -73,6 +96,16 @@ declare class SparkPoDetailComponent {
|
|
|
73
96
|
* from a JSON file and must not be able to put arbitrary classes on the button.
|
|
74
97
|
*/
|
|
75
98
|
protected customActionClass(action: CustomActionDefinition): string;
|
|
99
|
+
/**
|
|
100
|
+
* The action currently running, or null. Drives the disabled state on every custom-action
|
|
101
|
+
* button.
|
|
102
|
+
*
|
|
103
|
+
* A custom action is not necessarily quick: Coverage's Resync makes paged GitHub App calls for
|
|
104
|
+
* every account the caller manages, inside the request. Without this the button stayed live and
|
|
105
|
+
* looked inert for several seconds, and a second click queued a second full run -- which is how
|
|
106
|
+
* a slow action and a broken one became indistinguishable.
|
|
107
|
+
*/
|
|
108
|
+
runningAction: _angular_core.WritableSignal<string | null>;
|
|
76
109
|
onCustomAction(action: CustomActionDefinition): Promise<void>;
|
|
77
110
|
onEdit(): void;
|
|
78
111
|
onDelete(): Promise<void>;
|
|
@@ -42,6 +42,7 @@ declare class SparkStreamingService {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
declare class SparkService {
|
|
45
|
+
#private;
|
|
45
46
|
private readonly config;
|
|
46
47
|
private readonly baseUrl;
|
|
47
48
|
private readonly http;
|
|
@@ -53,6 +54,14 @@ declare class SparkService {
|
|
|
53
54
|
getPermissions(entityTypeId: string): Promise<EntityPermissions>;
|
|
54
55
|
getQueries(): Promise<SparkQuery[]>;
|
|
55
56
|
getQuery(id: string): Promise<SparkQuery>;
|
|
57
|
+
/**
|
|
58
|
+
* Resolves a query by name, fetching the catalogue at most once per service instance.
|
|
59
|
+
*
|
|
60
|
+
* Without the cache this costs a full `GET /spark/queries` per call, and a form with several
|
|
61
|
+
* reference attributes resolves them in parallel — so opening one page fetched the whole query
|
|
62
|
+
* catalogue N times over. The catalogue is per-caller and effectively static for a page's
|
|
63
|
+
* lifetime; the service is scoped to the app, so a permission change lands on the next load.
|
|
64
|
+
*/
|
|
56
65
|
getQueryByName(name: string): Promise<SparkQuery | undefined>;
|
|
57
66
|
executeQuery(queryId: string, options?: {
|
|
58
67
|
sortColumns?: SortColumn[];
|
|
@@ -62,12 +71,23 @@ declare class SparkService {
|
|
|
62
71
|
take?: number;
|
|
63
72
|
search?: string;
|
|
64
73
|
}): Promise<QueryResult>;
|
|
74
|
+
/**
|
|
75
|
+
* Runs a query identified by name.
|
|
76
|
+
*
|
|
77
|
+
* It used to forward only the parent, dropping skip/take/search — so every reference picker and
|
|
78
|
+
* AsDetail reference column silently saw the server's default of 50 candidates, with no indication
|
|
79
|
+
* that the list was cut. A picker that omits the option you are looking for, and says nothing, is
|
|
80
|
+
* worse than one that fails.
|
|
81
|
+
*/
|
|
65
82
|
executeQueryByName(queryName: string, options?: {
|
|
66
83
|
parentId?: string;
|
|
67
84
|
parentType?: string;
|
|
85
|
+
skip?: number;
|
|
86
|
+
take?: number;
|
|
87
|
+
search?: string;
|
|
88
|
+
sortColumns?: SortColumn[];
|
|
68
89
|
}): Promise<QueryResult>;
|
|
69
90
|
getProgramUnits(): Promise<ProgramUnitsConfiguration>;
|
|
70
|
-
list(type: string): Promise<PersistentObject[]>;
|
|
71
91
|
get(type: string, id: string): Promise<PersistentObject>;
|
|
72
92
|
create(type: string, data: Partial<PersistentObject>): Promise<PersistentObject>;
|
|
73
93
|
update(type: string, id: string, data: Partial<PersistentObject>): Promise<PersistentObject>;
|