@mintplayer/ng-spark 22.1.0 → 22.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +69 -4
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-grid.mjs +111 -0
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-models.mjs +112 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +2 -2
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +211 -54
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +2 -2
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +88 -46
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/package.json +5 -1
- package/types/mintplayer-ng-spark-client-operations.d.ts +30 -4
- package/types/mintplayer-ng-spark-grid.d.ts +63 -0
- package/types/mintplayer-ng-spark-models.d.ts +56 -2
- package/types/mintplayer-ng-spark-po-detail.d.ts +112 -3
- package/types/mintplayer-ng-spark-query-list.d.ts +37 -4
|
@@ -157,14 +157,40 @@ declare class SparkToastContainerComponent {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
|
-
* Registers the built-in client-operation handlers
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* Registers the built-in client-operation handlers: `notify` and `refreshQuery`.
|
|
161
|
+
* Apps add this once in their bootstrap providers.
|
|
162
|
+
*
|
|
163
|
+
* Unregistered operation types are dropped SILENTLY by the dispatcher, which is why
|
|
164
|
+
* `refreshQuery` did nothing at all for as long as it went unhandled — the server emitted
|
|
165
|
+
* it, nothing listened, and no error said so. `disableAction` is in that state today: it is
|
|
166
|
+
* registered below purely to log, so the gap is visible rather than invisible.
|
|
163
167
|
*
|
|
164
168
|
* To register custom operation types alongside the built-ins, add additional
|
|
165
169
|
* `multi: true` providers using <see cref="SPARK_CLIENT_OPERATION_HANDLERS" />.
|
|
166
170
|
*/
|
|
167
171
|
declare function provideSparkClientOperations(): EnvironmentProviders;
|
|
168
172
|
|
|
169
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Carries a server-issued `refreshQuery` to whichever grids are showing that query.
|
|
175
|
+
*
|
|
176
|
+
* A broadcast signal rather than a registry of component handles: grids come and go behind
|
|
177
|
+
* `@if` and lazy routes, and nothing else in ng-spark holds a component reference. A grid
|
|
178
|
+
* reads {@link tokenFor} in an effect and re-fetches when it changes, which is the same
|
|
179
|
+
* declarative shape as the `reloadToken` input a host would use.
|
|
180
|
+
*
|
|
181
|
+
* Until this existed the server could emit the operation and the dispatcher dropped it: only
|
|
182
|
+
* `notify` was registered, and unknown types are ignored silently — so `refreshOnCompleted`
|
|
183
|
+
* on the server had no effect on any grid the action did not happen to be hosted in.
|
|
184
|
+
*/
|
|
185
|
+
declare class SparkQueryRefreshService {
|
|
186
|
+
private readonly tokens;
|
|
187
|
+
/** Bumped every time the server asks for this query to refresh. */
|
|
188
|
+
tokenFor(queryId: string | undefined): number;
|
|
189
|
+
/** Ask every grid showing `queryId` to re-fetch. Matched on id AND alias, since a grid may hold either. */
|
|
190
|
+
request(queryId: string): void;
|
|
191
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkQueryRefreshService, never>;
|
|
192
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SparkQueryRefreshService>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export { NotificationKind, SPARK_CLIENT_OPERATION_HANDLERS, SparkClientOperationDispatcher, SparkNotificationService, SparkQueryRefreshService, SparkToastContainerComponent, provideSparkClientOperations };
|
|
170
196
|
export type { ClientOperation, ClientOperationEnvelope, ClientOperationHandler, ClientOperationHandlerRegistration, DisableActionOperation, DisableTarget, NavigateOperation, NotifyOperation, RefreshAttributeOperation, RefreshQueryOperation, RetryOperation, SparkToast };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { DatatableSettings } from '@mintplayer/ng-bootstrap/datatable';
|
|
2
|
+
import { SparkQuery, EntityType, EntityAttributeDefinition, PersistentObject, LookupReference } from '@mintplayer/ng-spark/models';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { Type } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
/** Page sizes offered by every Spark grid. */
|
|
7
|
+
declare const SPARK_GRID_PAGE_SIZES: number[];
|
|
8
|
+
/**
|
|
9
|
+
* The attributes a grid shows, in display order.
|
|
10
|
+
*
|
|
11
|
+
* Shared so the two grids cannot disagree about what "visible" means — they each had their own
|
|
12
|
+
* copy of this expression, which is the kind of thing that stays identical right up until it
|
|
13
|
+
* doesn't.
|
|
14
|
+
*/
|
|
15
|
+
declare function visibleGridAttributes(entityType: EntityType | null): EntityAttributeDefinition[];
|
|
16
|
+
/**
|
|
17
|
+
* Initial datatable settings for a query, seeded with the query's declared sort.
|
|
18
|
+
*
|
|
19
|
+
* The datatable owns paging and sorting from here on and calls the fetch callback per page; this
|
|
20
|
+
* only decides where it starts.
|
|
21
|
+
*/
|
|
22
|
+
declare function initialGridSettings(query: SparkQuery | null): DatatableSettings;
|
|
23
|
+
/** Whether a query renders as a virtual-scrolling grid rather than a paged one. */
|
|
24
|
+
declare function isVirtualScrollingQuery(query: SparkQuery | null): boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The parts of a Spark grid that both grid components need and that were, until this existed,
|
|
28
|
+
* written out twice.
|
|
29
|
+
*
|
|
30
|
+
* `spark-query-list` and `spark-sub-query` had byte-identical copies of the renderer lookup, the
|
|
31
|
+
* renderer input construction and the lookup-reference loading — around 120 lines between them.
|
|
32
|
+
* That duplication is not a tidiness complaint: it is what produced the drift. The two copies
|
|
33
|
+
* disagreed about `[indeterminate]`, about resetting permission state, about whether a fetch
|
|
34
|
+
* failure surfaces or is swallowed, and about virtual-scroll sizing — four user-visible bugs, each
|
|
35
|
+
* fixed on one side and not the other, because nothing made the two files move together.
|
|
36
|
+
*
|
|
37
|
+
* Kept deliberately small and stateless. The two components differ in real ways — one is
|
|
38
|
+
* route-coupled and carries streaming, search and a websocket dependency graph — so merging them
|
|
39
|
+
* into a single component would drag all of that into every detail page's bundle. Shared logic
|
|
40
|
+
* belongs here; shared *state* does not.
|
|
41
|
+
*/
|
|
42
|
+
declare class SparkGridRenderers {
|
|
43
|
+
private readonly registry;
|
|
44
|
+
private readonly sparkService;
|
|
45
|
+
/** The registered column component for an attribute, or null to fall back to the default cell. */
|
|
46
|
+
columnComponentFor(attr: EntityAttributeDefinition): Type<any> | null;
|
|
47
|
+
/**
|
|
48
|
+
* Inputs for a column renderer, filtered to what the component actually declares —
|
|
49
|
+
* `NgComponentOutlet` throws on an input the target does not have, which is what lets every
|
|
50
|
+
* member of the renderer contract be optional.
|
|
51
|
+
*/
|
|
52
|
+
columnInputsFor(component: Type<any>, item: PersistentObject, attr: EntityAttributeDefinition): Record<string, any>;
|
|
53
|
+
/**
|
|
54
|
+
* Loads every lookup reference the visible attributes need, in one pass.
|
|
55
|
+
*
|
|
56
|
+
* Returns an empty map rather than throwing when there are none, so callers never branch on it.
|
|
57
|
+
*/
|
|
58
|
+
loadLookupOptions(attributes: EntityAttributeDefinition[]): Promise<Record<string, LookupReference>>;
|
|
59
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SparkGridRenderers, never>;
|
|
60
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SparkGridRenderers>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { SPARK_GRID_PAGE_SIZES, SparkGridRenderers, initialGridSettings, isVirtualScrollingQuery, visibleGridAttributes };
|
|
@@ -290,6 +290,13 @@ interface RetryActionResult {
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
interface EntityPermissions {
|
|
293
|
+
/**
|
|
294
|
+
* Whether the caller may list this type. Independently grantable from `canRead` — `Query/Person`
|
|
295
|
+
* alone lists rows while refusing a by-id load — and reported since preview.60. The combined
|
|
296
|
+
* `QueryRead` right bundles the two invisibly, which is why this was the one action introspection
|
|
297
|
+
* never mentioned.
|
|
298
|
+
*/
|
|
299
|
+
canQuery: boolean;
|
|
293
300
|
canRead: boolean;
|
|
294
301
|
canCreate: boolean;
|
|
295
302
|
canEdit: boolean;
|
|
@@ -368,5 +375,52 @@ declare function nestedPoToDisplayRow(po: PersistentObject | null | undefined):
|
|
|
368
375
|
*/
|
|
369
376
|
declare function dictToNestedPo(dict: Record<string, any> | null | undefined, entityType: EntityType, resolve: EntityTypeResolver): PersistentObject;
|
|
370
377
|
|
|
371
|
-
|
|
372
|
-
|
|
378
|
+
/**
|
|
379
|
+
* The custom actions a query should offer, from the entity type's full set.
|
|
380
|
+
*
|
|
381
|
+
* `showedOn` must include the query side. The accepted values are `"detail"`, `"query"`
|
|
382
|
+
* and `"both"` — as the server model and the custom-actions guide have always
|
|
383
|
+
* documented. Both grids previously tested for `"list"`, a value nothing emits, so an
|
|
384
|
+
* action authored per the documentation rendered nowhere at all.
|
|
385
|
+
*
|
|
386
|
+
* ⚠️ This narrows what is DISPLAYED. It is NOT an authorization boundary: the grant
|
|
387
|
+
* is, and it is enforced independently in `ExecuteCustomAction` regardless of which
|
|
388
|
+
* query the caller clicked from — a caller can always POST directly.
|
|
389
|
+
*/
|
|
390
|
+
declare function filterQueryActions(actions: CustomActionDefinition[]): CustomActionDefinition[];
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Parses a custom action's `selectionRule` — a cardinality expression over the number
|
|
394
|
+
* of selected rows — into a predicate.
|
|
395
|
+
*
|
|
396
|
+
* A port of the server's `SelectionRuleParser`, and the two MUST agree: they are tested
|
|
397
|
+
* against one shared fixture (`selection-rule.fixture.json`) for exactly this reason.
|
|
398
|
+
* Vidyano, where this grammar comes from, has the same algorithm in C# and JavaScript and
|
|
399
|
+
* the two have already drifted — one throws on a non-numeric operand where the other
|
|
400
|
+
* silently permits everything.
|
|
401
|
+
*
|
|
402
|
+
* Grammar: `X` is the count placeholder, whitespace is insignificant, terms split on `X`
|
|
403
|
+
* are AND-combined (`1<X<5` is a range), operators are `<= >= < > != =` matched in that
|
|
404
|
+
* order so `>=` is never read as `>`, and a number-first term is mirrored (`0<X` is `>0`).
|
|
405
|
+
*
|
|
406
|
+
* Client-side this only drives whether a button is disabled. The server enforces the same
|
|
407
|
+
* rule independently — and neither is an authorization boundary: the action's grant is.
|
|
408
|
+
*/
|
|
409
|
+
declare function parseSelectionRule(rule?: string | null): (count: number) => boolean;
|
|
410
|
+
|
|
411
|
+
type SparkSelectionMode = 'none' | 'single' | 'multiple';
|
|
412
|
+
/**
|
|
413
|
+
* The selection mode a grid needs in order to satisfy the actions offered on it.
|
|
414
|
+
*
|
|
415
|
+
* Derived rather than configured, so a grid gains a checkbox column exactly when an
|
|
416
|
+
* action needs one and is otherwise pixel-identical to a grid with no selection at all.
|
|
417
|
+
* Vidyano's query grid does the same thing — it renders the checkbox column only if some
|
|
418
|
+
* action is selection-gated.
|
|
419
|
+
*
|
|
420
|
+
* `'single'` when every gated action is satisfied by one row and refused by two; anything
|
|
421
|
+
* else that cares about the count gets `'multiple'`.
|
|
422
|
+
*/
|
|
423
|
+
declare function selectionModeFor(actions: CustomActionDefinition[]): SparkSelectionMode;
|
|
424
|
+
|
|
425
|
+
export { AS_DETAIL_BREADCRUMBS_KEY, ELookupDisplayType, EReferenceDisplayType, ShowedOn, currentLanguage, dictToNestedPo, filterQueryActions, hasShowedOnFlag, nestedPoToDict, nestedPoToDisplayRow, parseSelectionRule, resolveTranslation, selectionModeFor };
|
|
426
|
+
export type { AttributeGroup, AttributeTab, CustomActionDefinition, EntityAttributeDefinition, EntityPermissions, EntityType, EntityTypeResolver, LookupReference, LookupReferenceListItem, LookupReferenceValue, PersistentObject, PersistentObjectAttribute, PersistentObjectPermissions, ProgramUnit, ProgramUnitGroup, ProgramUnitsConfiguration, QueryResult, RetryActionPayload, RetryActionResult, SparkQuery, SparkQueryRenderMode, SparkQuerySortColumn, SparkSelectionMode, StreamingErrorMessage, StreamingMessage, StreamingPatchItem, StreamingPatchMessage, StreamingSnapshotMessage, TranslatedString, ValidationError, ValidationErrorResponse, ValidationRule };
|
|
@@ -2,13 +2,16 @@ import * as _angular_core from '@angular/core';
|
|
|
2
2
|
import { TemplateRef, Type } from '@angular/core';
|
|
3
3
|
import { Color } from '@mintplayer/ng-bootstrap';
|
|
4
4
|
import { SparkLanguageService } from '@mintplayer/ng-spark/services';
|
|
5
|
+
import * as _mintplayer_ng_spark_models from '@mintplayer/ng-spark/models';
|
|
5
6
|
import { PersistentObject, EntityType, CustomActionDefinition, LookupReference, EntityAttributeDefinition, AttributeTab, AttributeGroup, SparkQuery } from '@mintplayer/ng-spark/models';
|
|
7
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
6
8
|
import { DatatableSettings, BsDatatableFetch } from '@mintplayer/ng-bootstrap/datatable';
|
|
7
9
|
|
|
8
10
|
declare class SparkPoDetailComponent {
|
|
9
11
|
private readonly route;
|
|
10
12
|
private readonly router;
|
|
11
13
|
private readonly sparkService;
|
|
14
|
+
private readonly queryRefresh;
|
|
12
15
|
protected readonly lang: SparkLanguageService;
|
|
13
16
|
private readonly rendererRegistry;
|
|
14
17
|
showCustomActions: _angular_core.InputSignal<boolean>;
|
|
@@ -61,29 +64,135 @@ declare class SparkPoDetailComponent {
|
|
|
61
64
|
|
|
62
65
|
declare class SparkSubQueryComponent {
|
|
63
66
|
private readonly sparkService;
|
|
64
|
-
private readonly
|
|
67
|
+
private readonly gridRenderers;
|
|
68
|
+
readonly lang: SparkLanguageService;
|
|
65
69
|
queryId: _angular_core.InputSignal<string>;
|
|
70
|
+
/**
|
|
71
|
+
* The parent persistent object this query is scoped to, when it has one.
|
|
72
|
+
*
|
|
73
|
+
* Optional, because not every query is a detail of something: a page can host
|
|
74
|
+
* a grid that stands on its own — "my accounts", a dashboard list — and the
|
|
75
|
+
* server already treats an absent parent as "no parent" rather than as an
|
|
76
|
+
* error. Leaving these required made that shape impossible to express: the
|
|
77
|
+
* component simply never loaded, with no request, no error and no log.
|
|
78
|
+
*
|
|
79
|
+
* Pass both or neither. One without the other is ignored, matching
|
|
80
|
+
* `SparkService.executeQuery`, which omits either param when it is falsy, and
|
|
81
|
+
* the execute endpoint, which resolves a parent only when both are present.
|
|
82
|
+
*/
|
|
66
83
|
parentId: _angular_core.InputSignal<string>;
|
|
67
84
|
parentType: _angular_core.InputSignal<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Change this to re-run the query. Any value works; only its identity matters.
|
|
87
|
+
*
|
|
88
|
+
* A declarative token rather than only a `reload()` method, because calling a
|
|
89
|
+
* method means holding a component handle, and hosts wrap this grid in `@if`,
|
|
90
|
+
* where a `viewChild` is intermittently undefined. Nothing else in ng-spark
|
|
91
|
+
* uses `viewChild` either — the house idiom is to re-seed a signal.
|
|
92
|
+
*
|
|
93
|
+
* This drives the CHEAP refresh (see {@link reload}). It deliberately does not
|
|
94
|
+
* feed the main effect: re-running `loadData` would re-resolve the query, the
|
|
95
|
+
* entity types, the permissions and the lookups, and reset the user's page and
|
|
96
|
+
* sort on every button press.
|
|
97
|
+
*/
|
|
98
|
+
reloadToken: _angular_core.InputSignal<unknown>;
|
|
99
|
+
/**
|
|
100
|
+
* Render without the surrounding card, for a host that owns its own chrome — a tab
|
|
101
|
+
* body, a modal, a dashboard tile.
|
|
102
|
+
*
|
|
103
|
+
* This is the escape hatch for a genuinely chromeless embed. It only serves a host
|
|
104
|
+
* that instantiated this component by hand — where the component is auto-rendered
|
|
105
|
+
* from `EntityTypeDefinition.Queries` there is no host to pass it.
|
|
106
|
+
*/
|
|
107
|
+
showCard: _angular_core.InputSignal<boolean>;
|
|
108
|
+
/**
|
|
109
|
+
* Replace the header for one hand-instantiated usage.
|
|
110
|
+
*
|
|
111
|
+
* A `TemplateRef` rather than `<ng-content>` deliberately: it matches
|
|
112
|
+
* `spark-po-detail`'s `extraActionsTemplate`/`extraContentTemplate`, and unlike
|
|
113
|
+
* projection it can be forwarded by a host that is itself several layers up.
|
|
114
|
+
*
|
|
115
|
+
* Precedence is headerTemplate -> caption + query actions.
|
|
116
|
+
*/
|
|
117
|
+
headerTemplate: _angular_core.InputSignal<TemplateRef<{
|
|
118
|
+
$implicit: SparkQuery;
|
|
119
|
+
}> | null>;
|
|
120
|
+
colors: typeof Color;
|
|
68
121
|
query: _angular_core.WritableSignal<SparkQuery | null>;
|
|
69
122
|
entityType: _angular_core.WritableSignal<EntityType | null>;
|
|
70
123
|
allEntityTypes: _angular_core.WritableSignal<EntityType[]>;
|
|
71
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Why the component renders its own failure instead of only reporting one.
|
|
126
|
+
*
|
|
127
|
+
* `SparkService` is a bare `firstValueFrom` passthrough with no interceptor, so
|
|
128
|
+
* every failure surfaces here and nowhere else. A host embedding this grid cannot
|
|
129
|
+
* surface what it never sees, and the default has to be visible with no host
|
|
130
|
+
* cooperation — hence a rendered alert, not just an output.
|
|
131
|
+
*
|
|
132
|
+
* A 404 is deliberately vague. `Endpoints/Queries/Get.cs` answers 404 for BOTH
|
|
133
|
+
* "no such query" and "you may not see it", with byte-identical bodies, so that
|
|
134
|
+
* existence is not disclosed (security audit M-3). This component therefore
|
|
135
|
+
* genuinely cannot tell the two apart, and any message claiming otherwise would
|
|
136
|
+
* either leak or mislead.
|
|
137
|
+
*/
|
|
138
|
+
errorMessage: _angular_core.WritableSignal<string | null>;
|
|
139
|
+
/**
|
|
140
|
+
* Actions the query declares, rendered in this component's own header.
|
|
141
|
+
*
|
|
142
|
+
* This is what makes a query's chrome work with no host: a sub-query is rendered
|
|
143
|
+
* automatically from `EntityTypeDefinition.Queries`, so there is nobody to project
|
|
144
|
+
* a toolbar in. The query says what belongs in its header, and it follows the query
|
|
145
|
+
* wherever it is rendered.
|
|
146
|
+
*/
|
|
147
|
+
customActions: _angular_core.WritableSignal<CustomActionDefinition[]>;
|
|
148
|
+
/** Emitted whenever a load or a page fetch fails, for a host in bespoke chrome. */
|
|
149
|
+
error: _angular_core.OutputEmitterRef<HttpErrorResponse>;
|
|
72
150
|
lookupReferenceOptions: _angular_core.WritableSignal<Record<string, LookupReference>>;
|
|
73
151
|
loading: _angular_core.WritableSignal<boolean>;
|
|
74
152
|
canRead: _angular_core.WritableSignal<boolean>;
|
|
75
153
|
settings: _angular_core.WritableSignal<DatatableSettings>;
|
|
76
154
|
fetchFn: _angular_core.WritableSignal<BsDatatableFetch<PersistentObject> | null>;
|
|
155
|
+
/**
|
|
156
|
+
* Rows the user has ticked. Lives here rather than in the datatable so the action bar can
|
|
157
|
+
* read it, and MUST be cleared whenever the source changes — otherwise route A's selection
|
|
158
|
+
* is POSTed as ids of route B's type.
|
|
159
|
+
*/
|
|
160
|
+
selection: _angular_core.WritableSignal<PersistentObject[]>;
|
|
161
|
+
private readonly queryRefresh;
|
|
162
|
+
/** 'none' unless an action is selection-gated, so unaffected grids gain no checkbox column. */
|
|
163
|
+
selectionMode: _angular_core.Signal<_mintplayer_ng_spark_models.SparkSelectionMode>;
|
|
164
|
+
/** Whether an action's selection rule is satisfied right now. The server checks it again. */
|
|
165
|
+
isActionEnabled(action: CustomActionDefinition): boolean;
|
|
77
166
|
isVirtualScrolling: _angular_core.Signal<boolean>;
|
|
78
167
|
visibleAttributes: _angular_core.Signal<EntityAttributeDefinition[]>;
|
|
79
168
|
constructor();
|
|
169
|
+
/**
|
|
170
|
+
* Re-run the query, keeping the current page, sort and scroll position.
|
|
171
|
+
*
|
|
172
|
+
* Data-level on purpose: it re-seeds the fetch closure and nothing else, mirroring
|
|
173
|
+
* `SparkQueryListComponent.reload()`. Use it after something mutates server-side
|
|
174
|
+
* state the query reads from. For a definition change — new columns, a renamed
|
|
175
|
+
* query — the inputs themselves must change; that is the expensive path.
|
|
176
|
+
*/
|
|
177
|
+
onCustomAction(action: CustomActionDefinition): Promise<void>;
|
|
178
|
+
private reportError;
|
|
179
|
+
/**
|
|
180
|
+
* A 404 is deliberately generic.
|
|
181
|
+
*
|
|
182
|
+
* `Endpoints/Queries/Get.cs` answers 404 with byte-identical bodies for "no such
|
|
183
|
+
* query" and "you may not see it", so existence is not disclosed (audit M-3). The
|
|
184
|
+
* component therefore cannot tell them apart, and both "Not found" and "Access
|
|
185
|
+
* denied" would be a guess — one of them leaking, the other misleading.
|
|
186
|
+
*/
|
|
187
|
+
private describe;
|
|
188
|
+
reload(): void;
|
|
80
189
|
private loadData;
|
|
81
190
|
private makeFetch;
|
|
82
191
|
private loadLookupReferenceOptions;
|
|
83
192
|
getColumnRendererComponent(attr: EntityAttributeDefinition): Type<any> | null;
|
|
84
193
|
getColumnRendererInputs(component: Type<any>, item: PersistentObject, attr: EntityAttributeDefinition): Record<string, any>;
|
|
85
194
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkSubQueryComponent, never>;
|
|
86
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkSubQueryComponent, "spark-sub-query", never, { "queryId": { "alias": "queryId"; "required": true; "isSignal": true; }; "parentId": { "alias": "parentId"; "required":
|
|
195
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkSubQueryComponent, "spark-sub-query", never, { "queryId": { "alias": "queryId"; "required": true; "isSignal": true; }; "parentId": { "alias": "parentId"; "required": false; "isSignal": true; }; "parentType": { "alias": "parentType"; "required": false; "isSignal": true; }; "reloadToken": { "alias": "reloadToken"; "required": false; "isSignal": true; }; "showCard": { "alias": "showCard"; "required": false; "isSignal": true; }; "headerTemplate": { "alias": "headerTemplate"; "required": false; "isSignal": true; }; }, { "error": "error"; }, never, never, true, never>;
|
|
87
196
|
}
|
|
88
197
|
|
|
89
198
|
export { SparkPoDetailComponent, SparkSubQueryComponent };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import * as _mintplayer_ng_spark_models from '@mintplayer/ng-spark/models';
|
|
2
|
+
import { PersistentObject, CustomActionDefinition, SparkQuery, EntityType, LookupReference, EntityAttributeDefinition } from '@mintplayer/ng-spark/models';
|
|
1
3
|
import * as _angular_core from '@angular/core';
|
|
2
4
|
import { TemplateRef, Type } from '@angular/core';
|
|
3
5
|
import { Color } from '@mintplayer/ng-bootstrap';
|
|
4
6
|
import { BsDatatableFetch, DatatableSettings } from '@mintplayer/ng-bootstrap/datatable';
|
|
5
7
|
import { SparkLanguageService } from '@mintplayer/ng-spark/services';
|
|
6
|
-
import { PersistentObject, CustomActionDefinition, SparkQuery, EntityType, LookupReference, EntityAttributeDefinition } from '@mintplayer/ng-spark/models';
|
|
7
8
|
|
|
8
9
|
declare class SparkQueryListComponent {
|
|
9
10
|
private readonly route;
|
|
@@ -11,7 +12,7 @@ declare class SparkQueryListComponent {
|
|
|
11
12
|
private readonly sparkService;
|
|
12
13
|
private readonly streamingService;
|
|
13
14
|
protected readonly lang: SparkLanguageService;
|
|
14
|
-
private readonly
|
|
15
|
+
private readonly gridRenderers;
|
|
15
16
|
private readonly destroyRef;
|
|
16
17
|
extraActionsTemplate: _angular_core.InputSignal<TemplateRef<void> | null>;
|
|
17
18
|
showCustomActions: _angular_core.InputSignal<boolean>;
|
|
@@ -39,6 +40,12 @@ declare class SparkQueryListComponent {
|
|
|
39
40
|
settings: _angular_core.WritableSignal<DatatableSettings>;
|
|
40
41
|
constructor();
|
|
41
42
|
private onParamsChange;
|
|
43
|
+
/**
|
|
44
|
+
* A load failure has to render, not just be swallowed: a denied query answers 404
|
|
45
|
+
* (audit M-3, so existence is not leaked), which is indistinguishable from a missing
|
|
46
|
+
* one -- hence a deliberately generic message rather than a guess at which it was.
|
|
47
|
+
*/
|
|
48
|
+
private reportLoadFailure;
|
|
42
49
|
onCustomAction(action: CustomActionDefinition): Promise<void>;
|
|
43
50
|
private resolveEntityTypeForQuery;
|
|
44
51
|
private extractSourceName;
|
|
@@ -49,10 +56,36 @@ declare class SparkQueryListComponent {
|
|
|
49
56
|
* refetches with the current search term.
|
|
50
57
|
*/
|
|
51
58
|
private makeFetch;
|
|
52
|
-
/**
|
|
53
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Force a refetch (e.g. after a custom action) without changing page/sort.
|
|
61
|
+
*
|
|
62
|
+
* Public so a host can drive it, and named to match
|
|
63
|
+
* `SparkSubQueryComponent.reload()` — the two grids had drifted into having the
|
|
64
|
+
* same mechanism under different names, one of them unreachable.
|
|
65
|
+
*/
|
|
66
|
+
reload(): void;
|
|
54
67
|
onSearchChange(): void;
|
|
55
68
|
clearSearch(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Whether the first column links to a detail page.
|
|
71
|
+
*
|
|
72
|
+
* Declared by the query, because the framework cannot derive it: `Database.*` rows
|
|
73
|
+
* are always real documents, but a `Custom.*` query may return loadable documents
|
|
74
|
+
* (Fleet's Stolen_Cars) or rows fabricated in memory (StreamItems). Absent means
|
|
75
|
+
* navigable -- defaulting Custom.* to false would strip the working links off every
|
|
76
|
+
* custom query that does return documents.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Rows the user has ticked. Lives here rather than in the datatable so the action bar can
|
|
80
|
+
* read it, and MUST be cleared whenever the source changes — otherwise route A's selection
|
|
81
|
+
* is POSTed as ids of route B's type.
|
|
82
|
+
*/
|
|
83
|
+
selection: _angular_core.WritableSignal<PersistentObject[]>;
|
|
84
|
+
private readonly queryRefresh;
|
|
85
|
+
/** 'none' unless an action is selection-gated, so unaffected grids gain no checkbox column. */
|
|
86
|
+
selectionMode: _angular_core.Signal<_mintplayer_ng_spark_models.SparkSelectionMode>;
|
|
87
|
+
/** Whether an action's selection rule is satisfied right now. The server checks it again. */
|
|
88
|
+
isActionEnabled(action: CustomActionDefinition): boolean;
|
|
56
89
|
isVirtualScrolling: _angular_core.Signal<boolean>;
|
|
57
90
|
visibleAttributes: _angular_core.Signal<EntityAttributeDefinition[]>;
|
|
58
91
|
getColumnRendererComponent(attr: EntityAttributeDefinition): Type<any> | null;
|