@meshmakers/octo-ui 3.4.1490 → 3.5.10

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.
@@ -275,6 +275,8 @@ All optional; without them the components behave as before.
275
275
  | Placeholder values of legacy STRING secrets | `ENTITY_FORM_SECRET_PLACEHOLDER_VALUES` (exact values that read "Not set"). SECRET-typed attributes (AB#5528) need nothing: their state comes from the server |
276
276
  | Create / edit in a dialog over the list | `mm-entity-page [editMode]="'dialog'"` (route option `editMode`, data `entityPageEditMode`) — see [Dialog mode](#dialog-mode-editmode-dialog-ab5623) |
277
277
  | CSS classes per list row (e.g. disabled rows) | `mm-entity-list [rowClass]` / `mm-entity-page [listRowClass]` (route option `rowClass`, data `entityListRowClass`) or `ENTITY_LIST_ROW_CLASS`: `(row) => string \| string[] \| Record<string, boolean> \| null`. Classes land on the grid's `<tr>`: style them globally (or `::ng-deep`) |
278
+ | Human row label (row action names, dialog / page title, delete confirmations) | `mm-entity-list [rowLabelField]` / `mm-entity-page [listRowLabelField]` (route option `rowLabelField`, data `entityListRowLabelField`); dotted paths allowed. Absent = `name`, well-known name, display name, rtId (AB#5623) |
279
+ | Boolean columns as icons | `mm-entity-list [booleanDisplay]="'icon'"` / `mm-entity-page [listBooleanDisplay]` (route option `booleanDisplay`, data `entityListBooleanDisplay`) for every plain BOOLEAN column, or `display: icon` on one list column of the form — check / x icon named "<column>: Yes\|No" (`messages.toggleOn` / `toggleOff`), boolean row filter (AB#5623) |
278
280
  | Placeholder values of NON-secret config fields | `ENTITY_FORM_UNSET_PLACEHOLDER_VALUES` — see [Unset placeholders](#unset-placeholders-entity_form_unset_placeholder_values-ab5623) |
279
281
 
280
282
  ### Dialog mode (`editMode: 'dialog'`, AB#5623)
@@ -6,7 +6,7 @@ import * as i1 from 'apollo-angular';
6
6
  import { gql } from 'apollo-angular';
7
7
  import * as i1$1 from '@angular/forms';
8
8
  import { FormGroup, FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms';
9
- import { MM_ACTION_ICONS, EntitySelectInputComponent, CronBuilderComponent, ListViewComponent, FetchResultTyped, DataSourceBase, ConfirmationService, NotificationDisplayService, HAS_UNSAVED_CHANGES, UnsavedChangesGuard } from '@meshmakers/shared-ui';
9
+ import { MM_ACTION_ICONS, EntitySelectInputComponent, CronBuilderComponent, ListViewComponent, FetchResultTyped, DataSourceBase, ConfirmationService, NotificationDisplayService, resolveListRowLabel, HAS_UNSAVED_CHANGES, UnsavedChangesGuard } from '@meshmakers/shared-ui';
10
10
  import * as i5$1 from '@progress/kendo-angular-icons';
11
11
  import { KENDO_SVGICON } from '@progress/kendo-angular-icons';
12
12
  import * as i4 from '@progress/kendo-angular-dateinputs';
@@ -1539,7 +1539,7 @@ function listColumnType(attribute) {
1539
1539
  }
1540
1540
  function normaliseDisplay(display, valueType) {
1541
1541
  const d = (display ?? '').trim().toLowerCase();
1542
- if (d === 'text' || d === 'chip' || d === 'date' || d === 'mono') {
1542
+ if (d === 'text' || d === 'chip' || d === 'date' || d === 'mono' || d === 'icon') {
1543
1543
  return d;
1544
1544
  }
1545
1545
  return isDateType(valueType) ? 'date' : 'text';
@@ -6419,6 +6419,10 @@ function toListViewRowClass(rowClass) {
6419
6419
  }
6420
6420
  };
6421
6421
  }
6422
+ /** Whether a column is a single (non-array) BOOLEAN attribute. */
6423
+ function isBooleanColumn(column) {
6424
+ return (column.valueType ?? '').toUpperCase() === 'BOOLEAN';
6425
+ }
6422
6426
  /** Whether a column's cells need formatting by CK value type (enum names, yes/no). */
6423
6427
  function isFormattedType(column) {
6424
6428
  const type = (column.valueType ?? '').toUpperCase().replace(/_ARRAY$/, '');
@@ -6448,7 +6452,7 @@ function chipLabels(column, labels) {
6448
6452
  * CK value type like the reference display of the form (AB#5547): ENUM → the enum value's name
6449
6453
  * (the API returns the key), BOOLEAN → yes/no, dates → localized date and time.
6450
6454
  */
6451
- function toEntityListColumn(column, labels = {}, unsetPlaceholders) {
6455
+ function toEntityListColumn(column, labels = {}, unsetPlaceholders, options = {}) {
6452
6456
  // AB#5623: a placeholder value of a non-secret attribute reads "Not configured".
6453
6457
  const placeholderValues = column.kind === 'attribute' && unsetPlaceholders && !isSecretValueType(column.valueType)
6454
6458
  ? [...unsetPlaceholders.global, ...(unsetPlaceholders.attributes.get(column.field.toLowerCase()) ?? [])]
@@ -6464,6 +6468,12 @@ function toEntityListColumn(column, labels = {}, unsetPlaceholders) {
6464
6468
  ? { attributeName: column.field, valueType: column.valueType, isOptional: true, defaultValues: [], secret: false, enumOptions: column.enumOptions }
6465
6469
  : undefined;
6466
6470
  const format = (value) => formatReferenceDisplayValue(value, attribute, labels) ?? '';
6471
+ // AB#5623: boolean as icon — per column (`display: icon`) or for every plain BOOLEAN column.
6472
+ const asIcon = isBooleanColumn(column)
6473
+ && (column.display === 'icon' || (column.display === 'text' && options.booleanDisplay === 'icon'));
6474
+ if (asIcon) {
6475
+ return { ...base, dataType: 'booleanIcon' };
6476
+ }
6467
6477
  switch (column.display) {
6468
6478
  case 'chip': {
6469
6479
  let badgeMapping = chipLabels(column, labels);
@@ -6583,6 +6593,20 @@ class EntityListComponent {
6583
6593
  */
6584
6594
  rowClass = input(undefined, /* @ts-ignore */
6585
6595
  ...(ngDevMode ? [{ debugName: "rowClass" }] : /* istanbul ignore next */ []));
6596
+ /**
6597
+ * How BOOLEAN columns without an explicit display render (AB#5623): `'text'` (Yes / No, default)
6598
+ * or `'icon'` (check / x with an accessible name, boolean filter). A column's own
6599
+ * `display: icon` always renders as icon.
6600
+ */
6601
+ booleanDisplay = input('text', /* @ts-ignore */
6602
+ ...(ngDevMode ? [{ debugName: "booleanDisplay" }] : /* istanbul ignore next */ []));
6603
+ /**
6604
+ * Row field used as the row's human label (AB#5623): row action names ("Actions for <label>"),
6605
+ * the delete confirmation target. A dotted path reads a nested value. Absent = today's
6606
+ * behaviour (`name`, then `rtWellKnownName`, display name, `rtId`).
6607
+ */
6608
+ rowLabelField = input(undefined, /* @ts-ignore */
6609
+ ...(ngDevMode ? [{ debugName: "rowLabelField" }] : /* istanbul ignore next */ []));
6586
6610
  /** "New" was confirmed; carries the concrete type (after the subtype picker for abstract types). */
6587
6611
  createRequested = output();
6588
6612
  /** A row was opened. */
@@ -6596,6 +6620,8 @@ class EntityListComponent {
6596
6620
  listViewMessages = computed(() => ({
6597
6621
  searchPlaceholder: this.msgs().searchPlaceholder,
6598
6622
  noRecords: this.msgs().emptyList,
6623
+ booleanYes: this.msgs().toggleOn,
6624
+ booleanNo: this.msgs().toggleOff,
6599
6625
  }), /* @ts-ignore */
6600
6626
  ...(ngDevMode ? [{ debugName: "listViewMessages" }] : /* istanbul ignore next */ []));
6601
6627
  columns = computed(() => {
@@ -6604,7 +6630,7 @@ class EntityListComponent {
6604
6630
  const model = this.model();
6605
6631
  const secrets = new Set(model.secretFields.map((f) => f.toLowerCase()));
6606
6632
  const columns = localizeEntityListColumns(model, this.labelResolver() ?? this.injectedLabelResolver)
6607
- .map((c) => toEntityListColumn(c, labels, secrets.has(c.field.toLowerCase()) ? undefined : this.unsetPlaceholders));
6633
+ .map((c) => toEntityListColumn(c, labels, secrets.has(c.field.toLowerCase()) ? undefined : this.unsetPlaceholders, { booleanDisplay: this.booleanDisplay() }));
6608
6634
  if (this.showTypeColumn() && !columns.some((c) => c.field === 'ckTypeId')) {
6609
6635
  const titles = this.typeTitles();
6610
6636
  const changed = columns.findIndex((c) => c.field === 'rtChangedDateTime');
@@ -6776,7 +6802,8 @@ class EntityListComponent {
6776
6802
  return;
6777
6803
  }
6778
6804
  const m = this.msgs();
6779
- const options = entityDeleteConfirmation(m, rows.map(rowName));
6805
+ const labelField = this.rowLabelField();
6806
+ const options = entityDeleteConfirmation(m, rows.map((row) => rowName(row, labelField)));
6780
6807
  if (!await confirmEntityFormDanger(this.dangerConfirmation, this.confirmationService, options, request)) {
6781
6808
  return;
6782
6809
  }
@@ -6821,13 +6848,17 @@ class EntityListComponent {
6821
6848
  }
6822
6849
  }
6823
6850
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6824
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.5", type: EntityListComponent, isStandalone: true, selector: "mm-entity-list", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, listStateKey: { classPropertyName: "listStateKey", publicName: "listStateKey", isSignal: true, isRequired: false, transformFunction: null }, showTypeColumn: { classPropertyName: "showTypeColumn", publicName: "showTypeColumn", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, toolbarActions: { classPropertyName: "toolbarActions", publicName: "toolbarActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, rowMenuActions: { classPropertyName: "rowMenuActions", publicName: "rowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, rowClass: { classPropertyName: "rowClass", publicName: "rowClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { createRequested: "createRequested", openRequested: "openRequested", deleted: "deleted" }, viewQueries: [{ propertyName: "dataSource", first: true, predicate: EntityListDataSourceDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<mm-list-view\n mmEntityListDataSource\n [columns]=\"columns()\"\n [sortable]=\"true\"\n [rowFilterEnabled]=\"true\"\n [searchTextBoxEnabled]=\"true\"\n [autoPageSize]=\"true\"\n [selectable]=\"{ mode: 'single', enabled: true }\"\n [showRowCheckBoxes]=\"false\"\n [actionsColumnWidth]=\"actionsColumnWidth()\"\n [actionCommandItems]=\"actionItems()\"\n [contextMenuCommandItems]=\"contextMenuItems()\"\n [leftToolbarActions]=\"toolbarItems()\"\n [listStateKey]=\"listStateKey()\"\n [messages]=\"listViewMessages()\"\n [rowClass]=\"listViewRowClass()\"\n (rowClicked)=\"onRowClicked($event)\"\n>\n</mm-list-view>\n", styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%}mm-list-view{flex:1 1 auto;min-height:0}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "rowActions", "maxInlineRowActions", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "collapseCommandsBelow", "hasExternalFilters", "rowClass", "messages", "selectable", "columns", "rowLabelField"], outputs: ["rowClicked", "rowAction", "resetFilters"] }, { kind: "directive", type: EntityListDataSourceDirective, selector: "[mmEntityListDataSource]", exportAs: ["mmEntityListDataSource"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6851
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.5", type: EntityListComponent, isStandalone: true, selector: "mm-entity-list", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, listStateKey: { classPropertyName: "listStateKey", publicName: "listStateKey", isSignal: true, isRequired: false, transformFunction: null }, showTypeColumn: { classPropertyName: "showTypeColumn", publicName: "showTypeColumn", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, toolbarActions: { classPropertyName: "toolbarActions", publicName: "toolbarActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, rowMenuActions: { classPropertyName: "rowMenuActions", publicName: "rowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, rowClass: { classPropertyName: "rowClass", publicName: "rowClass", isSignal: true, isRequired: false, transformFunction: null }, booleanDisplay: { classPropertyName: "booleanDisplay", publicName: "booleanDisplay", isSignal: true, isRequired: false, transformFunction: null }, rowLabelField: { classPropertyName: "rowLabelField", publicName: "rowLabelField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { createRequested: "createRequested", openRequested: "openRequested", deleted: "deleted" }, viewQueries: [{ propertyName: "dataSource", first: true, predicate: EntityListDataSourceDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<mm-list-view\n mmEntityListDataSource\n [columns]=\"columns()\"\n [sortable]=\"true\"\n [rowFilterEnabled]=\"true\"\n [searchTextBoxEnabled]=\"true\"\n [autoPageSize]=\"true\"\n [selectable]=\"{ mode: 'single', enabled: true }\"\n [showRowCheckBoxes]=\"false\"\n [actionsColumnWidth]=\"actionsColumnWidth()\"\n [actionCommandItems]=\"actionItems()\"\n [contextMenuCommandItems]=\"contextMenuItems()\"\n [leftToolbarActions]=\"toolbarItems()\"\n [listStateKey]=\"listStateKey()\"\n [messages]=\"listViewMessages()\"\n [rowClass]=\"listViewRowClass()\"\n [rowLabelField]=\"rowLabelField() || 'name'\"\n (rowClicked)=\"onRowClicked($event)\"\n>\n</mm-list-view>\n", styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%}mm-list-view{flex:1 1 auto;min-height:0}\n"], dependencies: [{ kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "rowActions", "maxInlineRowActions", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "collapseCommandsBelow", "hasExternalFilters", "emptyState", "emptyTemplate", "rowClass", "messages", "selectable", "columns", "rowLabelField"], outputs: ["rowClicked", "rowAction", "resetFilters"] }, { kind: "directive", type: EntityListDataSourceDirective, selector: "[mmEntityListDataSource]", exportAs: ["mmEntityListDataSource"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6825
6852
  }
6826
6853
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityListComponent, decorators: [{
6827
6854
  type: Component,
6828
- args: [{ selector: 'mm-entity-list', standalone: true, imports: [ListViewComponent, EntityListDataSourceDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mm-list-view\n mmEntityListDataSource\n [columns]=\"columns()\"\n [sortable]=\"true\"\n [rowFilterEnabled]=\"true\"\n [searchTextBoxEnabled]=\"true\"\n [autoPageSize]=\"true\"\n [selectable]=\"{ mode: 'single', enabled: true }\"\n [showRowCheckBoxes]=\"false\"\n [actionsColumnWidth]=\"actionsColumnWidth()\"\n [actionCommandItems]=\"actionItems()\"\n [contextMenuCommandItems]=\"contextMenuItems()\"\n [leftToolbarActions]=\"toolbarItems()\"\n [listStateKey]=\"listStateKey()\"\n [messages]=\"listViewMessages()\"\n [rowClass]=\"listViewRowClass()\"\n (rowClicked)=\"onRowClicked($event)\"\n>\n</mm-list-view>\n", styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%}mm-list-view{flex:1 1 auto;min-height:0}\n"] }]
6829
- }], ctorParameters: () => [], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], canWrite: [{ type: i0.Input, args: [{ isSignal: true, alias: "canWrite", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], listStateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "listStateKey", required: false }] }], showTypeColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTypeColumn", required: false }] }], defaultSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSort", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], toolbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarActions", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], rowMenuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowMenuActions", required: false }] }], rowClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowClass", required: false }] }], createRequested: [{ type: i0.Output, args: ["createRequested"] }], openRequested: [{ type: i0.Output, args: ["openRequested"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], dataSource: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EntityListDataSourceDirective), { isSignal: true }] }] } });
6830
- function rowName(row) {
6855
+ args: [{ selector: 'mm-entity-list', standalone: true, imports: [ListViewComponent, EntityListDataSourceDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mm-list-view\n mmEntityListDataSource\n [columns]=\"columns()\"\n [sortable]=\"true\"\n [rowFilterEnabled]=\"true\"\n [searchTextBoxEnabled]=\"true\"\n [autoPageSize]=\"true\"\n [selectable]=\"{ mode: 'single', enabled: true }\"\n [showRowCheckBoxes]=\"false\"\n [actionsColumnWidth]=\"actionsColumnWidth()\"\n [actionCommandItems]=\"actionItems()\"\n [contextMenuCommandItems]=\"contextMenuItems()\"\n [leftToolbarActions]=\"toolbarItems()\"\n [listStateKey]=\"listStateKey()\"\n [messages]=\"listViewMessages()\"\n [rowClass]=\"listViewRowClass()\"\n [rowLabelField]=\"rowLabelField() || 'name'\"\n (rowClicked)=\"onRowClicked($event)\"\n>\n</mm-list-view>\n", styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%}mm-list-view{flex:1 1 auto;min-height:0}\n"] }]
6856
+ }], ctorParameters: () => [], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], canWrite: [{ type: i0.Input, args: [{ isSignal: true, alias: "canWrite", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], listStateKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "listStateKey", required: false }] }], showTypeColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTypeColumn", required: false }] }], defaultSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSort", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], toolbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "toolbarActions", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], rowMenuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowMenuActions", required: false }] }], rowClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowClass", required: false }] }], booleanDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "booleanDisplay", required: false }] }], rowLabelField: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowLabelField", required: false }] }], createRequested: [{ type: i0.Output, args: ["createRequested"] }], openRequested: [{ type: i0.Output, args: ["openRequested"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], dataSource: [{ type: i0.ViewChild, args: [i0.forwardRef(() => EntityListDataSourceDirective), { isSignal: true }] }] } });
6857
+ function rowName(row, labelField) {
6858
+ const label = labelField ? resolveListRowLabel(row, labelField, []) : '';
6859
+ if (label) {
6860
+ return label;
6861
+ }
6831
6862
  const name = row['name'];
6832
6863
  if (typeof name === 'string' && name) {
6833
6864
  return name;
@@ -6987,6 +7018,20 @@ class EntityPageComponent {
6987
7018
  */
6988
7019
  listRowClass = input(undefined, /* @ts-ignore */
6989
7020
  ...(ngDevMode ? [{ debugName: "listRowClass" }] : /* istanbul ignore next */ []));
7021
+ /**
7022
+ * How the list renders BOOLEAN columns (AB#5623), passed to `mm-entity-list`'s `booleanDisplay`:
7023
+ * `'text'` (default) or `'icon'`. Falls back to route data `entityListBooleanDisplay`.
7024
+ */
7025
+ listBooleanDisplay = input(undefined, /* @ts-ignore */
7026
+ ...(ngDevMode ? [{ debugName: "listBooleanDisplay" }] : /* istanbul ignore next */ []));
7027
+ /**
7028
+ * Field naming a row / entity for people (AB#5623): passed to `mm-entity-list`'s
7029
+ * `rowLabelField` (row action names, delete confirmation) and used for the dialog / page title
7030
+ * ("Edit <label>") and the delete confirmation of the open entity. Falls back to route data
7031
+ * `entityListRowLabelField`; absent = today's behaviour (`name`, well-known name, display name, rtId).
7032
+ */
7033
+ listRowLabelField = input(undefined, /* @ts-ignore */
7034
+ ...(ngDevMode ? [{ debugName: "listRowLabelField" }] : /* istanbul ignore next */ []));
6990
7035
  /** Emitted for every list / create / edit transition. */
6991
7036
  navigate = output();
6992
7037
  /** Emitted after a successful create or update (not for "no changes"). Hosts refresh their lists on it. */
@@ -7096,6 +7141,19 @@ class EntityPageComponent {
7096
7141
  return typeof fromData === 'function' ? fromData : undefined;
7097
7142
  }, /* @ts-ignore */
7098
7143
  ...(ngDevMode ? [{ debugName: "effectiveListRowClass" }] : /* istanbul ignore next */ []));
7144
+ /** Row label field: input, else route data `entityListRowLabelField`, else none (default naming). */
7145
+ effectiveRowLabelField = computed(() => {
7146
+ this.routeData();
7147
+ const bound = this.listRowLabelField() ?? this.inheritedData('entityListRowLabelField');
7148
+ return typeof bound === 'string' && bound.trim() ? bound.trim() : undefined;
7149
+ }, /* @ts-ignore */
7150
+ ...(ngDevMode ? [{ debugName: "effectiveRowLabelField" }] : /* istanbul ignore next */ []));
7151
+ /** Boolean columns of the list: input, else route data `entityListBooleanDisplay`, else text. */
7152
+ effectiveListBooleanDisplay = computed(() => {
7153
+ this.routeData();
7154
+ return (this.listBooleanDisplay() ?? this.inheritedData('entityListBooleanDisplay')) === 'icon' ? 'icon' : 'text';
7155
+ }, /* @ts-ignore */
7156
+ ...(ngDevMode ? [{ debugName: "effectiveListBooleanDisplay" }] : /* istanbul ignore next */ []));
7099
7157
  /** The prefill of the current create form (AB#5623), computed when the form opens. */
7100
7158
  createInitialValues = signal(null, /* @ts-ignore */
7101
7159
  ...(ngDevMode ? [{ debugName: "createInitialValues" }] : /* istanbul ignore next */ []));
@@ -7559,7 +7617,7 @@ class EntityPageComponent {
7559
7617
  this.entityRtId.set(rtId);
7560
7618
  this.entityCkTypeId.set(ckTypeId);
7561
7619
  this.state.set(state);
7562
- const name = displayNameOf(state, rtId, rtDisplayName);
7620
+ const name = displayNameOf(state, rtId, rtDisplayName, untracked(() => this.effectiveRowLabelField()));
7563
7621
  this.entityName.set(name);
7564
7622
  }
7565
7623
  async recordsFor(model) {
@@ -7756,12 +7814,12 @@ class EntityPageComponent {
7756
7814
  }
7757
7815
  }
7758
7816
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7759
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityPageComponent, isStandalone: true, selector: "mm-entity-page", inputs: { formKey: { classPropertyName: "formKey", publicName: "formKey", isSignal: true, isRequired: false, transformFunction: null }, ckTypeId: { classPropertyName: "ckTypeId", publicName: "ckTypeId", isSignal: true, isRequired: false, transformFunction: null }, rtId: { classPropertyName: "rtId", publicName: "rtId", isSignal: true, isRequired: false, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, routerNavigation: { classPropertyName: "routerNavigation", publicName: "routerNavigation", isSignal: true, isRequired: false, transformFunction: null }, actionBarPosition: { classPropertyName: "actionBarPosition", publicName: "actionBarPosition", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null }, listToolbarActions: { classPropertyName: "listToolbarActions", publicName: "listToolbarActions", isSignal: true, isRequired: false, transformFunction: null }, listRowActions: { classPropertyName: "listRowActions", publicName: "listRowActions", isSignal: true, isRequired: false, transformFunction: null }, listRowMenuActions: { classPropertyName: "listRowMenuActions", publicName: "listRowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, listRowClass: { classPropertyName: "listRowClass", publicName: "listRowClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate", saved: "saved", deleted: "deleted" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], queries: [{ propertyName: "pageActions", first: true, predicate: EntityPageActionsDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "form", first: true, predicate: ["entityForm"], descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["entityList"], descendants: true, isSignal: true }, { propertyName: "listElement", first: true, predicate: ["entityList"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions layout=\"end\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"], dependencies: [{ kind: "component", type: EntityListComponent, selector: "mm-entity-list", inputs: ["model", "canWrite", "messages", "listStateKey", "showTypeColumn", "defaultSort", "labelResolver", "toolbarActions", "rowActions", "rowMenuActions", "rowClass"], outputs: ["createRequested", "openRequested", "deleted"] }, { kind: "component", type: EntityFormComponent, selector: "mm-entity-form", inputs: ["model", "mode", "state", "readOnly", "messages", "records", "labelResolver", "initialValues", "beforeSave"], outputs: ["changeSetChange", "validChange", "dirtyChange"] }, { kind: "component", type: EntityIdInfoComponent, selector: "mm-entity-id-info", inputs: ["rtId", "rtCkTypeId", "ckTypeId", "buttonText", "tooltip", "copiedMessage", "copyFailedMessage"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1$3.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "closable", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$3.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "directive", type: i1$3.CustomMessagesComponent, selector: "kendo-dialog-messages, kendo-window-messages" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7817
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EntityPageComponent, isStandalone: true, selector: "mm-entity-page", inputs: { formKey: { classPropertyName: "formKey", publicName: "formKey", isSignal: true, isRequired: false, transformFunction: null }, ckTypeId: { classPropertyName: "ckTypeId", publicName: "ckTypeId", isSignal: true, isRequired: false, transformFunction: null }, rtId: { classPropertyName: "rtId", publicName: "rtId", isSignal: true, isRequired: false, transformFunction: null }, canWrite: { classPropertyName: "canWrite", publicName: "canWrite", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, routerNavigation: { classPropertyName: "routerNavigation", publicName: "routerNavigation", isSignal: true, isRequired: false, transformFunction: null }, actionBarPosition: { classPropertyName: "actionBarPosition", publicName: "actionBarPosition", isSignal: true, isRequired: false, transformFunction: null }, labelResolver: { classPropertyName: "labelResolver", publicName: "labelResolver", isSignal: true, isRequired: false, transformFunction: null }, defaultSort: { classPropertyName: "defaultSort", publicName: "defaultSort", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, beforeSave: { classPropertyName: "beforeSave", publicName: "beforeSave", isSignal: true, isRequired: false, transformFunction: null }, listToolbarActions: { classPropertyName: "listToolbarActions", publicName: "listToolbarActions", isSignal: true, isRequired: false, transformFunction: null }, listRowActions: { classPropertyName: "listRowActions", publicName: "listRowActions", isSignal: true, isRequired: false, transformFunction: null }, listRowMenuActions: { classPropertyName: "listRowMenuActions", publicName: "listRowMenuActions", isSignal: true, isRequired: false, transformFunction: null }, editMode: { classPropertyName: "editMode", publicName: "editMode", isSignal: true, isRequired: false, transformFunction: null }, listRowClass: { classPropertyName: "listRowClass", publicName: "listRowClass", isSignal: true, isRequired: false, transformFunction: null }, listBooleanDisplay: { classPropertyName: "listBooleanDisplay", publicName: "listBooleanDisplay", isSignal: true, isRequired: false, transformFunction: null }, listRowLabelField: { classPropertyName: "listRowLabelField", publicName: "listRowLabelField", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { navigate: "navigate", saved: "saved", deleted: "deleted" }, providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], queries: [{ propertyName: "pageActions", first: true, predicate: EntityPageActionsDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "form", first: true, predicate: ["entityForm"], descendants: true, isSignal: true }, { propertyName: "list", first: true, predicate: ["entityList"], descendants: true, isSignal: true }, { propertyName: "listElement", first: true, predicate: ["entityList"], descendants: true, read: ElementRef, isSignal: true }], ngImport: i0, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n [booleanDisplay]=\"effectiveListBooleanDisplay()\"\n [rowLabelField]=\"effectiveRowLabelField()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions layout=\"end\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"], dependencies: [{ kind: "component", type: EntityListComponent, selector: "mm-entity-list", inputs: ["model", "canWrite", "messages", "listStateKey", "showTypeColumn", "defaultSort", "labelResolver", "toolbarActions", "rowActions", "rowMenuActions", "rowClass", "booleanDisplay", "rowLabelField"], outputs: ["createRequested", "openRequested", "deleted"] }, { kind: "component", type: EntityFormComponent, selector: "mm-entity-form", inputs: ["model", "mode", "state", "readOnly", "messages", "records", "labelResolver", "initialValues", "beforeSave"], outputs: ["changeSetChange", "validChange", "dirtyChange"] }, { kind: "component", type: EntityIdInfoComponent, selector: "mm-entity-id-info", inputs: ["rtId", "rtCkTypeId", "ckTypeId", "buttonText", "tooltip", "copiedMessage", "copyFailedMessage"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1$3.DialogComponent, selector: "kendo-dialog", inputs: ["actions", "actionsLayout", "autoFocusedElement", "closable", "title", "width", "minWidth", "maxWidth", "height", "minHeight", "maxHeight", "animation"], outputs: ["action", "close"], exportAs: ["kendoDialog"] }, { kind: "component", type: i1$3.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "directive", type: i1$3.CustomMessagesComponent, selector: "kendo-dialog-messages, kendo-window-messages" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7760
7818
  }
7761
7819
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityPageComponent, decorators: [{
7762
7820
  type: Component,
7763
- args: [{ selector: 'mm-entity-page', standalone: true, imports: [EntityListComponent, EntityFormComponent, EntityIdInfoComponent, ButtonComponent, NgTemplateOutlet, KENDO_DIALOG], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions layout=\"end\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"] }]
7764
- }], ctorParameters: () => [], propDecorators: { formKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "formKey", required: false }] }], ckTypeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "ckTypeId", required: false }] }], rtId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rtId", required: false }] }], canWrite: [{ type: i0.Input, args: [{ isSignal: true, alias: "canWrite", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], routerNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerNavigation", required: false }] }], actionBarPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionBarPosition", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], defaultSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSort", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], beforeSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "beforeSave", required: false }] }], listToolbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listToolbarActions", required: false }] }], listRowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowActions", required: false }] }], listRowMenuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowMenuActions", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], listRowClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowClass", required: false }] }], navigate: [{ type: i0.Output, args: ["navigate"] }], saved: [{ type: i0.Output, args: ["saved"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], form: [{ type: i0.ViewChild, args: ['entityForm', { isSignal: true }] }], list: [{ type: i0.ViewChild, args: ['entityList', { isSignal: true }] }], listElement: [{ type: i0.ViewChild, args: ['entityList', { ...{ read: ElementRef }, isSignal: true }] }], pageActions: [{ type: i0.ContentChild, args: [i0.forwardRef(() => EntityPageActionsDirective), { isSignal: true }] }] } });
7821
+ args: [{ selector: 'mm-entity-page', standalone: true, imports: [EntityListComponent, EntityFormComponent, EntityIdInfoComponent, ButtonComponent, NgTemplateOutlet, KENDO_DIALOG], providers: [{ provide: HAS_UNSAVED_CHANGES, useExisting: EntityPageComponent }], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"mm-entity-page\">\n @switch (view()) {\n @case ('loading') {\n <div class=\"mm-entity-page__state\">{{ msgs().loading }}</div>\n }\n\n @case ('error') {\n <div class=\"mm-entity-page__state mm-entity-page__state--error\" role=\"alert\">\n <p>{{ errorMessage() }}</p>\n @if (baseModel() && !isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" (click)=\"onBack()\">{{ msgs().back }}</button>\n }\n </div>\n }\n\n @case ('list') {\n @if (baseModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ listTitle() }}</h2>\n @if (localizedBase()?.description; as description) {\n <p class=\"mm-entity-page__description\">{{ description }}</p>\n }\n </div>\n @if (pageActions(); as actions) {\n <div class=\"mm-entity-page__actions\" data-entity-page-host-actions>\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n </div>\n }\n </header>\n <mm-entity-list\n #entityList\n class=\"mm-entity-page__list\"\n [model]=\"model\"\n [canWrite]=\"effectiveCanWrite()\"\n [messages]=\"msgs()\"\n [showTypeColumn]=\"showTypeColumn()\"\n [defaultSort]=\"effectiveDefaultSort()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [toolbarActions]=\"listToolbarActions()\"\n [rowActions]=\"listRowActions()\"\n [rowMenuActions]=\"listRowMenuActions()\"\n [rowClass]=\"effectiveListRowClass()\"\n [booleanDisplay]=\"effectiveListBooleanDisplay()\"\n [rowLabelField]=\"effectiveRowLabelField()\"\n (createRequested)=\"onCreateRequested($event)\"\n (openRequested)=\"onOpenRequested($event)\"\n />\n\n <!-- Dialog mode (editMode 'dialog', AB#5623): create / edit over the list, actions in the\n dialog's bottom bar (Cancel left of the primary Save, as in the record row dialog). -->\n @if (dialogOpen()) {\n @if (formModel(); as formModelInDialog) {\n <kendo-dialog\n class=\"mm-entity-page__dialog\"\n data-entity-page-dialog\n [title]=\"title()\"\n [width]=\"760\"\n [maxWidth]=\"'95vw'\"\n [maxHeight]=\"'90vh'\"\n (close)=\"onDialogCancel()\"\n >\n <kendo-dialog-messages [closeTitle]=\"msgs().close\" />\n <div class=\"mm-entity-page__dialog-body\">\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"formModelInDialog\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n </div>\n <kendo-dialog-actions layout=\"end\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: dialogActionsContext()\" />\n }\n <button kendoButton type=\"button\" data-entity-page-dialog-cancel (click)=\"onDialogCancel()\">\n {{ mode() === 'view' ? msgs().close : msgs().cancel }}\n </button>\n @if (canDeleteEntity()) {\n <button kendoButton type=\"button\" fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton type=\"button\" themeColor=\"primary\" [svgIcon]=\"saveIcon\"\n [disabled]=\"saving() || !!saveBlockedReason()\" [attr.title]=\"saveBlockedReason()\"\n data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </kendo-dialog-actions>\n </kendo-dialog>\n }\n }\n }\n }\n\n @case ('form') {\n @if (formModel(); as model) {\n <header class=\"mm-entity-page__header\">\n <div class=\"mm-entity-page__titles\">\n <h2 class=\"mm-entity-page__title\">{{ title() }}</h2>\n @if (mode() !== 'create' && entityRtId()) {\n <mm-entity-id-info\n [rtId]=\"entityRtId()!\"\n [rtCkTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [ckTypeId]=\"entityCkTypeId() ?? model.rtCkTypeId\"\n [buttonText]=\"msgs().copyId\"\n [tooltip]=\"msgs().copyIdTooltip\"\n [copiedMessage]=\"msgs().copiedId\"\n [copyFailedMessage]=\"msgs().copyFailed\"\n />\n }\n </div>\n @if (effectiveActionBarPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"formActions\" />\n }\n </header>\n @if (mode() === 'view') {\n <p class=\"mm-entity-page__notice\">{{ msgs().readOnlyNotice }}</p>\n }\n @if (mode() === 'create' && singletonWellKnownName()) {\n <p class=\"mm-entity-page__notice\">{{ msgs().singletonCreateHint }}</p>\n }\n <mm-entity-form\n #entityForm\n class=\"mm-entity-page__form\"\n [model]=\"model\"\n [mode]=\"mode()\"\n [state]=\"state()\"\n [readOnly]=\"readOnly()\"\n [messages]=\"msgs()\"\n [records]=\"records()\"\n [labelResolver]=\"effectiveLabelResolver()\"\n [initialValues]=\"createInitialValues()\"\n />\n @if (effectiveActionBarPosition() === 'bottom') {\n <footer class=\"mm-entity-page__footer\" data-entity-page-footer>\n <ng-container *ngTemplateOutlet=\"formActions\" />\n </footer>\n }\n\n <ng-template #formActions>\n <div class=\"mm-entity-page__actions\">\n @if (pageActions(); as actions) {\n <ng-container *ngTemplateOutlet=\"actions.templateRef; context: actionsContext()\" />\n }\n @if (!isSingleton()) {\n <button kendoButton fillMode=\"flat\" [svgIcon]=\"backIcon\" data-entity-page-back (click)=\"onBack()\">\n {{ mode() === 'view' ? msgs().back : msgs().cancel }}\n </button>\n }\n @if (canDeleteEntity()) {\n <button kendoButton fillMode=\"outline\" themeColor=\"error\" [svgIcon]=\"deleteIcon\" (click)=\"onDelete()\">\n {{ msgs().delete }}\n </button>\n }\n @if (mode() !== 'view') {\n <button kendoButton themeColor=\"primary\" [svgIcon]=\"saveIcon\" [disabled]=\"saving() || !!saveBlockedReason()\"\n [attr.title]=\"saveBlockedReason()\" data-entity-page-save (click)=\"onSave()\">\n {{ msgs().save }}\n </button>\n }\n </div>\n </ng-template>\n }\n }\n }\n</div>\n", styles: [":host{display:block;height:100%;min-height:0}.mm-entity-page{display:flex;flex-direction:column;gap:12px;height:100%;min-height:0;padding:16px;box-sizing:border-box;color:var(--theme-text-primary, inherit)}.mm-entity-page__header{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:12px}.mm-entity-page__titles{display:flex;flex-direction:column;gap:4px;min-width:0}.mm-entity-page__title{margin:0;font-size:1.25rem;font-weight:600;overflow-wrap:anywhere}.mm-entity-page__description,.mm-entity-page__notice{margin:0;color:var(--theme-text-secondary, inherit);opacity:.85}.mm-entity-page__actions{display:flex;flex-wrap:wrap;gap:8px}.mm-entity-page__list{flex:1 1 auto;min-height:300px}.mm-entity-page__form{flex:1 1 auto;min-height:0;overflow:auto}.mm-entity-page__state{padding:24px 0;color:var(--theme-text-secondary, inherit)}.mm-entity-page__state--error{color:var(--theme-status-error, inherit)}.mm-entity-page__footer{display:flex;justify-content:flex-end;flex-shrink:0;padding-top:12px;border-top:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .12))}.mm-entity-page__dialog-body{display:flex;flex-direction:column;gap:12px}\n"] }]
7822
+ }], ctorParameters: () => [], propDecorators: { formKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "formKey", required: false }] }], ckTypeId: [{ type: i0.Input, args: [{ isSignal: true, alias: "ckTypeId", required: false }] }], rtId: [{ type: i0.Input, args: [{ isSignal: true, alias: "rtId", required: false }] }], canWrite: [{ type: i0.Input, args: [{ isSignal: true, alias: "canWrite", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], routerNavigation: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerNavigation", required: false }] }], actionBarPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionBarPosition", required: false }] }], labelResolver: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelResolver", required: false }] }], defaultSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultSort", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], beforeSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "beforeSave", required: false }] }], listToolbarActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listToolbarActions", required: false }] }], listRowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowActions", required: false }] }], listRowMenuActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowMenuActions", required: false }] }], editMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editMode", required: false }] }], listRowClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowClass", required: false }] }], listBooleanDisplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "listBooleanDisplay", required: false }] }], listRowLabelField: [{ type: i0.Input, args: [{ isSignal: true, alias: "listRowLabelField", required: false }] }], navigate: [{ type: i0.Output, args: ["navigate"] }], saved: [{ type: i0.Output, args: ["saved"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], form: [{ type: i0.ViewChild, args: ['entityForm', { isSignal: true }] }], list: [{ type: i0.ViewChild, args: ['entityList', { isSignal: true }] }], listElement: [{ type: i0.ViewChild, args: ['entityList', { ...{ read: ElementRef }, isSignal: true }] }], pageActions: [{ type: i0.ContentChild, args: [i0.forwardRef(() => EntityPageActionsDirective), { isSignal: true }] }] } });
7765
7823
  /** The focused element (the dialog's trigger), or `null` outside a browser. */
