@mintplayer/ng-spark 22.24.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.
Files changed (46) hide show
  1. package/README.md +15 -0
  2. package/fesm2022/mintplayer-ng-spark-client-operations.mjs +5 -3
  3. package/fesm2022/mintplayer-ng-spark-client-operations.mjs.map +1 -1
  4. package/fesm2022/mintplayer-ng-spark-contributions.mjs +721 -0
  5. package/fesm2022/mintplayer-ng-spark-contributions.mjs.map +1 -0
  6. package/fesm2022/mintplayer-ng-spark-grid.mjs +131 -4
  7. package/fesm2022/mintplayer-ng-spark-grid.mjs.map +1 -1
  8. package/fesm2022/mintplayer-ng-spark-history.mjs +1 -14
  9. package/fesm2022/mintplayer-ng-spark-history.mjs.map +1 -1
  10. package/fesm2022/mintplayer-ng-spark-models.mjs +41 -2
  11. package/fesm2022/mintplayer-ng-spark-models.mjs.map +1 -1
  12. package/fesm2022/mintplayer-ng-spark-moderation.mjs +4 -4
  13. package/fesm2022/mintplayer-ng-spark-moderation.mjs.map +1 -1
  14. package/fesm2022/mintplayer-ng-spark-panels.mjs +9 -1
  15. package/fesm2022/mintplayer-ng-spark-panels.mjs.map +1 -1
  16. package/fesm2022/mintplayer-ng-spark-pipes.mjs +39 -3
  17. package/fesm2022/mintplayer-ng-spark-pipes.mjs.map +1 -1
  18. package/fesm2022/mintplayer-ng-spark-po-detail.mjs +15 -6
  19. package/fesm2022/mintplayer-ng-spark-po-detail.mjs.map +1 -1
  20. package/fesm2022/mintplayer-ng-spark-po-edit.mjs +924 -16
  21. package/fesm2022/mintplayer-ng-spark-po-edit.mjs.map +1 -1
  22. package/fesm2022/mintplayer-ng-spark-po-form.mjs +78 -20
  23. package/fesm2022/mintplayer-ng-spark-po-form.mjs.map +1 -1
  24. package/fesm2022/mintplayer-ng-spark-query-list.mjs +60 -5
  25. package/fesm2022/mintplayer-ng-spark-query-list.mjs.map +1 -1
  26. package/fesm2022/mintplayer-ng-spark-renderers.mjs +28 -1
  27. package/fesm2022/mintplayer-ng-spark-renderers.mjs.map +1 -1
  28. package/fesm2022/mintplayer-ng-spark-shell.mjs +31 -13
  29. package/fesm2022/mintplayer-ng-spark-shell.mjs.map +1 -1
  30. package/fesm2022/mintplayer-ng-spark.mjs +4 -1
  31. package/fesm2022/mintplayer-ng-spark.mjs.map +1 -1
  32. package/package.json +7 -2
  33. package/types/mintplayer-ng-spark-client-operations.d.ts +7 -1
  34. package/types/mintplayer-ng-spark-contributions.d.ts +231 -0
  35. package/types/mintplayer-ng-spark-grid.d.ts +35 -3
  36. package/types/mintplayer-ng-spark-history.d.ts +3 -10
  37. package/types/mintplayer-ng-spark-models.d.ts +60 -3
  38. package/types/mintplayer-ng-spark-panels.d.ts +36 -1
  39. package/types/mintplayer-ng-spark-pipes.d.ts +12 -1
  40. package/types/mintplayer-ng-spark-po-detail.d.ts +4 -1
  41. package/types/mintplayer-ng-spark-po-edit.d.ts +305 -1
  42. package/types/mintplayer-ng-spark-po-form.d.ts +64 -15
  43. package/types/mintplayer-ng-spark-query-list.d.ts +26 -1
  44. package/types/mintplayer-ng-spark-renderers.d.ts +44 -2
  45. package/types/mintplayer-ng-spark-shell.d.ts +24 -9
  46. package/types/mintplayer-ng-spark.d.ts +12 -0
