@mintplayer/ng-spark 22.28.1 → 22.30.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.
Files changed (29) hide show
  1. package/README.md +1 -1
  2. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +82 -4
  3. package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
  4. package/fesm2022/mintplayer-ng-spark-grid.mjs +59 -18
  5. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  6. package/fesm2022/mintplayer-ng-spark-models.mjs +2 -1
  7. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  8. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +14 -4
  9. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  10. package/fesm2022/mintplayer-ng-spark-po-form.mjs +6 -3
  11. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  12. package/fesm2022/mintplayer-ng-spark-query-list.mjs +5 -2
  13. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  14. package/fesm2022/mintplayer-ng-spark-renderers.mjs +109 -4
  15. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  16. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs +36 -6
  17. package/fesm2022/mintplayer-ng-spark-retry-action-modal.mjs.map +1 -1
  18. package/fesm2022/mintplayer-ng-spark-services.mjs +37 -5
  19. package/fesm2022/mintplayer-ng-spark-services.mjs.map +1 -1
  20. package/package.json +3 -3
  21. package/types/mintplayer-ng-spark-client-operations.d.ts +81 -4
  22. package/types/mintplayer-ng-spark-grid.d.ts +36 -4
  23. package/types/mintplayer-ng-spark-models.d.ts +28 -0
  24. package/types/mintplayer-ng-spark-po-detail.d.ts +8 -0
  25. package/types/mintplayer-ng-spark-po-form.d.ts +2 -0
  26. package/types/mintplayer-ng-spark-query-list.d.ts +2 -0
  27. package/types/mintplayer-ng-spark-renderers.d.ts +47 -0
  28. package/types/mintplayer-ng-spark-retry-action-modal.d.ts +1 -0
  29. package/types/mintplayer-ng-spark-services.d.ts +27 -1
@@ -53,6 +53,12 @@ export interface RetryOperation {
53
53
  defaultOption?: string | null;
54
54
  persistentObject?: PersistentObject | null;
55
55
  message?: string | null;
56
+ /** Whether the client offers its own translated Cancel, answered as `'Cancel'` (`IRetryAccessor.Action(..., cancellable)`). */
57
+ cancellable?: boolean;
58
+ /** A client method to run instead of a modal (`IRetryAccessor.Invoke`); see `provideSparkClientMethods`. */
59
+ clientMethod?: string | null;
60
+ /** Its argument, as the server serialized it. */
61
+ arguments?: unknown;
56
62
  }
57
63
  /**
58
64
  * Discriminated union of known operation types, plus an open shape for unknown
@@ -120,6 +126,70 @@ export interface ClientOperationHandlerRegistration {
120
126
  * providers using this token.
121
127
  */
122
128
  export declare const SPARK_CLIENT_OPERATION_HANDLERS: InjectionToken<readonly ClientOperationHandlerRegistration[]>;
