@mintplayer/ng-spark 22.17.0 → 22.18.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-models.mjs +177 -4
- package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-pipes.mjs +37 -1
- package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-create.mjs +18 -4
- package/fesm2022/mintplayer-ng-spark-po-create.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs +3 -3
- package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs +70 -5
- package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-po-form.mjs +12 -3
- package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +1 -1
- package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
- package/fesm2022/mintplayer-ng-spark-services.mjs +122 -40
- package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mintplayer-ng-spark-models.d.ts +91 -1
- package/types/mintplayer-ng-spark-pipes.d.ts +24 -1
- package/types/mintplayer-ng-spark-po-create.d.ts +8 -1
- package/types/mintplayer-ng-spark-po-edit.d.ts +17 -1
- package/types/mintplayer-ng-spark-po-form.d.ts +11 -2
- package/types/mintplayer-ng-spark-services.d.ts +52 -5
|
@@ -53,6 +53,16 @@ interface PersistentObject {
|
|
|
53
53
|
name: string;
|
|
54
54
|
objectTypeId: string;
|
|
55
55
|
breadcrumb?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Optimistic-concurrency token -- RavenDB's change vector for the document behind this object.
|
|
58
|
+
* The server stamps it on every `/po/load` and expects it back on update.
|
|
59
|
+
*
|
|
60
|
+
* ⚠️ The check is opt-in BY PRESENCE of this field. Dropping it does not fail loudly; it makes
|
|
61
|
+
* the save unconditional, so two people editing the same record both succeed and the second
|
|
62
|
+
* silently overwrites the first. That is what used to happen here: `SparkClient` round-tripped
|
|
63
|
+
* the token and got a 409, the browser did not and got last-write-wins, on the same endpoint.
|
|
64
|
+
*/
|
|
65
|
+
etag?: string;
|
|
56
66
|
attributes: PersistentObjectAttribute[];
|
|
57
67
|
/** Per-row edit/delete affordances; undefined = fall back to type-level permissions. */
|
|
58
68
|
can?: PersistentObjectPermissions;
|
|
@@ -552,6 +562,70 @@ interface StreamingErrorMessage {
|
|
|
552
562
|
}
|
|
553
563
|
type StreamingMessage = StreamingSnapshotMessage | StreamingPatchMessage | StreamingErrorMessage;
|
|
554
564
|
|
|
565
|
+
/**
|
|
566
|
+
* Conversions between the wire format for a timestamp and what an `<input type="datetime-local">`
|
|
567
|
+
* or `<input type="date">` will accept.
|
|
568
|
+
*
|
|
569
|
+
* A `DateTimeOffset` in Spark means an **instant**. The wire carries a full ISO-8601 string with an
|
|
570
|
+
* offset (`2026-12-31T23:59:00-08:00`); an HTML date/time control speaks only bare local wall clock
|
|
571
|
+
* (`2026-12-31T23:59`). Neither end can consume the other's format, so both directions need
|
|
572
|
+
* converting, and the browser is deliberately the side that does it: its timezone rules are kept
|
|
573
|
+
* fresh by the operating system, while a container's are frozen at image build time.
|
|
574
|
+
*
|
|
575
|
+
* Assigning a wire value straight to a `datetime-local` input does not throw and does not warn -- the
|
|
576
|
+
* control simply renders **blank**, and saving the untouched form then writes that blank back.
|
|
577
|
+
*/
|
|
578
|
+
/**
|
|
579
|
+
* Parses a wire timestamp. Returns `null` for anything unusable, matching the contract of
|
|
580
|
+
* `parsedDate` / `queryCellValue` -- a bad value renders as empty rather than as `Invalid Date`.
|
|
581
|
+
*/
|
|
582
|
+
declare function parseWireDate(value: unknown): Date | null;
|
|
583
|
+
/**
|
|
584
|
+
* Wire value -> the `yyyy-MM-ddTHH:mm` a `datetime-local` input needs, in the **viewer's** zone.
|
|
585
|
+
*
|
|
586
|
+
* The conversion is date-sensitive, not a fixed shift: a value is rendered using the zone's offset
|
|
587
|
+
* *on that value's own date*, so a timestamp in July and one in January convert differently in a
|
|
588
|
+
* zone that observes DST.
|
|
589
|
+
*/
|
|
590
|
+
declare function toDateTimeLocalInput(value: unknown): string;
|
|
591
|
+
/** Wire value -> the `yyyy-MM-dd` a `date` input needs, in the viewer's zone. */
|
|
592
|
+
declare function toDateInput(value: unknown): string;
|
|
593
|
+
/**
|
|
594
|
+
* `yyyy-MM-ddTHH:mm` from the control -> a complete ISO-8601 string carrying the viewer's offset
|
|
595
|
+
* **for the entered date**.
|
|
596
|
+
*
|
|
597
|
+
* Building the `Date` from its parts rather than parsing the string is what makes this correct: it
|
|
598
|
+
* lets the browser apply its own timezone rules for that date, including DST. Using the *current*
|
|
599
|
+
* offset instead would be wrong for any value outside the present season -- entering a January date
|
|
600
|
+
* during summer would record an offset an hour off, and the stored instant would be an hour wrong.
|
|
601
|
+
*
|
|
602
|
+
* Across a DST discontinuity the browser resolves the wall clock itself, taking the offset in force
|
|
603
|
+
* before a fall-back and after a spring-forward. That is specified ECMAScript behaviour, and the
|
|
604
|
+
* server's conversion helper deliberately reproduces the same choice so the two cannot drift.
|
|
605
|
+
*/
|
|
606
|
+
declare function fromDateTimeLocalInput(local: unknown): string | null;
|
|
607
|
+
/** `yyyy-MM-dd` from a `date` control -> an ISO string at local midnight with the viewer's offset. */
|
|
608
|
+
declare function fromDateInput(local: unknown): string | null;
|
|
609
|
+
/**
|
|
610
|
+
* Compares two wire timestamps **by instant**, which is what a `DateTimeOffset` means in Spark.
|
|
611
|
+
*
|
|
612
|
+
* Round-tripping a value through a date control legitimately rewrites its text -- a document holding
|
|
613
|
+
* `2026-12-31T23:59:00-08:00` comes back as `2027-01-01T08:59:00+01:00` from a viewer in Brussels --
|
|
614
|
+
* so a string comparison would mark every untouched date as edited and send a needless write on every
|
|
615
|
+
* save. Both of those name the same moment.
|
|
616
|
+
*
|
|
617
|
+
* Note this is the *opposite* of the trap on the server side, where `DateTimeOffset.Equals` compares
|
|
618
|
+
* the instant and silently hides a destroyed offset. Here comparing by instant is the correct thing:
|
|
619
|
+
* we are asking "did the user change this value", not "is the offset intact".
|
|
620
|
+
*/
|
|
621
|
+
declare function wireDatesEqual(a: unknown, b: unknown): boolean;
|
|
622
|
+
/** True for the attribute data types that are edited through a native date/time control. */
|
|
623
|
+
declare function isDateDataType(dataType: string | null | undefined): dataType is 'date' | 'datetime';
|
|
624
|
+
/** Wire -> control, picking the right shape for the data type. */
|
|
625
|
+
declare function toDateInputValue(dataType: string | null | undefined, value: unknown): string;
|
|
626
|
+
/** Control -> wire, picking the right shape for the data type. */
|
|
627
|
+
declare function fromDateInputValue(dataType: string | null | undefined, value: unknown): string | null;
|
|
628
|
+
|
|
555
629
|
/**
|
|
556
630
|
* Resolves an `EntityType` by its CLR type name (e.g. `"HR.Entities.Address"`).
|
|
557
631
|
* Callers typically close over a list they already hold. `getEntityTypes()` is NOT cached --
|
|
@@ -629,6 +703,22 @@ declare function resolvedBreadcrumb(value: unknown, typeName?: string): string |
|
|
|
629
703
|
* reference-query options page. Prefixed to avoid colliding with a real attribute name.
|
|
630
704
|
*/
|
|
631
705
|
declare const AS_DETAIL_BREADCRUMBS_KEY = "__sparkBreadcrumbs";
|
|
706
|
+
/**
|
|
707
|
+
* Reserved key under which a flattened row keeps the **wire** values of its date cells, keyed by
|
|
708
|
+
* attribute name.
|
|
709
|
+
*
|
|
710
|
+
* A date cell is edited through a native control that speaks only a bare local wall clock, so
|
|
711
|
+
* flattening converts the stored instant into the viewer's zone and saving converts it back. That
|
|
712
|
+
* round trip preserves the instant but necessarily rewrites the **offset** to the viewer's. For a
|
|
713
|
+
* cell the user actually edited that is correct — the offset is not business data. For one nobody
|
|
714
|
+
* touched it is pure loss: merely opening a row and saving would relabel a Seattle timestamp as a
|
|
715
|
+
* Brussels one.
|
|
716
|
+
*
|
|
717
|
+
* Keeping the original lets {@link dictToNestedPo} send back exactly what it was given whenever the
|
|
718
|
+
* instant is unchanged. Safe to carry for the same reason as the other reserved keys: the rebuild
|
|
719
|
+
* walks the entity type's attributes, never the dict's keys.
|
|
720
|
+
*/
|
|
721
|
+
declare const AS_DETAIL_ORIGINAL_DATES_KEY = "__sparkOriginalDates";
|
|
632
722
|
/**
|
|
633
723
|
* Whether a flattened-row key is one this module reserved rather than a model attribute.
|
|
634
724
|
*
|
|
@@ -791,5 +881,5 @@ interface EvaluableAttribute {
|
|
|
791
881
|
*/
|
|
792
882
|
declare function evaluateRules(attr: EvaluableAttribute, value: any): RuleFailure[];
|
|
793
883
|
|
|
794
|
-
export { AS_DETAIL_BREADCRUMBS_KEY, AS_DETAIL_ROW_KEY, AS_DETAIL_SELF_BREADCRUMB_KEY, ELookupDisplayType, EReferenceDisplayType, ShowedOn, applyOverlay, currentLanguage, dictToNestedPo, evaluateRules, filterQueryActions, hasShowedOnFlag, isPersistentObject, isQueryRow, isReservedAsDetailKey, mergeRefreshValues, nestedPoToDict, nestedPoToDisplayRow, overlayFromResponse, parseSelectionRule, resolveTranslation, resolvedBreadcrumb, selectionModeFor, selfBreadcrumb, valueFor };
|
|
884
|
+
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 };
|
|
795
885
|
export type { AttributeGroup, AttributeOverlay, AttributeTab, CustomActionDefinition, EntityAttributeDefinition, EntityPermissions, EntityType, EntityTypeResolver, EvaluableAttribute, LookupReference, LookupReferenceListItem, LookupReferenceValue, PersistentObject, PersistentObjectAttribute, PersistentObjectPermissions, ProgramUnit, ProgramUnitGroup, ProgramUnitsConfiguration, QueryColumn, QueryResult, QueryResultItem, QueryResultItemValue, RefreshOverlay, RefreshedOption, RetryActionPayload, RetryActionResult, RuleFailure, SparkCellColumn, SparkQuery, SparkQueryRenderMode, SparkQuerySortColumn, SparkRow, SparkSelectionMode, StreamingErrorMessage, StreamingMessage, StreamingPatchItem, StreamingPatchMessage, StreamingSnapshotMessage, TranslatedString, ValidationError, ValidationErrorResponse, ValidationRule };
|
|
@@ -21,6 +21,29 @@ declare class InputTypePipe implements PipeTransform {
|
|
|
21
21
|
static ɵpipe: i0.ɵɵPipeDeclaration<InputTypePipe, "inputType", true>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Parses a wire value into a `Date`, or `null` when it is absent or unparseable.
|
|
26
|
+
*
|
|
27
|
+
* Exists so the detail page and the grid agree. The grid gets its `Date` from `queryCellValue`, which
|
|
28
|
+
* needs a cell and a column and so cannot be reused on a detail attribute; before this, the detail page
|
|
29
|
+
* had no parsing step at all and printed the raw ISO string — `2026-12-31T23:59:00-08:00` in a
|
|
30
|
+
* definition list, while the grid showed `01/01/2027, 08:59` for the same document.
|
|
31
|
+
*
|
|
32
|
+
* The parsing contract is deliberately identical to `queryCellValue`'s: `new Date(...)`, and an
|
|
33
|
+
* unparseable value yields `null` so the caller can fall back to its own text rather than rendering
|
|
34
|
+
* "Invalid Date".
|
|
35
|
+
*
|
|
36
|
+
* Note what `new Date(...)` does to an offset, because it is the whole reason this is a separate step:
|
|
37
|
+
* it collapses the value to an instant and forgets the offset it was written with. That is correct for
|
|
38
|
+
* display — a viewer wants the moment in their own zone — but it means a `Date` can never be the thing
|
|
39
|
+
* you reach for when you need the *originating* wall clock. Read that from the wire value instead.
|
|
40
|
+
*/
|
|
41
|
+
declare class ParsedDatePipe implements PipeTransform {
|
|
42
|
+
transform(value: unknown): Date | null;
|
|
43
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ParsedDatePipe, never>;
|
|
44
|
+
static ɵpipe: i0.ɵɵPipeDeclaration<ParsedDatePipe, "parsedDate", true>;
|
|
45
|
+
}
|
|
46
|
+
|
|
24
47
|
declare class AttributeValuePipe implements PipeTransform {
|
|
25
48
|
transform(attrName: string, item: PersistentObject | null, entityType: EntityType | null, lookupRefOptions: Record<string, LookupReference>, allEntityTypes: EntityType[]): any;
|
|
26
49
|
private formatAsDetailValue;
|
|
@@ -265,5 +288,5 @@ declare class QueryReferenceChipsPipe implements PipeTransform {
|
|
|
265
288
|
static ɵpipe: i0.ɵɵPipeDeclaration<QueryReferenceChipsPipe, "queryReferenceChips", true>;
|
|
266
289
|
}
|
|
267
290
|
|
|
268
|
-
export { ArrayValuePipe, AsDetailCellValuePipe, AsDetailColumnsPipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AttributeValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, CanEditDetailRowPipe, ErrorForAttributePipe, IconNamePipe, InlineRefOptionsPipe, InputTypePipe, LookupDisplayTypePipe, LookupDisplayValuePipe, LookupOptionsPipe, QueryCellValuePipe, QueryReferenceChipsPipe, RawAttributeValuePipe, ReferenceAttrValuePipe, ReferenceChipsPipe, ReferenceDisplayValuePipe, ReferenceLinkRoutePipe, ResolveTranslationPipe, RouterLinkPipe, TranslateKeyPipe };
|
|
291
|
+
export { ArrayValuePipe, AsDetailCellValuePipe, AsDetailColumnsPipe, AsDetailDisplayValuePipe, AsDetailTypePipe, AttributeValuePipe, CanCreateDetailRowPipe, CanDeleteDetailRowPipe, CanEditDetailRowPipe, ErrorForAttributePipe, IconNamePipe, InlineRefOptionsPipe, InputTypePipe, LookupDisplayTypePipe, LookupDisplayValuePipe, LookupOptionsPipe, ParsedDatePipe, QueryCellValuePipe, QueryReferenceChipsPipe, RawAttributeValuePipe, ReferenceAttrValuePipe, ReferenceChipsPipe, ReferenceDisplayValuePipe, ReferenceLinkRoutePipe, ResolveTranslationPipe, RouterLinkPipe, TranslateKeyPipe };
|
|
269
292
|
export type { AsDetailCellValue, ReferenceChip };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _mintplayer_ng_spark_models from '@mintplayer/ng-spark/models';
|
|
2
|
-
import { PersistentObject, EntityType, ValidationError } from '@mintplayer/ng-spark/models';
|
|
2
|
+
import { PersistentObject, EntityType, RefreshOverlay, ValidationError } from '@mintplayer/ng-spark/models';
|
|
3
3
|
import * as _angular_core from '@angular/core';
|
|
4
4
|
import { Color } from '@mintplayer/ng-bootstrap';
|
|
5
5
|
|
|
@@ -13,6 +13,8 @@ declare class SparkPoCreateComponent {
|
|
|
13
13
|
entityType: _angular_core.WritableSignal<EntityType | null>;
|
|
14
14
|
type: _angular_core.WritableSignal<string>;
|
|
15
15
|
formData: _angular_core.WritableSignal<Record<string, any>>;
|
|
16
|
+
/** Bound two-way to the form. See {@link getEditableAttributes}. */
|
|
17
|
+
refreshOverlay: _angular_core.WritableSignal<RefreshOverlay>;
|
|
16
18
|
validationErrors: _angular_core.WritableSignal<ValidationError[]>;
|
|
17
19
|
isSaving: _angular_core.WritableSignal<boolean>;
|
|
18
20
|
private allEntityTypes;
|
|
@@ -20,6 +22,11 @@ declare class SparkPoCreateComponent {
|
|
|
20
22
|
constructor();
|
|
21
23
|
private onParamsChange;
|
|
22
24
|
initFormData(): void;
|
|
25
|
+
/**
|
|
26
|
+
* ⚠️ Overlaid before filtering — same reason as <c>spark-po-edit</c>, and worse here: this list is
|
|
27
|
+
* the <em>only</em> source of the create payload, so an attribute a refresh hook revealed was not
|
|
28
|
+
* merely sent stale, it was absent from the new object entirely.
|
|
29
|
+
*/
|
|
23
30
|
getEditableAttributes(): _mintplayer_ng_spark_models.EntityAttributeDefinition[];
|
|
24
31
|
onSave(): Promise<void>;
|
|
25
32
|
onCancel(): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _mintplayer_ng_spark_models from '@mintplayer/ng-spark/models';
|
|
2
|
-
import { PersistentObject, EntityType, ValidationError } from '@mintplayer/ng-spark/models';
|
|
2
|
+
import { PersistentObject, EntityType, RefreshOverlay, ValidationError } from '@mintplayer/ng-spark/models';
|
|
3
3
|
import * as _angular_core from '@angular/core';
|
|
4
4
|
import { Color } from '@mintplayer/ng-bootstrap';
|
|
5
5
|
|
|
@@ -7,6 +7,7 @@ declare class SparkPoEditComponent {
|
|
|
7
7
|
private readonly route;
|
|
8
8
|
private readonly router;
|
|
9
9
|
private readonly sparkService;
|
|
10
|
+
private readonly language;
|
|
10
11
|
saved: _angular_core.OutputEmitterRef<PersistentObject>;
|
|
11
12
|
cancelled: _angular_core.OutputEmitterRef<void>;
|
|
12
13
|
colors: typeof Color;
|
|
@@ -15,6 +16,11 @@ declare class SparkPoEditComponent {
|
|
|
15
16
|
type: string;
|
|
16
17
|
id: string;
|
|
17
18
|
formData: _angular_core.WritableSignal<Record<string, any>>;
|
|
19
|
+
/**
|
|
20
|
+
* Bound two-way to the form, which is where refreshes land. Read by
|
|
21
|
+
* {@link getEditableAttributes} so the save sees the object the user was actually shown.
|
|
22
|
+
*/
|
|
23
|
+
refreshOverlay: _angular_core.WritableSignal<RefreshOverlay>;
|
|
18
24
|
validationErrors: _angular_core.WritableSignal<ValidationError[]>;
|
|
19
25
|
isSaving: _angular_core.WritableSignal<boolean>;
|
|
20
26
|
private allEntityTypes;
|
|
@@ -23,6 +29,16 @@ declare class SparkPoEditComponent {
|
|
|
23
29
|
private onParamsChange;
|
|
24
30
|
initFormData(): void;
|
|
25
31
|
private resolveEntityType;
|
|
32
|
+
/**
|
|
33
|
+
* The attributes this page will read values from when it builds the save.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ <b>Overlaid before filtering, not after loading.</b> A refresh hook can reveal an attribute
|
|
36
|
+
* that was hidden when the object was loaded, and the ordinary reason it does so is that the
|
|
37
|
+
* attribute has just become required. Filtering on the loaded state left such an attribute out of
|
|
38
|
+
* both {@link initFormData} and the save payload, so the user filled in a field whose value was
|
|
39
|
+
* then dropped on the floor and refused by the server as missing — with no way out of the form.
|
|
40
|
+
* The overlay is the form's, bound two-way, so the two halves cannot drift again.
|
|
41
|
+
*/
|
|
26
42
|
getEditableAttributes(): _mintplayer_ng_spark_models.EntityAttributeDefinition[];
|
|
27
43
|
onSave(): Promise<void>;
|
|
28
44
|
onCancel(): void;
|
|
@@ -83,8 +83,17 @@ declare class SparkPoFormComponent {
|
|
|
83
83
|
* `entityType` identity and `SparkService` caches nothing, so re-setting it would re-issue every
|
|
84
84
|
* reference query and lookup fetch on every refresh; mutating it in place would not re-render at
|
|
85
85
|
* all.
|
|
86
|
+
*
|
|
87
|
+
* ⚠️ A `model`, not a plain signal, because the page that owns the save has to see it. This form
|
|
88
|
+
* renders from the overlaid attribute list; `spark-po-edit` and `spark-po-create` build the
|
|
89
|
+
* payload from their own copy of the same filter. While the overlay stopped here, those two
|
|
90
|
+
* filtered on the attribute's state *as loaded* — so an attribute a refresh hook revealed was
|
|
91
|
+
* rendered, filled in by the user, and then silently left out of the save. When the same hook also
|
|
92
|
+
* made it required (the ordinary case — a field appears *because* it is now needed) the server
|
|
93
|
+
* refused the save for the very field the user had just filled, and the form became a dead end
|
|
94
|
+
* with no way forward from inside it.
|
|
86
95
|
*/
|
|
87
|
-
refreshOverlay: _angular_core.
|
|
96
|
+
refreshOverlay: _angular_core.ModelSignal<RefreshOverlay>;
|
|
88
97
|
isRefreshing: _angular_core.WritableSignal<boolean>;
|
|
89
98
|
colors: typeof Color;
|
|
90
99
|
referenceOptions: _angular_core.WritableSignal<Record<string, QueryResultItem[]>>;
|
|
@@ -269,7 +278,7 @@ declare class SparkPoFormComponent {
|
|
|
269
278
|
removeArrayItem(attr: EntityAttributeDefinition, index: number): Promise<void>;
|
|
270
279
|
onAsDetailReorder(attr: EntityAttributeDefinition, event: CdkDragDrop<Record<string, any>[]>): void;
|
|
271
280
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkPoFormComponent, never>;
|
|
272
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkPoFormComponent, "spark-po-form", never, { "entityType": { "alias": "entityType"; "required": false; "isSignal": true; }; "formData": { "alias": "formData"; "required": false; "isSignal": true; }; "validationErrors": { "alias": "validationErrors"; "required": false; "isSignal": true; }; "showButtons": { "alias": "showButtons"; "required": false; "isSignal": true; }; "isSaving": { "alias": "isSaving"; "required": false; "isSignal": true; }; "parentId": { "alias": "parentId"; "required": false; "isSignal": true; }; "parentType": { "alias": "parentType"; "required": false; "isSignal": true; }; "objectTypeId": { "alias": "objectTypeId"; "required": false; "isSignal": true; }; "objectId": { "alias": "objectId"; "required": false; "isSignal": true; }; }, { "formData": "formDataChange"; "save": "save"; "cancel": "cancel"; }, never, never, true, never>;
|
|
281
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkPoFormComponent, "spark-po-form", never, { "entityType": { "alias": "entityType"; "required": false; "isSignal": true; }; "formData": { "alias": "formData"; "required": false; "isSignal": true; }; "validationErrors": { "alias": "validationErrors"; "required": false; "isSignal": true; }; "showButtons": { "alias": "showButtons"; "required": false; "isSignal": true; }; "isSaving": { "alias": "isSaving"; "required": false; "isSignal": true; }; "parentId": { "alias": "parentId"; "required": false; "isSignal": true; }; "parentType": { "alias": "parentType"; "required": false; "isSignal": true; }; "objectTypeId": { "alias": "objectTypeId"; "required": false; "isSignal": true; }; "objectId": { "alias": "objectId"; "required": false; "isSignal": true; }; "refreshOverlay": { "alias": "refreshOverlay"; "required": false; "isSignal": true; }; }, { "formData": "formDataChange"; "save": "save"; "cancel": "cancel"; "refreshOverlay": "refreshOverlayChange"; }, never, never, true, never>;
|
|
273
282
|
}
|
|
274
283
|
|
|
275
284
|
/**
|
|
@@ -3,6 +3,7 @@ import { RetryActionPayload, RetryActionResult, TranslatedString, StreamingMessa
|
|
|
3
3
|
import { Observable } from 'rxjs';
|
|
4
4
|
import { SortColumn } from '@mintplayer/pagination';
|
|
5
5
|
import { SafeHtml } from '@angular/platform-browser';
|
|
6
|
+
import { HttpInterceptorFn, HttpFeature, HttpFeatureKind } from '@angular/common/http';
|
|
6
7
|
|
|
7
8
|
declare class RetryActionService {
|
|
8
9
|
private resolveRetry;
|
|
@@ -72,6 +73,13 @@ declare class SparkService {
|
|
|
72
73
|
private readonly baseUrl;
|
|
73
74
|
private readonly http;
|
|
74
75
|
private readonly retryActionService;
|
|
76
|
+
/**
|
|
77
|
+
* How many prompts one request will answer before giving up. Matches the .NET client's
|
|
78
|
+
* `SparkClient.MaxRetryDepth`, and for the same reason: this is a termination bound, not a
|
|
79
|
+
* capacity one. Far above any real conversation (Fleet's longest is two) and far below anything
|
|
80
|
+
* that could hide a spin.
|
|
81
|
+
*/
|
|
82
|
+
private static readonly MAX_RETRY_DEPTH;
|
|
75
83
|
private readonly dispatcher;
|
|
76
84
|
getEntityTypes(): Promise<EntityType[]>;
|
|
77
85
|
getEntityType(id: string): Promise<EntityType>;
|
|
@@ -146,8 +154,9 @@ declare class SparkService {
|
|
|
146
154
|
* it is editing, and the removal is persisted with the parent. A hook that refuses rejects with a
|
|
147
155
|
* 400 whose `error.error.result.errors` carries the readable reason, exactly like a save.
|
|
148
156
|
*
|
|
149
|
-
* A POST
|
|
150
|
-
* DELETE
|
|
157
|
+
* A POST — as everything is now. It used to be worth explaining: the framework's real delete route
|
|
158
|
+
* was a catch-all that would have swallowed a sibling DELETE. The catch-all is gone with the rest
|
|
159
|
+
* of the route variables.
|
|
151
160
|
*/
|
|
152
161
|
deleteRow(type: string, options: DeleteRowOptions): Promise<void>;
|
|
153
162
|
delete(type: string, id: string): Promise<void>;
|
|
@@ -172,8 +181,16 @@ declare class SparkService {
|
|
|
172
181
|
updateLookupReferenceValue(name: string, key: string, value: LookupReferenceValue): Promise<LookupReferenceValue>;
|
|
173
182
|
deleteLookupReferenceValue(name: string, key: string): Promise<void>;
|
|
174
183
|
private postWithEnvelope;
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
/**
|
|
185
|
+
* A read: posts the request, and returns the response **as-is** rather than unwrapping an
|
|
186
|
+
* envelope.
|
|
187
|
+
*
|
|
188
|
+
* The read endpoints moved from GET to POST so their hooks could prompt, but their success
|
|
189
|
+
* responses are still bare — a `PersistentObject`, a `QueryResult`. Only the 449 is enveloped,
|
|
190
|
+
* because a retry has nowhere else to live. So this shares the retry loop with the mutating calls
|
|
191
|
+
* and nothing else.
|
|
192
|
+
*/
|
|
193
|
+
private sendRead;
|
|
177
194
|
private sendWithEnvelope;
|
|
178
195
|
private handleEnvelopeRetryError;
|
|
179
196
|
static ɵfac: i0.ɵɵFactoryDeclaration<SparkService, never>;
|
|
@@ -271,5 +288,35 @@ declare class SparkQueryActionsService {
|
|
|
271
288
|
static ɵprov: i0.ɵɵInjectableDeclaration<SparkQueryActionsService>;
|
|
272
289
|
}
|
|
273
290
|
|
|
274
|
-
|
|
291
|
+
/**
|
|
292
|
+
* The header carrying the viewer's IANA timezone id, e.g. `Europe/Brussels`.
|
|
293
|
+
* Must stay in lockstep with `RequestTimeZoneResolver.HeaderName` on the server.
|
|
294
|
+
*/
|
|
295
|
+
declare const SPARK_TIMEZONE_HEADER = "X-Spark-Timezone";
|
|
296
|
+
/**
|
|
297
|
+
* Returns the browser's IANA zone id, or `null` when the environment cannot name one.
|
|
298
|
+
*
|
|
299
|
+
* An id is deliberately sent rather than a numeric offset: an offset is only valid at one instant,
|
|
300
|
+
* so a server asked to render "next Tuesday at 09:00" from an offset captured today gets it wrong
|
|
301
|
+
* across a DST boundary. A zone id carries the rules, not one sample of them.
|
|
302
|
+
*/
|
|
303
|
+
declare function resolveBrowserTimeZone(): string | null;
|
|
304
|
+
/**
|
|
305
|
+
* Attaches {@link SPARK_TIMEZONE_HEADER} to same-origin requests.
|
|
306
|
+
*
|
|
307
|
+
* **This does not participate in reading or writing timestamps.** A `DateTimeOffset` means an
|
|
308
|
+
* instant, and the browser converts in both directions on those paths. The header exists for work
|
|
309
|
+
* the server starts on its own — a scheduled export, a notification email — where there is no
|
|
310
|
+
* browser in the loop to do the converting but the output still has to read as local time.
|
|
311
|
+
*/
|
|
312
|
+
declare const sparkTimezoneInterceptor: HttpInterceptorFn;
|
|
313
|
+
/**
|
|
314
|
+
* `provideHttpClient(...withSparkTimezone())` — registers {@link sparkTimezoneInterceptor}.
|
|
315
|
+
*
|
|
316
|
+
* Spreadable alongside `withSparkAuth()`:
|
|
317
|
+
* `provideHttpClient(...withSparkAuth(), ...withSparkTimezone())`.
|
|
318
|
+
*/
|
|
319
|
+
declare function withSparkTimezone(): HttpFeature<HttpFeatureKind>[];
|
|
320
|
+
|
|
321
|
+
export { RetryActionService, SPARK_TIMEZONE_HEADER, SparkIconRegistry, SparkLanguageService, SparkQueryActionsService, SparkService, SparkStreamingService, resolveBrowserTimeZone, sparkTimezoneInterceptor, withSparkTimezone };
|
|
275
322
|
export type { DeleteRowOptions, NewObjectOptions };
|