@@ -3,7 +3,8 @@ import { Type } from "@angular/core";
3
3
  import { CdkDragDrop } from "@angular/cdk/drag-drop";
4
4
  import { Color } from "@mintplayer/ng-bootstrap";
5
5
  import { InMemoryTreeSelectProvider, TreeNode } from "@mintplayer/ng-bootstrap/tree-select";
6
- import { AttributeGroup, AttributeTab, ELookupDisplayType, EReferenceDisplayType, EntityAttributeDefinition, EntityPermissions, EntityType, LookupReference, LookupReferenceValue, PersistentObject, QueryResultItem, RefreshOverlay, RuleFailure, ValidationError } from "@mintplayer/ng-spark/models";
6
+ import { AttributeGroup, AttributeTab, ELookupDisplayType, EReferenceDisplayType, EntityAttributeDefinition, EntityPermissions, EntityType, LookupReference, LookupReferenceValue, PersistentObject, QueryResultItem, RefreshOverlay, RefreshTrigger, RuleFailure, ValidationError } from "@mintplayer/ng-spark/models";
7
+ import { SparkResolvedRowRenderer } from "@mintplayer/ng-spark/renderers";
7
8
  import { DatatableSettings } from "@mintplayer/ng-bootstrap/datatable";
8
9
  import { PaginationResponse } from "@mintplayer/pagination";
9
10
  /** What the coordinator needs from its host, so it can be tested without mounting a form. */