7766
7824
  function activeElement() {
7767
7825
  const element = typeof document !== 'undefined' ? document.activeElement : null;
@@ -7777,7 +7835,11 @@ function paramValue(map, key) {
7777
7835
  * Entity label: `name` attribute, then `rtWellKnownName`, then a computed `rtDisplayName`
7778
7836
  * (the backend's synthetic `<ckTypeId>@<rtId>` form counts as absent), then the rtId.
7779
7837
  */
7780
- function displayNameOf(state, rtId, rtDisplayName) {
7838
+ function displayNameOf(state, rtId, rtDisplayName, labelField) {
7839
+ const label = labelField ? resolveListRowLabel(state.values, labelField, []) : '';
7840
+ if (label) {
7841
+ return label;
7842
+ }
7781
7843
  const name = state.values['name'];
7782
7844
  if (typeof name === 'string' && name) {
7783
7845
  return name;
@@ -7808,7 +7870,7 @@ var entityPage_component = /*#__PURE__*/Object.freeze({
7808
7870
  * ```
7809
7871
  */
7810
7872
  function entityFormRoutes(opts = {}) {
7811
- const { formKey, ckTypeId, canWrite, messages, breadcrumbUrl, breadcrumbLabel = '{{entityFormTitle}}', newBreadcrumbLabel = 'New', entityBreadcrumbLabel = '{{entityName}}', svgIcon, title, showTypeColumn, defaultSort, actionBarPosition, initialValues, beforeSave, rowClass, editMode, data = {}, } = opts;
7873
+ const { formKey, ckTypeId, canWrite, messages, breadcrumbUrl, breadcrumbLabel = '{{entityFormTitle}}', newBreadcrumbLabel = 'New', entityBreadcrumbLabel = '{{entityName}}', svgIcon, title, showTypeColumn, defaultSort, actionBarPosition, initialValues, beforeSave, rowClass, editMode, booleanDisplay, rowLabelField, data = {}, } = opts;
7812
7874
  const baseData = {
7813
7875
  ...data,
7814
7876
  ...(formKey !== undefined && { formKey }),
@@ -7823,6 +7885,8 @@ function entityFormRoutes(opts = {}) {
7823
7885
  ...(beforeSave !== undefined && { entityFormBeforeSave: beforeSave }),
7824
7886
  ...(rowClass !== undefined && { entityListRowClass: rowClass }),
7825
7887
  ...(editMode !== undefined && { entityPageEditMode: editMode }),
7888
+ ...(booleanDisplay !== undefined && { entityListBooleanDisplay: booleanDisplay }),
7889
+ ...(rowLabelField !== undefined && { entityListRowLabelField: rowLabelField }),
7826
7890
  };
7827
7891
  const listCrumb = breadcrumbUrl !== undefined
7828
7892
  ? { label: breadcrumbLabel, url: breadcrumbUrl, ...(svgIcon && { svgIcon }) }