@openmfp/ngx 0.18.10 → 0.18.12

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.
@@ -1,11 +1,11 @@
1
- import * as _angular_core from '@angular/core';
2
- import { OnInit, OnDestroy, Type } from '@angular/core';
3
- import { FormGroup, FormControl } from '@angular/forms';
4
1
  import * as _openmfp_ngx from '@openmfp/ngx';
5
2
  import * as gridstack from 'gridstack';
6
3
  import { Breakpoint, GridStackOptions } from 'gridstack';
4
+ import * as _angular_core from '@angular/core';
5
+ import { OnInit, OnDestroy, Type, PipeTransform } from '@angular/core';
7
6
  import { GridStackEngine } from 'gridstack/dist/gridstack-engine';
8
7
  import { SafeHtml } from '@angular/platform-browser';
8
+ import { FormGroup, FormControl } from '@angular/forms';
9
9
 
10
10
  /** Subset of fields of a generic resource that the table/form components rely on. */
11
11
  interface GenericResource extends Record<string, unknown> {
@@ -136,241 +136,574 @@ interface FieldDefinition {
136
136
  * column/input of an entry. Mirrors `propertyField` naming for consistency.
137
137
  */
138
138
  propertyCollection?: FieldDefinition[];
139
+ /** Verb required to render this field (e.g. 'update', 'delete').
140
+ * Evaluated against the row's granted actions. Absent → always render. */
141
+ requirePermission?: string;
139
142
  }
140
143
 
141
- /** Table column definition extends `FieldDefinition` with optional column grouping. */
142
- interface TableFieldDefinition extends FieldDefinition {
143
- /** Groups this column visually with adjacent columns that share the same `name`. */
144
- group?: {
145
- /** Logical group identifier. */
146
- name: string;
147
- /** Group header label shown above the grouped cells. */
148
- label?: string;
149
- /** Separator placed between values in the same group cell. */
150
- delimiter?: string;
151
- /** When `true`, each value is rendered on its own line. */
152
- multiline?: boolean;
153
- };
154
- }
155
-
156
- type GroupBase = NonNullable<TableFieldDefinition['group']>;
157
- type ProcessedGroup = GroupBase & {
158
- fields?: TableFieldDefinition[];
159
- };
160
- type ProcessedTableFieldDefinition = Omit<TableFieldDefinition, 'group'> & {
161
- group?: ProcessedGroup;
144
+ type DashboardLanguage = 'en' | 'de';
145
+ declare const DASHBOARD_I18N_KEYS: {
146
+ readonly UNSAVED_CHANGES: "unsavedChanges";
147
+ readonly EDIT_CARDS: "editCards";
148
+ readonly EDIT_VIEW: "editView";
149
+ readonly ACTIONS: "actions";
150
+ readonly SAVE: "save";
151
+ readonly CANCEL: "cancel";
152
+ readonly DISCARD: "discard";
153
+ readonly DISCARD_CHANGES: "discardChanges";
154
+ readonly DISCARD_CONFIRM_BODY: "discardConfirmBody";
155
+ readonly UNSAVED_NAV_BODY: "unsavedNavBody";
156
+ readonly NO_CARDS_AVAILABLE: "noCardsAvailable";
157
+ readonly REMOVE_SECTION: "removeSection";
158
+ readonly REMOVE_CARD: "removeCard";
159
+ readonly RESIZABLE: "resizable";
162
160
  };
161
+ type DashboardI18nKey = (typeof DASHBOARD_I18N_KEYS)[keyof typeof DASHBOARD_I18N_KEYS];
163
162
 
164
- declare class DeclarativeTable<T extends GenericResource> {
165
- columns: _angular_core.InputSignal<TableFieldDefinition[]>;
166
- resources: _angular_core.InputSignal<T[]>;
167
- trackByPath: _angular_core.InputSignal<string>;
168
- totalItemsCount: _angular_core.InputSignal<number | undefined>;
169
- paginationLimit: _angular_core.InputSignal<number>;
170
- hasMore: _angular_core.InputSignal<boolean>;
171
- loadMode: _angular_core.InputSignal<"button" | "scroll" | "pager">;
172
- loadMoreButtonText: _angular_core.InputSignal<string>;
173
- height: _angular_core.InputSignal<number | undefined>;
174
- currentPage: _angular_core.InputSignal<number>;
175
- readonly buttonClick: _angular_core.OutputEmitterRef<ResourceFieldButtonClickEvent<T>>;
176
- readonly tableRowClicked: _angular_core.OutputEmitterRef<T>;
177
- readonly loadMoreResources: _angular_core.OutputEmitterRef<void>;
178
- readonly paginationLimitChanged: _angular_core.OutputEmitterRef<number>;
179
- readonly pageChange: _angular_core.OutputEmitterRef<number>;
180
- columnTrackBy: (column: TableFieldDefinition, index: number) => string | number | string[];
181
- rowTrackBy: (_index: number, item: T) => unknown;
182
- viewColumns: _angular_core.Signal<ProcessedTableFieldDefinition[]>;
183
- onRowClick(item: T): void;
184
- isPagerMode: _angular_core.Signal<boolean>;
185
- knowsTotal: _angular_core.Signal<boolean>;
186
- hasResults: _angular_core.Signal<boolean>;
187
- totalPages: _angular_core.Signal<number>;
188
- canPrev: _angular_core.Signal<boolean>;
189
- canNext: _angular_core.Signal<boolean>;
190
- goToPage(page: number): void;
191
- firstPage: () => void;
192
- prevPage: () => void;
193
- nextPage: () => void;
194
- lastPage: () => void;
195
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeclarativeTable<any>, never>;
196
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeTable<any>, "mfp-declarative-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "resources": { "alias": "resources"; "required": true; "isSignal": true; }; "trackByPath": { "alias": "trackByPath"; "required": false; "isSignal": true; }; "totalItemsCount": { "alias": "totalItemsCount"; "required": false; "isSignal": true; }; "paginationLimit": { "alias": "paginationLimit"; "required": false; "isSignal": true; }; "hasMore": { "alias": "hasMore"; "required": false; "isSignal": true; }; "loadMode": { "alias": "loadMode"; "required": false; "isSignal": true; }; "loadMoreButtonText": { "alias": "loadMoreButtonText"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; }, { "buttonClick": "buttonClick"; "tableRowClicked": "tableRowClicked"; "loadMoreResources": "loadMoreResources"; "paginationLimitChanged": "paginationLimitChanged"; "pageChange": "pageChange"; }, never, never, true, never>;
163
+ /**
164
+ * Holds the dashboard's current language and resolves translation keys for
165
+ * the dashboard chrome (toolbar buttons, dialogs, a11y labels). Provided at
166
+ * the `Dashboard` component level so every nested dashboard component shares
167
+ * the same language signal — child components inject the same instance and
168
+ * react to language changes automatically because `getTranslation` reads the
169
+ * signal on every call.
170
+ */
171
+ declare class DashboardI18nService {
172
+ readonly language: _angular_core.WritableSignal<DashboardLanguage>;
173
+ getTranslation(key: DashboardI18nKey): string;
174
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DashboardI18nService, never>;
175
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DashboardI18nService>;
197
176
  }
198
177
 
199
- /** Definition for a single form field rendered by `mfp-declarative-form`. */
200
- interface FormFieldDefinition {
201
- /** JSON-path key used to read and write the field value (e.g. `metadata.name`). */
202
- name: string;
203
- /** Display label shown above the input. */
204
- label: string;
205
- /** When `true`, passes the `required` attribute to the UI5 input shows a visual required indicator. Validation itself is the host's responsibility via `FormFieldErrors`. */
206
- required?: boolean;
207
- /** Fixed list of options rendered as a select/dropdown. */
208
- values?: string[];
209
- /** When `true`, the field is disabled (not interactive). */
210
- disabled?: boolean;
211
- /** Controls when `fieldChange` is emitted for this field. When omitted, `fieldChange` is never emitted. */
212
- validation?: 'onBlur' | 'onChange';
178
+ declare const CARD_TYPES: {
179
+ readonly WC: "wc";
180
+ readonly ANGULAR: "angular";
181
+ readonly SAP_UI: "sap-ui";
182
+ };
183
+ type CardsType = (typeof CARD_TYPES)[keyof typeof CARD_TYPES];
184
+ /** Configuration for a single card placed in the dashboard grid or a section. */
185
+ interface CardConfig {
186
+ /** Unique identifier for this card. Used as a stable key for position persistence. */
187
+ id: string;
188
+ /** Column span (1–12). Defaults to 12 when omitted. */
189
+ w?: number;
190
+ /** Row span number of CSS grid rows occupied (1 row = 10 px by default). Defaults to 100 when omitted. */
191
+ h?: number;
192
+ /** Starting column index (0-based). Omit to let the grid auto-place the card. */
193
+ x?: number;
194
+ /** Starting row index (0-based). Omit to let the grid auto-place the card. */
195
+ y?: number;
196
+ /** Maximum row span in edit mode. */
197
+ maxH?: number;
198
+ /** Maximum column span in edit mode. */
199
+ maxW?: number;
200
+ /** Minimum row span in edit mode. */
201
+ minH?: number;
202
+ /** Minimum column span in edit mode. */
203
+ minW?: number;
204
+ /** ID of the parent section. Omit to place the card in the loose-card grid. */
205
+ sectionId?: string;
213
206
  /**
214
- * Nested field definitions describing one item of an object collection.
215
- *
216
- * When set, this field represents an array of objects; the form renders it
217
- * as a stack of expandable/collapsible cards. Each card is a nested
218
- * `mfp-declarative-form` whose `fields` are the entries in
219
- * `propertyCollection`; an inline Add button appends entries and a trash
220
- * button removes them. Editing is live — no per-card Save/Cancel.
221
- *
222
- * The submitted value at this field's path is `Array<Record<string, unknown>>`,
223
- * with each entry keyed by the sub-fields' `name`s. When `required` is
224
- * `true`, the host is expected to require at least one entry in the array.
207
+ * Custom-element tag name (for `'wc'`/omitted), Angular component selector (for `'angular'`),
208
+ * or SAP UI5 component name (for `'sap-ui'`).
225
209
  */
226
- propertyCollection?: FormFieldDefinition[];
227
- }
228
- /** Event payload emitted each time a single form field value changes. */
229
- interface FormFieldChangeEvent {
230
- /** The `name` (JSON-path key) of the field that changed. */
231
- fieldProperty: string;
232
- /** The new value entered by the user. */
233
- value: unknown;
234
- }
235
- /** Map of field names to their current validation error messages (`null` = no error). */
236
- type FormFieldErrors = Record<string, string | null>;
237
-
238
- declare class DeclarativeForm<T extends GenericResource> {
239
- readonly fields: _angular_core.InputSignal<FormFieldDefinition[]>;
240
- readonly initialValues: _angular_core.InputSignal<T>;
241
- readonly fieldErrors: _angular_core.InputSignal<FormFieldErrors>;
242
- readonly fieldChange: _angular_core.OutputEmitterRef<FormFieldChangeEvent>;
243
- readonly formSubmit: _angular_core.OutputEmitterRef<T>;
244
- readonly formValueChange: _angular_core.OutputEmitterRef<Record<string, unknown>>;
245
- readonly form: FormGroup;
246
- protected readonly collectionSeeds: _angular_core.WritableSignal<Record<string, Record<string, unknown>[]>>;
247
- private readonly fb;
248
- constructor();
249
- setFormControlValue($event: Event, field: FormFieldDefinition): void;
250
- onCollectionValueChange(field: FormFieldDefinition, entries: Record<string, unknown>[]): void;
251
- getError(name: string): string | null;
252
- getValueState(name: string): 'None' | 'Negative';
253
- onFieldBlur(field: FormFieldDefinition): void;
254
- submit(): void;
255
- clear(): void;
256
- collectionEntries(field: FormFieldDefinition): Record<string, unknown>[];
257
- private rebuildControls;
258
- private setInitialValues;
259
- private buildOutputValue;
260
- private buildEntryGroup;
261
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeclarativeForm<any>, never>;
262
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeForm<any>, "mfp-declarative-form", never, { "fields": { "alias": "fields"; "required": true; "isSignal": true; }; "initialValues": { "alias": "initialValues"; "required": false; "isSignal": true; }; "fieldErrors": { "alias": "fieldErrors"; "required": false; "isSignal": true; }; }, { "fieldChange": "fieldChange"; "formSubmit": "formSubmit"; "formValueChange": "formValueChange"; }, never, never, true, never>;
263
- }
264
-
265
- /** Configuration for the create/edit resource form rendered inside the table card dialogs. */
266
- interface ResourceFormConfig {
210
+ component: string;
267
211
  /**
268
- * Ordered list of fields to render in the form. May be a plain array, or a
269
- * thunk returning a promise of the fields the thunk form is resolved lazily
270
- * when the dialog opens (e.g. to fetch dynamic select options on demand
271
- * rather than prefetching them on render).
212
+ * Render strategy for the card.
213
+ * - `'wc'` (default) creates a custom element and sets `componentInputs` as DOM properties.
214
+ * - `'angular'` — looks up the Angular registry; warns and renders nothing if not found.
215
+ * - `'sap-ui'` mounts via `window.sap.ui.require` + `ComponentContainer`.
272
216
  */
273
- fields: FormFieldDefinition[] | (() => Promise<FormFieldDefinition[]>);
274
- /** Dialog title shown in the header. */
217
+ type?: CardsType;
218
+ /** Key/value pairs passed to the rendered card. Behaviour depends on `type`. */
219
+ componentInputs?: Record<string, unknown>;
220
+ /** Human-readable label shown in the "Edit Cards" dialog. */
221
+ label?: string;
222
+ }
223
+ type MountCfg = Pick<CardConfig, 'type' | 'component' | 'componentInputs'>;
224
+ /** Configuration for a named horizontal section that groups cards. */
225
+ interface SectionConfig {
226
+ /** Unique identifier for this section. */
227
+ id: string;
228
+ /** Column span (1–12). Defaults to 12 when omitted. */
229
+ w?: number;
230
+ /** Section heading displayed in the UI. */
275
231
  title?: string;
276
- /** Label for the confirm/submit button. */
277
- confirmLabel?: string;
278
- /** Label for the cancel button. */
279
- cancelLabel?: string;
232
+ /** When `false`, the section and its cards are excluded from edit mode. Defaults to `true` when omitted. */
233
+ editable?: boolean;
280
234
  }
281
- /** Runtime validation and submit state passed to the table card from the host. */
282
- interface TableCardFormState {
283
- /** Map of field names to their current error messages. Any truthy error in the map disables the submit button. */
284
- fieldErrors?: FormFieldErrors;
235
+ /** Overrides for the two built-in dashboard toolbar buttons. */
236
+ interface DashboardButtonsSettings {
237
+ /** Partial override merged on top of the Edit View button defaults. */
238
+ editViewButton?: Partial<ButtonSettings>;
239
+ /** Partial override merged on top of the Edit Cards button defaults. */
240
+ editCardsButton?: Partial<ButtonSettings>;
285
241
  }
286
- /** Configuration for the delete-confirmation dialog. */
287
- interface DeleteResourceConfirmationConfig {
288
- /** Dialog title. */
289
- title?: string;
290
- /** Explanatory message shown below the title. */
291
- message?: string;
292
- /** Label for the confirm/delete button. */
293
- confirmLabel?: string;
294
- /** Label for the cancel button. */
295
- cancelLabel?: string;
242
+ /** Top-level configuration for the `<mfp-dashboard>` component. */
243
+ interface DashboardConfig {
244
+ /** Dashboard title rendered in the toolbar. */
245
+ title: string;
246
+ /** Optional subtitle shown below the title. */
247
+ description?: string;
248
+ /** URL of the background image applied to the dashboard host element. */
249
+ backgroundImageUrl?: string;
250
+ /** Overrides for the built-in Edit View and Edit Cards toolbar buttons. */
251
+ buttonsSettings?: DashboardButtonsSettings;
252
+ /** Extra action buttons rendered in the toolbar alongside the built-in ones. */
253
+ customActions?: ButtonSettings[];
254
+ /** When `true`, shows the Edit View button in the toolbar, allowing the user to enter edit mode. */
255
+ editable?: boolean;
256
+ /** When `true`, the Edit View button is rendered before the custom actions instead of after. Defaults to `false`. */
257
+ editButtonFirst?: boolean;
258
+ /** When provided, enable z-flow layout. */
259
+ zFlow?: {
260
+ /** Sets the height of each card in the z-flow layout. */
261
+ cardHeight: number;
262
+ };
296
263
  }
264
+
297
265
  /**
298
- * One entry in the {@link TableCardSearchConfig.filterTabs} strip rendered
299
- * above the table. Clicking a tab activates that filter; the host receives the
300
- * selected definition via the `filterTabChanged` output and is responsible for
301
- * applying the filter to its data set.
302
- *
303
- * The strip renders exactly the array of `FieldFilterDefinition` it receives
304
- * — no extra "All" / no-filter tab is auto-added. If the host wants such an
305
- * option it must author it as a regular filter entry.
266
+ * Layout strategy applied at each breakpoint when Gridstack changes column
267
+ * count. See ColumnOptions in gridstack/dist/types.d.ts:27 for the full set.
306
268
  */
307
- interface FieldFilterDefinition {
308
- /** Visible label rendered as the tab text. */
309
- label: string;
310
- /** Name of the property the value applies to. Passed through to the host. */
311
- property: string;
312
- /** Value compared against `property` when the host applies the filter. */
313
- value: string;
314
- /** When `true`, this tab is selected on initial render; otherwise the first tab is. */
315
- default?: boolean;
269
+ type LayoutStrategy = 'compact' | 'list' | 'none';
270
+ type DashboardBreakpoint = Readonly<Required<Pick<Breakpoint, 'w' | 'c'>> & {
271
+ layout: LayoutStrategy;
272
+ }>;
273
+
274
+ interface EngineProfile {
275
+ /** GridStack engine class, or undefined to use GridStack's native engine. */
276
+ engineClass: typeof GridStackEngine | undefined;
277
+ /** Column breakpoint table fed to GridStack columnOpts. */
278
+ breakpoints: readonly DashboardBreakpoint[];
279
+ /** Column counts for [sm, md, lg, xl] page size. Pushed to CSS vars so the section grids match. */
280
+ sectionColumns: readonly [number, number, number, number];
281
+ /** When true, all loose cards get a fixed h/maxH from the engine's config. */
282
+ fixedCardHeight: boolean;
283
+ /** When true, the XL-page width swap (3↔4) runs. */
284
+ xlWidthSwap: boolean;
285
+ /** When true, the origin position is rendered. */
286
+ renderOriginPosition: boolean;
316
287
  }
317
- /** Configuration for the inner `mfp-declarative-table`. */
318
- interface TableConfig {
319
- /** Column definitions. */
320
- fields: TableFieldDefinition[];
321
- /** Total number of items on the server (used by pagination). */
322
- totalItemsCount?: number;
323
- /** Page size in `pager` mode; batch size for the grow modes otherwise. */
324
- paginationLimit?: number;
325
- /** 1-based current page. Only used when `loadMode` is `'pager'`. */
326
- currentPage?: number;
327
- /** When `true`, the "Load More" control is shown. Grow modes only. */
328
- hasMore?: boolean;
329
- height?: number;
288
+
289
+ declare class Dashboard implements OnInit, OnDestroy {
290
+ static registerAngularComponents(componentTypes: Type<unknown>[]): void;
291
+ private readonly hostEl;
292
+ private readonly injector;
293
+ private readonly sanitizer;
294
+ protected readonly i18n: DashboardI18nService;
295
+ config: _angular_core.InputSignal<DashboardConfig>;
296
+ sections: _angular_core.ModelSignal<SectionConfig[]>;
297
+ cards: _angular_core.ModelSignal<CardConfig[]>;
298
+ availableCards: _angular_core.InputSignal<CardConfig[]>;
299
+ language: _angular_core.InputSignal<DashboardLanguage>;
300
+ readonly saved: _angular_core.OutputEmitterRef<{
301
+ sections: SectionConfig[];
302
+ cards: CardConfig[];
303
+ }>;
304
+ readonly actionButtonClick: _angular_core.OutputEmitterRef<{
305
+ event: MouseEvent;
306
+ action: ButtonSettings;
307
+ }>;
308
+ readonly unsavedChangesChange: _angular_core.OutputEmitterRef<boolean>;
309
+ protected readonly i18nKeys: {
310
+ readonly UNSAVED_CHANGES: "unsavedChanges";
311
+ readonly EDIT_CARDS: "editCards";
312
+ readonly EDIT_VIEW: "editView";
313
+ readonly ACTIONS: "actions";
314
+ readonly SAVE: "save";
315
+ readonly CANCEL: "cancel";
316
+ readonly DISCARD: "discard";
317
+ readonly DISCARD_CHANGES: "discardChanges";
318
+ readonly DISCARD_CONFIRM_BODY: "discardConfirmBody";
319
+ readonly UNSAVED_NAV_BODY: "unsavedNavBody";
320
+ readonly NO_CARDS_AVAILABLE: "noCardsAvailable";
321
+ readonly REMOVE_SECTION: "removeSection";
322
+ readonly REMOVE_CARD: "removeCard";
323
+ readonly RESIZABLE: "resizable";
324
+ };
325
+ /** True once the user has dragged/resized any grid item while in edit mode. */
326
+ private gridDirty;
327
+ private isXLPage;
328
+ editMode: _angular_core.WritableSignal<boolean>;
329
+ compactToolbar: _angular_core.WritableSignal<boolean>;
330
+ toolbarMenuOpen: _angular_core.WritableSignal<boolean>;
331
+ cardDialogOpen: _angular_core.WritableSignal<boolean>;
332
+ discardDialogOpen: _angular_core.WritableSignal<boolean>;
333
+ unsavedNavDialogOpen: _angular_core.WritableSignal<boolean>;
334
+ backgroundImageHeight: _angular_core.WritableSignal<number | null>;
335
+ dragOriginStyle: _angular_core.WritableSignal<{
336
+ top: string;
337
+ left: string;
338
+ width: string;
339
+ height: string;
340
+ } | null>;
341
+ protected hasUnsavedChanges: _angular_core.Signal<boolean>;
342
+ protected safeTitle: _angular_core.Signal<SafeHtml>;
343
+ protected safeDescription: _angular_core.Signal<SafeHtml | null>;
344
+ protected engineProfile: _angular_core.Signal<EngineProfile>;
345
+ protected gridStackEngine: _angular_core.Signal<typeof gridstack.GridStackEngine | undefined>;
346
+ protected gridBreakpoints: _angular_core.Signal<Readonly<Required<Pick<gridstack.Breakpoint, "w" | "c">> & {
347
+ layout: "compact" | "list" | "none";
348
+ }>[]>;
349
+ protected columnVars: _angular_core.Signal<{
350
+ '--dashboard-cols-sm': number;
351
+ '--dashboard-cols-md': number;
352
+ '--dashboard-cols-lg': number;
353
+ '--dashboard-cols-xl': number;
354
+ }>;
355
+ protected customActions: _angular_core.Signal<ButtonSettings[]>;
356
+ protected addedCardsIds: _angular_core.Signal<Set<string>>;
357
+ protected editViewButton: _angular_core.Signal<{
358
+ text: string;
359
+ icon: string;
360
+ endIcon?: string;
361
+ design: "Default" | "Positive" | "Negative" | "Transparent" | "Emphasized" | "Attention";
362
+ tooltip: string;
363
+ action?: (("openInModal" | "navigate" | "edit" | "delete") | (string & {})) | undefined;
364
+ modalSettings?: _openmfp_ngx.ModalSettings;
365
+ }>;
366
+ protected editCardsButton: _angular_core.Signal<{
367
+ text: string;
368
+ icon: string;
369
+ endIcon?: string;
370
+ design: "Default" | "Positive" | "Negative" | "Transparent" | "Emphasized" | "Attention";
371
+ tooltip: string;
372
+ action?: (("openInModal" | "navigate" | "edit" | "delete") | (string & {})) | undefined;
373
+ modalSettings?: _openmfp_ngx.ModalSettings;
374
+ }>;
375
+ protected sectionCards: _angular_core.Signal<(sectionId: string) => CardConfig[]>;
376
+ protected looseCards: _angular_core.WritableSignal<CardConfig[]>;
377
+ protected gridOptions: _angular_core.Signal<GridStackOptions>;
378
+ /** JSON snapshots of sections/cards taken on entering edit mode, used to detect changes. */
379
+ private sectionsSnapshotJson;
380
+ private cardsSnapshotJson;
381
+ private sectionsSnapshot;
382
+ private cardsSnapshot;
383
+ private gridStack;
384
+ private addCardBtn;
385
+ private resizeObserver?;
386
+ private cardsPosition;
387
+ /** Callback that resumes the intercepted navigation once the user resolves the dialog. */
388
+ private pendingNavigation;
389
+ /** beforeunload handler kept on instance so add/removeEventListener pair up. */
390
+ private readonly beforeUnloadHandler;
391
+ constructor();
392
+ ngOnInit(): void;
393
+ ngOnDestroy(): void;
394
+ onMenuItemClick(actionId: string, event: Event): void;
395
+ enterEditMode(): void;
396
+ saveEdit(): void;
397
+ cancelEdit(): void;
398
+ confirmDiscard(): void;
399
+ cancelDiscard(): void;
330
400
  /**
331
- * How additional rows are presented:
332
- * - `'scroll'` / `'button'` grow the list in place via `ui5-table-growing`.
333
- * - `'pager'`classic arrow pager (first/prev/next/last) emitting `pageChange`.
401
+ * Public framework-agnostic navigation guard. Consumer apps (Angular Router
402
+ * CanDeactivate guard, Luigi navigation listener, plain `<a>` click handler,
403
+ * window history listener anything) call this before performing their
404
+ * navigation:
405
+ *
406
+ * if (dashboard.requestNavigation(() => router.navigateByUrl(target))) {
407
+ * // already navigated synchronously — clean state
408
+ * } else {
409
+ * // dashboard popped the unsaved-changes dialog; the navigation will
410
+ * // resume from the user's choice (Save → proceed, Discard → proceed,
411
+ * // Cancel → drop the request entirely).
412
+ * }
413
+ *
414
+ * Returns `true` when navigation may proceed immediately (no unsaved
415
+ * changes — `proceed` was invoked synchronously). Returns `false` when the
416
+ * dialog has been opened and the caller must NOT navigate; the dashboard
417
+ * will run the callback later if the user picks Save or Discard.
418
+ *
419
+ * If a previous navigation is already pending, that one is dropped in
420
+ * favour of the new request — Cancel always means "stay here", so losing
421
+ * the older queued navigation is the correct outcome.
334
422
  */
335
- loadMode?: 'scroll' | 'button' | 'pager';
336
- /** Text on the grow "Load More" button. Grow modes only. */
337
- loadMoreButtonText?: string;
338
- }
339
- /** Overrides for the table card's built-in action buttons. */
340
- interface TableCardButtonSettings {
341
- /** Partial override for the "Create" button. */
342
- createButton?: Partial<ButtonSettings>;
343
- /** Partial override for the search toggle button. */
344
- searchButton?: Partial<ButtonSettings>;
345
- /** Partial override for the per-row "Edit" button. */
346
- editButton?: Partial<ButtonSettings>;
347
- /** Partial override for the per-row "Delete" button. */
348
- deleteButton?: Partial<ButtonSettings>;
423
+ requestNavigation(proceed: () => void): boolean;
424
+ /** Save persist changes, close the dialog, then resume navigation. */
425
+ onUnsavedNavSave(): void;
426
+ /** Discard → revert to snapshot, close the dialog, then resume navigation. */
427
+ onUnsavedNavDiscard(): void;
428
+ /** Cancel → drop the queued navigation and stay in edit mode. */
429
+ onUnsavedNavCancel(): void;
430
+ private runPendingNavigation;
431
+ private discardEdit;
432
+ removeSection(id: string): void;
433
+ removeCard(id: string): void;
434
+ openCardPanel(): void;
435
+ closeCardPanel(): void;
436
+ onCardsEdited(event: {
437
+ added: CardConfig[];
438
+ removed: string[];
439
+ }): void;
440
+ onDragStart(event: {
441
+ el: Element;
442
+ }): void;
443
+ onDragStop(): void;
444
+ onGridChange(): void;
445
+ private saveCardsPosition;
446
+ private updateCardsPositions;
447
+ private getZFlowEngine;
448
+ private updateCardsForBreakpoint;
449
+ private changeCardSettingsForXlPage;
450
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<Dashboard, never>;
451
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<Dashboard, "mfp-dashboard", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; "sections": { "alias": "sections"; "required": false; "isSignal": true; }; "cards": { "alias": "cards"; "required": false; "isSignal": true; }; "availableCards": { "alias": "availableCards"; "required": false; "isSignal": true; }; "language": { "alias": "language"; "required": false; "isSignal": true; }; }, { "sections": "sectionsChange"; "cards": "cardsChange"; "saved": "saved"; "actionButtonClick": "actionButtonClick"; "unsavedChangesChange": "unsavedChangesChange"; }, never, ["[slot=dashboard-subheader]"], true, never>;
349
452
  }
453
+
350
454
  /**
351
- * Groups all search/filter concerns for `<mfp-declarative-table-card>`. Passing
352
- * this object opts the card into showing the search input and (if `filterTabs`
353
- * is set) the filter-tab strip. Omit the whole object to hide both.
455
+ * `createCustomElement` only proxies `@Input()`/`output()` public methods on
456
+ * the component class are NOT reachable from the DOM. This forwards the
457
+ * dashboard's public methods onto the custom-element prototype so that
458
+ * non-Angular consumers (UI5, plain JS, Luigi, etc.) can call them directly on
459
+ * the `<mfp-wc-dashboard>` DOM node.
354
460
  *
355
- * `initialSearch` and `initialFilter` are **one-shot seeds** read once when
356
- * the card mounts (or when they first appear) and never re-applied afterwards.
357
- * User-driven updates continue to flow through the `searchChanged` and
358
- * `filterTabChanged` outputs; the host is expected to keep its own state.
461
+ * `requestNavigation` needs a synchronous fallback when the Angular component
462
+ * isn't created yet: run the navigation immediately (returning `true`) rather
463
+ * than silently blocking the user this preserves the original, pre-guard
464
+ * behaviour. The remaining handlers no-op until the component exists.
359
465
  */
360
- interface TableCardSearchConfig {
361
- /**
362
- * One-shot seed for the search input. Applied to the internal `searchControl`
363
- * on first render (or the first time `searchConfig` appears), without
364
- * emitting `searchChanged`. Later changes to this value have no effect.
365
- */
366
- initialSearch?: string;
367
- /**
368
- * Placeholder text shown in the always-visible search input to prompt
369
- * searching. Defaults to `Search` when omitted.
370
- */
371
- placeholder?: string;
466
+ declare function defineDashboardElementMethods(elementCtor: CustomElementConstructor): void;
467
+
468
+ /** Definition for a single form field rendered by `mfp-declarative-form`. */
469
+ interface FormFieldDefinition {
470
+ /** JSON-path key used to read and write the field value (e.g. `metadata.name`). */
471
+ name: string;
472
+ /** Display label shown above the input. */
473
+ label: string;
474
+ /** When `true`, passes the `required` attribute to the UI5 input shows a visual required indicator. Validation itself is the host's responsibility via `FormFieldErrors`. */
475
+ required?: boolean;
476
+ /** Fixed list of options rendered as a select/dropdown. */
477
+ values?: string[];
478
+ /** When `true`, the field is disabled (not interactive). */
479
+ disabled?: boolean;
480
+ /** Controls when `fieldChange` is emitted for this field. When omitted, `fieldChange` is never emitted. */
481
+ validation?: 'onBlur' | 'onChange';
372
482
  /**
373
- * Predefined filters rendered as a horizontal tab strip above the table.
483
+ * Nested field definitions describing one item of an object collection.
484
+ *
485
+ * When set, this field represents an array of objects; the form renders it
486
+ * as a stack of expandable/collapsible cards. Each card is a nested
487
+ * `mfp-declarative-form` whose `fields` are the entries in
488
+ * `propertyCollection`; an inline Add button appends entries and a trash
489
+ * button removes them. Editing is live — no per-card Save/Cancel.
490
+ *
491
+ * The submitted value at this field's path is `Array<Record<string, unknown>>`,
492
+ * with each entry keyed by the sub-fields' `name`s. When `required` is
493
+ * `true`, the host is expected to require at least one entry in the array.
494
+ */
495
+ propertyCollection?: FormFieldDefinition[];
496
+ }
497
+ /** Event payload emitted each time a single form field value changes. */
498
+ interface FormFieldChangeEvent {
499
+ /** The `name` (JSON-path key) of the field that changed. */
500
+ fieldProperty: string;
501
+ /** The new value entered by the user. */
502
+ value: unknown;
503
+ }
504
+ /** Map of field names to their current validation error messages (`null` = no error). */
505
+ type FormFieldErrors = Record<string, string | null>;
506
+
507
+ declare class DeclarativeForm<T extends GenericResource> {
508
+ readonly fields: _angular_core.InputSignal<FormFieldDefinition[]>;
509
+ readonly initialValues: _angular_core.InputSignal<T>;
510
+ readonly fieldErrors: _angular_core.InputSignal<FormFieldErrors>;
511
+ readonly fieldChange: _angular_core.OutputEmitterRef<FormFieldChangeEvent>;
512
+ readonly formSubmit: _angular_core.OutputEmitterRef<T>;
513
+ readonly formValueChange: _angular_core.OutputEmitterRef<Record<string, unknown>>;
514
+ readonly form: FormGroup;
515
+ protected readonly collectionSeeds: _angular_core.WritableSignal<Record<string, Record<string, unknown>[]>>;
516
+ private readonly fb;
517
+ constructor();
518
+ setFormControlValue($event: Event, field: FormFieldDefinition): void;
519
+ onCollectionValueChange(field: FormFieldDefinition, entries: Record<string, unknown>[]): void;
520
+ getError(name: string): string | null;
521
+ getValueState(name: string): 'None' | 'Negative';
522
+ onFieldBlur(field: FormFieldDefinition): void;
523
+ submit(): void;
524
+ clear(): void;
525
+ collectionEntries(field: FormFieldDefinition): Record<string, unknown>[];
526
+ private rebuildControls;
527
+ private setInitialValues;
528
+ private buildOutputValue;
529
+ private buildEntryGroup;
530
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeclarativeForm<any>, never>;
531
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeForm<any>, "mfp-declarative-form", never, { "fields": { "alias": "fields"; "required": true; "isSignal": true; }; "initialValues": { "alias": "initialValues"; "required": false; "isSignal": true; }; "fieldErrors": { "alias": "fieldErrors"; "required": false; "isSignal": true; }; }, { "fieldChange": "fieldChange"; "formSubmit": "formSubmit"; "formValueChange": "formValueChange"; }, never, never, true, never>;
532
+ }
533
+
534
+ /** Table column definition — extends `FieldDefinition` with optional column grouping. */
535
+ interface TableFieldDefinition extends FieldDefinition {
536
+ /** Groups this column visually with adjacent columns that share the same `name`. */
537
+ group?: {
538
+ /** Logical group identifier. */
539
+ name: string;
540
+ /** Group header label shown above the grouped cells. */
541
+ label?: string;
542
+ /** Separator placed between values in the same group cell. */
543
+ delimiter?: string;
544
+ /** When `true`, each value is rendered on its own line. */
545
+ multiline?: boolean;
546
+ };
547
+ }
548
+
549
+ type GroupBase = NonNullable<TableFieldDefinition['group']>;
550
+ type ProcessedGroup = GroupBase & {
551
+ fields?: TableFieldDefinition[];
552
+ };
553
+ type ProcessedTableFieldDefinition = Omit<TableFieldDefinition, 'group'> & {
554
+ group?: ProcessedGroup;
555
+ };
556
+
557
+ declare class DeclarativeTable<T extends GenericResource> {
558
+ columns: _angular_core.InputSignal<TableFieldDefinition[]>;
559
+ resources: _angular_core.InputSignal<T[]>;
560
+ trackByPath: _angular_core.InputSignal<string>;
561
+ permissions: _angular_core.InputSignal<Record<string, string[]> | undefined>;
562
+ totalItemsCount: _angular_core.InputSignal<number | undefined>;
563
+ paginationLimit: _angular_core.InputSignal<number>;
564
+ hasMore: _angular_core.InputSignal<boolean>;
565
+ loadMode: _angular_core.InputSignal<"button" | "scroll" | "pager">;
566
+ loadMoreButtonText: _angular_core.InputSignal<string>;
567
+ height: _angular_core.InputSignal<number | undefined>;
568
+ currentPage: _angular_core.InputSignal<number>;
569
+ readonly buttonClick: _angular_core.OutputEmitterRef<ResourceFieldButtonClickEvent<T>>;
570
+ readonly tableRowClicked: _angular_core.OutputEmitterRef<T>;
571
+ readonly loadMoreResources: _angular_core.OutputEmitterRef<void>;
572
+ readonly paginationLimitChanged: _angular_core.OutputEmitterRef<number>;
573
+ readonly pageChange: _angular_core.OutputEmitterRef<number>;
574
+ columnTrackBy: (column: TableFieldDefinition, index: number) => string | number | string[];
575
+ rowTrackBy: (_index: number, item: T) => unknown;
576
+ viewColumns: _angular_core.Signal<ProcessedTableFieldDefinition[]>;
577
+ onRowClick(item: T): void;
578
+ isPagerMode: _angular_core.Signal<boolean>;
579
+ knowsTotal: _angular_core.Signal<boolean>;
580
+ hasResults: _angular_core.Signal<boolean>;
581
+ totalPages: _angular_core.Signal<number>;
582
+ canPrev: _angular_core.Signal<boolean>;
583
+ canNext: _angular_core.Signal<boolean>;
584
+ goToPage(page: number): void;
585
+ firstPage: () => void;
586
+ prevPage: () => void;
587
+ nextPage: () => void;
588
+ lastPage: () => void;
589
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeclarativeTable<any>, never>;
590
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeTable<any>, "mfp-declarative-table", never, { "columns": { "alias": "columns"; "required": true; "isSignal": true; }; "resources": { "alias": "resources"; "required": true; "isSignal": true; }; "trackByPath": { "alias": "trackByPath"; "required": false; "isSignal": true; }; "permissions": { "alias": "permissions"; "required": false; "isSignal": true; }; "totalItemsCount": { "alias": "totalItemsCount"; "required": false; "isSignal": true; }; "paginationLimit": { "alias": "paginationLimit"; "required": false; "isSignal": true; }; "hasMore": { "alias": "hasMore"; "required": false; "isSignal": true; }; "loadMode": { "alias": "loadMode"; "required": false; "isSignal": true; }; "loadMoreButtonText": { "alias": "loadMoreButtonText"; "required": false; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "currentPage": { "alias": "currentPage"; "required": false; "isSignal": true; }; }, { "buttonClick": "buttonClick"; "tableRowClicked": "tableRowClicked"; "loadMoreResources": "loadMoreResources"; "paginationLimitChanged": "paginationLimitChanged"; "pageChange": "pageChange"; }, never, never, true, never>;
591
+ }
592
+
593
+ /** Configuration for the create/edit resource form rendered inside the table card dialogs. */
594
+ interface ResourceFormConfig {
595
+ /**
596
+ * Ordered list of fields to render in the form. May be a plain array, or a
597
+ * thunk returning a promise of the fields — the thunk form is resolved lazily
598
+ * when the dialog opens (e.g. to fetch dynamic select options on demand
599
+ * rather than prefetching them on render).
600
+ */
601
+ fields: FormFieldDefinition[] | (() => Promise<FormFieldDefinition[]>);
602
+ /** Dialog title shown in the header. May contain HTML, which is sanitized before rendering. */
603
+ title?: string;
604
+ /** Label for the confirm/submit button. */
605
+ confirmLabel?: string;
606
+ /** Label for the cancel button. */
607
+ cancelLabel?: string;
608
+ }
609
+ /** Runtime validation and submit state passed to the table card from the host. */
610
+ interface TableCardFormState {
611
+ /** Map of field names to their current error messages. Any truthy error in the map disables the submit button. */
612
+ fieldErrors?: FormFieldErrors;
613
+ }
614
+ /** Configuration for the delete-confirmation dialog. */
615
+ interface DeleteResourceConfirmationConfig {
616
+ /** Dialog title. May contain HTML, which is sanitized before rendering. */
617
+ title?: string;
618
+ /** Explanatory message shown below the title. May contain HTML, which is sanitized before rendering. */
619
+ message?: string;
620
+ /**
621
+ * When set, the dialog renders a text input and keeps the confirm button
622
+ * disabled until the typed value matches this text (case-insensitive,
623
+ * trimmed). Use it to require the user to type e.g. the resource name before
624
+ * deleting. Omit to allow immediate confirmation.
625
+ */
626
+ confirmationText?: string;
627
+ /** Placeholder for the confirmation input. Defaults to `Type to confirm`. Only used when {@link confirmationText} is set. */
628
+ confirmationPlaceholder?: string;
629
+ /** Label for the confirm/delete button. */
630
+ confirmLabel?: string;
631
+ /** Label for the cancel button. */
632
+ cancelLabel?: string;
633
+ }
634
+ /**
635
+ * One entry in the {@link TableCardSearchConfig.filterTabs} strip rendered
636
+ * above the table. Clicking a tab activates that filter; the host receives the
637
+ * selected definition via the `filterTabChanged` output and is responsible for
638
+ * applying the filter to its data set.
639
+ *
640
+ * The strip renders exactly the array of `FieldFilterDefinition` it receives
641
+ * — no extra "All" / no-filter tab is auto-added. If the host wants such an
642
+ * option it must author it as a regular filter entry.
643
+ */
644
+ interface FieldFilterDefinition {
645
+ /** Visible label rendered as the tab text. */
646
+ label: string;
647
+ /** Name of the property the value applies to. Passed through to the host. */
648
+ property: string;
649
+ /** Value compared against `property` when the host applies the filter. */
650
+ value: string;
651
+ /** When `true`, this tab is selected on initial render; otherwise the first tab is. */
652
+ default?: boolean;
653
+ }
654
+ /** Configuration for the inner `mfp-declarative-table`. */
655
+ interface TableConfig {
656
+ /** Column definitions. */
657
+ fields: TableFieldDefinition[];
658
+ /** Total number of items on the server (used by pagination). */
659
+ totalItemsCount?: number;
660
+ /** Page size in `pager` mode; batch size for the grow modes otherwise. */
661
+ paginationLimit?: number;
662
+ /** 1-based current page. Only used when `loadMode` is `'pager'`. */
663
+ currentPage?: number;
664
+ /** When `true`, the "Load More" control is shown. Grow modes only. */
665
+ hasMore?: boolean;
666
+ height?: number;
667
+ /**
668
+ * How additional rows are presented:
669
+ * - `'scroll'` / `'button'` — grow the list in place via `ui5-table-growing`.
670
+ * - `'pager'` — classic arrow pager (first/prev/next/last) emitting `pageChange`.
671
+ */
672
+ loadMode?: 'scroll' | 'button' | 'pager';
673
+ /** Text on the grow "Load More" button. Grow modes only. */
674
+ loadMoreButtonText?: string;
675
+ }
676
+ /** Overrides for the table card's built-in action buttons. */
677
+ interface TableCardButtonSettings {
678
+ /** Partial override for the "Create" button. */
679
+ createButton?: Partial<ButtonSettings>;
680
+ /** Partial override for the search toggle button. */
681
+ searchButton?: Partial<ButtonSettings>;
682
+ }
683
+ /**
684
+ * Groups all search/filter concerns for `<mfp-declarative-table-card>`. Passing
685
+ * this object opts the card into showing the search input and (if `filterTabs`
686
+ * is set) the filter-tab strip. Omit the whole object to hide both.
687
+ *
688
+ * `initialSearch` and `initialFilter` are **one-shot seeds** — read once when
689
+ * the card mounts (or when they first appear) and never re-applied afterwards.
690
+ * User-driven updates continue to flow through the `searchChanged` and
691
+ * `filterTabChanged` outputs; the host is expected to keep its own state.
692
+ */
693
+ interface TableCardSearchConfig {
694
+ /**
695
+ * One-shot seed for the search input. Applied to the internal `searchControl`
696
+ * on first render (or the first time `searchConfig` appears), without
697
+ * emitting `searchChanged`. Later changes to this value have no effect.
698
+ */
699
+ initialSearch?: string;
700
+ /**
701
+ * Placeholder text shown in the always-visible search input to prompt
702
+ * searching. Defaults to `Search` when omitted.
703
+ */
704
+ placeholder?: string;
705
+ /**
706
+ * Predefined filters rendered as a horizontal tab strip above the table.
374
707
  * Omit (or pass an empty array) to hide the strip while keeping the search
375
708
  * input visible.
376
709
  */
@@ -384,7 +717,7 @@ interface TableCardSearchConfig {
384
717
  initialFilter?: FieldFilterDefinition;
385
718
  }
386
719
  /** Top-level configuration for `<mfp-declarative-table-card>`. */
387
- interface TableCardConfig {
720
+ interface TableCardConfig<T extends GenericResource = GenericResource> {
388
721
  /** Card heading. */
389
722
  header?: string;
390
723
  /** Tooltip shown on hover of the card heading. */
@@ -402,39 +735,61 @@ interface TableCardConfig {
402
735
  /** When set, enables the "Create" button and create dialog. */
403
736
  createResourceFormConfig?: ResourceFormConfig;
404
737
  /** When set, enables per-row "Edit" button and edit dialog. */
405
- editResourceFormConfig?: ResourceFormConfig;
738
+ editResourceFormConfig?: (resource: T) => ResourceFormConfig;
406
739
  /** When set, enables per-row "Delete" button and confirmation dialog. */
407
- deleteResourceConfirmationConfig?: DeleteResourceConfirmationConfig;
740
+ deleteResourceConfirmationConfig?: (resource: T) => DeleteResourceConfirmationConfig;
408
741
  }
409
742
 
410
- declare class DeclarativeTableCard<T extends GenericResource> {
411
- resources: _angular_core.InputSignal<T[]>;
412
- config: _angular_core.InputSignal<TableCardConfig>;
743
+ declare class DeleteConfirmationDialog {
744
+ readonly open: _angular_core.InputSignal<boolean>;
745
+ readonly config: _angular_core.InputSignal<DeleteResourceConfirmationConfig | undefined>;
746
+ readonly confirmed: _angular_core.OutputEmitterRef<void>;
747
+ readonly cancelled: _angular_core.OutputEmitterRef<void>;
748
+ /** Input used to confirm deletion by typing `confirmationText`. */
749
+ protected readonly confirmationControl: FormControl<string>;
750
+ /** True when the config requires typing a confirmation phrase before deleting. */
751
+ protected readonly requiresConfirmation: _angular_core.Signal<boolean>;
752
+ /** Recomputes whenever the control's validity changes. */
753
+ private readonly status;
754
+ /** Disables the confirm button while the confirmation input is invalid. */
755
+ protected readonly confirmDisabled: _angular_core.Signal<boolean>;
756
+ constructor();
757
+ protected onConfirm(): void;
758
+ /** Passes only when the trimmed, case-insensitive control value equals `expected`. */
759
+ private matchValidator;
760
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeleteConfirmationDialog, never>;
761
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeleteConfirmationDialog, "mfp-delete-confirmation-dialog", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; }, { "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, never, true, never>;
762
+ }
763
+
764
+ declare class DeclarativeTableCard<R extends GenericResource> {
765
+ resources: _angular_core.InputSignal<R[]>;
766
+ permissions: _angular_core.InputSignal<Record<string, string[]> | undefined>;
767
+ config: _angular_core.InputSignal<TableCardConfig<R>>;
413
768
  createFormState: _angular_core.InputSignal<TableCardFormState>;
414
769
  editFormState: _angular_core.InputSignal<TableCardFormState>;
415
- readonly actionButtonClick: _angular_core.OutputEmitterRef<ResourceFieldButtonClickEvent<T>>;
416
- readonly tableRowClicked: _angular_core.OutputEmitterRef<T>;
770
+ readonly actionButtonClick: _angular_core.OutputEmitterRef<ResourceFieldButtonClickEvent<R>>;
771
+ readonly tableRowClicked: _angular_core.OutputEmitterRef<R>;
417
772
  readonly loadMoreResources: _angular_core.OutputEmitterRef<void>;
418
773
  readonly paginationLimitChanged: _angular_core.OutputEmitterRef<number>;
419
774
  readonly pageChange: _angular_core.OutputEmitterRef<number>;
420
775
  readonly searchChanged: _angular_core.OutputEmitterRef<string>;
421
776
  readonly createFieldChange: _angular_core.OutputEmitterRef<FormFieldChangeEvent>;
422
777
  readonly editFieldChange: _angular_core.OutputEmitterRef<{
423
- resource: T;
778
+ resource: R;
424
779
  formChangeEvent: FormFieldChangeEvent;
425
780
  }>;
426
- readonly createSubmit: _angular_core.OutputEmitterRef<T>;
781
+ readonly createSubmit: _angular_core.OutputEmitterRef<R>;
427
782
  readonly editSubmit: _angular_core.OutputEmitterRef<{
428
- resource: T;
783
+ resource: R;
429
784
  value: Record<string, unknown>;
430
785
  }>;
431
- readonly deleteSubmit: _angular_core.OutputEmitterRef<T>;
786
+ readonly deleteSubmit: _angular_core.OutputEmitterRef<R>;
432
787
  readonly filterTabChanged: _angular_core.OutputEmitterRef<FieldFilterDefinition | undefined>;
433
788
  protected searchControl: FormControl<string | null>;
434
789
  protected createDialogOpen: _angular_core.WritableSignal<boolean>;
435
790
  protected editDialogOpen: _angular_core.WritableSignal<boolean>;
436
791
  protected deleteDialogOpen: _angular_core.WritableSignal<boolean>;
437
- protected pendingResource: _angular_core.WritableSignal<T | null>;
792
+ protected pendingResource: _angular_core.WritableSignal<R | null>;
438
793
  protected resolvedCreateFields: _angular_core.WritableSignal<FormFieldDefinition[]>;
439
794
  protected resolvedEditFields: _angular_core.WritableSignal<FormFieldDefinition[]>;
440
795
  protected tableConfig: _angular_core.Signal<_openmfp_ngx.TableConfig>;
@@ -445,7 +800,7 @@ declare class DeclarativeTableCard<T extends GenericResource> {
445
800
  protected deleteConfirmationConfig: _angular_core.Signal<_openmfp_ngx.DeleteResourceConfirmationConfig | undefined>;
446
801
  protected createButtonConfig: _angular_core.Signal<Partial<_openmfp_ngx.ButtonSettings> | undefined>;
447
802
  protected searchButtonConfig: _angular_core.Signal<Partial<_openmfp_ngx.ButtonSettings> | undefined>;
448
- protected effectiveColumns: _angular_core.Signal<TableFieldDefinition[]>;
803
+ protected effectiveColumns: _angular_core.Signal<_openmfp_ngx.TableFieldDefinition[]>;
449
804
  protected editInitialValue: _angular_core.Signal<Record<string, unknown>>;
450
805
  protected searchConfig: _angular_core.Signal<_openmfp_ngx.TableCardSearchConfig | undefined>;
451
806
  protected resourcesSearchable: _angular_core.Signal<boolean>;
@@ -455,7 +810,7 @@ declare class DeclarativeTableCard<T extends GenericResource> {
455
810
  constructor();
456
811
  protected onFilterTabChanged(tab: FieldFilterDefinition | undefined): void;
457
812
  submitSearch(): void;
458
- onButtonClick(event: ResourceFieldButtonClickEvent<T>): void;
813
+ onButtonClick(event: ResourceFieldButtonClickEvent<R>): void;
459
814
  openCreateDialog(): Promise<void>;
460
815
  private openEditDialog;
461
816
  private resolveFormFields;
@@ -464,329 +819,43 @@ declare class DeclarativeTableCard<T extends GenericResource> {
464
819
  closeDeleteDialog(): void;
465
820
  onCreateFieldChange(event: FormFieldChangeEvent): void;
466
821
  onEditFieldChange(event: FormFieldChangeEvent): void;
467
- onCreateSubmit(value: T): void;
822
+ onCreateSubmit(value: Record<string, unknown>): void;
468
823
  onEditSubmit(value: Record<string, unknown>): void;
469
824
  onDeleteSubmit(): void;
470
- protected hasErrors(state: TableCardFormState): boolean;
471
- private addActionsColumn;
472
825
  private buildInitialValues;
473
826
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DeclarativeTableCard<any>, never>;
474
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeTableCard<any>, "mfp-declarative-table-card", never, { "resources": { "alias": "resources"; "required": true; "isSignal": true; }; "config": { "alias": "config"; "required": true; "isSignal": true; }; "createFormState": { "alias": "createFormState"; "required": false; "isSignal": true; }; "editFormState": { "alias": "editFormState"; "required": false; "isSignal": true; }; }, { "actionButtonClick": "actionButtonClick"; "tableRowClicked": "tableRowClicked"; "loadMoreResources": "loadMoreResources"; "paginationLimitChanged": "paginationLimitChanged"; "pageChange": "pageChange"; "searchChanged": "searchChanged"; "createFieldChange": "createFieldChange"; "editFieldChange": "editFieldChange"; "createSubmit": "createSubmit"; "editSubmit": "editSubmit"; "deleteSubmit": "deleteSubmit"; "filterTabChanged": "filterTabChanged"; }, never, never, true, never>;
827
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DeclarativeTableCard<any>, "mfp-declarative-table-card", never, { "resources": { "alias": "resources"; "required": true; "isSignal": true; }; "permissions": { "alias": "permissions"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": true; "isSignal": true; }; "createFormState": { "alias": "createFormState"; "required": false; "isSignal": true; }; "editFormState": { "alias": "editFormState"; "required": false; "isSignal": true; }; }, { "actionButtonClick": "actionButtonClick"; "tableRowClicked": "tableRowClicked"; "loadMoreResources": "loadMoreResources"; "paginationLimitChanged": "paginationLimitChanged"; "pageChange": "pageChange"; "searchChanged": "searchChanged"; "createFieldChange": "createFieldChange"; "editFieldChange": "editFieldChange"; "createSubmit": "createSubmit"; "editSubmit": "editSubmit"; "deleteSubmit": "deleteSubmit"; "filterTabChanged": "filterTabChanged"; }, never, never, true, never>;
475
828
  }
476
829
 
477
- type DashboardLanguage = 'en' | 'de';
478
- declare const DASHBOARD_I18N_KEYS: {
479
- readonly UNSAVED_CHANGES: "unsavedChanges";
480
- readonly EDIT_CARDS: "editCards";
481
- readonly EDIT_VIEW: "editView";
482
- readonly ACTIONS: "actions";
483
- readonly SAVE: "save";
484
- readonly CANCEL: "cancel";
485
- readonly DISCARD: "discard";
486
- readonly DISCARD_CHANGES: "discardChanges";
487
- readonly DISCARD_CONFIRM_BODY: "discardConfirmBody";
488
- readonly UNSAVED_NAV_BODY: "unsavedNavBody";
489
- readonly NO_CARDS_AVAILABLE: "noCardsAvailable";
490
- readonly REMOVE_SECTION: "removeSection";
491
- readonly REMOVE_CARD: "removeCard";
492
- readonly RESIZABLE: "resizable";
493
- };
494
- type DashboardI18nKey = (typeof DASHBOARD_I18N_KEYS)[keyof typeof DASHBOARD_I18N_KEYS];
495
-
496
- /**
497
- * Holds the dashboard's current language and resolves translation keys for
498
- * the dashboard chrome (toolbar buttons, dialogs, a11y labels). Provided at
499
- * the `Dashboard` component level so every nested dashboard component shares
500
- * the same language signal — child components inject the same instance and
501
- * react to language changes automatically because `getTranslation` reads the
502
- * signal on every call.
503
- */
504
- declare class DashboardI18nService {
505
- readonly language: _angular_core.WritableSignal<DashboardLanguage>;
506
- getTranslation(key: DashboardI18nKey): string;
507
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DashboardI18nService, never>;
508
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<DashboardI18nService>;
830
+ declare class ResourceFormDialog {
831
+ readonly open: _angular_core.InputSignal<boolean>;
832
+ readonly config: _angular_core.InputSignal<ResourceFormConfig | undefined>;
833
+ readonly fields: _angular_core.InputSignal<FormFieldDefinition[]>;
834
+ readonly fieldErrors: _angular_core.InputSignal<FormFieldErrors>;
835
+ readonly initialValues: _angular_core.InputSignal<Record<string, unknown>>;
836
+ readonly defaultTitle: _angular_core.InputSignal<string>;
837
+ readonly defaultConfirmLabel: _angular_core.InputSignal<string>;
838
+ readonly defaultCancelLabel: _angular_core.InputSignal<string>;
839
+ readonly dataTestidPrefix: _angular_core.InputSignal<string>;
840
+ readonly fieldChange: _angular_core.OutputEmitterRef<FormFieldChangeEvent>;
841
+ readonly submitted: _angular_core.OutputEmitterRef<Record<string, unknown>>;
842
+ readonly cancelled: _angular_core.OutputEmitterRef<void>;
843
+ protected hasErrors: _angular_core.Signal<boolean>;
844
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ResourceFormDialog, never>;
845
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ResourceFormDialog, "mfp-resource-form-dialog", never, { "open": { "alias": "open"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "fieldErrors": { "alias": "fieldErrors"; "required": false; "isSignal": true; }; "initialValues": { "alias": "initialValues"; "required": false; "isSignal": true; }; "defaultTitle": { "alias": "defaultTitle"; "required": false; "isSignal": true; }; "defaultConfirmLabel": { "alias": "defaultConfirmLabel"; "required": false; "isSignal": true; }; "defaultCancelLabel": { "alias": "defaultCancelLabel"; "required": false; "isSignal": true; }; "dataTestidPrefix": { "alias": "dataTestidPrefix"; "required": false; "isSignal": true; }; }, { "fieldChange": "fieldChange"; "submitted": "submitted"; "cancelled": "cancelled"; }, never, never, true, never>;
509
846
  }
510
847
 
511
- declare const CARD_TYPES: {
512
- readonly WC: "wc";
513
- readonly ANGULAR: "angular";
514
- readonly SAP_UI: "sap-ui";
515
- };
516
- type CardsType = (typeof CARD_TYPES)[keyof typeof CARD_TYPES];
517
- /** Configuration for a single card placed in the dashboard grid or a section. */
518
- interface CardConfig {
519
- /** Unique identifier for this card. Used as a stable key for position persistence. */
520
- id: string;
521
- /** Column span (1–12). Defaults to 12 when omitted. */
522
- w?: number;
523
- /** Row span — number of CSS grid rows occupied (1 row = 10 px by default). Defaults to 100 when omitted. */
524
- h?: number;
525
- /** Starting column index (0-based). Omit to let the grid auto-place the card. */
526
- x?: number;
527
- /** Starting row index (0-based). Omit to let the grid auto-place the card. */
528
- y?: number;
529
- /** Maximum row span in edit mode. */
530
- maxH?: number;
531
- /** Maximum column span in edit mode. */
532
- maxW?: number;
533
- /** Minimum row span in edit mode. */
534
- minH?: number;
535
- /** Minimum column span in edit mode. */
536
- minW?: number;
537
- /** ID of the parent section. Omit to place the card in the loose-card grid. */
538
- sectionId?: string;
539
- /**
540
- * Custom-element tag name (for `'wc'`/omitted), Angular component selector (for `'angular'`),
541
- * or SAP UI5 component name (for `'sap-ui'`).
542
- */
543
- component: string;
544
- /**
545
- * Render strategy for the card.
546
- * - `'wc'` (default) — creates a custom element and sets `componentInputs` as DOM properties.
547
- * - `'angular'` — looks up the Angular registry; warns and renders nothing if not found.
548
- * - `'sap-ui'` — mounts via `window.sap.ui.require` + `ComponentContainer`.
549
- */
550
- type?: CardsType;
551
- /** Key/value pairs passed to the rendered card. Behaviour depends on `type`. */
552
- componentInputs?: Record<string, unknown>;
553
- /** Human-readable label shown in the "Add Card" dialog. */
554
- label?: string;
555
- }
556
- type MountCfg = Pick<CardConfig, 'type' | 'component' | 'componentInputs'>;
557
- /** Configuration for a named horizontal section that groups cards. */
558
- interface SectionConfig {
559
- /** Unique identifier for this section. */
560
- id: string;
561
- /** Column span (1–12). Defaults to 12 when omitted. */
562
- w?: number;
563
- /** Section heading displayed in the UI. */
564
- title?: string;
565
- /** When `false`, the section and its cards are excluded from edit mode. Defaults to `true` when omitted. */
566
- editable?: boolean;
567
- }
568
- /** Overrides for the two built-in dashboard toolbar buttons. */
569
- interface DashboardButtonsSettings {
570
- /** Partial override merged on top of the Edit View button defaults. */
571
- editViewButton?: Partial<ButtonSettings>;
572
- /** Partial override merged on top of the Edit Cards button defaults. */
573
- editCardsButton?: Partial<ButtonSettings>;
574
- }
575
- /** Top-level configuration for the `<mfp-dashboard>` component. */
576
- interface DashboardConfig {
577
- /** Dashboard title rendered in the toolbar. */
578
- title: string;
579
- /** Optional subtitle shown below the title. */
580
- description?: string;
581
- /** URL of the background image applied to the dashboard host element. */
582
- backgroundImageUrl?: string;
583
- /** Overrides for the built-in Edit View and Add Card toolbar buttons. */
584
- buttonsSettings?: DashboardButtonsSettings;
585
- /** Extra action buttons rendered in the toolbar alongside the built-in ones. */
586
- customActions?: ButtonSettings[];
587
- /** When `true`, shows the Edit View button in the toolbar, allowing the user to enter edit mode. */
588
- editable?: boolean;
589
- /** When `true`, the Edit View button is rendered before the custom actions instead of after. Defaults to `false`. */
590
- editButtonFirst?: boolean;
591
- /** When provided, enable z-flow layout. */
592
- zFlow?: {
593
- /** Sets the height of each card in the z-flow layout. */
594
- cardHeight: number;
595
- };
596
- }
597
-
598
- /**
599
- * Layout strategy applied at each breakpoint when Gridstack changes column
600
- * count. See ColumnOptions in gridstack/dist/types.d.ts:27 for the full set.
601
- */
602
- type LayoutStrategy = 'compact' | 'list' | 'none';
603
- type DashboardBreakpoint = Readonly<Required<Pick<Breakpoint, 'w' | 'c'>> & {
604
- layout: LayoutStrategy;
605
- }>;
606
-
607
- interface EngineProfile {
608
- /** GridStack engine class, or undefined to use GridStack's native engine. */
609
- engineClass: typeof GridStackEngine | undefined;
610
- /** Column breakpoint table fed to GridStack columnOpts. */
611
- breakpoints: readonly DashboardBreakpoint[];
612
- /** Column counts for [sm, md, lg, xl] page size. Pushed to CSS vars so the section grids match. */
613
- sectionColumns: readonly [number, number, number, number];
614
- /** When true, all loose cards get a fixed h/maxH from the engine's config. */
615
- fixedCardHeight: boolean;
616
- /** When true, the XL-page width swap (3↔4) runs. */
617
- xlWidthSwap: boolean;
618
- /** When true, the origin position is rendered. */
619
- renderOriginPosition: boolean;
620
- }
621
-
622
- declare class Dashboard implements OnInit, OnDestroy {
623
- static registerAngularComponents(componentTypes: Type<unknown>[]): void;
624
- private readonly hostEl;
625
- private readonly injector;
848
+ declare class SanitizeHtmlPipe implements PipeTransform {
626
849
  private readonly sanitizer;
627
- protected readonly i18n: DashboardI18nService;
628
- config: _angular_core.InputSignal<DashboardConfig>;
629
- sections: _angular_core.ModelSignal<SectionConfig[]>;
630
- cards: _angular_core.ModelSignal<CardConfig[]>;
631
- availableCards: _angular_core.InputSignal<CardConfig[]>;
632
- language: _angular_core.InputSignal<DashboardLanguage>;
633
- readonly saved: _angular_core.OutputEmitterRef<{
634
- sections: SectionConfig[];
635
- cards: CardConfig[];
636
- }>;
637
- readonly actionButtonClick: _angular_core.OutputEmitterRef<{
638
- event: MouseEvent;
639
- action: ButtonSettings;
640
- }>;
641
- readonly unsavedChangesChange: _angular_core.OutputEmitterRef<boolean>;
642
- protected readonly i18nKeys: {
643
- readonly UNSAVED_CHANGES: "unsavedChanges";
644
- readonly EDIT_CARDS: "editCards";
645
- readonly EDIT_VIEW: "editView";
646
- readonly ACTIONS: "actions";
647
- readonly SAVE: "save";
648
- readonly CANCEL: "cancel";
649
- readonly DISCARD: "discard";
650
- readonly DISCARD_CHANGES: "discardChanges";
651
- readonly DISCARD_CONFIRM_BODY: "discardConfirmBody";
652
- readonly UNSAVED_NAV_BODY: "unsavedNavBody";
653
- readonly NO_CARDS_AVAILABLE: "noCardsAvailable";
654
- readonly REMOVE_SECTION: "removeSection";
655
- readonly REMOVE_CARD: "removeCard";
656
- readonly RESIZABLE: "resizable";
657
- };
658
- /** True once the user has dragged/resized any grid item while in edit mode. */
659
- private gridDirty;
660
- private isXLPage;
661
- editMode: _angular_core.WritableSignal<boolean>;
662
- compactToolbar: _angular_core.WritableSignal<boolean>;
663
- toolbarMenuOpen: _angular_core.WritableSignal<boolean>;
664
- cardDialogOpen: _angular_core.WritableSignal<boolean>;
665
- discardDialogOpen: _angular_core.WritableSignal<boolean>;
666
- unsavedNavDialogOpen: _angular_core.WritableSignal<boolean>;
667
- backgroundImageHeight: _angular_core.WritableSignal<number | null>;
668
- dragOriginStyle: _angular_core.WritableSignal<{
669
- top: string;
670
- left: string;
671
- width: string;
672
- height: string;
673
- } | null>;
674
- protected hasUnsavedChanges: _angular_core.Signal<boolean>;
675
- protected safeTitle: _angular_core.Signal<SafeHtml>;
676
- protected safeDescription: _angular_core.Signal<SafeHtml | null>;
677
- protected engineProfile: _angular_core.Signal<EngineProfile>;
678
- protected gridStackEngine: _angular_core.Signal<typeof gridstack.GridStackEngine | undefined>;
679
- protected gridBreakpoints: _angular_core.Signal<Readonly<Required<Pick<gridstack.Breakpoint, "w" | "c">> & {
680
- layout: "compact" | "list" | "none";
681
- }>[]>;
682
- protected columnVars: _angular_core.Signal<{
683
- '--dashboard-cols-sm': number;
684
- '--dashboard-cols-md': number;
685
- '--dashboard-cols-lg': number;
686
- '--dashboard-cols-xl': number;
687
- }>;
688
- protected customActions: _angular_core.Signal<ButtonSettings[]>;
689
- protected addedCardsIds: _angular_core.Signal<Set<string>>;
690
- protected editViewButton: _angular_core.Signal<{
691
- text: string;
692
- icon: string;
693
- endIcon?: string;
694
- design: "Default" | "Positive" | "Negative" | "Transparent" | "Emphasized" | "Attention";
695
- tooltip: string;
696
- action?: (("openInModal" | "navigate" | "edit" | "delete") | (string & {})) | undefined;
697
- modalSettings?: _openmfp_ngx.ModalSettings;
698
- }>;
699
- protected editCardsButton: _angular_core.Signal<{
700
- text: string;
701
- icon: string;
702
- endIcon?: string;
703
- design: "Default" | "Positive" | "Negative" | "Transparent" | "Emphasized" | "Attention";
704
- tooltip: string;
705
- action?: (("openInModal" | "navigate" | "edit" | "delete") | (string & {})) | undefined;
706
- modalSettings?: _openmfp_ngx.ModalSettings;
707
- }>;
708
- protected sectionCards: _angular_core.Signal<(sectionId: string) => CardConfig[]>;
709
- protected looseCards: _angular_core.WritableSignal<CardConfig[]>;
710
- protected gridOptions: _angular_core.Signal<GridStackOptions>;
711
- /** JSON snapshots of sections/cards taken on entering edit mode, used to detect changes. */
712
- private sectionsSnapshotJson;
713
- private cardsSnapshotJson;
714
- private sectionsSnapshot;
715
- private cardsSnapshot;
716
- private gridStack;
717
- private addCardBtn;
718
- private resizeObserver?;
719
- private cardsPosition;
720
- /** Callback that resumes the intercepted navigation once the user resolves the dialog. */
721
- private pendingNavigation;
722
- /** beforeunload handler kept on instance so add/removeEventListener pair up. */
723
- private readonly beforeUnloadHandler;
724
- constructor();
725
- ngOnInit(): void;
726
- ngOnDestroy(): void;
727
- onMenuItemClick(actionId: string, event: Event): void;
728
- enterEditMode(): void;
729
- saveEdit(): void;
730
- cancelEdit(): void;
731
- confirmDiscard(): void;
732
- cancelDiscard(): void;
733
- /**
734
- * Public framework-agnostic navigation guard. Consumer apps (Angular Router
735
- * CanDeactivate guard, Luigi navigation listener, plain `<a>` click handler,
736
- * window history listener — anything) call this before performing their
737
- * navigation:
738
- *
739
- * if (dashboard.requestNavigation(() => router.navigateByUrl(target))) {
740
- * // already navigated synchronously — clean state
741
- * } else {
742
- * // dashboard popped the unsaved-changes dialog; the navigation will
743
- * // resume from the user's choice (Save → proceed, Discard → proceed,
744
- * // Cancel → drop the request entirely).
745
- * }
746
- *
747
- * Returns `true` when navigation may proceed immediately (no unsaved
748
- * changes — `proceed` was invoked synchronously). Returns `false` when the
749
- * dialog has been opened and the caller must NOT navigate; the dashboard
750
- * will run the callback later if the user picks Save or Discard.
751
- *
752
- * If a previous navigation is already pending, that one is dropped in
753
- * favour of the new request — Cancel always means "stay here", so losing
754
- * the older queued navigation is the correct outcome.
755
- */
756
- requestNavigation(proceed: () => void): boolean;
757
- /** Save → persist changes, close the dialog, then resume navigation. */
758
- onUnsavedNavSave(): void;
759
- /** Discard → revert to snapshot, close the dialog, then resume navigation. */
760
- onUnsavedNavDiscard(): void;
761
- /** Cancel → drop the queued navigation and stay in edit mode. */
762
- onUnsavedNavCancel(): void;
763
- private runPendingNavigation;
764
- private discardEdit;
765
- removeSection(id: string): void;
766
- removeCard(id: string): void;
767
- openCardPanel(): void;
768
- closeCardPanel(): void;
769
- onCardsEdited(event: {
770
- added: CardConfig[];
771
- removed: string[];
772
- }): void;
773
- onDragStart(event: {
774
- el: Element;
775
- }): void;
776
- onDragStop(): void;
777
- onGridChange(): void;
778
- private saveCardsPosition;
779
- private updateCardsPositions;
780
- private getZFlowEngine;
781
- private updateCardsForBreakpoint;
782
- private changeCardSettingsForXlPage;
783
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<Dashboard, never>;
784
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<Dashboard, "mfp-dashboard", never, { "config": { "alias": "config"; "required": true; "isSignal": true; }; "sections": { "alias": "sections"; "required": false; "isSignal": true; }; "cards": { "alias": "cards"; "required": false; "isSignal": true; }; "availableCards": { "alias": "availableCards"; "required": false; "isSignal": true; }; "language": { "alias": "language"; "required": false; "isSignal": true; }; }, { "sections": "sectionsChange"; "cards": "cardsChange"; "saved": "saved"; "actionButtonClick": "actionButtonClick"; "unsavedChangesChange": "unsavedChangesChange"; }, never, ["[slot=dashboard-subheader]"], true, never>;
850
+ transform(value: string | null | undefined): string;
851
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SanitizeHtmlPipe, never>;
852
+ static ɵpipe: _angular_core.ɵɵPipeDeclaration<SanitizeHtmlPipe, "sanitizeHtml", true>;
785
853
  }
786
854
 
787
855
  declare class ResourceField<T extends GenericResource, F extends FieldDefinition> {
788
856
  fieldDefinition: _angular_core.InputSignal<F>;
789
857
  resource: _angular_core.InputSignal<T | undefined>;
858
+ permissions: _angular_core.InputSignal<Record<string, string[]> | undefined>;
790
859
  readonly buttonClick: _angular_core.OutputEmitterRef<ResourceFieldButtonClickEvent<T>>;
791
860
  value: _angular_core.Signal<any>;
792
861
  uiSettings: _angular_core.Signal<_openmfp_ngx.UiSettings | undefined>;
@@ -1325,6 +1394,7 @@ declare class ResourceField<T extends GenericResource, F extends FieldDefinition
1325
1394
  isVisible: _angular_core.WritableSignal<boolean>;
1326
1395
  copySuccess: _angular_core.WritableSignal<boolean>;
1327
1396
  isCollection: _angular_core.Signal<boolean>;
1397
+ protected canRenderField: _angular_core.Signal<boolean>;
1328
1398
  toggleVisibility(e: Event): void;
1329
1399
  private normalizeBoolean;
1330
1400
  private normalizeString;
@@ -1333,7 +1403,7 @@ declare class ResourceField<T extends GenericResource, F extends FieldDefinition
1333
1403
  copyValue(event: Event): void;
1334
1404
  protected buttonClicked(event: MouseEvent): void;
1335
1405
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ResourceField<any, any>, never>;
1336
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ResourceField<any, any>, "mfp-resource-field", never, { "fieldDefinition": { "alias": "fieldDefinition"; "required": true; "isSignal": true; }; "resource": { "alias": "resource"; "required": false; "isSignal": true; }; }, { "buttonClick": "buttonClick"; }, never, never, true, never>;
1406
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ResourceField<any, any>, "mfp-resource-field", never, { "fieldDefinition": { "alias": "fieldDefinition"; "required": true; "isSignal": true; }; "resource": { "alias": "resource"; "required": false; "isSignal": true; }; "permissions": { "alias": "permissions"; "required": false; "isSignal": true; }; }, { "buttonClick": "buttonClick"; }, never, never, true, never>;
1337
1407
  }
1338
1408
 
1339
1409
  declare const ICON_DESIGN_POSITIVE = "Positive";
@@ -1433,5 +1503,5 @@ declare class MockCard {
1433
1503
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MockCard, "mfp-mock-card", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1434
1504
  }
1435
1505
 
1436
- export { BooleanValue, CARD_TYPES, Dashboard, DeclarativeForm, DeclarativeTable, DeclarativeTableCard, Favorites, LinkValue, MockCard, ResourceField, SecretValue, ServiceStatusCard, TagListValue, VisitedServiceCard, WhatsNew };
1506
+ export { BooleanValue, CARD_TYPES, Dashboard, DeclarativeForm, DeclarativeTable, DeclarativeTableCard, DeleteConfirmationDialog, Favorites, LinkValue, MockCard, ResourceField, ResourceFormDialog, SanitizeHtmlPipe, SecretValue, ServiceStatusCard, TagListValue, VisitedServiceCard, WhatsNew, defineDashboardElementMethods };
1437
1507
  export type { ButtonSettings, CardConfig, CardsType, CssRule, DashboardButtonsSettings, DashboardConfig, DeleteResourceConfirmationConfig, FieldDefinition, FieldFilterDefinition, FormFieldChangeEvent, FormFieldDefinition, FormFieldErrors, GenericResource, IconDesignType, ModalSettings, MountCfg, PropertyField, ResourceFieldButtonClickEvent, ResourceFormConfig, RuleCondition, SectionConfig, ServiceStatusItem, ServiceStatusValue, TableCardButtonSettings, TableCardConfig, TableCardFormState, TableCardSearchConfig, TableConfig, TableFieldDefinition, TagSettings, TransformType, UiSettings, ValueRule };