@@ -35,6 +36,8 @@ declare class RefreshCoordinator {
35
36
  private sequence;
36
37
  private settled;
37
38
  private pending;
39
+ /** Debounce timers for `ValueChanged` free text, keyed by path. A path here is also in `pending`. */
40
+ private timers;
38
41
  constructor(host: RefreshCoordinatorHost);
39
42
  /** Whether a refresh is in flight. */
40
43
  get isRefreshing(): boolean;
@@ -43,26 +46,66 @@ declare class RefreshCoordinator {
43
46
  * would otherwise issue a request per keystroke. Flushed by {@link blur} or {@link flush}.
44
47
  */
45
48
  markPending(attributeName: string): void;
46
- /** Sends a pending refresh for `attributeName`, if one was marked. */
49
+ /**
50
+ * Routes a change by its {@link RefreshDispatch}: send now, send once typing pauses, or wait for
51
+ * blur. The one entry point a form needs, so the three editors' policies live here.
52
+ */
53
+ dispatch(attributeName: string, mode: RefreshDispatch): Promise<void>;
54
+ /** Sends a pending refresh for `attributeName`, if one was marked (or is waiting on its debounce). */
47
55
  blur(attributeName: string): Promise<void>;
48
56
  /**
49
- * Sends every refresh still marked pending. Called before save, so a value typed and never blurred
50
- * — the user tabbing straight to the save button — is still reflected before the object goes.
57
+ * Sends every refresh still marked pending, including any waiting on a debounce. Called before
58
+ * save, so a value typed and never blurred — the user tabbing straight to the save button — is
59
+ * still reflected before the object goes.
51
60
  */
52
61
  flush(): Promise<void>;
53
- /** Sends a refresh immediately — discrete editors, where every change is a committed one. */
54
- trigger(attributeName: string): Promise<void>;
62
+ /** Drops every pending mark and debounce timer without sending — the form is going away. */
63
+ dispose(): void;
64
+ /**
65
+ * Sends a refresh — immediately for discrete editors, where every change is a committed one.
66
+ *
67
+ * With `debounceMs`, the send waits until `attributeName` has been quiet for that long; each call
68
+ * restarts the wait, so a burst of keystrokes costs one request. Until it fires, the path counts as
69
+ * pending, so {@link blur} and {@link flush} send it straight away instead of waiting out the timer.
70
+ */
71
+ trigger(attributeName: string, options?: {
72
+ debounceMs?: number;
73
+ }): Promise<void>;
74
+ private clearTimer;
55
75
  }
76
+ /** How long `ValueChanged` free text waits for typing to pause before refreshing — like the search box. */
77
+ declare const SPARK_REFRESH_DEBOUNCE_MS = 300;
56
78
  /** The subset of an attribute definition that decides how its editor behaves. */
57
79
  interface RefreshTriggerShape {
58
80
  dataType?: string;
59
81
  lookupReferenceType?: string;
60
82
  isArray?: boolean;
83
+ triggersRefresh?: RefreshTrigger;
61
84
  }
85
+ /** When a change sends its refresh: on the change itself, on blur, or never. */
86
+ type EffectiveRefreshTrigger = 'change' | 'blur' | 'none';
87
+ /** How {@link RefreshCoordinator.dispatch} handles a change. */
88
+ type RefreshDispatch = 'immediate' | 'debounced' | 'blur';
89
+ /**
90
+ * Resolves the declared `triggersRefresh` against the editor the attribute renders as.
91
+ *
92
+ * - `None` / absent → `'none'`.
93
+ * - `Auto` → `'change'` for a discrete editor, `'blur'` for free text (the original behaviour).
94
+ * - `ValueChanged` → `'change'` (debounced for free text — see {@link refreshDispatch}).
95
+ * - `Blur` → `'blur'`, except on a discrete editor, which has no meaningful blur and so acts as
96
+ * `ValueChanged`. The server's `--spark-verify-model` warns about that declaration.
97
+ */
98
+ declare function effectiveTrigger(attr: RefreshTriggerShape | undefined): EffectiveRefreshTrigger;
99
+ /**
100
+ * How a change to `attr` is sent, or `null` when it sends nothing. A `'change'` trigger on free
101
+ * text is debounced; on a discrete editor it is immediate.
102
+ */
103
+ declare function refreshDispatch(attr: RefreshTriggerShape | undefined): RefreshDispatch | null;
104
+ /** Whether the change to `attr` is sent immediately (a discrete editor with a change trigger). */
105
+ declare function triggersImmediately(attr: RefreshTriggerShape | undefined): boolean;
62
106
  /**
63
- * Editors where every change is a deliberate, committed one, so a refresh fires immediately.
64
- * Everything else is free text, where firing per keystroke would be unacceptable and the refresh
65
- * waits for blur.
107
+ * Editors where every change is a deliberate, committed one. Everything else is free text, where
108
+ * firing per keystroke would be unacceptable.
66
109
  *
67
110
  * ⚠️ This asks how the attribute is **rendered**, not what its `dataType` says, and the difference
68
111
  * is not academic. A lookup attribute carries the data type of its *key* — Fleet's `Car.Status` is
@@ -70,24 +113,25 @@ interface RefreshTriggerShape {
70
113
  * classifies a `<bs-select>` as free text. It then waits for a blur that a select never emits, and
71
114
  * the refresh simply never fires: no request, no error, nothing to see.
72
115
  */
73
- declare function triggersImmediately(attr: RefreshTriggerShape | undefined): boolean;
116
+ declare function isDiscreteEditor(attr: RefreshTriggerShape | undefined): boolean;
74
117
  /** Empty overlay, so callers do not have to spell the type. */
75
118
  declare const NO_OVERLAY: RefreshOverlay;
76
119
  /**
77
120
  * A refresh a form embedded in another form is asking its host to issue on its behalf.
78
121
  *
79
- * `immediate` mirrors the distinction the host's own editors make: a discrete editor fires on
80
- * change, free text only marks itself pending and fires on blur.
122
+ * `dispatch` carries the decision the child's own editor made from its declared `triggersRefresh`
123
+ * — send now, send once typing pauses, or wait for blur — so the host applies exactly the semantics
124
+ * it would have applied to an editor of its own.
81
125
  */
82
126
  export interface NestedTriggerRequest {
83
127
  /** The full path the server addresses, e.g. `Gate.ProjectMode`. */
84
128
  path: string;
85
- immediate: boolean;
129
+ dispatch: RefreshDispatch;
86
130
  }
87
131
  export declare class SparkPoFormComponent {
88
132
  private readonly sparkService;
89
133
  private readonly translations;
90
- private readonly rendererRegistry;
134
+ protected readonly rendererRegistry: import("@mintplayer/ng-spark/renderers").SparkAttributeRendererRegistration[];
91
135
  entityType: import("@angular/core").InputSignal<EntityType | null>;
92
136
  formData: import("@angular/core").ModelSignal<Record<string, any>>;
93
137
  validationErrors: import("@angular/core").InputSignal<ValidationError[]>;
@@ -200,6 +244,8 @@ export declare class SparkPoFormComponent {
200
244
  getEditRendererInputs(component: Type<any>, attr: EntityAttributeDefinition): Record<string, any>;
201
245
  /** Column renderer for a cell of an AsDetail sub-table (so embedded rows honor `col.renderer` too). */
202
246
  getAsDetailCellRendererComponent(col: EntityAttributeDefinition): Type<any> | null;
247
+ /** Inputs of an AsDetail row renderer (`rowComponent`): the row and the object being edited. */
248
+ getRowRendererInputs(renderer: SparkResolvedRowRenderer, row: Record<string, any>): Record<string, any>;
203
249
  getAsDetailCellRendererInputs(component: Type<any>, row: Record<string, any>, col: EntityAttributeDefinition): Record<string, any>;
204
250
  /** Edit-renderer for an inline AsDetail cell (so inline editing honors `col.renderer`, not just display). */
205
251
  getAsDetailCellEditRenderer(col: EntityAttributeDefinition): Type<any> | null;
@@ -259,7 +305,10 @@ export declare class SparkPoFormComponent {
259
305
  */
260
306
  private applyNestedResponse;
261
307
  onInlineCellBlur(attr: EntityAttributeDefinition, rowIndex: number, col: EntityAttributeDefinition): void;
262
- /** Blur handler for free-text editors — sends the refresh their keystrokes only marked pending. */
308
+ /**
309
+ * Blur handler for free-text editors — sends the refresh their keystrokes only marked pending, or
310
+ * cuts short a `ValueChanged` debounce that is still waiting.
311
+ */
263
312
  onFieldBlur(attr: EntityAttributeDefinition): void;
264
313
  private noteChange;
265
314
  /** `Gate.ProjectMode` — the index-free counterpart of the inline grid's `Jobs[1].Kind`. */
@@ -3,7 +3,7 @@ import { TemplateRef } from "@angular/core";
3
3
  import { Color } from "@mintplayer/ng-bootstrap";
4
4
  import { SparkLanguageService } from "@mintplayer/ng-spark/services";
5
5
  import { SparkQueryToolbarAction } from "@mintplayer/ng-spark/grid";
6
- import { CustomActionDefinition, QueryColumn, QueryResultItem, SparkDeletedFilter } from "@mintplayer/ng-spark/models";
6
+ import { CustomActionDefinition, QueryColumn, QueryColumnFilter, QueryResultItem, SparkDeletedFilter } from "@mintplayer/ng-spark/models";
7
7
  import { SparkQueryListContext } from "@mintplayer/ng-spark/panels";
8
8
  /**
9
9
  * The routed query page: chrome around one {@link SparkQueryGridComponent}.
@@ -96,6 +96,31 @@ export declare class SparkQueryListComponent {
96
96
  */
97
97
  protected readonly gridData: import("@angular/core").Signal<QueryResultItem[] | null>;
98
98
  constructor();
99
+ /**
100
+ * The parent the URL scopes the query to (`?parentId=…&parentType=…`), sent exactly as a sub-query
101
+ * sends its container. Both or neither: one without the other is ignored, as the server does.
102
+ */
103
+ protected readonly urlParentId: import("@angular/core").WritableSignal<string>;
104
+ protected readonly urlParentType: import("@angular/core").WritableSignal<string>;
105
+ /**
106
+ * Column filters from the URL: every other query-string parameter, `?Language=en&Script=Latn`
107
+ * (repeat a name for several values). The grid applies only those naming an attribute of the
108
+ * query's type; the rest are ignored. This is the contributions History link's shape, and works for
109
+ * any query.
110
+ */
111
+ protected readonly urlFilters: import("@angular/core").WritableSignal<QueryColumnFilter[]>;
112
+ /** The URL filters the grid applied, as removable chips. */
113
+ protected readonly activeUrlFilters: import("@angular/core").Signal<QueryColumnFilter[]>;
114
+ /** Query-string names the page or the row links own, never column filters. */
115
+ private static readonly reservedParams;
116
+ private applyUrlScope;
117
+ /** Drops one URL filter (its query-string parameter); the grid refetches. */
118
+ protected clearUrlFilter(name: string): void;
119
+ /** Drops the parent and every URL filter. */
120
+ protected clearUrlScope(): void;
121
+ protected filterValues(filter: QueryColumnFilter): string;
122
+ /** The column's label for a chip: the query's own column label, else the attribute's, else its name. */
123
+ protected filterLabel(name: string): string;
99
124
  private onParamsChange;
100
125
  /**
101
126
  * A load failure has to render, not just be swallowed: a denied query answers 404 (audit M-3, so
@@ -1,5 +1,5 @@
1
1
  import { InjectionToken, InputSignal, Provider, Type } from "@angular/core";
2
- import { EntityAttributeDefinition, PersistentObject, PersistentObjectAttribute, QueryResultItem, QueryResultItemValue, SparkCellColumn } from "@mintplayer/ng-spark/models";
2
+ import { EntityAttributeDefinition, EntityType, PersistentObject, PersistentObjectAttribute, QueryResultItem, QueryResultItemValue, SparkCellColumn } from "@mintplayer/ng-spark/models";
3
3
  /**
4
4
  * Drops entries the component doesn't declare, so every contract member is
5
5
  * genuinely optional — NgComponentOutlet throws on an undeclared input.
@@ -72,6 +72,21 @@ export interface SparkAttributeColumnRenderer {
72
72
  */
73
73
  item?: InputSignal<QueryResultItem | Record<string, any> | undefined>;
74
74
  }
75
+ /**
76
+ * Contract for AsDetail **row** renderers (`rowComponent` of a registration): drawn once per row of an
77
+ * AsDetail table, on the detail page and in the edit form, for the row-type attributes carrying the
78
+ * renderer — which are then not drawn as columns.
79
+ */
80
+ export interface SparkAttributeRowRenderer {
81
+ /** The row: a flat record of the row's values (reserved `__spark…` keys included). */
82
+ row?: InputSignal<Record<string, any>>;
83
+ /** The row-type attributes carrying this renderer, in model order. */
84
+ attributes?: InputSignal<EntityAttributeDefinition[]>;
85
+ /** `rendererOptions` of the first of them. */
86
+ options?: InputSignal<Record<string, any> | undefined>;
87
+ /** The id of the object that owns the AsDetail list (undefined on a create page). */
88
+ ownerId?: InputSignal<string | undefined>;
89
+ }
75
90
  /**
76
91
  * Contract for edit-form renderers (spark-po-form on create/edit pages).
77
92
  * Replaces the default <input> for this attribute.
@@ -98,6 +113,16 @@ export interface SparkAttributeRendererRegistration {
98
113
  columnComponent?: Type<any> | null;
99
114
  /** Optional component for create/edit forms. Must implement SparkAttributeEditRenderer. When omitted, the default input is used. */
100
115
  editComponent?: Type<any>;
116
+ /**
117
+ * A **row** renderer for AsDetail tables (the PO detail page and the edit form). Attributes of a row
118
+ * type that carry this renderer are not drawn as columns; instead the component is drawn ONCE per
119
+ * row, under the row's first cell, given all of them. Must implement {@link SparkAttributeRowRenderer}.
120
+ *
121
+ * For facts about a row rather than columns of it — contributions' "by Alice · 3 days ago ·
122
+ * History (4)" line collapses three read-only attributes into one. `rendererOptions` are taken from
123
+ * the first such attribute (a library writes the same options on each).
124
+ */
125
+ rowComponent?: Type<any>;
101
126
  /**
102
127
  * Relabels this column's values in a filter panel (#431).
103
128
  *
@@ -122,4 +147,21 @@ export declare const SPARK_ATTRIBUTE_RENDERERS: InjectionToken<SparkAttributeRen
122
147
  * { name: 'color-swatch', detailComponent: ColorDetailComponent, columnComponent: ColorColumnComponent },
123
148
  * ])
124
149
  */
125
- export declare function provideSparkAttributeRenderers(renderers: SparkAttributeRendererRegistration[]): Provider;
150
+ export declare function provideSparkAttributeRenderers(renderers: SparkAttributeRendererRegistration[]): Provider;
151
+ /** The row renderer of an AsDetail row type, resolved once per type (see `rowComponent`). */
152
+ export interface SparkResolvedRowRenderer {
153
+ component: Type<any>;
154
+ /** The row-type attributes carrying the renderer, in model order. */
155
+ attributes: EntityAttributeDefinition[];
156
+ /** `rendererOptions` of the first of them. */
157
+ options: Record<string, any> | undefined;
158
+ }
159
+ /** Whether `attribute` is drawn by a row renderer (and therefore not as a column). */
160
+ export declare function isRowRendered(attribute: EntityAttributeDefinition, registry: readonly SparkAttributeRendererRegistration[] | null | undefined): boolean;
161
+ /**
162
+ * The first row renderer the row type's visible attributes name, or null. One per row: a row type
163
+ * whose attributes name two different row renderers gets the first in model order.
164
+ */
165
+ export declare function resolveRowRenderer(rowType: EntityType | null | undefined, registry: readonly SparkAttributeRendererRegistration[] | null | undefined): SparkResolvedRowRenderer | null;
166
+ /** The input bag for a row renderer, filtered to what the component declares. */
167
+ export declare function rowRendererInputs(renderer: SparkResolvedRowRenderer, row: Record<string, any>, ownerId: string | undefined): Record<string, any>;
@@ -1,6 +1,7 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { TemplateRef } from "@angular/core";
3
3
  import { BsShellState } from "@mintplayer/ng-bootstrap/shell";
4
+ import { BsThemeService, BsThemeToggleMode } from "@mintplayer/ng-bootstrap/theming";
4
5
  import { Breakpoint } from "@mintplayer/ng-bootstrap";
5
6
  import { ShellStateChangeEventDetail } from "@mintplayer/web-components/shell";
6
7
  import { ProgramUnitGroup } from "@mintplayer/ng-spark/models";
@@ -180,10 +181,16 @@ export declare class SparkShellMainHeaderDirective {
180
181
  * listens to `statechange` to keep the toggler's icon truthful in `auto` mode and only forces
181
182
  * `show`/`hide` on explicit toggles.
182
183
  *
183
- * Theming: the chrome colors are CSS custom properties with the classic dark-sidebar defaults —
184
- * `--spark-shell-topbar-bg`, `--spark-shell-sidebar-bg`, `--spark-shell-main-bg` — overridable on
185
- * the `<spark-shell>` element. `sidebarTheme` flips the sidebar's `data-bs-theme` (which is what
186
- * recolors the accordion internals across the shadow boundary) together with its default palette.
184
+ * Theming: the chrome colors are CSS custom properties —
185
+ * `--spark-shell-{topbar,sidebar,main}-{bg,color}` — declared per colour scheme under
186
+ * `[data-bs-theme=light]` / `[data-bs-theme=dark]` from Bootstrap tokens, so the whole shell follows
187
+ * the page's theme. An app restyles it by overriding those tokens, globally per scheme or on the
188
+ * `<spark-shell>` element.
189
+ *
190
+ * Colour mode: the shell injects `BsThemeService` itself, so 'auto' follows the OS live even when
191
+ * the topbar toggle is hidden with `[themeToggle]="false"` (an app may then place its own
192
+ * `<bs-theme-toggle>` elsewhere). The first paint is themed by `bs-theme-preboot.js` in the app's
193
+ * `index.html`, not by anything here.
187
194
  */
188
195
  export declare class SparkShellComponent {
189
196
  /** The sidebar heading. Ignored when a `*sparkShellSidebarHeader` slot is supplied. */
@@ -191,10 +198,18 @@ export declare class SparkShellComponent {
191
198
  /** Forwarded to `bs-shell`: below it the sidebar is an overlay drawer. */
192
199
  readonly breakpoint: import("@angular/core").InputSignal<Breakpoint>;
193
200
  /**
194
- * `data-bs-theme` for the sidebar — what flips the accordion's shadow-DOM internals between
195
- * palettes — plus the matching default background. `null` sets no theme (inherit the page's).
201
+ * Render the Auto / Light / Dark `bs-theme-toggle` in the topbar. `false` hides it; the theme
202
+ * service stays live either way.
203
+ */
204
+ readonly themeToggle: import("@angular/core").InputSignal<boolean>;
205
+ /**
206
+ * Instantiated here, not only through the toggle (PRD D3): without it, `[themeToggle]="false"`
207
+ * would leave 'auto' with no live `prefers-color-scheme` listener in Angular's view.
196
208
  */
197
- readonly sidebarTheme: import("@angular/core").InputSignal<"dark" | "light" | null>;
209
+ protected readonly theme: BsThemeService;
210
+ private readonly lang;
211
+ /** The toggle's cycle with Spark's translated labels (`theme.*` keys); icons stay ng-bootstrap's. */
212
+ protected readonly themeModes: import("@angular/core").Signal<readonly BsThemeToggleMode[]>;
198
213
  /** Forwarded to the menu: any changed value re-fetches the program units. */
199
214
  readonly reloadToken: import("@angular/core").InputSignal<unknown>;
200
215
  /** Extra sidebar tabs as data, for hosts that compute them; `*sparkShellTab` is the usual way. */
@@ -244,8 +259,8 @@ export declare class SparkShellComponent {
244
259
  "required": false;
245
260
  "isSignal": true;
246
261
  };
247
- "sidebarTheme": {
248
- "alias": "sidebarTheme";
262
+ "themeToggle": {
263
+ "alias": "themeToggle";
249
264
  "required": false;
250
265
  "isSignal": true;
251
266
  };
@@ -1,6 +1,18 @@
1
1
  import { InjectionToken, Provider, Signal } from "@angular/core";
2
2
  interface SparkConfig {
3
3
  baseUrl: string;
4
+ /**
5
+ * The concurrency-conflict notice and dialog on the edit page.
6
+ *
7
+ * `showChangedBy`: when true, "Changed by X" names whoever wrote the version merged against, but
8
+ * only when History resolves a display name for exactly that version (a `History/T` holder; one
9
+ * `POST /spark/po/revisions` request). Default false: no History request is made and no user is
10
+ * shown. A raw `ModifiedBy` user id is never shown in either mode. The "at T" time part is shown
11
+ * whenever the object carries `ModifiedAt`.
12
+ */
13
+ conflictDialog?: {
14
+ showChangedBy?: boolean;
15
+ };
4
16
  }
5
17
  export declare const SPARK_CONFIG: InjectionToken<SparkConfig>;
6
18
  export declare const defaultSparkConfig: SparkConfig;