129
+ /**
130
+ * One step a server action needs from the browser (`IRetryAccessor.Invoke` on the server): WebAuthn,
131
+ * a file picker, the clipboard. The answer travels back into the same server action as the retry's
132
+ * `value`, so authorization, state and the follow-up all stay inside that one action.
133
+ */
134
+ export interface SparkClientMethod {
135
+ /**
136
+ * Runs the step. Called in an injection context, so `inject()` works synchronously at the top.
137
+ * A rejection or a thrown error answers the server with `Cancel`, exactly like an unknown name.
138
+ */
139
+ invoke(args: unknown): Promise<unknown>;
140
+ /**
141
+ * Whether this browser can run the method at all. An action whose `requiresClient` names a method
142
+ * that is unsupported is shown disabled; an `Invoke` of it answers `Cancel` without running it.
143
+ * Absent means always supported.
144
+ */
145
+ supported?(): boolean;
146
+ /** The translation key explaining why the method is unsupported; defaults to `common.clientUnsupported`. */
147
+ unsupportedReason?: string;
148
+ }
149
+ /** Client methods by the name the server invokes them with, e.g. `{ 'webauthn.create': { invoke: … } }`. */
150
+ export type SparkClientMethodMap = Readonly<Record<string, SparkClientMethod>>;
151
+ /** Multi-provider token; use {@link provideSparkClientMethods}. A later registration of a name wins. */
152
+ export declare const SPARK_CLIENT_METHODS: InjectionToken<readonly Readonly<Record<string, SparkClientMethod>>[]>;
153
+ /** The reason shown on an action whose client method is missing or unsupported, when the method names none. */
154
+ export declare const SPARK_CLIENT_UNSUPPORTED_REASON = "common.clientUnsupported";
155
+ /**
156
+ * Registers client methods a server action may invoke through a retry (`IRetryAccessor.Invoke`).
157
+ *
158
+ * The set is closed on purpose: the server can only name a method the app registered here, and an
159
+ * unknown name answers `Cancel`. Nothing the server sends is evaluated.
160
+ *
161
+ * @example
162
+ * provideSparkClientMethods({
163
+ * 'clipboard.read': { invoke: () => navigator.clipboard.readText(), supported: () => !!navigator.clipboard },
164
+ * })
165
+ */
166
+ export declare function provideSparkClientMethods(methods: SparkClientMethodMap): EnvironmentProviders;
167
+ /** How a client method ended: its value, or a failure the server sees as `Cancel`. */
168
+ export type SparkClientMethodOutcome = {
169
+ ok: true;
170
+ value: unknown;
171
+ } | {
172
+ ok: false;
173
+ };
174
+ /** The registered client methods: whether one can run here, and running it. */
175
+ export declare class SparkClientMethodRegistry {
176
+ private readonly injector;
177
+ private readonly methods;
178
+ constructor();
179
+ /**
180
+ * Null when the method is registered and supported here; otherwise the translation key saying why
181
+ * it is not. Null for no name at all, so an action without `requiresClient` is never affected.
182
+ */
183
+ unavailableReason(name: string | null | undefined): string | null;
184
+ /**
185
+ * Runs the method registered under `name`. Fails closed: an unknown name, an unsupported method, a
186
+ * rejection or a thrown error all end as `{ ok: false }`, which the retry loop answers as `Cancel`.
187
+ */
188
+ invoke(name: string, args: unknown): Promise<SparkClientMethodOutcome>;
189
+ private isSupported;
190
+ static ɵfac: i0.ɵɵFactoryDeclaration<SparkClientMethodRegistry, never>;
191
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
192
+ }
123
193
  export interface SparkToast {
124
194
  id: string;
125
195
  message: string;
@@ -184,17 +254,24 @@ export declare function provideSparkClientOperations(): EnvironmentProviders;
184
254
  */
185
255
  export declare class SparkQueryRefreshService {
186
256
  private readonly tokens;
187
- /** Bumped every time the server asks for this query to refresh. */
257
+ /**
258
+ * Bumped every time a refresh is asked for this key.
259
+ *
260
+ * ⚠️ Reading it makes the caller depend on EVERY key, not just this one: the counters share one
261
+ * signal. A grid must therefore compare the value with the one it last saw, never react to the
262
+ * read alone (#319) — otherwise it re-fetches for every query refreshed anywhere in the app.
263
+ */
188
264
  tokenFor(queryId: string | undefined): number;
189
265
  /**
190
266
  * Ask every grid showing `queryId` to re-fetch.
191
267
  *
192
- * Matched on the EXACT string a grid passes to {@link tokenFor} -- whichever of id or alias
193
- * its `queryId` input holds. A caller that knows only the other form will not reach it.
268
+ * `queryId` is the query's id or its alias. A grid answers to both, whichever its own `queryId`
269
+ * input holds, because it learns the other from the query it resolved. Keys are matched
270
+ * case-insensitively, as the server resolves them (`QueryLoader.ResolveQuery`).
194
271
  *
195
272
  * Callers bumping several keys for one user action should do so in one synchronous run: the
196
273
  * signal coalesces bumps within a tick into a single effect run, and bumps split across an
197
- * await become one re-fetch each.
274
+ * await become one re-fetch each (#319).
198
275
  */
199
276
  request(queryId: string): void;
200
277
  static ɵfac: i0.ɵɵFactoryDeclaration<SparkQueryRefreshService, never>;
@@ -252,6 +252,7 @@ export declare class SparkQueryGridComponent {
252
252
  /** Add-on row-menu entries (`SPARK_QUERY_ROW_ACTIONS`), e.g. Contributions' revert. */
253
253
  private readonly addonRowActions;
254
254
  readonly lang: SparkLanguageService;
255
+ private readonly clientMethods;
255
256
  /** Query alias or id. */
256
257
  queryId: import("@angular/core").InputSignal<string>;
257
258
  /**
@@ -430,6 +431,11 @@ export declare class SparkQueryGridComponent {
430
431
  offersCreate: import("@angular/core").Signal<boolean>;
431
432
  visibleCustomActions: import("@angular/core").Signal<CustomActionDefinition[]>;
432
433
  fetchFn: import("@angular/core").WritableSignal<BsDatatableFetch<QueryResultItem> | null>;
434
+ /**
435
+ * The grid's own datatable, for {@link reload}. A `viewChild` is safe here: the `@if` concern above
436
+ * is about hosts holding this grid, while this is the grid's own template, read only on demand.
437
+ */
438
+ private readonly datatable;
433
439
  /**
434
440
  * Why the component renders its own failure instead of only reporting one.
435
441
  *
@@ -544,6 +550,13 @@ export declare class SparkQueryGridComponent {
544
550
  * Every column that ships is drawn (#264): there is no shipped-but-hidden column.
545
551
  */
546
552
  allColumns: import("@angular/core").Signal<QueryColumn[]>;
553
+ /** The internal name of the per-row ⋮ menu's column; never shown or announced (its `label` is "Actions"). */
554
+ readonly rowActionsColumn = "__sparkRowActions";
555
+ /**
556
+ * The datatable's `[labels]`: the resize handle and its options dialog, translated. The column
557
+ * each string names comes from `bsDatatableColumnLabel` in the template. See `sparkDatatableLabels`.
558
+ */
559
+ datatableLabels: import("@angular/core").Signal<import("@mintplayer/ng-spark/services").SparkDatatableLabels>;
547
560
  /**
548
561
  * True when rows do not come from this component's own fetch.
549
562
  *
@@ -554,8 +567,16 @@ export declare class SparkQueryGridComponent {
554
567
  * before the host had anything to bind.
555
568
  */
556
569
  hasExternalData: import("@angular/core").Signal<boolean>;
557
- /** Whether an action's selection rule is satisfied right now. The server checks it again. */
570
+ /**
571
+ * Whether an action can run right now: its selection rule is satisfied, and the client method it
572
+ * requires (`requiresClient`) is registered and supported here. The server checks the rule again.
573
+ */
558
574
  isActionEnabled(action: CustomActionDefinition): boolean;
575
+ /**
576
+ * Why an action is disabled regardless of the selection, translated, for its tooltip: its required
577
+ * client method is missing or unsupported in this browser (Q9). Null when nothing stands in the way.
578
+ */
579
+ actionUnavailableReason(action: CustomActionDefinition): string | null;
559
580
  constructor();
560
581
  /**
561
582
  * Re-run the query, keeping the current page, sort and scroll position.
@@ -563,8 +584,15 @@ export declare class SparkQueryGridComponent {
563
584
  * Data-level on purpose: it re-seeds the fetch closure and nothing else. For a definition
564
585
  * change — new columns, a renamed query — the inputs themselves must change; that is the
565
586
  * expensive path. Inert when rows come from the host: there is nothing here to re-run.
587
+ *
588
+ * Through the datatable's own `reload()` (mintplayer-ng-bootstrap#407), which re-queries the
589
+ * current page and coalesces calls within a microtask. Swapping the `[fetch]` identity, the only
590
+ * way before it existed, also disarmed the datatable's reload dedupe. The swap stays as the
591
+ * fallback while the datatable is not rendered (loading), where a fresh closure is what counts.
566
592
  */
567
- reload(): void;
593
+ reload(options?: {
594
+ resetPage?: boolean;
595
+ }): void;
568
596
  private onSearchChanged;
569
597
  /**
570
598
  * Replaces the fetched columns only when they actually differ.
@@ -627,11 +655,13 @@ export declare class SparkQueryGridComponent {
627
655
  */
628
656
  protected onFilterChange(detail: FilterChangeDetail): void;
629
657
  /**
630
- * Back to page 1 and a fresh fetch identity, exactly as a new search term does.
658
+ * Back to page 1 and a forced re-fetch.
631
659
  *
632
660
  * Both halves matter: the old page number means nothing against a different result set, and the
633
661
  * datatable dedupes reloads by `(page, perPage, sort)` — none of which a filter changes — so
634
- * without a new fetch identity the request is silently never made.
662
+ * without forcing it the request is silently never made. `resetPage` makes the datatable fetch
663
+ * page 1 itself: the settings binding reaches it only on the next change detection, after the
664
+ * reload already fetched.
635
665
  */
636
666
  private onFilterChanged;
637
667
  /**
@@ -858,6 +888,8 @@ export declare class SparkQueryCardComponent {
858
888
  protected readonly toolbarActions: import("@angular/core").Signal<SparkQueryToolbarAction[]>;
859
889
  protected actionClass(action: SparkQueryToolbarAction): string;
860
890
  protected isEnabled(action: SparkQueryToolbarAction): boolean;
891
+ /** The tooltip of an action disabled for want of its client method (`requiresClient`); null otherwise. */
892
+ protected unavailableReason(action: SparkQueryToolbarAction): string | null;
861
893
  protected run(action: SparkQueryToolbarAction): void;
862
894
  protected readonly selection: import("@angular/core").Signal<QueryResultItem[]>;
863
895
  static ɵfac: i0.ɵɵFactoryDeclaration<SparkQueryCardComponent, never>;
@@ -169,6 +169,12 @@ export interface CustomActionDefinition {
169
169
  * `/po/new`, the edit page and `/po/delete-many`, never `/actions/execute`. Absent for a custom action.
170
170
  */
171
171
  isDefault?: boolean;
172
+ /**
173
+ * The client method the action needs in the browser (`provideSparkClientMethods`), e.g.
174
+ * `'webauthn.create'`. When it is not registered, or its `supported()` says no, the action is shown
175
+ * disabled with the reason as its tooltip. Advisory: the server still handles a cancelled step.
176
+ */
177
+ requiresClient?: string;
172
178
  }
173
179
  /**
174
180
  * Whether a grid lets the user tick rows — what `<bs-datatable>` renders. There is no single
@@ -665,19 +671,41 @@ export interface LookupReferenceValue {
665
671
  isActive: boolean;
666
672
  extra?: Record<string, unknown>;
667
673
  }
674
+ /**
675
+ * The option a cancelled retry step answers with (`RetryResult.CancelOption` on the server): the
676
+ * modal's own Cancel button or its dismissal on a `cancellable` prompt, and a client method that did
677
+ * not answer. An identifier, never a label: the button shows `common.cancel` in the user's language.
678
+ */
679
+ export declare const SPARK_RETRY_CANCEL = "Cancel";
668
680
  export interface RetryActionPayload {
669
681
  type: 'retry-action';
670
682
  step: number;
671
683
  title: string;
672
684
  message?: string;
685
+ /** The action's own options, shown as given. Never `'Cancel'`: see {@link cancellable}. */
673
686
  options: string[];
674
687
  defaultOption?: string;
675
688
  persistentObject?: PersistentObject;
689
+ /**
690
+ * Whether the modal adds its own Cancel button, labelled `common.cancel`, which, like closing the
691
+ * modal, answers {@link SPARK_RETRY_CANCEL}. Without it a closed modal abandons the request.
692
+ */
693
+ cancellable?: boolean;
694
+ /**
695
+ * Set when the server asks for a client method (`IRetryAccessor.Invoke`) instead of a choice: the
696
+ * name a method was registered under with `provideSparkClientMethods`. No modal is shown then.
697
+ */
698
+ clientMethod?: string;
699
+ /** The client method's argument, as the server serialized it. */
700
+ arguments?: unknown;
676
701
  }
677
702
  export interface RetryActionResult {
678
703
  step: number;
704
+ /** The option chosen. For a client-method step `'OK'` when it answered, `'Cancel'` otherwise. */
679
705
  option: string;
680
706
  persistentObject?: PersistentObject;
707
+ /** What the client method resolved with; absent for an ordinary prompt and for a cancelled step. */
708
+ value?: unknown;
681
709
  }
682
710
  export interface EntityPermissions {
683
711
  /**
@@ -13,6 +13,7 @@ export declare class SparkPoDetailComponent {
13
13
  private readonly queryRefresh;
14
14
  private readonly attributeRefresh;
15
15
  protected readonly lang: SparkLanguageService;
16
+ private readonly clientMethods;
16
17
  protected readonly rendererRegistry: import("@mintplayer/ng-spark/renderers").SparkAttributeRendererRegistration[];
17
18
  /**
18
19
  * Add-on panels and action-bar buttons (#460, `SPARK_DETAIL_PANELS` / `SPARK_DETAIL_ACTIONS`).
@@ -118,6 +119,8 @@ export declare class SparkPoDetailComponent {
118
119
  resolvedTabs: import("@angular/core").Signal<AttributeTab[]>;
119
120
  groupsForTab(tab: AttributeTab): AttributeGroup[];
120
121
  attrsForGroup(group: AttributeGroup): EntityAttributeDefinition[];
122
+ /** Whether the attribute's renderer asks for the whole row, without a label (`fullWidth`). */
123
+ isFullWidthRenderer(attr: EntityAttributeDefinition): boolean;
121
124
  getDetailRendererComponent(attr: EntityAttributeDefinition): Type<any> | null;
122
125
  /** Inputs of an AsDetail row renderer (`rowComponent`): the row and the object that owns it. */
123
126
  getRowRendererInputs(renderer: SparkResolvedRowRenderer, row: Record<string, any>, item: PersistentObject): Record<string, any>;
@@ -146,6 +149,11 @@ export declare class SparkPoDetailComponent {
146
149
  * a slow action and a broken one became indistinguishable.
147
150
  */
148
151
  runningAction: import("@angular/core").WritableSignal<string | null>;
152
+ /**
153
+ * Why an action cannot run in this browser, translated, for its tooltip: the client method it
154
+ * requires (`requiresClient`) is not registered or not supported here (Q9). Null otherwise.
155
+ */
156
+ protected customActionUnavailableReason(action: CustomActionDefinition): string | null;
149
157
  onCustomAction(action: CustomActionDefinition): Promise<void>;
150
158
  onEdit(): void;
151
159
  onDelete(): Promise<void>;
@@ -516,6 +516,8 @@ export declare class SparkReferencePickerComponent {
516
516
  searchTerm: string;
517
517
  /** The picker lists query rows, so its columns are the query's: `showedOn` includes Query (#264; not None). */
518
518
  visibleAttributes: import("@angular/core").Signal<import("@mintplayer/ng-spark/models").EntityAttributeDefinition[]>;
519
+ /** The resize handle and its options dialog, translated; columns are named by `bsDatatableColumnLabel`. */
520
+ datatableLabels: import("@angular/core").Signal<import("@mintplayer/ng-spark/services").SparkDatatableLabels>;
519
521
  rows: import("@angular/core").Signal<QueryResultItem[]>;
520
522
  displayValue: import("@angular/core").Signal<string>;
521
523
  open(): Promise<void>;
@@ -85,6 +85,8 @@ export declare class SparkQueryListComponent {
85
85
  protected readonly toolbarActions: import("@angular/core").Signal<SparkQueryToolbarAction[]>;
86
86
  protected toolbarActionClass(action: SparkQueryToolbarAction): string;
87
87
  protected isToolbarActionEnabled(action: SparkQueryToolbarAction): boolean;
88
+ /** The tooltip of an action disabled for want of its client method (`requiresClient`); null otherwise. */
89
+ protected toolbarActionUnavailableReason(action: SparkQueryToolbarAction): string | null;
88
90
  protected runToolbarAction(action: SparkQueryToolbarAction): void;
89
91
  protected isActionEnabled(action: CustomActionDefinition): boolean;
90
92
  isStreaming: import("@angular/core").WritableSignal<boolean>;
@@ -1,3 +1,4 @@
1
+ import * as i0 from "@angular/core";
1
2
  import { InjectionToken, InputSignal, Provider, Type } from "@angular/core";
2
3
  import { EntityAttributeDefinition, EntityType, PersistentObject, PersistentObjectAttribute, QueryResultItem, QueryResultItemValue, SparkCellColumn } from "@mintplayer/ng-spark/models";
3
4
  /**
@@ -136,7 +137,17 @@ export interface SparkAttributeRendererRegistration {
136
137
  * give it, which is the whole reason the renderer itself cannot be used here.
137
138
  */
138
139
  filterLabel?: (value: unknown) => string;
140
+ /**
141
+ * The detail page draws the renderer across the whole row, with no label: for text blocks such
142
+ * as the core `paragraph` renderer, which are body text rather than a labelled value.
143
+ */
144
+ fullWidth?: boolean;
139
145
  }
146
+ /**
147
+ * The renderers ng-spark ships itself, available in every app without registration. An app's own
148
+ * registration of the same name wins (it comes first in the list).
149
+ */
150
+ export declare const sparkCoreRenderers: readonly SparkAttributeRendererRegistration[];
140
151
  export declare const SPARK_ATTRIBUTE_RENDERERS: InjectionToken<SparkAttributeRendererRegistration[]>;
141
152
  /**
142
153
  * Register custom attribute renderers globally.
@@ -148,6 +159,42 @@ export declare const SPARK_ATTRIBUTE_RENDERERS: InjectionToken<SparkAttributeRen
148
159
  * ])
149
160
  */
150
161
  export declare function provideSparkAttributeRenderers(renderers: SparkAttributeRendererRegistration[]): Provider;
162
+ /**
163
+ * The core `paragraph` renderer (generic passkeys page, D5): a read-only string shown as body text,
164
+ * full width and without a label — an explanatory text block on a persistent object, filled from
165
+ * translations by the actions class. Pair it with `showedOn: PersistentObject` so it never becomes a
166
+ * grid column.
167
+ *
168
+ * **Escaped by default.** The value is interpolated, so markup in it is shown as text. A blank line
169
+ * starts a new paragraph and a single newline is a line break.
170
+ *
171
+ * `"rendererOptions": { "sanitize": false }` renders the value as HTML instead, through Angular's
172
+ * `[innerHTML]`, whose sanitizer still strips scripts, event handlers and `javascript:` URLs. There is
173
+ * deliberately no `bypassSecurityTrustHtml` anywhere on this path: the opt-out is "allow markup",
174
+ * never "allow script".
175
+ */
176
+ export declare class SparkParagraphRendererComponent implements SparkAttributeDetailRenderer {
177
+ readonly value: import("@angular/core").InputSignal<any>;
178
+ readonly options: import("@angular/core").InputSignal<Record<string, any> | undefined>;
179
+ protected readonly text: import("@angular/core").Signal<string>;
180
+ /** Only an explicit `false` opts out of escaping; anything else, absent included, escapes. */
181
+ protected readonly asHtml: import("@angular/core").Signal<boolean>;
182
+ /** Paragraphs split on blank lines, each a list of its lines. */
183
+ protected readonly paragraphs: import("@angular/core").Signal<string[][]>;
184
+ static ɵfac: i0.ɵɵFactoryDeclaration<SparkParagraphRendererComponent, never>;
185
+ static ɵcmp: i0.ɵɵComponentDeclaration<SparkParagraphRendererComponent, "spark-paragraph-renderer", never, {
186
+ "value": {
187
+ "alias": "value";
188
+ "required": false;
189
+ "isSignal": true;
190
+ };
191
+ "options": {
192
+ "alias": "options";
193
+ "required": false;
194
+ "isSignal": true;
195
+ };
196
+ }, {}, never, never, true, never>;
197
+ }
151
198
  /** The row renderer of an AsDetail row type, resolved once per type (see `rowComponent`). */
152
199
  export interface SparkResolvedRowRenderer {
153
200
  component: Type<any>;
@@ -15,6 +15,7 @@ export declare class SparkRetryActionModalComponent {
15
15
  protected readonly retryActionService: RetryActionService;
16
16
  private readonly sparkService;
17
17
  colors: typeof Color;
18
+ protected readonly cancel = "Cancel";
18
19
  isOpen: import("@angular/core").Signal<boolean>;
19
20
  /**
20
21
  * EntityType definition for the incoming PO — fetched lazily via SparkService so the
@@ -102,6 +102,7 @@ export declare class SparkService {
102
102
  */
103
103
  private static readonly MAX_RETRY_DEPTH;
104
104
  private readonly dispatcher;
105
+ private readonly clientMethods;
105
106
  getEntityTypes(): Promise<EntityType[]>;
106
107
  /**
107
108
  * One entity type, shaped by the caller's attribute rights. `purpose` narrows it for one form (#264, G1/G2):
@@ -492,4 +493,29 @@ export declare class SparkReturnNavigationService {
492
493
  listRouteFor(entityTypeName: string): Promise<unknown[] | null>;
493
494
  static ɵfac: i0.ɵɵFactoryDeclaration<SparkReturnNavigationService, never>;
494
495
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
495
- }
496
+ }
497
+ /** The `<bs-datatable>` strings Spark translates: the column-resize handle and its options dialog. */
498
+ export interface SparkDatatableLabels {
499
+ resizeColumn: (column: string) => string;
500
+ resizeColumnHint: string;
501
+ resizeColumnOptions: (column: string) => string;
502
+ narrowerColumn: (column: string) => string;
503
+ widerColumn: (column: string) => string;
504
+ columnWidth: (px: number) => string;
505
+ fitColumn: string;
506
+ resetColumn: string;
507
+ }
508
+ /**
509
+ * The `[labels]` a Spark `<bs-datatable>` passes so the column-resize handle, its keymap
510
+ * announcement and its resize options dialog (ng-bootstrap 22.22.0 / web-components 2.19.0) speak
511
+ * the viewer's language.
512
+ *
513
+ * The `column` these formatters receive is the column's label: every Spark grid binds
514
+ * `bsDatatableColumnLabel` to the header's translated text (and the row-actions column to
515
+ * "Actions"), so the datatable no longer falls back to the internal name. The keys omitted here
516
+ * keep the web component's English defaults.
517
+ *
518
+ * Every translation is read EAGERLY, so a `computed` that calls this tracks the language and the
519
+ * translation map, and hands the datatable a new object — which re-renders it — when either changes.
520
+ */
521
+ export declare function sparkDatatableLabels(lang: SparkLanguageService): SparkDatatableLabels;