@mintplayer/ng-spark 22.23.0 → 22.25.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 +196 -0
- package/fesm2022/mintplayer-ng-spark-attribute-description.mjs +100 -47
- package/fesm2022/mintplayer-ng-spark-attribute-description.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs +310 -329
- package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-column-filter.mjs +175 -135
- package/fesm2022/mintplayer-ng-spark-column-filter.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-contributions.mjs +721 -0
- package/fesm2022/mintplayer-ng-spark-contributions.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-grid.mjs +2385 -1118
- package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-history.mjs +598 -0
- package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-icon.mjs +64 -27
- package/fesm2022/mintplayer-ng-spark-icon.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-models.mjs +405 -762
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-moderation.mjs +1212 -0
- package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-panels.mjs +60 -0
- package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +1158 -765
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +273 -169
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +795 -410
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +1196 -280
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +2244 -1224
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-query-list.mjs +571 -303
- package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-renderers.mjs +44 -55
- package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +216 -177
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-routes.mjs +24 -28
- package/fesm2022/mintplayer-ng-spark-routes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +625 -640
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-shell.mjs +1031 -397
- package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-soft-delete.mjs +294 -0
- package/fesm2022/mintplayer-ng-spark-soft-delete.mjs.map +1 -0
- package/fesm2022/mintplayer-ng-spark.mjs +14 -48
- package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
- package/package.json +23 -2
- package/types/mintplayer-ng-spark-attribute-description.d.ts +25 -18
- package/types/mintplayer-ng-spark-client-operations.d.ts +139 -160
- package/types/mintplayer-ng-spark-column-filter.d.ts +73 -55
- package/types/mintplayer-ng-spark-contributions.d.ts +231 -0
- package/types/mintplayer-ng-spark-grid.d.ts +917 -448
- package/types/mintplayer-ng-spark-history.d.ts +216 -0
- package/types/mintplayer-ng-spark-icon.d.ts +15 -13
- package/types/mintplayer-ng-spark-models.d.ts +681 -573
- package/types/mintplayer-ng-spark-moderation.d.ts +402 -0
- package/types/mintplayer-ng-spark-panels.d.ts +143 -0
- package/types/mintplayer-ng-spark-pipes.d.ts +131 -149
- package/types/mintplayer-ng-spark-po-create.d.ts +46 -37
- package/types/mintplayer-ng-spark-po-detail.d.ts +180 -117
- package/types/mintplayer-ng-spark-po-edit.d.ts +367 -64
- package/types/mintplayer-ng-spark-po-form.d.ts +558 -373
- package/types/mintplayer-ng-spark-query-list.d.ts +143 -82
- package/types/mintplayer-ng-spark-renderers.d.ts +121 -85
- package/types/mintplayer-ng-spark-retry-action-modal.d.ts +31 -34
- package/types/mintplayer-ng-spark-routes.d.ts +7 -11
- package/types/mintplayer-ng-spark-services.d.ts +377 -261
- package/types/mintplayer-ng-spark-shell.d.ts +228 -132
- package/types/mintplayer-ng-spark-soft-delete.d.ts +90 -0
- package/types/mintplayer-ng-spark.d.ts +19 -12
|
@@ -1,40 +1,35 @@
|
|
|
1
|
-
import { WritableSignal } from
|
|
2
|
-
|
|
3
|
-
type TranslatedString = Record<string, string>;
|
|
1
|
+
import { WritableSignal } from "@angular/core";
|
|
2
|
+
export type TranslatedString = Record<string, string>;
|
|
4
3
|
/** Global reactive language state — shared across library boundaries via globalThis */
|
|
5
|
-
declare const currentLanguage: WritableSignal<string>;
|
|
6
|
-
declare function resolveTranslation(ts: TranslatedString | undefined, lang?: string): string;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
errors: ValidationError[];
|
|
23
|
-
}
|
|
24
|
-
|
|
4
|
+
export declare const currentLanguage: WritableSignal<string>;
|
|
5
|
+
export declare function resolveTranslation(ts: TranslatedString | undefined, lang?: string): string;
|
|
6
|
+
export interface ValidationRule {
|
|
7
|
+
type: string;
|
|
8
|
+
value?: any;
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
message?: TranslatedString;
|
|
12
|
+
}
|
|
13
|
+
export interface ValidationError {
|
|
14
|
+
attributeName: string;
|
|
15
|
+
errorMessage: TranslatedString;
|
|
16
|
+
ruleType: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ValidationErrorResponse {
|
|
19
|
+
errors: ValidationError[];
|
|
20
|
+
}
|
|
25
21
|
/**
|
|
26
22
|
* Flags enum controlling on which pages an attribute should be displayed.
|
|
27
23
|
* Values can be combined: ShowedOn.Query | ShowedOn.PersistentObject
|
|
28
24
|
*/
|
|
29
|
-
declare enum ShowedOn {
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
export declare enum ShowedOn {
|
|
26
|
+
Query = 1,
|
|
27
|
+
PersistentObject = 2
|
|
32
28
|
}
|
|
33
29
|
/**
|
|
34
30
|
* Helper function to check if a ShowedOn value includes a specific flag.
|
|
35
31
|
*/
|
|
36
|
-
declare function hasShowedOnFlag(value: ShowedOn | string | undefined, flag: ShowedOn): boolean;
|
|
37
|
-
|
|
32
|
+
export declare function hasShowedOnFlag(value: ShowedOn | string | undefined, flag: ShowedOn): boolean;
|
|
38
33
|
/**
|
|
39
34
|
* Per-row action affordances (#236 G5). Present only when the entity type has a row-level rule;
|
|
40
35
|
* absent otherwise, so clients fall back to the type-level permissions from
|
|
@@ -44,262 +39,364 @@ declare function hasShowedOnFlag(value: ShowedOn | string | undefined, flag: Sho
|
|
|
44
39
|
* row rule (#243) — a present block never claims more than the permissions endpoint would, so
|
|
45
40
|
* letting it override the type-level answer is safe.
|
|
46
41
|
*/
|
|
47
|
-
interface PersistentObjectPermissions {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
interface PersistentObject {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
42
|
+
export interface PersistentObjectPermissions {
|
|
43
|
+
edit: boolean;
|
|
44
|
+
delete: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface PersistentObject {
|
|
47
|
+
id: string;
|
|
48
|
+
name: string;
|
|
49
|
+
objectTypeId: string;
|
|
50
|
+
breadcrumb?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Optimistic-concurrency token -- RavenDB's change vector for the document behind this object.
|
|
53
|
+
* The server stamps it on every `/po/load` and expects it back on update.
|
|
54
|
+
*
|
|
55
|
+
* ⚠️ The check is opt-in BY PRESENCE of this field. Dropping it does not fail loudly; it makes
|
|
56
|
+
* the save unconditional, so two people editing the same record both succeed and the second
|
|
57
|
+
* silently overwrites the first. That is what used to happen here: `SparkClient` round-tripped
|
|
58
|
+
* the token and got a 409, the browser did not and got last-write-wins, on the same endpoint.
|
|
59
|
+
*/
|
|
60
|
+
etag?: string;
|
|
61
|
+
attributes: PersistentObjectAttribute[];
|
|
62
|
+
/** Per-row edit/delete affordances; undefined = fall back to type-level permissions. */
|
|
63
|
+
can?: PersistentObjectPermissions;
|
|
64
|
+
/**
|
|
65
|
+
* Custom actions withheld for THIS object, by name. Absent or empty means every action the
|
|
66
|
+
* caller has the right to is offered.
|
|
67
|
+
*
|
|
68
|
+
* The action catalogue at `/spark/actions/{objectTypeId}` is per TYPE -- it is never told which
|
|
69
|
+
* row is open -- so an action that applies to only some rows cannot be filtered there. The
|
|
70
|
+
* entity's `OnDisableActionsAsync` hook decides on the stored entity, and the answer arrives here
|
|
71
|
+
* -- built-in actions (`Edit`, `Save`, `Delete`) included (#460, D13). The server asks the same
|
|
72
|
+
* hook again at submit and refuses a disabled action with 403.
|
|
73
|
+
*/
|
|
74
|
+
disabledActions?: string[];
|
|
75
|
+
/**
|
|
76
|
+
* Read-side facts an add-on attached to this object on load, keyed by the add-on (e.g.
|
|
77
|
+
* `{ contribution: { own: true } }` on a contribution row). Server-written; never sent back.
|
|
78
|
+
*/
|
|
79
|
+
metadata?: Record<string, any>;
|
|
80
|
+
}
|
|
81
|
+
export interface PersistentObjectAttribute {
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
label?: TranslatedString;
|
|
85
|
+
value?: any;
|
|
86
|
+
dataType: string;
|
|
87
|
+
isArray?: boolean;
|
|
88
|
+
isRequired: boolean;
|
|
89
|
+
isVisible: boolean;
|
|
90
|
+
isReadOnly: boolean;
|
|
91
|
+
order: number;
|
|
92
|
+
query?: string;
|
|
93
|
+
breadcrumb?: string;
|
|
94
|
+
/**
|
|
95
|
+
* For `dataType === 'Reference'` with `isArray === true`: resolved display label per
|
|
96
|
+
* referenced id (id → breadcrumb), so the UI can render a chip per selected reference.
|
|
97
|
+
* The single-reference counterpart is `breadcrumb`.
|
|
98
|
+
*/
|
|
99
|
+
breadcrumbs?: Record<string, string | null>;
|
|
100
|
+
/**
|
|
101
|
+
* Controls on which pages the attribute should be displayed.
|
|
102
|
+
* Query = shown in list views, PersistentObject = shown in detail/edit views.
|
|
103
|
+
* Can be a numeric flag value or a string like "Query, PersistentObject".
|
|
104
|
+
*/
|
|
105
|
+
showedOn?: ShowedOn | string;
|
|
106
|
+
isValueChanged?: boolean;
|
|
107
|
+
rules: ValidationRule[];
|
|
108
|
+
group?: string;
|
|
109
|
+
/** Renderer component name for custom display in detail/list views */
|
|
110
|
+
renderer?: string;
|
|
111
|
+
/** Options passed to the renderer component */
|
|
112
|
+
rendererOptions?: Record<string, any>;
|
|
113
|
+
/**
|
|
114
|
+
* When `dataType === 'AsDetail'` and `isArray === false`: the single nested
|
|
115
|
+
* PersistentObject carrying the detail entity's values. `null` when the field is unset.
|
|
116
|
+
* Mirrors the server's PersistentObjectAttributeAsDetail.Object.
|
|
117
|
+
*/
|
|
118
|
+
object?: PersistentObject | null;
|
|
119
|
+
/**
|
|
120
|
+
* When `dataType === 'AsDetail'` and `isArray === true`: the nested PO collection, one
|
|
121
|
+
* per array element. Mirrors PersistentObjectAttributeAsDetail.Objects.
|
|
122
|
+
*/
|
|
123
|
+
objects?: PersistentObject[] | null;
|
|
124
|
+
/**
|
|
125
|
+
* CLR type name of the detail entity for AsDetail attributes (e.g. `HR.Entities.Address`).
|
|
126
|
+
* Emitted by the server so the frontend can look up the matching EntityType metadata
|
|
127
|
+
* without re-resolving through `asDetailType` on the schema definition.
|
|
128
|
+
*/
|
|
129
|
+
asDetailType?: string;
|
|
130
|
+
}
|
|
131
|
+
export interface CustomActionDefinition {
|
|
132
|
+
name: string;
|
|
133
|
+
displayName: TranslatedString;
|
|
134
|
+
icon?: string;
|
|
135
|
+
description?: string;
|
|
136
|
+
showedOn: string;
|
|
137
|
+
selectionRule?: string;
|
|
138
|
+
refreshOnCompleted: boolean;
|
|
139
|
+
confirmationMessageKey?: string;
|
|
140
|
+
/**
|
|
141
|
+
* How prominently, and how warily, to present the action: 'primary', 'secondary', 'danger',
|
|
142
|
+
* 'warning'. Undefined renders the neutral default.
|
|
143
|
+
*
|
|
144
|
+
* Presentation only — the server decides who may see and run an action. A 'danger' variant just
|
|
145
|
+
* asks the button to look like what it does; pair it with `confirmationMessageKey` for anything
|
|
146
|
+
* irreversible, because the colour warns and the prompt is what actually prevents the accident.
|
|
147
|
+
*/
|
|
148
|
+
variant?: string;
|
|
149
|
+
offset: number;
|
|
150
|
+
/**
|
|
151
|
+
* True for the framework's built-in `New` and `Delete` (#460, D18): catalogue entries with a
|
|
152
|
+
* `showedOn` and a `selectionRule` like any custom action (defaults: New has no rule, Delete is
|
|
153
|
+
* `>0`; an app overrides them in `customActions.json`), but run through `/po/new` and
|
|
154
|
+
* `/po/delete-many`, never `/actions/execute`. Absent for a custom action.
|
|
155
|
+
*/
|
|
156
|
+
isDefault?: boolean;
|
|
157
|
+
}
|
|
158
|
+
/** How many rows a grid lets the user select — what `<bs-datatable>` renders. */
|
|
159
|
+
export type SparkSelectionMode = 'none' | 'single' | 'multiple';
|
|
160
|
+
/**
|
|
161
|
+
* What a query definition (or a sub-query entry) declares (#460, D17): a fixed mode, or `'auto'` —
|
|
162
|
+
* the default, and what an absent field means — to derive it from the actions offered.
|
|
163
|
+
*/
|
|
164
|
+
export type SparkSelectionModeSetting = 'auto' | SparkSelectionMode;
|
|
165
|
+
/**
|
|
166
|
+
* The selection mode a grid renders.
|
|
167
|
+
*
|
|
168
|
+
* A declared `'none'`, `'single'` or `'multiple'` wins outright. `'auto'` (or nothing) derives it,
|
|
169
|
+
* so a grid gains a checkbox column exactly when an action needs one and is otherwise
|
|
170
|
+
* pixel-identical to a grid with no selection at all — as Vidyano's query grid does. The offered
|
|
171
|
+
* actions include the default Delete (`>0`) when the caller may delete, so such a grid is
|
|
172
|
+
* multi-select.
|
|
173
|
+
*
|
|
174
|
+
* Derived: `'single'` when every gated action is satisfied by one row and refused by two; anything
|
|
175
|
+
* else that cares about the count gets `'multiple'`.
|
|
176
|
+
*/
|
|
177
|
+
export declare function selectionModeFor(actions: CustomActionDefinition[], declared?: SparkSelectionModeSetting | null): SparkSelectionMode;
|
|
178
|
+
/**
|
|
179
|
+
* One sub-query of a type, with the overrides the parent's type states for it (#460, D17).
|
|
180
|
+
*/
|
|
181
|
+
export interface SparkSubQuery {
|
|
182
|
+
/** The query's alias or id. */
|
|
183
|
+
query: string;
|
|
184
|
+
/** Overrides the query's own `selectionMode` on this parent's detail page. */
|
|
185
|
+
selectionMode?: SparkSelectionModeSetting;
|
|
186
|
+
/** The row attribute pointing at the parent, when the row type has several (server-side). */
|
|
187
|
+
parentReference?: string;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* An entry of `EntityType.queries` as it arrives on the wire: a bare alias — the shape every model
|
|
191
|
+
* had before #460 M15, and still what the server sends for an entry without overrides — or the
|
|
192
|
+
* object form.
|
|
193
|
+
*/
|
|
194
|
+
export type SparkSubQueryEntry = string | SparkSubQuery;
|
|
195
|
+
/** One entry in its object form, whichever shape it arrived in. */
|
|
196
|
+
export declare function normalizeSubQuery(entry: SparkSubQueryEntry): SparkSubQuery;
|
|
197
|
+
/** A type's sub-queries in object form; empty when it declares none. */
|
|
198
|
+
export declare function subQueriesOf(type: {
|
|
199
|
+
queries?: SparkSubQueryEntry[];
|
|
200
|
+
} | null | undefined): SparkSubQuery[];
|
|
135
201
|
/**
|
|
136
202
|
* Controls how a Reference attribute is picked in the PO-edit form.
|
|
137
203
|
* Serialized as a string by the server (mirrors the .NET EReferenceDisplayType).
|
|
138
204
|
*/
|
|
139
|
-
declare enum EReferenceDisplayType {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
205
|
+
export declare enum EReferenceDisplayType {
|
|
206
|
+
/** Renders as a `<bs-select>` listing every referenced item. */
|
|
207
|
+
Dropdown = "Dropdown",
|
|
208
|
+
/** Renders a readonly textbox + "…" button that opens a searchable modal grid picker. */
|
|
209
|
+
Modal = "Modal"
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* When changing an attribute asks the server to reshape the object (mirrors the .NET
|
|
213
|
+
* `ERefreshTrigger`, serialized PascalCase like {@link EReferenceDisplayType}).
|
|
214
|
+
*
|
|
215
|
+
* - `None` — no refresh; the same as absent.
|
|
216
|
+
* - `Auto` — free text refreshes on blur; discrete editors (lookup, reference, boolean, date,
|
|
217
|
+
* datetime, enum, color) refresh immediately.
|
|
218
|
+
* - `ValueChanged` — refreshes on every change; free text is debounced (300 ms) and flushed by
|
|
219
|
+
* blur or save.
|
|
220
|
+
* - `Blur` — refreshes on blur. A discrete editor never blurs meaningfully, so there it acts as
|
|
221
|
+
* `ValueChanged` (and `--spark-verify-model` warns).
|
|
222
|
+
*/
|
|
223
|
+
export type RefreshTrigger = 'None' | 'Auto' | 'ValueChanged' | 'Blur';
|
|
224
|
+
export interface EntityAttributeDefinition {
|
|
225
|
+
id: string;
|
|
226
|
+
name: string;
|
|
227
|
+
label?: TranslatedString;
|
|
228
|
+
/** Help text rendered as an [i] tooltip beside the label. Absent when the model declares none. */
|
|
229
|
+
description?: TranslatedString;
|
|
230
|
+
dataType: string;
|
|
231
|
+
isRequired: boolean;
|
|
232
|
+
isVisible: boolean;
|
|
233
|
+
isReadOnly: boolean;
|
|
234
|
+
order: number;
|
|
235
|
+
query?: string;
|
|
236
|
+
/** For reference attributes, specifies the target entity type's CLR type name */
|
|
237
|
+
referenceType?: string;
|
|
238
|
+
/** For AsDetail attributes, specifies the nested entity type's CLR type name */
|
|
239
|
+
asDetailType?: string;
|
|
240
|
+
/** When true, the attribute represents an array/collection of AsDetail objects */
|
|
241
|
+
isArray?: boolean;
|
|
242
|
+
/** For array AsDetail attributes: "modal" (default) or "inline" */
|
|
243
|
+
editMode?: 'inline' | 'modal';
|
|
244
|
+
/**
|
|
245
|
+
* For Reference attributes: 'Modal' renders the "…" + modal query-grid picker;
|
|
246
|
+
* 'Dropdown'/absent (default) renders a `<bs-select>`. Hand-set in the model JSON.
|
|
247
|
+
*/
|
|
248
|
+
referenceDisplayType?: EReferenceDisplayType;
|
|
249
|
+
/** For array AsDetail attributes: when true, rows can be drag-reordered (order = array position) */
|
|
250
|
+
isSortable?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* When set (and not `'None'`), changing this attribute's value posts the in-progress object to
|
|
253
|
+
* `/spark/po/{objectTypeId}/refresh` and applies the reshaped result as an overlay; the value
|
|
254
|
+
* decides when (see {@link RefreshTrigger}). Absent means no refresh.
|
|
255
|
+
* Schema-only by design — it never travels on a PersistentObjectAttribute, so a client
|
|
256
|
+
* cannot claim a trigger the model did not declare.
|
|
257
|
+
*/
|
|
258
|
+
triggersRefresh?: RefreshTrigger;
|
|
259
|
+
/** For LookupReference attributes, specifies the lookup reference type name */
|
|
260
|
+
lookupReferenceType?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Controls on which pages the attribute should be displayed.
|
|
263
|
+
* Query = shown in list views, PersistentObject = shown in detail/edit views.
|
|
264
|
+
* Can be a numeric flag value or a string like "Query, PersistentObject".
|
|
265
|
+
*/
|
|
266
|
+
showedOn?: ShowedOn | string;
|
|
267
|
+
rules: ValidationRule[];
|
|
268
|
+
/** References an AttributeGroup.id to assign this attribute to a group */
|
|
269
|
+
group?: string;
|
|
270
|
+
/** Number of grid columns this attribute spans within a tab's column layout */
|
|
271
|
+
columnSpan?: number;
|
|
272
|
+
/** Renderer component name for custom display in detail/list views */
|
|
273
|
+
renderer?: string;
|
|
274
|
+
/** Options passed to the renderer component */
|
|
275
|
+
rendererOptions?: Record<string, any>;
|
|
276
|
+
}
|
|
277
|
+
export interface AttributeTab {
|
|
278
|
+
id: string;
|
|
279
|
+
name: string;
|
|
280
|
+
label?: TranslatedString;
|
|
281
|
+
order: number;
|
|
282
|
+
/** Number of columns for the grid layout within this tab */
|
|
283
|
+
columnCount?: number;
|
|
284
|
+
}
|
|
285
|
+
export interface AttributeGroup {
|
|
286
|
+
id: string;
|
|
287
|
+
name: string;
|
|
288
|
+
label?: TranslatedString;
|
|
289
|
+
/** References an AttributeTab.id to assign this group to a tab */
|
|
290
|
+
tab?: string;
|
|
291
|
+
order: number;
|
|
292
|
+
}
|
|
293
|
+
export interface EntityType {
|
|
294
|
+
id: string;
|
|
295
|
+
name: string;
|
|
296
|
+
description?: TranslatedString;
|
|
297
|
+
/**
|
|
298
|
+
* The backing CLR type, or absent for a JSON-only virtual type (#325).
|
|
299
|
+
*
|
|
300
|
+
* Optional on purpose: the server sends null for a virtual type, and this was declared
|
|
301
|
+
* non-nullable, so any unguarded `.endsWith(...)` on it threw a TypeError naming an innocent
|
|
302
|
+
* query. Types are data from the wire, not a promise about it.
|
|
303
|
+
*/
|
|
304
|
+
clrType?: string;
|
|
305
|
+
/**
|
|
306
|
+
* Whether this caller may OPEN one of these, as opposed to list them.
|
|
307
|
+
*
|
|
308
|
+
* The catalogue is gated on Query, so its presence here means "you may list this type" and says
|
|
309
|
+
* nothing about opening one. A reference must not render as a link when this is false: it used
|
|
310
|
+
* to, and the click refused on arrival.
|
|
311
|
+
*/
|
|
312
|
+
canRead?: boolean;
|
|
313
|
+
alias?: string;
|
|
314
|
+
/**
|
|
315
|
+
* Breadcrumb template: literal text plus `{AttributeName}` placeholders. A scalar placeholder
|
|
316
|
+
* renders its value; a reference placeholder renders the referenced entity's breadcrumb.
|
|
317
|
+
* The server resolves this — clients only read the resulting strings. Example: "{Street}, {City}".
|
|
318
|
+
*/
|
|
319
|
+
breadcrumb?: string;
|
|
320
|
+
/**
|
|
321
|
+
* When false, the breadcrumb needs the collection document (a placeholder field is not on the
|
|
322
|
+
* projection). null/absent means renderable from the projection. Informational on the client.
|
|
323
|
+
*/
|
|
324
|
+
breadcrumbProjectionSatisfiable?: boolean;
|
|
325
|
+
tabs?: AttributeTab[];
|
|
326
|
+
groups?: AttributeGroup[];
|
|
327
|
+
attributes: EntityAttributeDefinition[];
|
|
328
|
+
/**
|
|
329
|
+
* The sub-queries displayed as related query tables on the detail page: a bare alias or id, or
|
|
330
|
+
* `{ query, selectionMode?, parentReference? }` (#460, D17). Read them with `subQueriesOf(type)`.
|
|
331
|
+
*/
|
|
332
|
+
queries?: SparkSubQueryEntry[];
|
|
333
|
+
/**
|
|
334
|
+
* The definitions of this type's AsDetail row types, sent alongside it so a detail table can draw
|
|
335
|
+
* its columns.
|
|
336
|
+
*
|
|
337
|
+
* Needed because a row type usually has no rights of its own — a row is edited through its parent
|
|
338
|
+
* — and the entity-type catalogue is gated on `Query`. Resolving a row type from the catalogue
|
|
339
|
+
* therefore failed silently, and the table rendered with **no columns at all**.
|
|
340
|
+
*
|
|
341
|
+
* Per-caller and gated on the *parent's* right, which is the same gate that already ships each
|
|
342
|
+
* row's attribute schema inside `attr.objects`. Pruned server-side: no `queryType`, `indexName`,
|
|
343
|
+
* `queries` or `alias`.
|
|
344
|
+
*/
|
|
345
|
+
detailTypes?: EntityType[];
|
|
346
|
+
/**
|
|
347
|
+
* Whether adding or removing a row of this type asks the server first.
|
|
348
|
+
*
|
|
349
|
+
* Absent or false — the default — keeps the purely client-side behaviour: New pushes a blank row,
|
|
350
|
+
* Delete splices it out, and the parent's save is the first the server hears of either. On, the
|
|
351
|
+
* grid calls `newObject` before showing a row and `deleteRow` before removing one, so
|
|
352
|
+
* `OnNewAsync` can default it and the delete hook can refuse.
|
|
353
|
+
*
|
|
354
|
+
* ⚠️ Read it off the **row type**, never the parent: the type that owns the hooks owns the
|
|
355
|
+
* decision. For a row type resolved out of `detailTypes` the flag survives the server-side
|
|
356
|
+
* pruning, so both sources agree.
|
|
357
|
+
*
|
|
358
|
+
* ⚠️ It governs the round trip and nothing else. It is not a permission, and it is outside the
|
|
359
|
+
* model hash, so nothing that gates a write may be conditional on it — the save path enforces the
|
|
360
|
+
* row type's New/Edit/Delete rights on every embedded collection whether this is on or off.
|
|
361
|
+
*/
|
|
362
|
+
serverSideRowLifecycle?: boolean;
|
|
363
|
+
}
|
|
364
|
+
export type SparkQueryRenderMode = 'Pagination' | 'VirtualScrolling';
|
|
365
|
+
export interface SparkQuerySortColumn {
|
|
366
|
+
property: string;
|
|
367
|
+
direction: string;
|
|
368
|
+
}
|
|
369
|
+
export interface SparkQuery {
|
|
370
|
+
id: string;
|
|
371
|
+
name: string;
|
|
372
|
+
description?: TranslatedString;
|
|
373
|
+
source: string;
|
|
374
|
+
alias?: string;
|
|
375
|
+
sortColumns: SparkQuerySortColumn[];
|
|
376
|
+
renderMode?: SparkQueryRenderMode;
|
|
377
|
+
/** The RavenDB index this query runs against, resolved by name server-side. */
|
|
378
|
+
indexName?: string;
|
|
379
|
+
/** Optional entity type name (e.g., "Person"). When set, used for entity type resolution. */
|
|
380
|
+
entityType?: string;
|
|
381
|
+
/** When true, this query uses WebSocket streaming with snapshot + patch updates. */
|
|
382
|
+
isStreamingQuery?: boolean;
|
|
383
|
+
/**
|
|
384
|
+
* Whether the grid offers row selection (#460, D17). Absent is `'auto'`: derived from the offered
|
|
385
|
+
* actions. A sub-query entry on the parent's type may override it.
|
|
386
|
+
*/
|
|
387
|
+
selectionMode?: SparkSelectionModeSetting;
|
|
388
|
+
/**
|
|
389
|
+
* The row type's attribute that points at the parent when the query is a sub-query — only needed
|
|
390
|
+
* when the row type references the parent's type more than once (#460, D19). Server-side use.
|
|
391
|
+
*/
|
|
392
|
+
parentReference?: string;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Which rows a query asks for with respect to soft deletion (#460). Core carries it to every row
|
|
396
|
+
* policy; the SoftDelete package's policy honours it only for holders of `ViewDeleted` on the type.
|
|
397
|
+
* Omitted means `'exclude'`.
|
|
398
|
+
*/
|
|
399
|
+
export type SparkDeletedFilter = 'exclude' | 'include' | 'only';
|
|
303
400
|
/**
|
|
304
401
|
* What a query returns: the column metadata once, then one lightweight row per result.
|
|
305
402
|
*
|
|
@@ -309,25 +406,23 @@ interface SparkQuery {
|
|
|
309
406
|
* **persistent object is a document**. Nothing here is entitled to act on a row — every
|
|
310
407
|
* mutating path re-loads by id and re-applies security server-side.
|
|
311
408
|
*/
|
|
312
|
-
interface QueryResult {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
*/
|
|
330
|
-
disabledActions?: string[];
|
|
409
|
+
export interface QueryResult {
|
|
410
|
+
columns: QueryColumn[];
|
|
411
|
+
items: QueryResultItem[];
|
|
412
|
+
/** Rows matching the query after filtering, before paging. */
|
|
413
|
+
totalItems: number;
|
|
414
|
+
skip: number;
|
|
415
|
+
take: number;
|
|
416
|
+
typeHints?: Record<string, string>;
|
|
417
|
+
/**
|
|
418
|
+
* Actions withheld for THIS query, by name (custom, and `New`). Absent or empty means every
|
|
419
|
+
* action the caller has the right to is offered.
|
|
420
|
+
*
|
|
421
|
+
* The mirror of `PersistentObject.disabledActions`, set server-side by the entity's
|
|
422
|
+
* `OnDisableActionsAsync` hook with a query target (#460, D13). The server asks the same hook when
|
|
423
|
+
* an action is submitted from this query and refuses a disabled one with 403.
|
|
424
|
+
*/
|
|
425
|
+
disabledActions?: string[];
|
|
331
426
|
}
|
|
332
427
|
/**
|
|
333
428
|
* The subset of column metadata a cell needs in order to render.
|
|
@@ -336,50 +431,50 @@ interface QueryResult {
|
|
|
336
431
|
* page's attribute) satisfy this, which is what lets one cell component serve the query grid and
|
|
337
432
|
* the AsDetail sub-table without either side knowing about the other's shape.
|
|
338
433
|
*/
|
|
339
|
-
interface SparkCellColumn {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
434
|
+
export interface SparkCellColumn {
|
|
435
|
+
name: string;
|
|
436
|
+
label?: TranslatedString;
|
|
437
|
+
/** Help text rendered as an [i] tooltip in the column header. Absent when the model declares none. */
|
|
438
|
+
description?: TranslatedString;
|
|
439
|
+
dataType: string;
|
|
440
|
+
isArray?: boolean;
|
|
441
|
+
renderer?: string;
|
|
442
|
+
rendererOptions?: Record<string, any>;
|
|
443
|
+
referenceType?: string;
|
|
444
|
+
lookupReferenceType?: string;
|
|
445
|
+
asDetailType?: string;
|
|
351
446
|
}
|
|
352
447
|
/** One column of a query result, sent once rather than repeated on every row. */
|
|
353
|
-
interface QueryColumn extends SparkCellColumn {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
448
|
+
export interface QueryColumn extends SparkCellColumn {
|
|
449
|
+
order: number;
|
|
450
|
+
/**
|
|
451
|
+
* Whether the grid offers a sort affordance for this column. Resolved server-side from the query's
|
|
452
|
+
* override then the attribute, so it arrives already decided.
|
|
453
|
+
*
|
|
454
|
+
* This replaced an `isSortable` that carried the server's AsDetail *drag-reorder* flag — a
|
|
455
|
+
* different concept that was `false` for every scalar column while the grid hard-coded every
|
|
456
|
+
* header sortable anyway. Neither side read it. The attribute-level `isSortable` on `EntityType`
|
|
457
|
+
* is the drag-reorder flag and stays.
|
|
458
|
+
*
|
|
459
|
+
* Absent means sortable, matching `isVisible`: a server predating the field still draws arrows.
|
|
460
|
+
*/
|
|
461
|
+
canSort?: boolean;
|
|
462
|
+
/** Whether the grid draws a filter cell for this column. Absent means filterable. */
|
|
463
|
+
canFilter?: boolean;
|
|
464
|
+
/**
|
|
465
|
+
* Whether this column's distinct values may be listed. When `false` and `canFilter` is true the
|
|
466
|
+
* panel offers a free-text filter instead of a value list — listing a column's values is a much
|
|
467
|
+
* stronger disclosure than filtering by one already known.
|
|
468
|
+
*/
|
|
469
|
+
canListDistincts?: boolean;
|
|
470
|
+
/**
|
|
471
|
+
* Whether the grid draws this column. `false` means the row carries the value but no column is
|
|
472
|
+
* rendered — for a renderer that needs a sibling value (a lock glyph beside a name) without
|
|
473
|
+
* spending a column on it. `showedOn` decides what ships; this decides what is drawn.
|
|
474
|
+
*/
|
|
475
|
+
isVisible?: boolean;
|
|
476
|
+
/** The query backing a Reference column, by name — the client's option source. */
|
|
477
|
+
query?: string;
|
|
383
478
|
}
|
|
384
479
|
/**
|
|
385
480
|
* One row: an id, a display string, and a value per column.
|
|
@@ -387,28 +482,28 @@ interface QueryColumn extends SparkCellColumn {
|
|
|
387
482
|
* Deliberately too weak to act on — no attribute metadata, no `can` block, no etag, because none
|
|
388
483
|
* of those can be trusted from a projection.
|
|
389
484
|
*/
|
|
390
|
-
interface QueryResultItem {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
485
|
+
export interface QueryResultItem {
|
|
486
|
+
/** Never null and unique within a result; the server refuses anything else. */
|
|
487
|
+
id: string;
|
|
488
|
+
/** What to show when the row is named rather than tabulated (a reference picker's value). */
|
|
489
|
+
breadcrumb?: string;
|
|
490
|
+
values: QueryResultItemValue[];
|
|
491
|
+
/** Presentation hints for the whole row. Keys arrive lower-cased. */
|
|
492
|
+
typeHints?: Record<string, string>;
|
|
398
493
|
}
|
|
399
494
|
/** One cell. */
|
|
400
|
-
interface QueryResultItemValue {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
495
|
+
export interface QueryResultItemValue {
|
|
496
|
+
/** The {@link QueryColumn.name} this value belongs to. */
|
|
497
|
+
key: string;
|
|
498
|
+
/** Typed JSON, not a string — the server converts on the way out. */
|
|
499
|
+
value?: any;
|
|
500
|
+
/** For a reference cell: the target document's id, so a link needs no second lookup. */
|
|
501
|
+
objectId?: string;
|
|
502
|
+
/** For a reference cell: the target's display string. */
|
|
503
|
+
breadcrumb?: string;
|
|
504
|
+
/** Resolved display labels per referenced id, for a multi-reference cell. */
|
|
505
|
+
breadcrumbs?: Record<string, string | null>;
|
|
506
|
+
typeHints?: Record<string, string>;
|
|
412
507
|
}
|
|
413
508
|
/**
|
|
414
509
|
* Every shape a renderer's `item` can arrive in.
|
|
@@ -419,7 +514,7 @@ interface QueryResultItemValue {
|
|
|
419
514
|
* grid and an AsDetail table therefore sees two of them, which is why {@link valueFor} reads all
|
|
420
515
|
* three rather than making every app write the branch.
|
|
421
516
|
*/
|
|
422
|
-
type SparkRow = QueryResultItem | PersistentObject | Record<string, unknown>;
|
|
517
|
+
export type SparkRow = QueryResultItem | PersistentObject | Record<string, unknown>;
|
|
423
518
|
/**
|
|
424
519
|
* The value a row carries for a column, whatever shape the row is in — or `undefined` when it
|
|
425
520
|
* carries none.
|
|
@@ -437,7 +532,7 @@ type SparkRow = QueryResultItem | PersistentObject | Record<string, unknown>;
|
|
|
437
532
|
* attribute marked `"showedOn": "PersistentObject"` is absent from a row by design, and this returns
|
|
438
533
|
* `undefined` for it; that is the first thing to check when a sibling read comes back empty.
|
|
439
534
|
*/
|
|
440
|
-
declare function valueFor(item: SparkRow | null | undefined, columnName: string): QueryResultItemValue | undefined;
|
|
535
|
+
export declare function valueFor(item: SparkRow | null | undefined, columnName: string): QueryResultItemValue | undefined;
|
|
441
536
|
/**
|
|
442
537
|
* Whether this row is a query result item.
|
|
443
538
|
*
|
|
@@ -445,9 +540,9 @@ declare function valueFor(item: SparkRow | null | undefined, columnName: string)
|
|
|
445
540
|
* legitimately have a column named `values` holding an array, and mistaking one for the other would
|
|
446
541
|
* silently read the wrong thing.
|
|
447
542
|
*/
|
|
448
|
-
declare function isQueryRow(row: SparkRow | null | undefined): row is QueryResultItem;
|
|
543
|
+
export declare function isQueryRow(row: SparkRow | null | undefined): row is QueryResultItem;
|
|
449
544
|
/** Whether this row is a full persistent object. Discriminated on elements, as above. */
|
|
450
|
-
declare function isPersistentObject(row: SparkRow | null | undefined): row is PersistentObject;
|
|
545
|
+
export declare function isPersistentObject(row: SparkRow | null | undefined): row is PersistentObject;
|
|
451
546
|
/**
|
|
452
547
|
* One column's value filter (#431): the values a caller picked, or the values they excluded.
|
|
453
548
|
*
|
|
@@ -460,10 +555,10 @@ declare function isPersistentObject(row: SparkRow | null | undefined): row is Pe
|
|
|
460
555
|
* moves values between them. `null` is a real, selectable value meaning "no value"; an empty or
|
|
461
556
|
* absent array is the absent filter.
|
|
462
557
|
*/
|
|
463
|
-
interface QueryColumnFilter {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
558
|
+
export interface QueryColumnFilter {
|
|
559
|
+
name: string;
|
|
560
|
+
includes?: unknown[];
|
|
561
|
+
excludes?: unknown[];
|
|
467
562
|
}
|
|
468
563
|
/**
|
|
469
564
|
* One selectable entry in a column's filter panel.
|
|
@@ -471,11 +566,11 @@ interface QueryColumnFilter {
|
|
|
471
566
|
* Structurally identical to the datatable's own `DistinctValue`, deliberately — it is what lets the
|
|
472
567
|
* HTTP response be handed straight to `[distincts]` with no mapper in between.
|
|
473
568
|
*/
|
|
474
|
-
interface DistinctValue {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
569
|
+
export interface DistinctValue {
|
|
570
|
+
/** The raw stored value. `null` is a real entry meaning "no value", not an absent one. */
|
|
571
|
+
value: unknown;
|
|
572
|
+
/** What the user reads. Never matched on. */
|
|
573
|
+
label: string;
|
|
479
574
|
}
|
|
480
575
|
/**
|
|
481
576
|
* A column's distinct values.
|
|
@@ -486,144 +581,130 @@ interface DistinctValue {
|
|
|
486
581
|
* `hasMore` reports that the cap truncated the list, and the panel re-queries only when it is set or
|
|
487
582
|
* the search term widens — so a dishonest `false` strands a user typing past the cap.
|
|
488
583
|
*/
|
|
489
|
-
interface DistinctValuesResult {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
confirmationMessageKey?: string;
|
|
589
|
-
/**
|
|
590
|
-
* How prominently, and how warily, to present the action: 'primary', 'secondary', 'danger',
|
|
591
|
-
* 'warning'. Undefined renders the neutral default.
|
|
592
|
-
*
|
|
593
|
-
* Presentation only — the server decides who may see and run an action. A 'danger' variant just
|
|
594
|
-
* asks the button to look like what it does; pair it with `confirmationMessageKey` for anything
|
|
595
|
-
* irreversible, because the colour warns and the prompt is what actually prevents the accident.
|
|
596
|
-
*/
|
|
597
|
-
variant?: string;
|
|
598
|
-
offset: number;
|
|
599
|
-
}
|
|
600
|
-
|
|
584
|
+
export interface DistinctValuesResult {
|
|
585
|
+
matching: DistinctValue[];
|
|
586
|
+
remaining: DistinctValue[];
|
|
587
|
+
hasMore: boolean;
|
|
588
|
+
}
|
|
589
|
+
export interface ProgramUnit {
|
|
590
|
+
id: string;
|
|
591
|
+
name: TranslatedString;
|
|
592
|
+
icon?: string;
|
|
593
|
+
/**
|
|
594
|
+
* Canonical unit type, exact-cased by the server's loader: 'query' | 'persistentObject' | 'url'.
|
|
595
|
+
* Kept as string rather than a union so an older client tolerates a newer server.
|
|
596
|
+
*/
|
|
597
|
+
type: string;
|
|
598
|
+
queryId?: string;
|
|
599
|
+
persistentObjectId?: string;
|
|
600
|
+
/**
|
|
601
|
+
* For a persistentObject unit: the specific object to open — the menu entry deep-links to
|
|
602
|
+
* `/po/{type}/{objectId}`. Absent means the type's default list. For a composed page this is
|
|
603
|
+
* whatever stable string the app declared; the server's Actions class may ignore it.
|
|
604
|
+
*/
|
|
605
|
+
objectId?: string;
|
|
606
|
+
/** For a url unit: the external address, rendered as a plain anchor (never a router link). */
|
|
607
|
+
url?: string;
|
|
608
|
+
order: number;
|
|
609
|
+
alias?: string;
|
|
610
|
+
}
|
|
611
|
+
export interface ProgramUnitGroup {
|
|
612
|
+
id: string;
|
|
613
|
+
name: TranslatedString;
|
|
614
|
+
icon?: string;
|
|
615
|
+
order: number;
|
|
616
|
+
programUnits: ProgramUnit[];
|
|
617
|
+
}
|
|
618
|
+
export interface ProgramUnitsConfiguration {
|
|
619
|
+
programUnitGroups: ProgramUnitGroup[];
|
|
620
|
+
}
|
|
621
|
+
export declare enum ELookupDisplayType {
|
|
622
|
+
Dropdown = 0,
|
|
623
|
+
Modal = 1
|
|
624
|
+
}
|
|
625
|
+
export interface LookupReferenceListItem {
|
|
626
|
+
name: string;
|
|
627
|
+
isTransient: boolean;
|
|
628
|
+
valueCount: number;
|
|
629
|
+
displayType: ELookupDisplayType;
|
|
630
|
+
}
|
|
631
|
+
export interface LookupReference {
|
|
632
|
+
name: string;
|
|
633
|
+
isTransient: boolean;
|
|
634
|
+
displayType: ELookupDisplayType;
|
|
635
|
+
values: LookupReferenceValue[];
|
|
636
|
+
}
|
|
637
|
+
export interface LookupReferenceValue {
|
|
638
|
+
key: string;
|
|
639
|
+
values: TranslatedString;
|
|
640
|
+
isActive: boolean;
|
|
641
|
+
extra?: Record<string, unknown>;
|
|
642
|
+
}
|
|
643
|
+
export interface RetryActionPayload {
|
|
644
|
+
type: 'retry-action';
|
|
645
|
+
step: number;
|
|
646
|
+
title: string;
|
|
647
|
+
message?: string;
|
|
648
|
+
options: string[];
|
|
649
|
+
defaultOption?: string;
|
|
650
|
+
persistentObject?: PersistentObject;
|
|
651
|
+
}
|
|
652
|
+
export interface RetryActionResult {
|
|
653
|
+
step: number;
|
|
654
|
+
option: string;
|
|
655
|
+
persistentObject?: PersistentObject;
|
|
656
|
+
}
|
|
657
|
+
export interface EntityPermissions {
|
|
658
|
+
/**
|
|
659
|
+
* Whether the caller may list this type. Independently grantable from `canRead` — `Query/Person`
|
|
660
|
+
* alone lists rows while refusing a by-id load — and reported since preview.60. The combined
|
|
661
|
+
* `QueryRead` right bundles the two invisibly, which is why this was the one action introspection
|
|
662
|
+
* never mentioned.
|
|
663
|
+
*/
|
|
664
|
+
canQuery: boolean;
|
|
665
|
+
canRead: boolean;
|
|
666
|
+
canCreate: boolean;
|
|
667
|
+
canEdit: boolean;
|
|
668
|
+
canDelete: boolean;
|
|
669
|
+
/**
|
|
670
|
+
* SoftDelete (#460): `Restore/T`, `Purge/T` and `ViewDeleted/T` (the recycle bin — query and load
|
|
671
|
+
* with `deleted: 'include' | 'only'`). Type-level only; a row may still refuse. Optional because a
|
|
672
|
+
* server older than 11.0.0-preview.91 does not send them — treat absent as `false`.
|
|
673
|
+
*/
|
|
674
|
+
canRestore?: boolean;
|
|
675
|
+
canPurge?: boolean;
|
|
676
|
+
canViewDeleted?: boolean;
|
|
677
|
+
/** History (#460): `History/T` (list and read revisions) and `Revert/T` together with `Edit/T`. */
|
|
678
|
+
canViewHistory?: boolean;
|
|
679
|
+
canRevert?: boolean;
|
|
680
|
+
/** Contributions: `RevertContribution/T` (make a contribution current again; a generated contribution type only). */
|
|
681
|
+
canRevertContribution?: boolean;
|
|
682
|
+
}
|
|
601
683
|
/**
|
|
602
684
|
* The opening message of a stream: the column metadata plus the rows so far.
|
|
603
685
|
*
|
|
604
686
|
* Columns arrive once, here. A stream is one result whose rows arrive over time, so its shape is
|
|
605
687
|
* fixed when it opens — patches carry values only.
|
|
606
688
|
*/
|
|
607
|
-
interface StreamingSnapshotMessage {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
689
|
+
export interface StreamingSnapshotMessage {
|
|
690
|
+
type: 'snapshot';
|
|
691
|
+
columns: QueryColumn[];
|
|
692
|
+
data: QueryResultItem[];
|
|
611
693
|
}
|
|
612
|
-
interface StreamingPatchItem {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
694
|
+
export interface StreamingPatchItem {
|
|
695
|
+
id: string;
|
|
696
|
+
/** Changed cell values, keyed by column name. Never metadata — the snapshot fixed that. */
|
|
697
|
+
values: Record<string, any>;
|
|
616
698
|
}
|
|
617
|
-
interface StreamingPatchMessage {
|
|
618
|
-
|
|
619
|
-
|
|
699
|
+
export interface StreamingPatchMessage {
|
|
700
|
+
type: 'patch';
|
|
701
|
+
updated: StreamingPatchItem[];
|
|
620
702
|
}
|
|
621
|
-
interface StreamingErrorMessage {
|
|
622
|
-
|
|
623
|
-
|
|
703
|
+
export interface StreamingErrorMessage {
|
|
704
|
+
type: 'error';
|
|
705
|
+
message: string;
|
|
624
706
|
}
|
|
625
|
-
type StreamingMessage = StreamingSnapshotMessage | StreamingPatchMessage | StreamingErrorMessage;
|
|
626
|
-
|
|
707
|
+
export type StreamingMessage = StreamingSnapshotMessage | StreamingPatchMessage | StreamingErrorMessage;
|
|
627
708
|
/**
|
|
628
709
|
* Conversions between the wire format for a timestamp and what an `<input type="datetime-local">`
|
|
629
710
|
* or `<input type="date">` will accept.
|
|
@@ -641,7 +722,7 @@ type StreamingMessage = StreamingSnapshotMessage | StreamingPatchMessage | Strea
|
|
|
641
722
|
* Parses a wire timestamp. Returns `null` for anything unusable, matching the contract of
|
|
642
723
|
* `parsedDate` / `queryCellValue` -- a bad value renders as empty rather than as `Invalid Date`.
|
|
643
724
|
*/
|
|
644
|
-
declare function parseWireDate(value: unknown): Date | null;
|
|
725
|
+
export declare function parseWireDate(value: unknown): Date | null;
|
|
645
726
|
/**
|
|
646
727
|
* Wire value -> the `yyyy-MM-ddTHH:mm` a `datetime-local` input needs, in the **viewer's** zone.
|
|
647
728
|
*
|
|
@@ -649,9 +730,9 @@ declare function parseWireDate(value: unknown): Date | null;
|
|
|
649
730
|
* *on that value's own date*, so a timestamp in July and one in January convert differently in a
|
|
650
731
|
* zone that observes DST.
|
|
651
732
|
*/
|
|
652
|
-
declare function toDateTimeLocalInput(value: unknown): string;
|
|
733
|
+
export declare function toDateTimeLocalInput(value: unknown): string;
|
|
653
734
|
/** Wire value -> the `yyyy-MM-dd` a `date` input needs, in the viewer's zone. */
|
|
654
|
-
declare function toDateInput(value: unknown): string;
|
|
735
|
+
export declare function toDateInput(value: unknown): string;
|
|
655
736
|
/**
|
|
656
737
|
* `yyyy-MM-ddTHH:mm` from the control -> a complete ISO-8601 string carrying the viewer's offset
|
|
657
738
|
* **for the entered date**.
|
|
@@ -665,9 +746,9 @@ declare function toDateInput(value: unknown): string;
|
|
|
665
746
|
* before a fall-back and after a spring-forward. That is specified ECMAScript behaviour, and the
|
|
666
747
|
* server's conversion helper deliberately reproduces the same choice so the two cannot drift.
|
|
667
748
|
*/
|
|
668
|
-
declare function fromDateTimeLocalInput(local: unknown): string | null;
|
|
749
|
+
export declare function fromDateTimeLocalInput(local: unknown): string | null;
|
|
669
750
|
/** `yyyy-MM-dd` from a `date` control -> an ISO string at local midnight with the viewer's offset. */
|
|
670
|
-
declare function fromDateInput(local: unknown): string | null;
|
|
751
|
+
export declare function fromDateInput(local: unknown): string | null;
|
|
671
752
|
/**
|
|
672
753
|
* Compares two wire timestamps **by instant**, which is what a `DateTimeOffset` means in Spark.
|
|
673
754
|
*
|
|
@@ -680,21 +761,20 @@ declare function fromDateInput(local: unknown): string | null;
|
|
|
680
761
|
* the instant and silently hides a destroyed offset. Here comparing by instant is the correct thing:
|
|
681
762
|
* we are asking "did the user change this value", not "is the offset intact".
|
|
682
763
|
*/
|
|
683
|
-
declare function wireDatesEqual(a: unknown, b: unknown): boolean;
|
|
764
|
+
export declare function wireDatesEqual(a: unknown, b: unknown): boolean;
|
|
684
765
|
/** True for the attribute data types that are edited through a native date/time control. */
|
|
685
|
-
declare function isDateDataType(dataType: string | null | undefined): dataType is 'date' | 'datetime';
|
|
766
|
+
export declare function isDateDataType(dataType: string | null | undefined): dataType is 'date' | 'datetime';
|
|
686
767
|
/** Wire -> control, picking the right shape for the data type. */
|
|
687
|
-
declare function toDateInputValue(dataType: string | null | undefined, value: unknown): string;
|
|
768
|
+
export declare function toDateInputValue(dataType: string | null | undefined, value: unknown): string;
|
|
688
769
|
/** Control -> wire, picking the right shape for the data type. */
|
|
689
|
-
declare function fromDateInputValue(dataType: string | null | undefined, value: unknown): string | null;
|
|
690
|
-
|
|
770
|
+
export declare function fromDateInputValue(dataType: string | null | undefined, value: unknown): string | null;
|
|
691
771
|
/**
|
|
692
772
|
* Resolves an `EntityType` by its CLR type name (e.g. `"HR.Entities.Address"`).
|
|
693
773
|
* Callers typically close over a list they already hold. `getEntityTypes()` is NOT cached --
|
|
694
774
|
* it issues a request per call -- so resolve against a list you fetched once rather than
|
|
695
775
|
* calling it inside the resolver.
|
|
696
776
|
*/
|
|
697
|
-
type EntityTypeResolver = (clrTypeName: string) => EntityType | undefined;
|
|
777
|
+
export type EntityTypeResolver = (clrTypeName: string) => EntityType | undefined;
|
|
698
778
|
/**
|
|
699
779
|
* Flattens a nested `PersistentObject` into the plain `Record<string, any>` shape the
|
|
700
780
|
* form state uses throughout ng-spark. Primitive / reference attributes contribute their
|
|
@@ -704,7 +784,7 @@ type EntityTypeResolver = (clrTypeName: string) => EntityType | undefined;
|
|
|
704
784
|
* This is the ONE place that reads the server's new AsDetail wire shape and collapses it
|
|
705
785
|
* back to the flat dict the form components already handle.
|
|
706
786
|
*/
|
|
707
|
-
declare function nestedPoToDict(po: PersistentObject | null | undefined): Record<string, any>;
|
|
787
|
+
export declare function nestedPoToDict(po: PersistentObject | null | undefined): Record<string, any>;
|
|
708
788
|
/**
|
|
709
789
|
* Reserved key under which a flattened nested object keeps the breadcrumb the SERVER resolved for
|
|
710
790
|
* that object itself (as opposed to {@link AS_DETAIL_BREADCRUMBS_KEY}, which keys the breadcrumbs
|
|
@@ -717,7 +797,7 @@ declare function nestedPoToDict(po: PersistentObject | null | undefined): Record
|
|
|
717
797
|
* used to discard the resolved string, leaving the form to substitute `{Crumb}` against a dict that
|
|
718
798
|
* can never contain it.
|
|
719
799
|
*/
|
|
720
|
-
declare const AS_DETAIL_SELF_BREADCRUMB_KEY = "__sparkBreadcrumb";
|
|
800
|
+
export declare const AS_DETAIL_SELF_BREADCRUMB_KEY = "__sparkBreadcrumb";
|
|
721
801
|
/**
|
|
722
802
|
* Reserved key under which a flattened nested object keeps its own row key — the value of whatever
|
|
723
803
|
* property the server registered as that type's `[ValueKey]`.
|
|
@@ -737,7 +817,7 @@ declare const AS_DETAIL_SELF_BREADCRUMB_KEY = "__sparkBreadcrumb";
|
|
|
737
817
|
* Safe to carry, for the same reason the breadcrumb is: `dictToNestedPo` walks the entity type's
|
|
738
818
|
* attributes and never the dict's keys, so a reserved key is never sent back as an attribute.
|
|
739
819
|
*/
|
|
740
|
-
declare const AS_DETAIL_ROW_KEY = "__sparkRowKey";
|
|
820
|
+
export declare const AS_DETAIL_ROW_KEY = "__sparkRowKey";
|
|
741
821
|
/**
|
|
742
822
|
* The breadcrumb the server resolved for a flattened object, or null when it resolved to nothing.
|
|
743
823
|
*
|
|
@@ -746,7 +826,7 @@ declare const AS_DETAIL_ROW_KEY = "__sparkRowKey";
|
|
|
746
826
|
* (EntityMapper.cs:209-211). That is a placeholder, not data, and rendering it would be worse than
|
|
747
827
|
* rendering nothing — it reads as a real value. `typeName` lets a caller filter it back out.
|
|
748
828
|
*/
|
|
749
|
-
declare function selfBreadcrumb(row: Record<string, any> | null | undefined, typeName?: string): string | null;
|
|
829
|
+
export declare function selfBreadcrumb(row: Record<string, any> | null | undefined, typeName?: string): string | null;
|
|
750
830
|
/**
|
|
751
831
|
* The same filter as {@link selfBreadcrumb}, for a caller holding the server's breadcrumb string
|
|
752
832
|
* directly rather than a flattened row dict — `attr.object.breadcrumb` on a detail page, or a query
|
|
@@ -757,14 +837,14 @@ declare function selfBreadcrumb(row: Record<string, any> | null | undefined, typ
|
|
|
757
837
|
* first; the two that read the string straight off the wire kept printing `BuildFeedback` and
|
|
758
838
|
* `GateSettings` at users (#384). A second copy of the comparison is how that happens again.
|
|
759
839
|
*/
|
|
760
|
-
declare function resolvedBreadcrumb(value: unknown, typeName?: string): string | null;
|
|
840
|
+
export declare function resolvedBreadcrumb(value: unknown, typeName?: string): string | null;
|
|
761
841
|
/**
|
|
762
842
|
* Reserved key under which {@link nestedPoToDisplayRow} stashes the server-resolved breadcrumb of
|
|
763
843
|
* each reference attribute (keyed by attribute name). Lets an AsDetail reference cell render the
|
|
764
844
|
* label the server already resolved by id — page-independent — instead of guessing from a single
|
|
765
845
|
* reference-query options page. Prefixed to avoid colliding with a real attribute name.
|
|
766
846
|
*/
|
|
767
|
-
declare const AS_DETAIL_BREADCRUMBS_KEY = "__sparkBreadcrumbs";
|
|
847
|
+
export declare const AS_DETAIL_BREADCRUMBS_KEY = "__sparkBreadcrumbs";
|
|
768
848
|
/**
|
|
769
849
|
* Reserved key under which a flattened row keeps the **wire** values of its date cells, keyed by
|
|
770
850
|
* attribute name.
|
|
@@ -780,7 +860,7 @@ declare const AS_DETAIL_BREADCRUMBS_KEY = "__sparkBreadcrumbs";
|
|
|
780
860
|
* instant is unchanged. Safe to carry for the same reason as the other reserved keys: the rebuild
|
|
781
861
|
* walks the entity type's attributes, never the dict's keys.
|
|
782
862
|
*/
|
|
783
|
-
declare const AS_DETAIL_ORIGINAL_DATES_KEY = "__sparkOriginalDates";
|
|
863
|
+
export declare const AS_DETAIL_ORIGINAL_DATES_KEY = "__sparkOriginalDates";
|
|
784
864
|
/**
|
|
785
865
|
* Whether a flattened-row key is one this module reserved rather than a model attribute.
|
|
786
866
|
*
|
|
@@ -790,7 +870,15 @@ declare const AS_DETAIL_ORIGINAL_DATES_KEY = "__sparkOriginalDates";
|
|
|
790
870
|
* dict to build display text: a caller joining `Object.values(dict)` prints the row's guid and its
|
|
791
871
|
* own breadcrumb as though they were fields.
|
|
792
872
|
*/
|
|
793
|
-
declare function isReservedAsDetailKey(key: string): boolean;
|
|
873
|
+
export declare function isReservedAsDetailKey(key: string): boolean;
|
|
874
|
+
/**
|
|
875
|
+
* Reserved key under which a flattened row keeps the {@link PersistentObject.metadata} the server
|
|
876
|
+
* attached to it on load (an add-on's read-side facts — contributions' `{ contribution: { own } }`).
|
|
877
|
+
* Never sent back: `dictToNestedPo` walks the entity type's attributes, never the dict's keys.
|
|
878
|
+
*/
|
|
879
|
+
export declare const AS_DETAIL_METADATA_KEY = "__sparkMetadata";
|
|
880
|
+
/** The metadata the server attached to a flattened row under `key`, or undefined. */
|
|
881
|
+
export declare function rowMetadata<T = any>(row: Record<string, any> | null | undefined, key: string): T | undefined;
|
|
794
882
|
/**
|
|
795
883
|
* Like {@link nestedPoToDict}, but for the read-only detail display path. In addition to each
|
|
796
884
|
* attribute's value it preserves the server-resolved per-reference `breadcrumb` under
|
|
@@ -798,7 +886,7 @@ declare function isReservedAsDetailKey(key: string): boolean;
|
|
|
798
886
|
* regardless of whether the referenced document fits on the reference query's first options page.
|
|
799
887
|
* The form/edit path keeps using {@link nestedPoToDict}, which never carries breadcrumbs.
|
|
800
888
|
*/
|
|
801
|
-
declare function nestedPoToDisplayRow(po: PersistentObject | null | undefined): Record<string, any>;
|
|
889
|
+
export declare function nestedPoToDisplayRow(po: PersistentObject | null | undefined): Record<string, any>;
|
|
802
890
|
/**
|
|
803
891
|
* Builds a nested `PersistentObject` from a flat dict against the schema in
|
|
804
892
|
* <paramref name="entityType"/>. Used when the form is about to save — AsDetail attributes
|
|
@@ -809,22 +897,61 @@ declare function nestedPoToDisplayRow(po: PersistentObject | null | undefined):
|
|
|
809
897
|
* `getEntityTypes()` list, keyed by CLR type name). Nested AsDetail inside AsDetail is
|
|
810
898
|
* handled recursively.
|
|
811
899
|
*/
|
|
812
|
-
declare function dictToNestedPo(dict: Record<string, any> | null | undefined, entityType: EntityType, resolve: EntityTypeResolver): PersistentObject;
|
|
813
|
-
|
|
900
|
+
export declare function dictToNestedPo(dict: Record<string, any> | null | undefined, entityType: EntityType, resolve: EntityTypeResolver): PersistentObject;
|
|
901
|
+
/**
|
|
902
|
+
* The one answer to "do these two reads hold the same content?", shared by History's revision diff
|
|
903
|
+
* and po-edit's three-way conflict merge.
|
|
904
|
+
*
|
|
905
|
+
* Two reads of identical content are NOT byte-identical: their envelopes carry per-read fields
|
|
906
|
+
* (etags, breadcrumbs, row keys, the wire values a flattened row keeps for its date cells) that
|
|
907
|
+
* differ between reads, and comparing them reports every AsDetail attribute as changed. Both
|
|
908
|
+
* functions below reduce a value to its content first. They come in two shapes because the two
|
|
909
|
+
* callers hold two shapes: History compares wire attributes, po-edit compares the flat form dict.
|
|
910
|
+
*/
|
|
911
|
+
/**
|
|
912
|
+
* A comparable form of a wire attribute's content.
|
|
913
|
+
*
|
|
914
|
+
* Nested objects (AsDetail rows, references rendered as objects) are reduced to their attributes'
|
|
915
|
+
* values: their envelopes carry per-read fields (etags, breadcrumbs, row keys) that differ between two
|
|
916
|
+
* reads of identical content and would report every AsDetail attribute as changed.
|
|
917
|
+
*/
|
|
918
|
+
export declare function comparableValue(attribute: PersistentObjectAttribute | undefined): string;
|
|
919
|
+
/**
|
|
920
|
+
* A comparable form of a value in the flat form dict ({@link nestedPoToDict}'s shape).
|
|
921
|
+
*
|
|
922
|
+
* The reserved keys a flattened row carries (its row key, its breadcrumb, the wire values of its
|
|
923
|
+
* dates) are dropped, and object keys are sorted, so two flattenings of the same content compare
|
|
924
|
+
* equal whatever order their attributes arrived in. `undefined` and `null` are the same absence.
|
|
925
|
+
*/
|
|
926
|
+
export declare function comparableFormValue(value: unknown): string;
|
|
927
|
+
/** Whether two form-dict values hold the same content (see {@link comparableFormValue}). */
|
|
928
|
+
export declare function formValuesEqual(a: unknown, b: unknown): boolean;
|
|
929
|
+
/** Whether `showedOn` offers the action on a query: `"query"` or `"both"`, in any casing. */
|
|
930
|
+
export declare function isShowedOnQuery(showedOn: string | undefined | null): boolean;
|
|
931
|
+
/** Whether `showedOn` offers the action on a detail page: `"detail"` or `"both"`, in any casing. */
|
|
932
|
+
export declare function isShowedOnDetail(showedOn: string | undefined | null): boolean;
|
|
814
933
|
/**
|
|
815
934
|
* The custom actions a query should offer, from the entity type's full set.
|
|
816
935
|
*
|
|
817
936
|
* `showedOn` must include the query side. The accepted values are `"detail"`, `"query"`
|
|
818
937
|
* and `"both"` — as the server model and the custom-actions guide have always
|
|
819
|
-
* documented
|
|
820
|
-
*
|
|
938
|
+
* documented — compared case-insensitively (#460 M15: `"Both"` used to render nowhere).
|
|
939
|
+
*
|
|
940
|
+
* The built-in New and Delete (`isDefault`, #460 D18) are left out: they are not executed as
|
|
941
|
+
* custom actions, and the grid offers them itself (see {@link defaultQueryActions}).
|
|
821
942
|
*
|
|
822
943
|
* ⚠️ This narrows what is DISPLAYED. It is NOT an authorization boundary: the grant
|
|
823
944
|
* is, and it is enforced independently in `ExecuteCustomAction` regardless of which
|
|
824
945
|
* query the caller clicked from — a caller can always POST directly.
|
|
825
946
|
*/
|
|
826
|
-
declare function filterQueryActions(actions: CustomActionDefinition[]): CustomActionDefinition[];
|
|
827
|
-
|
|
947
|
+
export declare function filterQueryActions(actions: CustomActionDefinition[]): CustomActionDefinition[];
|
|
948
|
+
/** The custom actions a detail page should offer — the detail-side counterpart of {@link filterQueryActions}. */
|
|
949
|
+
export declare function filterDetailActions(actions: CustomActionDefinition[]): CustomActionDefinition[];
|
|
950
|
+
/**
|
|
951
|
+
* The built-in New and Delete the server listed for this caller (#460, D18), when their `showedOn`
|
|
952
|
+
* includes the query side. Present only when the caller holds `New/T` or `Delete/T`.
|
|
953
|
+
*/
|
|
954
|
+
export declare function defaultQueryActions(actions: CustomActionDefinition[]): CustomActionDefinition[];
|
|
828
955
|
/**
|
|
829
956
|
* Parses a custom action's `selectionRule` — a cardinality expression over the number
|
|
830
957
|
* of selected rows — into a predicate.
|
|
@@ -842,29 +969,14 @@ declare function filterQueryActions(actions: CustomActionDefinition[]): CustomAc
|
|
|
842
969
|
* Client-side this only drives whether a button is disabled. The server enforces the same
|
|
843
970
|
* rule independently — and neither is an authorization boundary: the action's grant is.
|
|
844
971
|
*/
|
|
845
|
-
declare function parseSelectionRule(rule?: string | null): (count: number) => boolean;
|
|
846
|
-
|
|
847
|
-
type SparkSelectionMode = 'none' | 'single' | 'multiple';
|
|
848
|
-
/**
|
|
849
|
-
* The selection mode a grid needs in order to satisfy the actions offered on it.
|
|
850
|
-
*
|
|
851
|
-
* Derived rather than configured, so a grid gains a checkbox column exactly when an
|
|
852
|
-
* action needs one and is otherwise pixel-identical to a grid with no selection at all.
|
|
853
|
-
* Vidyano's query grid does the same thing — it renders the checkbox column only if some
|
|
854
|
-
* action is selection-gated.
|
|
855
|
-
*
|
|
856
|
-
* `'single'` when every gated action is satisfied by one row and refused by two; anything
|
|
857
|
-
* else that cares about the count gets `'multiple'`.
|
|
858
|
-
*/
|
|
859
|
-
declare function selectionModeFor(actions: CustomActionDefinition[]): SparkSelectionMode;
|
|
860
|
-
|
|
972
|
+
export declare function parseSelectionRule(rule?: string | null): (count: number) => boolean;
|
|
861
973
|
/**
|
|
862
974
|
* One selectable value, as replaced by a refresh hook. Mirrors the server's
|
|
863
975
|
* `PersistentObjectAttributeOption`.
|
|
864
976
|
*/
|
|
865
|
-
interface RefreshedOption {
|
|
866
|
-
|
|
867
|
-
|
|
977
|
+
export interface RefreshedOption {
|
|
978
|
+
key: string;
|
|
979
|
+
label?: Record<string, string>;
|
|
868
980
|
}
|
|
869
981
|
/**
|
|
870
982
|
* What a refresh changed about one attribute's *presentation*.
|
|
@@ -876,25 +988,25 @@ interface RefreshedOption {
|
|
|
876
988
|
* Mutating the existing object instead is inert, because the rendering computed would not re-run.
|
|
877
989
|
* An overlay is the only shape that is both reactive and free.
|
|
878
990
|
*/
|
|
879
|
-
interface AttributeOverlay {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
991
|
+
export interface AttributeOverlay {
|
|
992
|
+
isRequired?: boolean;
|
|
993
|
+
isReadOnly?: boolean;
|
|
994
|
+
isVisible?: boolean;
|
|
995
|
+
rules?: ValidationRule[];
|
|
996
|
+
query?: string;
|
|
997
|
+
/** `undefined` means the hook did not touch the options; an empty array means there are none. */
|
|
998
|
+
options?: RefreshedOption[];
|
|
887
999
|
}
|
|
888
|
-
type RefreshOverlay = Record<string, AttributeOverlay>;
|
|
1000
|
+
export type RefreshOverlay = Record<string, AttributeOverlay>;
|
|
889
1001
|
/** Applies an overlay to one attribute definition, returning a new object when anything changed. */
|
|
890
|
-
declare function applyOverlay(attr: EntityAttributeDefinition, overlay: AttributeOverlay | undefined): EntityAttributeDefinition;
|
|
1002
|
+
export declare function applyOverlay(attr: EntityAttributeDefinition, overlay: AttributeOverlay | undefined): EntityAttributeDefinition;
|
|
891
1003
|
/**
|
|
892
1004
|
* Reads a refresh response into an overlay.
|
|
893
1005
|
*
|
|
894
1006
|
* Everything here is presentation the server owns outright, so it is taken verbatim — there is no
|
|
895
1007
|
* merging to do on this half, only on values.
|
|
896
1008
|
*/
|
|
897
|
-
declare function overlayFromResponse(response: PersistentObject): RefreshOverlay;
|
|
1009
|
+
export declare function overlayFromResponse(response: PersistentObject): RefreshOverlay;
|
|
898
1010
|
/**
|
|
899
1011
|
* Merges a refresh response's values into the live form.
|
|
900
1012
|
*
|
|
@@ -915,19 +1027,18 @@ declare function overlayFromResponse(response: PersistentObject): RefreshOverlay
|
|
|
915
1027
|
* @param current values as they are now, which may have moved on
|
|
916
1028
|
* @param response the reshaped object
|
|
917
1029
|
*/
|
|
918
|
-
declare function mergeRefreshValues(sent: Record<string, any>, current: Record<string, any>, response: PersistentObject): Record<string, any>;
|
|
919
|
-
|
|
1030
|
+
export declare function mergeRefreshValues(sent: Record<string, any>, current: Record<string, any>, response: PersistentObject): Record<string, any>;
|
|
920
1031
|
/** One rule failure, in the shape the form already renders per field. */
|
|
921
|
-
interface RuleFailure {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1032
|
+
export interface RuleFailure {
|
|
1033
|
+
attributeName: string;
|
|
1034
|
+
ruleType: string;
|
|
1035
|
+
message: string;
|
|
925
1036
|
}
|
|
926
|
-
interface EvaluableAttribute {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1037
|
+
export interface EvaluableAttribute {
|
|
1038
|
+
name: string;
|
|
1039
|
+
label?: TranslatedString;
|
|
1040
|
+
isRequired?: boolean;
|
|
1041
|
+
rules?: ValidationRule[];
|
|
931
1042
|
}
|
|
932
1043
|
/**
|
|
933
1044
|
* Evaluates an attribute's rules against a value, mirroring the server's `ValidationService`.
|
|
@@ -941,7 +1052,4 @@ interface EvaluableAttribute {
|
|
|
941
1052
|
* This exists because a refresh hook that imposes a rule needs it to bite before Save — previously
|
|
942
1053
|
* `rules` was carried on the wire and never evaluated in the browser at all.
|
|
943
1054
|
*/
|
|
944
|
-
declare function evaluateRules(attr: EvaluableAttribute, value: any): RuleFailure[];
|
|
945
|
-
|
|
946
|
-
export { AS_DETAIL_BREADCRUMBS_KEY, AS_DETAIL_ORIGINAL_DATES_KEY, AS_DETAIL_ROW_KEY, AS_DETAIL_SELF_BREADCRUMB_KEY, ELookupDisplayType, EReferenceDisplayType, ShowedOn, applyOverlay, currentLanguage, dictToNestedPo, evaluateRules, filterQueryActions, fromDateInput, fromDateInputValue, fromDateTimeLocalInput, hasShowedOnFlag, isDateDataType, isPersistentObject, isQueryRow, isReservedAsDetailKey, mergeRefreshValues, nestedPoToDict, nestedPoToDisplayRow, overlayFromResponse, parseSelectionRule, parseWireDate, resolveTranslation, resolvedBreadcrumb, selectionModeFor, selfBreadcrumb, toDateInput, toDateInputValue, toDateTimeLocalInput, valueFor, wireDatesEqual };
|
|
947
|
-
export type { AttributeGroup, AttributeOverlay, AttributeTab, CustomActionDefinition, DistinctValue, DistinctValuesResult, EntityAttributeDefinition, EntityPermissions, EntityType, EntityTypeResolver, EvaluableAttribute, LookupReference, LookupReferenceListItem, LookupReferenceValue, PersistentObject, PersistentObjectAttribute, PersistentObjectPermissions, ProgramUnit, ProgramUnitGroup, ProgramUnitsConfiguration, QueryColumn, QueryColumnFilter, QueryResult, QueryResultItem, QueryResultItemValue, RefreshOverlay, RefreshedOption, RetryActionPayload, RetryActionResult, RuleFailure, SparkCellColumn, SparkQuery, SparkQueryRenderMode, SparkQuerySortColumn, SparkRow, SparkSelectionMode, StreamingErrorMessage, StreamingMessage, StreamingPatchItem, StreamingPatchMessage, StreamingSnapshotMessage, TranslatedString, ValidationError, ValidationErrorResponse, ValidationRule };
|
|
1055
|
+
export declare function evaluateRules(attr: EvaluableAttribute, value: any): RuleFailure[];
|