@meshmakers/octo-ui 3.4.1450 → 3.4.1490

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
1
  import * as i0 from '@angular/core';
2
- import { inject, ChangeDetectionStrategy, Component, Injectable, Input, EventEmitter, Output, ElementRef, forwardRef, ViewChild, signal, computed, input, model, output, effect, untracked, Directive, InjectionToken, viewChild, HostListener, makeEnvironmentProviders } from '@angular/core';
2
+ import { inject, ChangeDetectionStrategy, Component, Injectable, Input, EventEmitter, Output, LOCALE_ID, ElementRef, forwardRef, ViewChild, signal, computed, input, model, output, effect, untracked, Directive, booleanAttribute, viewChild, afterEveryRender, InjectionToken, HostListener, makeEnvironmentProviders } from '@angular/core';
3
3
  import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
4
- import { AttributeSelectorService, AttributeValueTypeDto as AttributeValueTypeDto$1, CkTypeSelectorService, CkTypeAttributeService, GetEntitiesByCkTypeDtoGQL, RuntimeEntitySelectDataSource, RuntimeEntityDialogDataSource, SearchFilterTypesDto, SortOrdersDto, FieldFilterOperatorsDto, GetCkTypesDtoGQL, GetCkModelByIdDtoGQL, GraphDirectionDto, CkTypeMetaData, AssociationModOptionsDto, GraphQL, DeleteStrategiesDto, CommunicationService, provideOctoServices } from '@meshmakers/octo-services';
4
+ import { AttributeSelectorService, AttributeValueTypeDto as AttributeValueTypeDto$1, CkTypeSelectorService, CkTypeAttributeService, toSecretState, secretStateFromAttribute, isSecretValueType, isSecretStateObject, secretStatusOf, formatSecretStatus, GetEntitiesByCkTypeDtoGQL, RuntimeEntitySelectDataSource, RuntimeEntityDialogDataSource, SearchFilterTypesDto, SortOrdersDto, FieldFilterOperatorsDto, GetCkTypesDtoGQL, GetCkModelByIdDtoGQL, GraphDirectionDto, CkTypeMetaData, AssociationModOptionsDto, GraphQL, isSecretAttributeCandidate, toUniqueCamelCaseNames, toCamelCaseAttributeName, DeleteStrategiesDto, CommunicationService, provideOctoServices } from '@meshmakers/octo-services';
5
5
  import { Roles, provideMmSharedAuth } from '@meshmakers/shared-auth';
6
- import { WindowStateService, EntitySelectInputComponent, DataSourceTyped, HierarchyDataSourceBase, NotificationDisplayService, TreeComponent, ListViewComponent, FetchResultTyped, DataSourceBase, InputService, BaseTreeDetailComponent, ConfirmationService, provideMmSharedUi } from '@meshmakers/shared-ui';
6
+ import { WindowStateService, EntitySelectInputComponent, DataSourceTyped, HierarchyDataSourceBase, NotificationDisplayService, TreeComponent, ListViewComponent, FetchResultTyped, DataSourceBase, MM_ACTION_ICONS, ConfirmationService, InputService, BaseTreeDetailComponent, provideMmSharedUi } from '@meshmakers/shared-ui';
7
7
  import * as i1$2 from '@angular/common';
8
- import { CommonModule, Location } from '@angular/common';
8
+ import { CommonModule, formatDate, Location } from '@angular/common';
9
9
  import * as i1 from '@angular/forms';
10
10
  import { FormsModule, FormControl, ReactiveFormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormArray, Validators, FormGroup, FormBuilder } from '@angular/forms';
11
11
  import * as i1$1 from '@progress/kendo-angular-buttons';
@@ -19,8 +19,8 @@ import * as i5$1 from '@progress/kendo-angular-icons';
19
19
  import { IconsModule, SVGIconModule, SVGIconComponent } from '@progress/kendo-angular-icons';
20
20
  import * as i5 from '@progress/kendo-angular-inputs';
21
21
  import { InputsModule, TextBoxModule, KENDO_INPUTS, SwitchModule } from '@progress/kendo-angular-inputs';
22
- import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, filterClearIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, chevronRightIcon, chevronDownIcon, downloadIcon, windowIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, pencilIcon, trashIcon, copyIcon, folderMoreIcon, gearIcon, folderOpenIcon, plusIcon, minusIcon, dollarIcon, hyperlinkOpenIcon, infoCircleIcon, eyeIcon, arrowRotateCcwIcon, locationsIcon, arrowRotateCwIcon, xIcon, checkCircleIcon, exclamationCircleIcon, xCircleIcon, warningCircleIcon, gridIcon, uploadIcon, linkIcon, lightbulbOutlineIcon, brightnessContrastIcon } from '@progress/kendo-svg-icons';
23
- import { Subject, firstValueFrom, Subscription, of, forkJoin, map as map$1, takeUntil as takeUntil$1, catchError as catchError$1, defer, from, finalize, switchMap as switchMap$1, startWith } from 'rxjs';
22
+ import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, filterClearIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, chevronRightIcon, chevronDownIcon, downloadIcon, windowIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, pencilIcon, trashIcon, copyIcon, folderMoreIcon, gearIcon, folderOpenIcon, plusIcon, minusIcon, dollarIcon, hyperlinkOpenIcon, infoCircleIcon, eyeIcon, arrowRotateCcwIcon, locationsIcon, arrowRotateCwIcon, checkCircleIcon, exclamationCircleIcon, xCircleIcon, warningCircleIcon, gridIcon, xIcon, linkIcon, lightbulbOutlineIcon, brightnessContrastIcon } from '@progress/kendo-svg-icons';
23
+ import { Subject, firstValueFrom, Subscription, of, forkJoin, map as map$1, catchError as catchError$1, takeUntil as takeUntil$1, defer, from, switchMap as switchMap$1, finalize, startWith } from 'rxjs';
24
24
  import { debounceTime, distinctUntilChanged, map, switchMap, tap, catchError, takeUntil } from 'rxjs/operators';
25
25
  import { LoaderModule, BadgeModule } from '@progress/kendo-angular-indicators';
26
26
  import * as i1$3 from 'apollo-angular';
@@ -266,6 +266,8 @@ class AttributeSortSelectorDialogComponent {
266
266
  kendoButton
267
267
  [svgIcon]="searchIcon"
268
268
  fillMode="clear"
269
+ title="Search"
270
+ aria-label="Search"
269
271
  ></button>
270
272
  </ng-template>
271
273
  </kendo-textbox>
@@ -340,7 +342,7 @@ class AttributeSortSelectorDialogComponent {
340
342
  "
341
343
  (click)="setSortOrder('ascending')"
342
344
  class="sort-button"
343
- title="Ascending"
345
+ title="Ascending" aria-label="Ascending"
344
346
  ></button>
345
347
  <button
346
348
  kendoButton
@@ -353,7 +355,7 @@ class AttributeSortSelectorDialogComponent {
353
355
  "
354
356
  (click)="setSortOrder('descending')"
355
357
  class="sort-button"
356
- title="Descending"
358
+ title="Descending" aria-label="Descending"
357
359
  ></button>
358
360
  </div>
359
361
 
@@ -447,6 +449,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
447
449
  kendoButton
448
450
  [svgIcon]="searchIcon"
449
451
  fillMode="clear"
452
+ title="Search"
453
+ aria-label="Search"
450
454
  ></button>
451
455
  </ng-template>
452
456
  </kendo-textbox>
@@ -521,7 +525,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
521
525
  "
522
526
  (click)="setSortOrder('ascending')"
523
527
  class="sort-button"
524
- title="Ascending"
528
+ title="Ascending" aria-label="Ascending"
525
529
  ></button>
526
530
  <button
527
531
  kendoButton
@@ -534,7 +538,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
534
538
  "
535
539
  (click)="setSortOrder('descending')"
536
540
  class="sort-button"
537
- title="Descending"
541
+ title="Descending" aria-label="Descending"
538
542
  ></button>
539
543
  </div>
540
544
 
@@ -919,13 +923,13 @@ class CkTypeSelectorDialogComponent {
919
923
  [placeholder]="_messages.typeSearchPlaceholder"
920
924
  class="filter-input">
921
925
  <ng-template kendoTextBoxSuffixTemplate>
922
- <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
926
+ <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small" title="Search" aria-label="Search"></button>
923
927
  </ng-template>
924
928
  </kendo-textbox>
925
929
  </div>
926
930
  <div class="filter-item filter-actions">
927
931
  <label>&nbsp;</label>
928
- <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" [title]="_messages.clearFiltersTitle"></button>
932
+ <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" [title]="_messages.clearFiltersTitle" [attr.aria-label]="_messages.clearFiltersTitle"></button>
929
933
  </div>
930
934
  </div>
931
935
  </div>
@@ -986,7 +990,7 @@ class CkTypeSelectorDialogComponent {
986
990
  <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">{{ _messages.ok }}</button>
987
991
  </div>
988
992
  </div>
989
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.ck-type-selector-container{display:flex;flex-direction:column;flex:1;min-height:0;padding:20px;box-sizing:border-box;gap:12px}.filter-container{margin-bottom:16px;flex-shrink:0}.filter-row{display:flex;gap:16px;align-items:flex-end}.filter-item{display:flex;flex-direction:column;gap:4px}.filter-item label{font-size:12px;font-weight:500}.filter-item.flex-grow{flex:1}.filter-item.filter-actions{flex-shrink:0}.filter-input{min-width:180px}.grid-container{flex:1;min-height:0;display:flex;flex-direction:column}.grid-container kendo-grid,.grid-container .type-grid{flex:1;min-height:200px}.type-grid{border-radius:4px}.type-grid ::ng-deep .k-grid-table tbody tr{cursor:pointer}.abstract-type{font-style:italic;opacity:.7}.final-type{font-weight:600}.type-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:10px;margin-left:8px;text-transform:uppercase}.type-badge.abstract{background-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-on-warning, #000);opacity:.8}.type-badge.final{background-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-on-success, #fff);opacity:.8}.selection-info{margin-top:12px;padding:8px 12px;background:var(--kendo-color-success-subtle, #d4edda);border:1px solid var(--kendo-color-success, #28a745);border-radius:4px;font-size:14px;flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;padding:8px 20px 0;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: i3.SelectionDirective, selector: "[kendoGridSelectBy]" }, { kind: "component", type: i3.CustomMessagesComponent, selector: "kendo-grid-messages" }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1$1.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: "ngmodule", type: InputsModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: i5.TextBoxSuffixTemplateDirective, selector: "[kendoTextBoxSuffixTemplate]", inputs: ["showSeparator"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "ngmodule", type: IconsModule }, { kind: "ngmodule", type: LoaderModule }, { kind: "ngmodule", type: WindowModule }], changeDetection: i0.ChangeDetectionStrategy.Eager });
993
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%}.ck-type-selector-container{display:flex;flex-direction:column;flex:1;min-height:0;padding:20px;box-sizing:border-box;gap:12px}.filter-container{margin-bottom:16px;flex-shrink:0}.filter-row{display:flex;gap:16px;align-items:flex-end}.filter-item{display:flex;flex-direction:column;gap:4px}.filter-item label{font-size:12px;font-weight:500}.filter-item.flex-grow{flex:1}.filter-item.filter-actions{flex-shrink:0}.filter-input{min-width:180px}.grid-container{flex:1;min-height:0;display:flex;flex-direction:column}.grid-container kendo-grid,.grid-container .type-grid{flex:1;min-height:200px}.type-grid{border-radius:4px}.type-grid ::ng-deep .k-grid-table tbody tr{cursor:pointer}.abstract-type{font-style:italic;opacity:.7}.final-type{font-weight:600}.type-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:10px;margin-left:8px}.type-badge.abstract{background-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-on-warning, #000);opacity:.8}.type-badge.final{background-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-on-success, #fff);opacity:.8}.selection-info{margin-top:12px;padding:8px 12px;background:var(--kendo-color-success-subtle, #d4edda);border:1px solid var(--kendo-color-success, #28a745);border-radius:4px;font-size:14px;flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;padding:8px 20px 0;flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: i3.SelectionDirective, selector: "[kendoGridSelectBy]" }, { kind: "component", type: i3.CustomMessagesComponent, selector: "kendo-grid-messages" }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1$1.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: "ngmodule", type: InputsModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "directive", type: i5.TextBoxSuffixTemplateDirective, selector: "[kendoTextBoxSuffixTemplate]", inputs: ["showSeparator"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "ngmodule", type: IconsModule }, { kind: "ngmodule", type: LoaderModule }, { kind: "ngmodule", type: WindowModule }], changeDetection: i0.ChangeDetectionStrategy.Eager });
990
994
  }
991
995
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: CkTypeSelectorDialogComponent, decorators: [{
992
996
  type: Component,
@@ -1024,13 +1028,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
1024
1028
  [placeholder]="_messages.typeSearchPlaceholder"
1025
1029
  class="filter-input">
1026
1030
  <ng-template kendoTextBoxSuffixTemplate>
1027
- <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
1031
+ <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small" title="Search" aria-label="Search"></button>
1028
1032
  </ng-template>
1029
1033
  </kendo-textbox>
1030
1034
  </div>
1031
1035
  <div class="filter-item filter-actions">
1032
1036
  <label>&nbsp;</label>
1033
- <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" [title]="_messages.clearFiltersTitle"></button>
1037
+ <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" [title]="_messages.clearFiltersTitle" [attr.aria-label]="_messages.clearFiltersTitle"></button>
1034
1038
  </div>
1035
1039
  </div>
1036
1040
  </div>
@@ -1091,7 +1095,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
1091
1095
  <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">{{ _messages.ok }}</button>
1092
1096
  </div>
1093
1097
  </div>
1094
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%}.ck-type-selector-container{display:flex;flex-direction:column;flex:1;min-height:0;padding:20px;box-sizing:border-box;gap:12px}.filter-container{margin-bottom:16px;flex-shrink:0}.filter-row{display:flex;gap:16px;align-items:flex-end}.filter-item{display:flex;flex-direction:column;gap:4px}.filter-item label{font-size:12px;font-weight:500}.filter-item.flex-grow{flex:1}.filter-item.filter-actions{flex-shrink:0}.filter-input{min-width:180px}.grid-container{flex:1;min-height:0;display:flex;flex-direction:column}.grid-container kendo-grid,.grid-container .type-grid{flex:1;min-height:200px}.type-grid{border-radius:4px}.type-grid ::ng-deep .k-grid-table tbody tr{cursor:pointer}.abstract-type{font-style:italic;opacity:.7}.final-type{font-weight:600}.type-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:10px;margin-left:8px;text-transform:uppercase}.type-badge.abstract{background-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-on-warning, #000);opacity:.8}.type-badge.final{background-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-on-success, #fff);opacity:.8}.selection-info{margin-top:12px;padding:8px 12px;background:var(--kendo-color-success-subtle, #d4edda);border:1px solid var(--kendo-color-success, #28a745);border-radius:4px;font-size:14px;flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;padding:8px 20px 0;flex-shrink:0}\n"] }]
1098
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%}.ck-type-selector-container{display:flex;flex-direction:column;flex:1;min-height:0;padding:20px;box-sizing:border-box;gap:12px}.filter-container{margin-bottom:16px;flex-shrink:0}.filter-row{display:flex;gap:16px;align-items:flex-end}.filter-item{display:flex;flex-direction:column;gap:4px}.filter-item label{font-size:12px;font-weight:500}.filter-item.flex-grow{flex:1}.filter-item.filter-actions{flex-shrink:0}.filter-input{min-width:180px}.grid-container{flex:1;min-height:0;display:flex;flex-direction:column}.grid-container kendo-grid,.grid-container .type-grid{flex:1;min-height:200px}.type-grid{border-radius:4px}.type-grid ::ng-deep .k-grid-table tbody tr{cursor:pointer}.abstract-type{font-style:italic;opacity:.7}.final-type{font-weight:600}.type-badge{display:inline-block;font-size:10px;padding:1px 6px;border-radius:10px;margin-left:8px}.type-badge.abstract{background-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-on-warning, #000);opacity:.8}.type-badge.final{background-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-on-success, #fff);opacity:.8}.selection-info{margin-top:12px;padding:8px 12px;background:var(--kendo-color-success-subtle, #d4edda);border:1px solid var(--kendo-color-success, #28a745);border-radius:4px;font-size:14px;flex-shrink:0}.dialog-actions{display:flex;justify-content:flex-end;gap:8px;padding:8px 20px 0;flex-shrink:0}\n"] }]
1095
1099
  }], propDecorators: { messages: [{
1096
1100
  type: Input
1097
1101
  }] } });
@@ -1196,6 +1200,8 @@ var AttributeValueTypeDto;
1196
1200
  AttributeValueTypeDto["IntArrayDto"] = "INT_ARRAY";
1197
1201
  AttributeValueTypeDto["RecordDto"] = "RECORD";
1198
1202
  AttributeValueTypeDto["RecordArrayDto"] = "RECORD_ARRAY";
1203
+ /** SECRET value type (AB#5528): the value is never read; `value` holds a `SecretState`. */
1204
+ AttributeValueTypeDto["SecretDto"] = "SECRET";
1199
1205
  AttributeValueTypeDto["StringDto"] = "STRING";
1200
1206
  AttributeValueTypeDto["StringArrayDto"] = "STRING_ARRAY";
1201
1207
  AttributeValueTypeDto["TimeSpanDto"] = "TIME_SPAN";
@@ -1434,6 +1440,24 @@ class PropertyConverterService {
1434
1440
  * Convert a single attribute to PropertyGridItem
1435
1441
  */
1436
1442
  convertSingleAttribute(attr, index, ckAttributeMap) {
1443
+ // SECRET (AB#5528): never a value — the set / not-set state is shown as a read-only badge.
1444
+ const ckType = attr?.attributeName ? ckAttributeMap.get(attr.attributeName) : undefined;
1445
+ const marker = attr?.value && typeof attr.value === 'object' && 'isSet' in attr.value
1446
+ ? toSecretState(attr.value)
1447
+ : null;
1448
+ const secretState = secretStateFromAttribute(attr) ?? (isSecretValueType(ckType) ? marker : null);
1449
+ if (secretState || isSecretValueType(ckType)) {
1450
+ return {
1451
+ id: `attr_${index}_${attr?.attributeName || 'unknown'}`,
1452
+ name: attr?.attributeName || `attribute_${index}`,
1453
+ displayName: attr?.attributeName || `attribute_${index}`,
1454
+ value: secretState ?? { isSet: false, keyMissing: false, setAt: null },
1455
+ type: AttributeValueTypeDto.SecretDto,
1456
+ category: DefaultPropertyCategory.Attributes,
1457
+ readOnly: true,
1458
+ description: `Attribute: ${attr?.attributeName} (secret, write-only)`
1459
+ };
1460
+ }
1437
1461
  const value = this.convertRtEntityAttributeValueSync(attr?.value);
1438
1462
  return {
1439
1463
  id: `attr_${index}_${attr?.attributeName || 'unknown'}`,
@@ -1484,6 +1508,7 @@ class PropertyConverterService {
1484
1508
  'RECORD_ARRAY': AttributeValueTypeDto.RecordArrayDto,
1485
1509
  'STRING': AttributeValueTypeDto.StringDto,
1486
1510
  'STRING_ARRAY': AttributeValueTypeDto.StringArrayDto,
1511
+ 'SECRET': AttributeValueTypeDto.SecretDto,
1487
1512
  'TIME_SPAN': AttributeValueTypeDto.TimeSpanDto
1488
1513
  };
1489
1514
  return typeMap[ckType] || AttributeValueTypeDto.StringDto;
@@ -1930,7 +1955,7 @@ class RecordDetailDialogComponent {
1930
1955
  </kendo-grid>
1931
1956
  }
1932
1957
  </div>
1933
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.record-detail-content{display:flex;flex-direction:column;height:100%;gap:8px;padding:12px 16px;box-sizing:border-box;overflow:hidden}.record-toolbar{display:flex;align-items:center;gap:8px;flex-shrink:0;padding-bottom:4px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.toolbar-spacer{flex:1}.search-input{flex:0 1 220px;min-width:0;padding:4px 8px;font:inherit;color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;outline:none}.search-input::placeholder{color:var(--kendo-color-subtle, #6c757d)}.search-input:focus{border-color:var(--kendo-color-primary, #0d6efd)}.search-clear{flex-shrink:0;width:22px;height:22px;padding:0;background:transparent;border:none;cursor:pointer;font-size:1.1em;line-height:1;color:var(--kendo-color-subtle, #6c757d);border-radius:3px}.search-clear:hover{color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent)}.match-count{flex-shrink:0;font-size:.8em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.no-matches{padding:16px;text-align:center;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.record-array-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex:1;min-height:0}.record-array-item{display:block;flex-shrink:0;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.array-item-header{display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--kendo-color-surface-alt, #f8f9fa);transition:background-color .15s ease}.array-item-header:hover{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-chevron{width:14px;height:14px;color:var(--kendo-color-subtle);flex-shrink:0}.array-item-index{font-family:Roboto Mono,monospace;font-size:.8em;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.array-item-label{font-size:.85em;color:var(--kendo-color-on-app-surface, #1d1b20);font-weight:500}.array-item-summary{margin-left:auto;font-size:.75em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.detail-grid{display:block!important;height:auto!important;border:none;border-top:1px solid var(--kendo-color-border, #dee2e6)}:host ::ng-deep .detail-grid .k-grid-aria-root{height:auto}.property-name-cell{display:flex;align-items:center;gap:8px}.type-icon{width:16px;height:16px;opacity:.7}.property-name{font-weight:500}.property-value{word-break:break-word;white-space:pre-wrap}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;text-transform:uppercase;font-weight:500;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);color:var(--kendo-color-on-app-surface, #1d1b20)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
1958
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.record-detail-content{display:flex;flex-direction:column;height:100%;gap:8px;padding:12px 16px;box-sizing:border-box;overflow:hidden}.record-toolbar{display:flex;align-items:center;gap:8px;flex-shrink:0;padding-bottom:4px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.toolbar-spacer{flex:1}.search-input{flex:0 1 220px;min-width:0;padding:4px 8px;font:inherit;color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;outline:none}.search-input::placeholder{color:var(--kendo-color-subtle, #6c757d)}.search-input:focus{border-color:var(--kendo-color-primary, #0d6efd)}.search-clear{flex-shrink:0;width:22px;height:22px;padding:0;background:transparent;border:none;cursor:pointer;font-size:1.1em;line-height:1;color:var(--kendo-color-subtle, #6c757d);border-radius:3px}.search-clear:hover{color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent)}.match-count{flex-shrink:0;font-size:.8em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.no-matches{padding:16px;text-align:center;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.record-array-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex:1;min-height:0}.record-array-item{display:block;flex-shrink:0;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.array-item-header{display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--kendo-color-surface-alt, #f8f9fa);transition:background-color .15s ease}.array-item-header:hover{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-chevron{width:14px;height:14px;color:var(--kendo-color-subtle);flex-shrink:0}.array-item-index{font-family:Roboto Mono,monospace;font-size:.8em;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.array-item-label{font-size:.85em;color:var(--kendo-color-on-app-surface, #1d1b20);font-weight:500}.array-item-summary{margin-left:auto;font-size:.75em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.detail-grid{display:block!important;height:auto!important;border:none;border-top:1px solid var(--kendo-color-border, #dee2e6)}:host ::ng-deep .detail-grid .k-grid-aria-root{height:auto}.property-name-cell{display:flex;align-items:center;gap:8px}.type-icon{width:16px;height:16px;opacity:.7}.property-name{font-weight:500}.property-value{word-break:break-word;white-space:pre-wrap}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;font-weight:500;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);color:var(--kendo-color-on-app-surface, #1d1b20)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
1934
1959
  }
1935
1960
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RecordDetailDialogComponent, decorators: [{
1936
1961
  type: Component,
@@ -2041,7 +2066,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
2041
2066
  </kendo-grid>
2042
2067
  }
2043
2068
  </div>
2044
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.record-detail-content{display:flex;flex-direction:column;height:100%;gap:8px;padding:12px 16px;box-sizing:border-box;overflow:hidden}.record-toolbar{display:flex;align-items:center;gap:8px;flex-shrink:0;padding-bottom:4px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.toolbar-spacer{flex:1}.search-input{flex:0 1 220px;min-width:0;padding:4px 8px;font:inherit;color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;outline:none}.search-input::placeholder{color:var(--kendo-color-subtle, #6c757d)}.search-input:focus{border-color:var(--kendo-color-primary, #0d6efd)}.search-clear{flex-shrink:0;width:22px;height:22px;padding:0;background:transparent;border:none;cursor:pointer;font-size:1.1em;line-height:1;color:var(--kendo-color-subtle, #6c757d);border-radius:3px}.search-clear:hover{color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent)}.match-count{flex-shrink:0;font-size:.8em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.no-matches{padding:16px;text-align:center;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.record-array-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex:1;min-height:0}.record-array-item{display:block;flex-shrink:0;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.array-item-header{display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--kendo-color-surface-alt, #f8f9fa);transition:background-color .15s ease}.array-item-header:hover{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-chevron{width:14px;height:14px;color:var(--kendo-color-subtle);flex-shrink:0}.array-item-index{font-family:Roboto Mono,monospace;font-size:.8em;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.array-item-label{font-size:.85em;color:var(--kendo-color-on-app-surface, #1d1b20);font-weight:500}.array-item-summary{margin-left:auto;font-size:.75em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.detail-grid{display:block!important;height:auto!important;border:none;border-top:1px solid var(--kendo-color-border, #dee2e6)}:host ::ng-deep .detail-grid .k-grid-aria-root{height:auto}.property-name-cell{display:flex;align-items:center;gap:8px}.type-icon{width:16px;height:16px;opacity:.7}.property-name{font-weight:500}.property-value{word-break:break-word;white-space:pre-wrap}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;text-transform:uppercase;font-weight:500;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);color:var(--kendo-color-on-app-surface, #1d1b20)}\n"] }]
2069
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.record-detail-content{display:flex;flex-direction:column;height:100%;gap:8px;padding:12px 16px;box-sizing:border-box;overflow:hidden}.record-toolbar{display:flex;align-items:center;gap:8px;flex-shrink:0;padding-bottom:4px;border-bottom:1px solid var(--kendo-color-border, #dee2e6)}.toolbar-spacer{flex:1}.search-input{flex:0 1 220px;min-width:0;padding:4px 8px;font:inherit;color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;outline:none}.search-input::placeholder{color:var(--kendo-color-subtle, #6c757d)}.search-input:focus{border-color:var(--kendo-color-primary, #0d6efd)}.search-clear{flex-shrink:0;width:22px;height:22px;padding:0;background:transparent;border:none;cursor:pointer;font-size:1.1em;line-height:1;color:var(--kendo-color-subtle, #6c757d);border-radius:3px}.search-clear:hover{color:var(--kendo-color-on-app-surface, #1d1b20);background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent)}.match-count{flex-shrink:0;font-size:.8em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.no-matches{padding:16px;text-align:center;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.record-array-list{display:flex;flex-direction:column;gap:8px;overflow-y:auto;flex:1;min-height:0}.record-array-item{display:block;flex-shrink:0;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;overflow:hidden}.array-item-header{display:flex;align-items:center;gap:8px;padding:6px 10px;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--kendo-color-surface-alt, #f8f9fa);transition:background-color .15s ease}.array-item-header:hover{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-chevron{width:14px;height:14px;color:var(--kendo-color-subtle);flex-shrink:0}.array-item-index{font-family:Roboto Mono,monospace;font-size:.8em;font-weight:600;color:var(--kendo-color-primary, #0d6efd)}.array-item-label{font-size:.85em;color:var(--kendo-color-on-app-surface, #1d1b20);font-weight:500}.array-item-summary{margin-left:auto;font-size:.75em;color:var(--kendo-color-subtle, #6c757d);font-style:italic}.detail-grid{display:block!important;height:auto!important;border:none;border-top:1px solid var(--kendo-color-border, #dee2e6)}:host ::ng-deep .detail-grid .k-grid-aria-root{height:auto}.property-name-cell{display:flex;align-items:center;gap:8px}.type-icon{width:16px;height:16px;opacity:.7}.property-name{font-weight:500}.property-value{word-break:break-word;white-space:pre-wrap}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;font-weight:500;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);color:var(--kendo-color-on-app-surface, #1d1b20)}\n"] }]
2045
2070
  }], propDecorators: { attributeName: [{
2046
2071
  type: Input
2047
2072
  }], value: [{
@@ -2052,6 +2077,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
2052
2077
  type: Output
2053
2078
  }] } });
2054
2079
 
2080
+ /**
2081
+ * A secret record member as projected by the server (AB#5528): the marker `{ isSet }` (optionally
2082
+ * with `keyMissing` / `setAt`), or a normalised `SecretState`. Nothing else has exactly these keys.
2083
+ */
2084
+ function isSecretMarker(value) {
2085
+ return isSecretStateObject(value);
2086
+ }
2055
2087
  /**
2056
2088
  * Component for displaying property values with appropriate formatting
2057
2089
  */
@@ -2065,6 +2097,9 @@ class PropertyValueDisplayComponent {
2065
2097
  // Expansion state
2066
2098
  isExpanded = false;
2067
2099
  windowService = inject(WindowService);
2100
+ locale = inject(LOCALE_ID);
2101
+ /** Non-null when the value is a secret state (SECRET value type or record member marker). */
2102
+ secretStatus = null;
2068
2103
  // Pre-computed template properties — recomputed in ngOnInit and ngOnChanges so Kendo Grid row recycling (cell component reuse with new inputs) does not display stale values.
2069
2104
  expandableRecord = false;
2070
2105
  complexType = false;
@@ -2111,6 +2146,7 @@ class PropertyValueDisplayComponent {
2111
2146
  this.recomputeDerivedValues();
2112
2147
  }
2113
2148
  recomputeDerivedValues() {
2149
+ this.secretStatus = this.computeSecretStatus();
2114
2150
  this.expandableRecord = this.computeIsExpandableRecord();
2115
2151
  this.complexType = this.computeIsComplexType();
2116
2152
  this.binaryLinkedWithDownload = this.computeIsBinaryLinkedWithDownload();
@@ -2133,7 +2169,18 @@ class PropertyValueDisplayComponent {
2133
2169
  this.formattedBinarySize = '';
2134
2170
  }
2135
2171
  }
2172
+ /** Set / not set / key missing for a SECRET value or a record member marker `{ isSet }` (AB#5528). */
2173
+ computeSecretStatus() {
2174
+ if (this.type !== AttributeValueTypeDto.SecretDto && !isSecretMarker(this.value)) {
2175
+ return null;
2176
+ }
2177
+ return secretStatusOf(this.value);
2178
+ }
2136
2179
  computeFormattedValue() {
2180
+ if (this.secretStatus) {
2181
+ const v = (this.value ?? {});
2182
+ return formatSecretStatus(toSecretState({ isSet: v.isSet === true, keyMissing: v.keyMissing, setAt: v.setAt }), (date) => formatDate(date, 'medium', this.locale));
2183
+ }
2137
2184
  if (this.value === null) {
2138
2185
  return '<null>';
2139
2186
  }
@@ -2438,6 +2485,9 @@ class PropertyValueDisplayComponent {
2438
2485
  if (value === null || value === undefined) {
2439
2486
  return AttributeValueTypeDto.StringDto;
2440
2487
  }
2488
+ if (isSecretMarker(value)) {
2489
+ return AttributeValueTypeDto.SecretDto;
2490
+ }
2441
2491
  if (typeof value === 'boolean') {
2442
2492
  return AttributeValueTypeDto.BooleanDto;
2443
2493
  }
@@ -2529,7 +2579,7 @@ class PropertyValueDisplayComponent {
2529
2579
  size="small"
2530
2580
  fillMode="flat"
2531
2581
  [svgIcon]="windowIcon"
2532
- title="Show details"
2582
+ title="Show details" aria-label="Show details"
2533
2583
  class="detail-button"
2534
2584
  (click)="openDetailDialog($event)">
2535
2585
  </button>
@@ -2609,6 +2659,9 @@ class PropertyValueDisplayComponent {
2609
2659
  </div>
2610
2660
  }
2611
2661
  </div>
2662
+ } @else if (secretStatus) {
2663
+ <!-- SECRET (AB#5528): set / not set / key missing badge, never a value -->
2664
+ <span class="secret-badge" [ngClass]="'secret-badge--' + secretStatus" [attr.data-secret-state]="secretStatus">{{ formattedValue }}</span>
2612
2665
  } @else if (binaryLinkedWithDownload) {
2613
2666
  <!-- Binary Linked with download capability -->
2614
2667
  <div class="binary-linked-display">
@@ -2655,7 +2708,7 @@ class PropertyValueDisplayComponent {
2655
2708
  }
2656
2709
 
2657
2710
  </div>
2658
- `, isInline: true, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;width:100%;min-width:0}.text-display,.default-display{word-break:break-word;white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.json-display{font-family:Roboto Mono,monospace;font-size:.8em;white-space:pre-wrap;word-break:break-word;margin:0;flex:1;min-width:0}.type-indicator{font-family:Roboto Mono,monospace;font-size:.7em;padding:1px 5px;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);border-radius:3px;color:var(--kendo-color-on-app-surface, #1d1b20);white-space:nowrap;flex-shrink:0}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 0;border-radius:3px;transition:background-color .15s ease}.record-header:hover{background-color:var(--kendo-color-base-subtle, rgba(0,0,0,.04))}.expand-icon{flex-shrink:0;width:14px;height:14px;color:var(--kendo-color-subtle)}.record-summary{color:var(--kendo-color-subtle);font-size:.85em;font-style:italic;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.detail-button{flex-shrink:0;opacity:.6;transition:opacity .15s ease}.detail-button:hover{opacity:1}.record-content{margin-left:20px;padding-left:8px;border-left:1px solid var(--kendo-color-border, #dee2e6)}.array-item{margin:4px 0}.array-index{font-family:Roboto Mono,monospace;font-size:.8em;color:var(--kendo-color-subtle)}.record-array-list{max-height:320px;overflow-y:auto}.record-table-container{max-height:320px;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;margin-top:4px}.record-table{width:100%;border-collapse:collapse;font-size:.85em;table-layout:auto}.record-table th{position:sticky;top:0;z-index:1;background:var(--kendo-color-surface-alt, #f8f9fa);color:var(--kendo-color-subtle);text-align:left;padding:4px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6);font-weight:500;font-size:.85em;white-space:nowrap}.record-table td{padding:3px 8px;border-bottom:1px solid color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent);vertical-align:top;word-break:break-word}.record-table tr:last-child td{border-bottom:none}.record-table tr:hover td{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-table .row-index{color:var(--kendo-color-subtle);font-family:Roboto Mono,monospace;font-size:.85em;text-align:right;width:1px;white-space:nowrap}.nested-properties{margin-left:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;padding:2px 0}.property-key{font-weight:500;white-space:nowrap;flex-shrink:0;color:var(--kendo-color-subtle);font-size:.85em}.binary-linked-display{display:flex;align-items:center;gap:12px;width:100%}.binary-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.filename{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:.85em;color:var(--kendo-color-subtle);flex-shrink:0}.content-type{font-size:.75em;padding:2px 6px;background:var(--kendo-color-base-subtle);border-radius:3px;color:var(--kendo-color-subtle);flex-shrink:0}\n"], dependencies: [{ kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode", "attributeName"], outputs: ["binaryDownload"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2711
+ `, isInline: true, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;width:100%;min-width:0}.text-display,.default-display{word-break:break-word;white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.json-display{font-family:Roboto Mono,monospace;font-size:.8em;white-space:pre-wrap;word-break:break-word;margin:0;flex:1;min-width:0}.type-indicator{font-family:Roboto Mono,monospace;font-size:.7em;padding:1px 5px;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);border-radius:3px;color:var(--kendo-color-on-app-surface, #1d1b20);white-space:nowrap;flex-shrink:0}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 0;border-radius:3px;transition:background-color .15s ease}.record-header:hover{background-color:var(--kendo-color-base-subtle, rgba(0,0,0,.04))}.expand-icon{flex-shrink:0;width:14px;height:14px;color:var(--kendo-color-subtle)}.record-summary{color:var(--kendo-color-subtle);font-size:.85em;font-style:italic;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.detail-button{flex-shrink:0;opacity:.6;transition:opacity .15s ease}.detail-button:hover{opacity:1}.record-content{margin-left:20px;padding-left:8px;border-left:1px solid var(--kendo-color-border, #dee2e6)}.array-item{margin:4px 0}.array-index{font-family:Roboto Mono,monospace;font-size:.8em;color:var(--kendo-color-subtle)}.record-array-list{max-height:320px;overflow-y:auto}.record-table-container{max-height:320px;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;margin-top:4px}.record-table{width:100%;border-collapse:collapse;font-size:.85em;table-layout:auto}.record-table th{position:sticky;top:0;z-index:1;background:var(--kendo-color-surface-alt, #f8f9fa);color:var(--kendo-color-subtle);text-align:left;padding:4px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6);font-weight:500;font-size:.85em;white-space:nowrap}.record-table td{padding:3px 8px;border-bottom:1px solid color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent);vertical-align:top;word-break:break-word}.record-table tr:last-child td{border-bottom:none}.record-table tr:hover td{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-table .row-index{color:var(--kendo-color-subtle);font-family:Roboto Mono,monospace;font-size:.85em;text-align:right;width:1px;white-space:nowrap}.nested-properties{margin-left:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;padding:2px 0}.property-key{font-weight:500;white-space:nowrap;flex-shrink:0;color:var(--kendo-color-subtle);font-size:.85em}.binary-linked-display{display:flex;align-items:center;gap:12px;width:100%}.binary-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.filename{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:.85em;color:var(--kendo-color-subtle);flex-shrink:0}.secret-badge{display:inline-block;font-size:.85em;padding:1px 8px;border-radius:999px;background:var(--kendo-color-base-subtle);color:var(--kendo-color-subtle)}.secret-badge--set{background:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}.secret-badge--keyMissing{background:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}.content-type{font-size:.75em;padding:2px 6px;background:var(--kendo-color-base-subtle);border-radius:3px;color:var(--kendo-color-subtle);flex-shrink:0}\n"], dependencies: [{ kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode", "attributeName"], outputs: ["binaryDownload"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2659
2712
  }
2660
2713
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PropertyValueDisplayComponent, decorators: [{
2661
2714
  type: Component,
@@ -2676,7 +2729,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
2676
2729
  size="small"
2677
2730
  fillMode="flat"
2678
2731
  [svgIcon]="windowIcon"
2679
- title="Show details"
2732
+ title="Show details" aria-label="Show details"
2680
2733
  class="detail-button"
2681
2734
  (click)="openDetailDialog($event)">
2682
2735
  </button>
@@ -2756,6 +2809,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
2756
2809
  </div>
2757
2810
  }
2758
2811
  </div>
2812
+ } @else if (secretStatus) {
2813
+ <!-- SECRET (AB#5528): set / not set / key missing badge, never a value -->
2814
+ <span class="secret-badge" [ngClass]="'secret-badge--' + secretStatus" [attr.data-secret-state]="secretStatus">{{ formattedValue }}</span>
2759
2815
  } @else if (binaryLinkedWithDownload) {
2760
2816
  <!-- Binary Linked with download capability -->
2761
2817
  <div class="binary-linked-display">
@@ -2802,7 +2858,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
2802
2858
  }
2803
2859
 
2804
2860
  </div>
2805
- `, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;width:100%;min-width:0}.text-display,.default-display{word-break:break-word;white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.json-display{font-family:Roboto Mono,monospace;font-size:.8em;white-space:pre-wrap;word-break:break-word;margin:0;flex:1;min-width:0}.type-indicator{font-family:Roboto Mono,monospace;font-size:.7em;padding:1px 5px;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);border-radius:3px;color:var(--kendo-color-on-app-surface, #1d1b20);white-space:nowrap;flex-shrink:0}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 0;border-radius:3px;transition:background-color .15s ease}.record-header:hover{background-color:var(--kendo-color-base-subtle, rgba(0,0,0,.04))}.expand-icon{flex-shrink:0;width:14px;height:14px;color:var(--kendo-color-subtle)}.record-summary{color:var(--kendo-color-subtle);font-size:.85em;font-style:italic;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.detail-button{flex-shrink:0;opacity:.6;transition:opacity .15s ease}.detail-button:hover{opacity:1}.record-content{margin-left:20px;padding-left:8px;border-left:1px solid var(--kendo-color-border, #dee2e6)}.array-item{margin:4px 0}.array-index{font-family:Roboto Mono,monospace;font-size:.8em;color:var(--kendo-color-subtle)}.record-array-list{max-height:320px;overflow-y:auto}.record-table-container{max-height:320px;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;margin-top:4px}.record-table{width:100%;border-collapse:collapse;font-size:.85em;table-layout:auto}.record-table th{position:sticky;top:0;z-index:1;background:var(--kendo-color-surface-alt, #f8f9fa);color:var(--kendo-color-subtle);text-align:left;padding:4px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6);font-weight:500;font-size:.85em;white-space:nowrap}.record-table td{padding:3px 8px;border-bottom:1px solid color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent);vertical-align:top;word-break:break-word}.record-table tr:last-child td{border-bottom:none}.record-table tr:hover td{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-table .row-index{color:var(--kendo-color-subtle);font-family:Roboto Mono,monospace;font-size:.85em;text-align:right;width:1px;white-space:nowrap}.nested-properties{margin-left:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;padding:2px 0}.property-key{font-weight:500;white-space:nowrap;flex-shrink:0;color:var(--kendo-color-subtle);font-size:.85em}.binary-linked-display{display:flex;align-items:center;gap:12px;width:100%}.binary-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.filename{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:.85em;color:var(--kendo-color-subtle);flex-shrink:0}.content-type{font-size:.75em;padding:2px 6px;background:var(--kendo-color-base-subtle);border-radius:3px;color:var(--kendo-color-subtle);flex-shrink:0}\n"] }]
2861
+ `, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;width:100%;min-width:0}.text-display,.default-display{word-break:break-word;white-space:pre-wrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.json-display{font-family:Roboto Mono,monospace;font-size:.8em;white-space:pre-wrap;word-break:break-word;margin:0;flex:1;min-width:0}.type-indicator{font-family:Roboto Mono,monospace;font-size:.7em;padding:1px 5px;background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 12%,transparent);border-radius:3px;color:var(--kendo-color-on-app-surface, #1d1b20);white-space:nowrap;flex-shrink:0}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 0;border-radius:3px;transition:background-color .15s ease}.record-header:hover{background-color:var(--kendo-color-base-subtle, rgba(0,0,0,.04))}.expand-icon{flex-shrink:0;width:14px;height:14px;color:var(--kendo-color-subtle)}.record-summary{color:var(--kendo-color-subtle);font-size:.85em;font-style:italic;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.detail-button{flex-shrink:0;opacity:.6;transition:opacity .15s ease}.detail-button:hover{opacity:1}.record-content{margin-left:20px;padding-left:8px;border-left:1px solid var(--kendo-color-border, #dee2e6)}.array-item{margin:4px 0}.array-index{font-family:Roboto Mono,monospace;font-size:.8em;color:var(--kendo-color-subtle)}.record-array-list{max-height:320px;overflow-y:auto}.record-table-container{max-height:320px;overflow:auto;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:3px;margin-top:4px}.record-table{width:100%;border-collapse:collapse;font-size:.85em;table-layout:auto}.record-table th{position:sticky;top:0;z-index:1;background:var(--kendo-color-surface-alt, #f8f9fa);color:var(--kendo-color-subtle);text-align:left;padding:4px 8px;border-bottom:1px solid var(--kendo-color-border, #dee2e6);font-weight:500;font-size:.85em;white-space:nowrap}.record-table td{padding:3px 8px;border-bottom:1px solid color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 8%,transparent);vertical-align:top;word-break:break-word}.record-table tr:last-child td{border-bottom:none}.record-table tr:hover td{background:color-mix(in srgb,var(--kendo-color-on-app-surface, #1d1b20) 6%,transparent)}.record-table .row-index{color:var(--kendo-color-subtle);font-family:Roboto Mono,monospace;font-size:.85em;text-align:right;width:1px;white-space:nowrap}.nested-properties{margin-left:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;padding:2px 0}.property-key{font-weight:500;white-space:nowrap;flex-shrink:0;color:var(--kendo-color-subtle);font-size:.85em}.binary-linked-display{display:flex;align-items:center;gap:12px;width:100%}.binary-info{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.filename{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:.85em;color:var(--kendo-color-subtle);flex-shrink:0}.secret-badge{display:inline-block;font-size:.85em;padding:1px 8px;border-radius:999px;background:var(--kendo-color-base-subtle);color:var(--kendo-color-subtle)}.secret-badge--set{background:var(--kendo-color-success-subtle);color:var(--kendo-color-success-on-subtle)}.secret-badge--keyMissing{background:var(--kendo-color-warning-subtle);color:var(--kendo-color-warning-on-subtle)}.content-type{font-size:.75em;padding:2px 6px;background:var(--kendo-color-base-subtle);border-radius:3px;color:var(--kendo-color-subtle);flex-shrink:0}\n"] }]
2806
2862
  }], propDecorators: { value: [{
2807
2863
  type: Input
2808
2864
  }], type: [{
@@ -3052,7 +3108,7 @@ class PropertyGridComponent {
3052
3108
 
3053
3109
  </kendo-grid>
3054
3110
  </div>
3055
- `, isInline: true, styles: [".mm-property-grid{display:flex;flex-direction:column;border:1px solid var(--kendo-color-border);border-radius:4px;overflow:hidden}.search-toolbar{padding:8px;border-bottom:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle)}.property-grid{flex:1;border:none}.property-name-cell{display:flex;align-items:center;gap:8px;min-height:24px}.type-icon{width:16px;height:16px;opacity:.7}.property-info{display:flex;align-items:center;gap:4px;flex:1}.property-name{font-weight:500}.required-indicator{color:var(--kendo-color-error);font-weight:700}.readonly-indicator{font-size:12px;opacity:.7}.property-editor{width:100%;min-width:200px}.validation-error{color:var(--kendo-color-error);font-size:.8em;margin-top:4px}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;text-transform:uppercase;font-weight:500;background:var(--kendo-color-base-subtle);color:var(--kendo-color-on-base)}.grid-toolbar{padding:8px;border-top:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle);display:flex;align-items:center;gap:8px}.changes-indicator{margin-left:auto;font-size:.9em;color:var(--kendo-color-primary);font-style:italic}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "ngmodule", type: ButtonsModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode", "attributeName"], outputs: ["binaryDownload"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
3111
+ `, isInline: true, styles: [".mm-property-grid{display:flex;flex-direction:column;border:1px solid var(--kendo-color-border);border-radius:4px;overflow:hidden}.search-toolbar{padding:8px;border-bottom:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle)}.property-grid{flex:1;border:none}.property-name-cell{display:flex;align-items:center;gap:8px;min-height:24px}.type-icon{width:16px;height:16px;opacity:.7}.property-info{display:flex;align-items:center;gap:4px;flex:1}.property-name{font-weight:500}.required-indicator{color:var(--kendo-color-error);font-weight:700}.readonly-indicator{font-size:12px;opacity:.7}.property-editor{width:100%;min-width:200px}.validation-error{color:var(--kendo-color-error);font-size:.8em;margin-top:4px}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;font-weight:500;background:var(--kendo-color-base-subtle);color:var(--kendo-color-on-base)}.grid-toolbar{padding:8px;border-top:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle);display:flex;align-items:center;gap:8px}.changes-indicator{margin-left:auto;font-size:.9em;color:var(--kendo-color-primary);font-style:italic}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "ngmodule", type: DropDownsModule }, { kind: "ngmodule", type: ButtonsModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode", "attributeName"], outputs: ["binaryDownload"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
3056
3112
  }
3057
3113
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PropertyGridComponent, decorators: [{
3058
3114
  type: Component,
@@ -3148,7 +3204,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
3148
3204
 
3149
3205
  </kendo-grid>
3150
3206
  </div>
3151
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mm-property-grid{display:flex;flex-direction:column;border:1px solid var(--kendo-color-border);border-radius:4px;overflow:hidden}.search-toolbar{padding:8px;border-bottom:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle)}.property-grid{flex:1;border:none}.property-name-cell{display:flex;align-items:center;gap:8px;min-height:24px}.type-icon{width:16px;height:16px;opacity:.7}.property-info{display:flex;align-items:center;gap:4px;flex:1}.property-name{font-weight:500}.required-indicator{color:var(--kendo-color-error);font-weight:700}.readonly-indicator{font-size:12px;opacity:.7}.property-editor{width:100%;min-width:200px}.validation-error{color:var(--kendo-color-error);font-size:.8em;margin-top:4px}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;text-transform:uppercase;font-weight:500;background:var(--kendo-color-base-subtle);color:var(--kendo-color-on-base)}.grid-toolbar{padding:8px;border-top:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle);display:flex;align-items:center;gap:8px}.changes-indicator{margin-left:auto;font-size:.9em;color:var(--kendo-color-primary);font-style:italic}\n"] }]
3207
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mm-property-grid{display:flex;flex-direction:column;border:1px solid var(--kendo-color-border);border-radius:4px;overflow:hidden}.search-toolbar{padding:8px;border-bottom:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle)}.property-grid{flex:1;border:none}.property-name-cell{display:flex;align-items:center;gap:8px;min-height:24px}.type-icon{width:16px;height:16px;opacity:.7}.property-info{display:flex;align-items:center;gap:4px;flex:1}.property-name{font-weight:500}.required-indicator{color:var(--kendo-color-error);font-weight:700}.readonly-indicator{font-size:12px;opacity:.7}.property-editor{width:100%;min-width:200px}.validation-error{color:var(--kendo-color-error);font-size:.8em;margin-top:4px}.type-badge{font-size:.75em;padding:2px 6px;border-radius:3px;font-weight:500;background:var(--kendo-color-base-subtle);color:var(--kendo-color-on-base)}.grid-toolbar{padding:8px;border-top:1px solid var(--kendo-color-border);background:var(--kendo-color-base-subtle);display:flex;align-items:center;gap:8px}.changes-indicator{margin-left:auto;font-size:.9em;color:var(--kendo-color-primary);font-style:italic}\n"] }]
3152
3208
  }], propDecorators: { data: [{
3153
3209
  type: Input
3154
3210
  }], config: [{
@@ -3521,7 +3577,7 @@ class CkTypeSelectorInputComponent {
3521
3577
  type="button"
3522
3578
  [svgIcon]="searchIcon"
3523
3579
  [disabled]="disabled"
3524
- [title]="advancedSearchLabel || _messages.advancedSearchLabel"
3580
+ [title]="advancedSearchLabel || _messages.advancedSearchLabel" [attr.aria-label]="advancedSearchLabel || _messages.advancedSearchLabel"
3525
3581
  class="dialog-button"
3526
3582
  (click)="openDialog()">
3527
3583
  </button>
@@ -3598,7 +3654,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
3598
3654
  type="button"
3599
3655
  [svgIcon]="searchIcon"
3600
3656
  [disabled]="disabled"
3601
- [title]="advancedSearchLabel || _messages.advancedSearchLabel"
3657
+ [title]="advancedSearchLabel || _messages.advancedSearchLabel" [attr.aria-label]="advancedSearchLabel || _messages.advancedSearchLabel"
3602
3658
  class="dialog-button"
3603
3659
  (click)="openDialog()">
3604
3660
  </button>
@@ -4145,6 +4201,8 @@ class AttributeSelectorDialogComponent {
4145
4201
  kendoButton
4146
4202
  [svgIcon]="searchIcon"
4147
4203
  fillMode="clear"
4204
+ title="Search"
4205
+ aria-label="Search"
4148
4206
  ></button>
4149
4207
  </ng-template>
4150
4208
  </kendo-textbox>
@@ -4235,14 +4293,14 @@ class AttributeSelectorDialogComponent {
4235
4293
  [svgIcon]="arrowRightIcon"
4236
4294
  [disabled]="selectedAvailableKeys.length === 0"
4237
4295
  (click)="addSelected()"
4238
- title="Add selected"
4296
+ title="Add selected" aria-label="Add selected"
4239
4297
  ></button>
4240
4298
  <button
4241
4299
  kendoButton
4242
4300
  [svgIcon]="arrowLeftIcon"
4243
4301
  [disabled]="selectedChosenKeys.length === 0"
4244
4302
  (click)="removeSelected()"
4245
- title="Remove selected"
4303
+ title="Remove selected" aria-label="Remove selected"
4246
4304
  ></button>
4247
4305
  <div class="separator"></div>
4248
4306
  <button
@@ -4250,14 +4308,14 @@ class AttributeSelectorDialogComponent {
4250
4308
  [svgIcon]="chevronDoubleRightIcon"
4251
4309
  [disabled]="availableAttributes.length === 0"
4252
4310
  (click)="addAll()"
4253
- title="Add all"
4311
+ title="Add all" aria-label="Add all"
4254
4312
  ></button>
4255
4313
  <button
4256
4314
  kendoButton
4257
4315
  [svgIcon]="chevronDoubleLeftIcon"
4258
4316
  [disabled]="selectedAttributes.length === 0"
4259
4317
  (click)="removeAll()"
4260
- title="Remove all"
4318
+ title="Remove all" aria-label="Remove all"
4261
4319
  ></button>
4262
4320
  </div>
4263
4321
 
@@ -4300,7 +4358,7 @@ class AttributeSelectorDialogComponent {
4300
4358
  fillMode="flat"
4301
4359
  size="small"
4302
4360
  [svgIcon]="pencilIcon"
4303
- title="Edit entity selector (pin the target entity)"
4361
+ title="Edit entity selector (pin the target entity)" aria-label="Edit entity selector (pin the target entity)"
4304
4362
  (click)="openSelectorEditor(dataItem); $event.stopPropagation()"
4305
4363
  ></button>
4306
4364
  }
@@ -4315,14 +4373,14 @@ class AttributeSelectorDialogComponent {
4315
4373
  [svgIcon]="arrowUpIcon"
4316
4374
  [disabled]="!canMoveUp()"
4317
4375
  (click)="moveUp()"
4318
- title="Move up"
4376
+ title="Move up" aria-label="Move up"
4319
4377
  ></button>
4320
4378
  <button
4321
4379
  kendoButton
4322
4380
  [svgIcon]="arrowDownIcon"
4323
4381
  [disabled]="!canMoveDown()"
4324
4382
  (click)="moveDown()"
4325
- title="Move down"
4383
+ title="Move down" aria-label="Move down"
4326
4384
  ></button>
4327
4385
  </div>
4328
4386
  </div>
@@ -4435,6 +4493,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
4435
4493
  kendoButton
4436
4494
  [svgIcon]="searchIcon"
4437
4495
  fillMode="clear"
4496
+ title="Search"
4497
+ aria-label="Search"
4438
4498
  ></button>
4439
4499
  </ng-template>
4440
4500
  </kendo-textbox>
@@ -4525,14 +4585,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
4525
4585
  [svgIcon]="arrowRightIcon"
4526
4586
  [disabled]="selectedAvailableKeys.length === 0"
4527
4587
  (click)="addSelected()"
4528
- title="Add selected"
4588
+ title="Add selected" aria-label="Add selected"
4529
4589
  ></button>
4530
4590
  <button
4531
4591
  kendoButton
4532
4592
  [svgIcon]="arrowLeftIcon"
4533
4593
  [disabled]="selectedChosenKeys.length === 0"
4534
4594
  (click)="removeSelected()"
4535
- title="Remove selected"
4595
+ title="Remove selected" aria-label="Remove selected"
4536
4596
  ></button>
4537
4597
  <div class="separator"></div>
4538
4598
  <button
@@ -4540,14 +4600,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
4540
4600
  [svgIcon]="chevronDoubleRightIcon"
4541
4601
  [disabled]="availableAttributes.length === 0"
4542
4602
  (click)="addAll()"
4543
- title="Add all"
4603
+ title="Add all" aria-label="Add all"
4544
4604
  ></button>
4545
4605
  <button
4546
4606
  kendoButton
4547
4607
  [svgIcon]="chevronDoubleLeftIcon"
4548
4608
  [disabled]="selectedAttributes.length === 0"
4549
4609
  (click)="removeAll()"
4550
- title="Remove all"
4610
+ title="Remove all" aria-label="Remove all"
4551
4611
  ></button>
4552
4612
  </div>
4553
4613
 
@@ -4590,7 +4650,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
4590
4650
  fillMode="flat"
4591
4651
  size="small"
4592
4652
  [svgIcon]="pencilIcon"
4593
- title="Edit entity selector (pin the target entity)"
4653
+ title="Edit entity selector (pin the target entity)" aria-label="Edit entity selector (pin the target entity)"
4594
4654
  (click)="openSelectorEditor(dataItem); $event.stopPropagation()"
4595
4655
  ></button>
4596
4656
  }
@@ -4605,14 +4665,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
4605
4665
  [svgIcon]="arrowUpIcon"
4606
4666
  [disabled]="!canMoveUp()"
4607
4667
  (click)="moveUp()"
4608
- title="Move up"
4668
+ title="Move up" aria-label="Move up"
4609
4669
  ></button>
4610
4670
  <button
4611
4671
  kendoButton
4612
4672
  [svgIcon]="arrowDownIcon"
4613
4673
  [disabled]="!canMoveDown()"
4614
4674
  (click)="moveDown()"
4615
- title="Move down"
4675
+ title="Move down" aria-label="Move down"
4616
4676
  ></button>
4617
4677
  </div>
4618
4678
  </div>
@@ -4996,7 +5056,7 @@ class RuntimeEntityVariableDialogComponent {
4996
5056
  [svgIcon]="trashIcon"
4997
5057
  fillMode="flat"
4998
5058
  themeColor="error"
4999
- title="Remove">
5059
+ title="Remove" aria-label="Remove">
5000
5060
  </button>
5001
5061
  </div>
5002
5062
  </div>
@@ -5089,7 +5149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5089
5149
  [svgIcon]="trashIcon"
5090
5150
  fillMode="flat"
5091
5151
  themeColor="error"
5092
- title="Remove">
5152
+ title="Remove" aria-label="Remove">
5093
5153
  </button>
5094
5154
  </div>
5095
5155
  </div>
@@ -5157,7 +5217,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5157
5217
  }] });
5158
5218
 
5159
5219
  const GetRuntimeEntityByIdDocumentDto = gql `
5160
- query getRuntimeEntityById($rtId: OctoObjectId!, $ckTypeId: String!) {
5220
+ query getRuntimeEntityById($rtId: OctoObjectId!, $ckTypeId: String!, $attributeNames: [String!]!) {
5161
5221
  runtime {
5162
5222
  runtimeEntities(ckId: $ckTypeId, rtId: $rtId) {
5163
5223
  items {
@@ -5168,10 +5228,13 @@ const GetRuntimeEntityByIdDocumentDto = gql `
5168
5228
  rtWellKnownName
5169
5229
  rtCreationDateTime
5170
5230
  rtChangedDateTime
5171
- attributes(resolveEnumValuesToNames: true) {
5231
+ attributes(attributeNames: $attributeNames, resolveEnumValuesToNames: true) {
5172
5232
  items {
5173
5233
  attributeName
5174
5234
  value
5235
+ secretIsSet
5236
+ secretKeyMissing
5237
+ secretSetAt
5175
5238
  }
5176
5239
  }
5177
5240
  associations {
@@ -5219,6 +5282,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5219
5282
  * `sourceAttributePath` fallback when no specific state is configured.
5220
5283
  */
5221
5284
  const DEFAULT_DATA_POINT = 'currentValue';
5285
+ /**
5286
+ * Attributes {@link extractDataPoints} reads, as the SECRET-safe `attributeNames` filter of
5287
+ * `getRuntimeEntityById` (AB#5542). The filter also applies inside records, so the record
5288
+ * sub-attributes (`name`, `currentValue`) are part of the same list.
5289
+ */
5290
+ const DATA_POINT_ATTRIBUTE_NAMES = ['currentValue', 'states', 'dataPoints', 'name'];
5222
5291
  /**
5223
5292
  * Extracts the available data points (name + last known value) from an
5224
5293
  * entity's attribute list. Always includes {@link DEFAULT_DATA_POINT} first
@@ -5373,7 +5442,7 @@ class DataPointResolverService {
5373
5442
  try {
5374
5443
  const entity = await firstValueFrom(this.getRuntimeEntityByIdGQL
5375
5444
  .fetch({
5376
- variables: { rtId, ckTypeId },
5445
+ variables: { rtId, ckTypeId, attributeNames: [...DATA_POINT_ATTRIBUTE_NAMES] },
5377
5446
  fetchPolicy: 'network-only',
5378
5447
  })
5379
5448
  .pipe(map$1(r => r.data?.runtime?.runtimeEntities?.items?.[0] ?? null)));
@@ -5701,6 +5770,14 @@ class EntityIdInfoComponent {
5701
5770
  rtCkTypeId;
5702
5771
  /** The CkTypeId - full versioned Construction Kit type ID (e.g., System.Communication-2.0.3/MeshAdapter-1) */
5703
5772
  ckTypeId;
5773
+ /** Button text (translatable, AB#5623). Default `Copy ID`. */
5774
+ buttonText = 'Copy ID';
5775
+ /** Tooltip of the button (translatable, AB#5623). Default `Copy Entity ID to clipboard`. */
5776
+ tooltip = 'Copy Entity ID to clipboard';
5777
+ /** Notification after copying; `{label}` is replaced by the copied ID kind (AB#5623). Default `{label} copied`. */
5778
+ copiedMessage = '{label} copied';
5779
+ /** Notification when copying failed (AB#5623). Default `Failed to copy to clipboard`. */
5780
+ copyFailedMessage = 'Failed to copy to clipboard';
5704
5781
  get copyOptions() {
5705
5782
  const fullCkTypeId = this.ckTypeId || this.rtCkTypeId;
5706
5783
  const rtEntityId = `${this.rtCkTypeId}@${this.rtId}`;
@@ -5735,21 +5812,21 @@ class EntityIdInfoComponent {
5735
5812
  async copyToClipboard(option) {
5736
5813
  try {
5737
5814
  await navigator.clipboard.writeText(option.value);
5738
- this.notificationService.showSuccess(`${option.label} copied`, 2000);
5815
+ this.notificationService.showSuccess(this.copiedMessage.split('{label}').join(option.label), 2000);
5739
5816
  }
5740
5817
  catch (error) {
5741
5818
  console.error('Failed to copy to clipboard:', error);
5742
- this.notificationService.showError('Failed to copy to clipboard');
5819
+ this.notificationService.showError(this.copyFailedMessage);
5743
5820
  }
5744
5821
  }
5745
5822
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityIdInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5746
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.5", type: EntityIdInfoComponent, isStandalone: true, selector: "mm-entity-id-info", inputs: { rtId: "rtId", rtCkTypeId: "rtCkTypeId", ckTypeId: "ckTypeId" }, ngImport: i0, template: `
5823
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.5", type: EntityIdInfoComponent, isStandalone: true, selector: "mm-entity-id-info", inputs: { rtId: "rtId", rtCkTypeId: "rtCkTypeId", ckTypeId: "ckTypeId", buttonText: "buttonText", tooltip: "tooltip", copiedMessage: "copiedMessage", copyFailedMessage: "copyFailedMessage" }, ngImport: i0, template: `
5747
5824
  <kendo-dropdownbutton
5748
5825
  [data]="copyOptions"
5749
5826
  [svgIcon]="copyIcon"
5750
5827
  look="flat"
5751
5828
  size="small"
5752
- title="Copy Entity ID to clipboard"
5829
+ [title]="tooltip"
5753
5830
  (itemClick)="copyToClipboard($event)">
5754
5831
  <ng-template kendoDropDownButtonItemTemplate let-item>
5755
5832
  <div class="copy-item">
@@ -5757,9 +5834,9 @@ class EntityIdInfoComponent {
5757
5834
  <span class="copy-value">{{ item.displayText }}</span>
5758
5835
  </div>
5759
5836
  </ng-template>
5760
- Copy ID
5837
+ {{ buttonText }}
5761
5838
  </kendo-dropdownbutton>
5762
- `, isInline: true, styles: [":host{display:inline-block}.copy-item{display:flex;flex-direction:column;gap:2px;padding:8px 12px;width:100%}.copy-label{font-size:.7rem;font-weight:600;color:var(--kendo-color-primary, #64ceb9);text-transform:uppercase;letter-spacing:.5px}.copy-value{font-family:Roboto Mono,monospace;font-size:.75rem;color:var(--kendo-color-subtle, #9292a6);word-break:break-all}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1$1.DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }, { kind: "directive", type: i1$1.ButtonItemTemplateDirective, selector: "[kendoDropDownButtonItemTemplate],[kendoSplitButtonItemTemplate]" }, { kind: "ngmodule", type: SVGIconModule }], changeDetection: i0.ChangeDetectionStrategy.Eager });
5839
+ `, isInline: true, styles: [":host{display:inline-block}.copy-item{display:flex;flex-direction:column;gap:2px;padding:8px 12px;width:100%}.copy-label{font-size:.7rem;font-weight:600;color:var(--kendo-color-primary, #64ceb9)}.copy-value{font-family:Roboto Mono,monospace;font-size:.75rem;color:var(--kendo-color-subtle, #9292a6);word-break:break-all}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i1$1.DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }, { kind: "directive", type: i1$1.ButtonItemTemplateDirective, selector: "[kendoDropDownButtonItemTemplate],[kendoSplitButtonItemTemplate]" }, { kind: "ngmodule", type: SVGIconModule }], changeDetection: i0.ChangeDetectionStrategy.Eager });
5763
5840
  }
5764
5841
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityIdInfoComponent, decorators: [{
5765
5842
  type: Component,
@@ -5773,7 +5850,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5773
5850
  [svgIcon]="copyIcon"
5774
5851
  look="flat"
5775
5852
  size="small"
5776
- title="Copy Entity ID to clipboard"
5853
+ [title]="tooltip"
5777
5854
  (itemClick)="copyToClipboard($event)">
5778
5855
  <ng-template kendoDropDownButtonItemTemplate let-item>
5779
5856
  <div class="copy-item">
@@ -5781,9 +5858,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5781
5858
  <span class="copy-value">{{ item.displayText }}</span>
5782
5859
  </div>
5783
5860
  </ng-template>
5784
- Copy ID
5861
+ {{ buttonText }}
5785
5862
  </kendo-dropdownbutton>
5786
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:inline-block}.copy-item{display:flex;flex-direction:column;gap:2px;padding:8px 12px;width:100%}.copy-label{font-size:.7rem;font-weight:600;color:var(--kendo-color-primary, #64ceb9);text-transform:uppercase;letter-spacing:.5px}.copy-value{font-family:Roboto Mono,monospace;font-size:.75rem;color:var(--kendo-color-subtle, #9292a6);word-break:break-all}\n"] }]
5863
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:inline-block}.copy-item{display:flex;flex-direction:column;gap:2px;padding:8px 12px;width:100%}.copy-label{font-size:.7rem;font-weight:600;color:var(--kendo-color-primary, #64ceb9)}.copy-value{font-family:Roboto Mono,monospace;font-size:.75rem;color:var(--kendo-color-subtle, #9292a6);word-break:break-all}\n"] }]
5787
5864
  }], propDecorators: { rtId: [{
5788
5865
  type: Input,
5789
5866
  args: [{ required: true }]
@@ -5792,6 +5869,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
5792
5869
  args: [{ required: true }]
5793
5870
  }], ckTypeId: [{
5794
5871
  type: Input
5872
+ }], buttonText: [{
5873
+ type: Input
5874
+ }], tooltip: [{
5875
+ type: Input
5876
+ }], copiedMessage: [{
5877
+ type: Input
5878
+ }], copyFailedMessage: [{
5879
+ type: Input
5795
5880
  }] } });
5796
5881
 
5797
5882
  const DeleteEntitiesDocumentDto = gql `
@@ -6069,12 +6154,7 @@ const UpdateRuntimeEntitiesDocumentDto = gql `
6069
6154
  runtimeEntities {
6070
6155
  update(entities: $entities) {
6071
6156
  rtId
6072
- attributes {
6073
- items {
6074
- attributeName
6075
- value
6076
- }
6077
- }
6157
+ ckTypeId
6078
6158
  }
6079
6159
  }
6080
6160
  }
@@ -8923,6 +9003,10 @@ class FieldFilterEditorComponent {
8923
9003
  dataItem.useVariable
8924
9004
  ? 'Switch to literal value'
8925
9005
  : 'Use variable'
9006
+ " [attr.aria-label]="
9007
+ dataItem.useVariable
9008
+ ? 'Switch to literal value'
9009
+ : 'Use variable'
8926
9010
  "
8927
9011
  class="variable-toggle"
8928
9012
  ></button>
@@ -8939,7 +9023,7 @@ class FieldFilterEditorComponent {
8939
9023
  fillMode="flat"
8940
9024
  themeColor="error"
8941
9025
  (click)="removeFilter(dataItem)"
8942
- title="Remove this filter"
9026
+ title="Remove this filter" aria-label="Remove this filter"
8943
9027
  ></button>
8944
9028
  </ng-template>
8945
9029
  </kendo-grid-column>
@@ -9235,6 +9319,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
9235
9319
  dataItem.useVariable
9236
9320
  ? 'Switch to literal value'
9237
9321
  : 'Use variable'
9322
+ " [attr.aria-label]="
9323
+ dataItem.useVariable
9324
+ ? 'Switch to literal value'
9325
+ : 'Use variable'
9238
9326
  "
9239
9327
  class="variable-toggle"
9240
9328
  ></button>
@@ -9251,7 +9339,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
9251
9339
  fillMode="flat"
9252
9340
  themeColor="error"
9253
9341
  (click)="removeFilter(dataItem)"
9254
- title="Remove this filter"
9342
+ title="Remove this filter" aria-label="Remove this filter"
9255
9343
  ></button>
9256
9344
  </ng-template>
9257
9345
  </kendo-grid-column>
@@ -9486,6 +9574,165 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
9486
9574
  type: Input
9487
9575
  }] } });
9488
9576
 
9577
+ /** Marks projected content that replaces the page title text: `<span mmPageTitle>…</span>`. */
9578
+ class PageTitleDirective {
9579
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageTitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
9580
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.5", type: PageTitleDirective, isStandalone: true, selector: "[mmPageTitle]", ngImport: i0 });
9581
+ }
9582
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageTitleDirective, decorators: [{
9583
+ type: Directive,
9584
+ args: [{ selector: '[mmPageTitle]', standalone: true }]
9585
+ }] });
9586
+ /** Marks projected content shown under the title: `<span mmPageSubtitle>…</span>`. */
9587
+ class PageSubtitleDirective {
9588
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageSubtitleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
9589
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.5", type: PageSubtitleDirective, isStandalone: true, selector: "[mmPageSubtitle]", ngImport: i0 });
9590
+ }
9591
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageSubtitleDirective, decorators: [{
9592
+ type: Directive,
9593
+ args: [{ selector: '[mmPageSubtitle]', standalone: true }]
9594
+ }] });
9595
+ /** Marks projected page actions (buttons), rendered at the end of the header: `<div mmPageActions>…</div>`. */
9596
+ class PageActionsDirective {
9597
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageActionsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
9598
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.5", type: PageActionsDirective, isStandalone: true, selector: "[mmPageActions]", ngImport: i0 });
9599
+ }
9600
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageActionsDirective, decorators: [{
9601
+ type: Directive,
9602
+ args: [{ selector: '[mmPageActions]', standalone: true }]
9603
+ }] });
9604
+ /** True when a slot container holds an element or non-blank text. */
9605
+ function hasProjectedContent(element) {
9606
+ if (!element) {
9607
+ return false;
9608
+ }
9609
+ return Array.from(element.childNodes).some((node) => node.nodeType === Node.ELEMENT_NODE ||
9610
+ (node.nodeType === Node.TEXT_NODE && (node.textContent ?? '').trim() !== ''));
9611
+ }
9612
+ /**
9613
+ * Page layout: an optional header (title, subtitle, actions) above a content
9614
+ * area. Replaces the retired LCARS page triple (header, content panel and
9615
+ * READY footer); there is no footer.
9616
+ *
9617
+ * The header renders only when there is something to show — a `pageTitle` /
9618
+ * `pageSubtitle` input or projected `[mmPageTitle]`, `[mmPageSubtitle]` or
9619
+ * `[mmPageActions]` content — so pages inside a space shell, which already
9620
+ * shows the area title, can use `<mm-page>` as a bare content frame.
9621
+ * Projected content is detected from the rendered DOM, so the slots work
9622
+ * whether or not the consumer imports the marker directives (`MM_PAGE`).
9623
+ *
9624
+ * ```html
9625
+ * <mm-page pageTitle="Adapters" pageSubtitle="12 registered">
9626
+ * <div mmPageActions>
9627
+ * <button kendoButton themeColor="primary">New adapter</button>
9628
+ * </div>
9629
+ * <mm-list-view …></mm-list-view>
9630
+ * </mm-page>
9631
+ * ```
9632
+ *
9633
+ * The header is a plain `<div>` (no banner landmark) and the title defaults to
9634
+ * heading level 2 — the app/space shell owns level 1. Styling is token-based
9635
+ * (`--theme-*` with neutral fallbacks); the host fills its parent
9636
+ * (`height: 100%`) and the content area scrolls.
9637
+ */
9638
+ class PageComponent {
9639
+ /** Title text. Alternatively project `[mmPageTitle]` content. */
9640
+ pageTitle = input(undefined, /* @ts-ignore */
9641
+ ...(ngDevMode ? [{ debugName: "pageTitle" }] : /* istanbul ignore next */ []));
9642
+ /** Subtitle text under the title. Alternatively project `[mmPageSubtitle]` content. */
9643
+ pageSubtitle = input(undefined, /* @ts-ignore */
9644
+ ...(ngDevMode ? [{ debugName: "pageSubtitle" }] : /* istanbul ignore next */ []));
9645
+ /** `aria-level` of the title. Defaults to 2 — the app/space shell owns level 1. */
9646
+ headingLevel = input(2, /* @ts-ignore */
9647
+ ...(ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []));
9648
+ /** Pad the content area with the page gutter. Set `false` for full-bleed grids and editors. */
9649
+ padded = input(true, { ...(ngDevMode ? { debugName: "padded" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
9650
+ titleSlot = viewChild('titleSlot', /* @ts-ignore */
9651
+ ...(ngDevMode ? [{ debugName: "titleSlot" }] : /* istanbul ignore next */ []));
9652
+ subtitleSlot = viewChild('subtitleSlot', /* @ts-ignore */
9653
+ ...(ngDevMode ? [{ debugName: "subtitleSlot" }] : /* istanbul ignore next */ []));
9654
+ actionsSlot = viewChild('actionsSlot', /* @ts-ignore */
9655
+ ...(ngDevMode ? [{ debugName: "actionsSlot" }] : /* istanbul ignore next */ []));
9656
+ /** Which slots currently hold projected content (read from the DOM after each render). */
9657
+ projected = signal({ title: false, subtitle: false, actions: false }, /* @ts-ignore */
9658
+ ...(ngDevMode ? [{ debugName: "projected" }] : /* istanbul ignore next */ []));
9659
+ hasTitle = computed(() => !!this.pageTitle() || this.projected().title, /* @ts-ignore */
9660
+ ...(ngDevMode ? [{ debugName: "hasTitle" }] : /* istanbul ignore next */ []));
9661
+ hasSubtitle = computed(() => !!this.pageSubtitle() || this.projected().subtitle, /* @ts-ignore */
9662
+ ...(ngDevMode ? [{ debugName: "hasSubtitle" }] : /* istanbul ignore next */ []));
9663
+ hasHeader = computed(() => this.hasTitle() || this.hasSubtitle() || this.projected().actions, /* @ts-ignore */
9664
+ ...(ngDevMode ? [{ debugName: "hasHeader" }] : /* istanbul ignore next */ []));
9665
+ constructor() {
9666
+ // Projected nodes can appear or disappear with the consumer's own control
9667
+ // flow, so re-check after every render; the signal only changes (and only
9668
+ // schedules another pass) when a slot actually flips.
9669
+ afterEveryRender({
9670
+ read: () => {
9671
+ const next = {
9672
+ title: hasProjectedContent(this.titleSlot()?.nativeElement),
9673
+ subtitle: hasProjectedContent(this.subtitleSlot()?.nativeElement),
9674
+ actions: hasProjectedContent(this.actionsSlot()?.nativeElement),
9675
+ };
9676
+ const current = this.projected();
9677
+ if (next.title !== current.title ||
9678
+ next.subtitle !== current.subtitle ||
9679
+ next.actions !== current.actions) {
9680
+ this.projected.set(next);
9681
+ }
9682
+ },
9683
+ });
9684
+ }
9685
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9686
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.5", type: PageComponent, isStandalone: true, selector: "mm-page", inputs: { pageTitle: { classPropertyName: "pageTitle", publicName: "pageTitle", isSignal: true, isRequired: false, transformFunction: null }, pageSubtitle: { classPropertyName: "pageSubtitle", publicName: "pageSubtitle", isSignal: true, isRequired: false, transformFunction: null }, headingLevel: { classPropertyName: "headingLevel", publicName: "headingLevel", isSignal: true, isRequired: false, transformFunction: null }, padded: { classPropertyName: "padded", publicName: "padded", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.mm-page--flush": "!padded()", "class.mm-page--headerless": "!hasHeader()" }, classAttribute: "mm-page" }, viewQueries: [{ propertyName: "titleSlot", first: true, predicate: ["titleSlot"], descendants: true, isSignal: true }, { propertyName: "subtitleSlot", first: true, predicate: ["subtitleSlot"], descendants: true, isSignal: true }, { propertyName: "actionsSlot", first: true, predicate: ["actionsSlot"], descendants: true, isSignal: true }], ngImport: i0, template: `
9687
+ <div class="mm-page__header" [hidden]="!hasHeader()">
9688
+ <div class="mm-page__heading">
9689
+ <div class="mm-page__title" role="heading" [attr.aria-level]="headingLevel()" [hidden]="!hasTitle()">
9690
+ {{ pageTitle() ?? '' }}<span #titleSlot class="mm-page__slot"><ng-content select="[mmPageTitle]" /></span>
9691
+ </div>
9692
+ <div class="mm-page__subtitle" [hidden]="!hasSubtitle()">
9693
+ {{ pageSubtitle() ?? '' }}<span #subtitleSlot class="mm-page__slot"><ng-content select="[mmPageSubtitle]" /></span>
9694
+ </div>
9695
+ </div>
9696
+ <div #actionsSlot class="mm-page__actions" [hidden]="!projected().actions">
9697
+ <ng-content select="[mmPageActions]" />
9698
+ </div>
9699
+ </div>
9700
+ <div class="mm-page__content">
9701
+ <ng-content />
9702
+ </div>
9703
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;color:var(--theme-text-primary, inherit);font-family:var(--theme-font-ui, inherit)}[hidden]{display:none!important}.mm-page__slot{display:contents}.mm-page__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--theme-space-3, 12px) var(--theme-space-4, 16px);padding:var(--theme-space-4, 16px) var(--theme-space-4, 16px) var(--theme-space-3, 12px);flex:0 0 auto}.mm-page__heading{display:flex;flex-direction:column;gap:var(--theme-space-1, 4px);min-width:0}.mm-page__title{margin:0;font-family:var(--theme-font-display, inherit);font-size:1.25rem;line-height:1.4;font-weight:600;color:var(--theme-text-primary, inherit);overflow-wrap:anywhere}.mm-page__subtitle{font-size:.875rem;line-height:1.45;color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-page__actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--theme-space-2, 8px);margin-left:auto}.mm-page__content{flex:1 1 auto;min-height:0;overflow:auto;padding:0 var(--theme-space-4, 16px) var(--theme-space-4, 16px)}:host(.mm-page--headerless) .mm-page__content{padding-top:var(--theme-space-4, 16px)}:host(.mm-page--flush) .mm-page__content{padding:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9704
+ }
9705
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: PageComponent, decorators: [{
9706
+ type: Component,
9707
+ args: [{ selector: 'mm-page', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
9708
+ class: 'mm-page',
9709
+ '[class.mm-page--flush]': '!padded()',
9710
+ '[class.mm-page--headerless]': '!hasHeader()',
9711
+ }, template: `
9712
+ <div class="mm-page__header" [hidden]="!hasHeader()">
9713
+ <div class="mm-page__heading">
9714
+ <div class="mm-page__title" role="heading" [attr.aria-level]="headingLevel()" [hidden]="!hasTitle()">
9715
+ {{ pageTitle() ?? '' }}<span #titleSlot class="mm-page__slot"><ng-content select="[mmPageTitle]" /></span>
9716
+ </div>
9717
+ <div class="mm-page__subtitle" [hidden]="!hasSubtitle()">
9718
+ {{ pageSubtitle() ?? '' }}<span #subtitleSlot class="mm-page__slot"><ng-content select="[mmPageSubtitle]" /></span>
9719
+ </div>
9720
+ </div>
9721
+ <div #actionsSlot class="mm-page__actions" [hidden]="!projected().actions">
9722
+ <ng-content select="[mmPageActions]" />
9723
+ </div>
9724
+ </div>
9725
+ <div class="mm-page__content">
9726
+ <ng-content />
9727
+ </div>
9728
+ `, styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;box-sizing:border-box;color:var(--theme-text-primary, inherit);font-family:var(--theme-font-ui, inherit)}[hidden]{display:none!important}.mm-page__slot{display:contents}.mm-page__header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--theme-space-3, 12px) var(--theme-space-4, 16px);padding:var(--theme-space-4, 16px) var(--theme-space-4, 16px) var(--theme-space-3, 12px);flex:0 0 auto}.mm-page__heading{display:flex;flex-direction:column;gap:var(--theme-space-1, 4px);min-width:0}.mm-page__title{margin:0;font-family:var(--theme-font-display, inherit);font-size:1.25rem;line-height:1.4;font-weight:600;color:var(--theme-text-primary, inherit);overflow-wrap:anywhere}.mm-page__subtitle{font-size:.875rem;line-height:1.45;color:var(--theme-text-secondary, inherit);overflow-wrap:anywhere}.mm-page__actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--theme-space-2, 8px);margin-left:auto}.mm-page__content{flex:1 1 auto;min-height:0;overflow:auto;padding:0 var(--theme-space-4, 16px) var(--theme-space-4, 16px)}:host(.mm-page--headerless) .mm-page__content{padding-top:var(--theme-space-4, 16px)}:host(.mm-page--flush) .mm-page__content{padding:0}\n"] }]
9729
+ }], ctorParameters: () => [], propDecorators: { pageTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageTitle", required: false }] }], pageSubtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSubtitle", required: false }] }], headingLevel: [{ type: i0.Input, args: [{ isSignal: true, alias: "headingLevel", required: false }] }], padded: [{ type: i0.Input, args: [{ isSignal: true, alias: "padded", required: false }] }], titleSlot: [{ type: i0.ViewChild, args: ['titleSlot', { isSignal: true }] }], subtitleSlot: [{ type: i0.ViewChild, args: ['subtitleSlot', { isSignal: true }] }], actionsSlot: [{ type: i0.ViewChild, args: ['actionsSlot', { isSignal: true }] }] } });
9730
+ /**
9731
+ * Everything a template needs for `<mm-page>` and its slots:
9732
+ * `imports: [...MM_PAGE]` (or `imports: [MM_PAGE]`).
9733
+ */
9734
+ const MM_PAGE = [PageComponent, PageTitleDirective, PageSubtitleDirective, PageActionsDirective];
9735
+
9489
9736
  const CreateEntitiesDocumentDto = gql `
9490
9737
  mutation CreateEntities($entities: [RtEntityInput]!) {
9491
9738
  runtime {
@@ -9662,6 +9909,8 @@ const DEFAULT_RUNTIME_BROWSER_MESSAGES = {
9662
9909
  unloadRecord: 'Unload',
9663
9910
  longitudeHint: 'The longitude of the point on the Earth surface (-180 to 180 degrees).',
9664
9911
  latitudeHint: 'The latitude of the point on the Earth surface (-90 to 90 degrees).',
9912
+ secretWriteOnlyHint: 'Write-only. The stored value is never shown; leave empty to keep it.',
9913
+ recordWithSecretNotSaved: 'Some changed fields contain secret values that are never loaded here; those changes were not saved.',
9665
9914
  title: 'Runtime Browser',
9666
9915
  badgeLabel: 'Entities & Data',
9667
9916
  titlePrefix: 'REPOSITORY',
@@ -9709,6 +9958,9 @@ const DEFAULT_RUNTIME_BROWSER_MESSAGES = {
9709
9958
  create: 'Create',
9710
9959
  edit: 'Edit',
9711
9960
  delete: 'Delete',
9961
+ confirmDeleteEntityTitle: 'Delete {name}?',
9962
+ confirmDeleteEntityConsequence: 'The entity and all its child entities are erased. This cannot be undone.',
9963
+ confirmDeleteEntityConfirmText: 'Delete entity',
9712
9964
  createEntity: 'Create Entity',
9713
9965
  updateEntity: 'Update Entity',
9714
9966
  name: 'Name',
@@ -9757,6 +10009,7 @@ const DEFAULT_RUNTIME_BROWSER_MESSAGES = {
9757
10009
  treeMoveToRootUnsupported: 'Moving item to the root of the tree is not supported',
9758
10010
  treeMoveOnRootUnsupported: 'Moving item on the root of the tree is not supported',
9759
10011
  mappingHeader: 'MAPPING',
10012
+ mappingRemove: 'Remove mapping',
9760
10013
  mappingSourceDataPoint: 'Source Data Point',
9761
10014
  mappingAddMapping: '+ Add Mapping',
9762
10015
  mappingSaveAll: 'Save All Mappings',
@@ -9817,7 +10070,7 @@ class DataMappingListComponent {
9817
10070
  this.mappingChanged.emit(mapping);
9818
10071
  }
9819
10072
  plusIcon = plusIcon;
9820
- trashIcon = trashIcon;
10073
+ trashIcon = MM_ACTION_ICONS.delete;
9821
10074
  linkIcon = hyperlinkOpenIcon;
9822
10075
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DataMappingListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9823
10076
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: DataMappingListComponent, isStandalone: true, selector: "mm-data-mapping-list", inputs: { messages: "messages", mappings: "mappings", sourceEntity: "sourceEntity", expressionValidator: "expressionValidator" }, outputs: { addMapping: "addMapping", removeMapping: "removeMapping", selectTarget: "selectTarget", selectSourceAttribute: "selectSourceAttribute", selectTargetAttribute: "selectTargetAttribute", mappingChanged: "mappingChanged", navigateToTarget: "navigateToTarget", saveAll: "saveAll" }, ngImport: i0, template: `
@@ -9837,7 +10090,9 @@ class DataMappingListComponent {
9837
10090
  <div class="mapping-card">
9838
10091
  <div class="mapping-card-header">
9839
10092
  <span class="mapping-name">{{ mapping.name || ((messages?.mappingHeader ?? 'MAPPING') + ' ' + ($index + 1)) }}</span>
9840
- <button kendoButton fillMode="flat" size="small" [svgIcon]="trashIcon"
10093
+ <button kendoButton fillMode="flat" size="small" themeColor="error" [svgIcon]="trashIcon"
10094
+ [title]="messages?.mappingRemove ?? 'Remove mapping'" data-action="delete"
10095
+ [attr.aria-label]="(messages?.mappingRemove ?? 'Remove mapping') + ' ' + (mapping.name || ((messages?.mappingHeader ?? 'MAPPING') + ' ' + ($index + 1)))"
9841
10096
  (click)="removeMapping.emit(mapping)"></button>
9842
10097
  </div>
9843
10098
  <div class="mapping-card-body">
@@ -9871,7 +10126,7 @@ class DataMappingListComponent {
9871
10126
  <span class="entity-name">{{ mapping.targetName || mapping.targetRtId }}</span>
9872
10127
  @if (mapping.targetRtId) {
9873
10128
  <button kendoButton fillMode="flat" size="small" [svgIcon]="linkIcon"
9874
- title="Navigate to entity"
10129
+ title="Navigate to entity" aria-label="Navigate to entity"
9875
10130
  (click)="navigateToTarget.emit(mapping)"></button>
9876
10131
  }
9877
10132
  </div>
@@ -9912,7 +10167,7 @@ class DataMappingListComponent {
9912
10167
  </div>
9913
10168
  }
9914
10169
  </div>
9915
- `, isInline: true, styles: [".mapping-list{display:flex;flex-direction:column;gap:12px}.mapping-toolbar{display:flex;justify-content:flex-end}.mapping-empty-hint{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.mapping-card{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.mapping-card-header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.mapping-card-header .mapping-name{flex:1}.mapping-card-body{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.mapping-row{display:flex;flex-direction:column;gap:3px}.mapping-row label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.target-display{display:flex;align-items:center;gap:8px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);min-height:30px}.target-display .target-info{flex:1;font-size:.85rem;font-family:monospace}.mapping-actions{display:flex;justify-content:flex-end;padding-top:4px}.entity-info-display{display:flex;flex-direction:column;gap:2px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa)}.entity-info-main{display:flex;align-items:center;gap:4px}.entity-name{flex:1;font-size:.85rem;font-weight:600}.entity-info-details{display:flex;align-items:center;gap:2px;font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.entity-detail-separator{color:var(--kendo-color-subtle, #6c757d)}.expression-feedback{font-size:.75rem;padding:2px 0;font-family:monospace}.expression-error{color:var(--kendo-color-error, #dc3545)}.expression-success{color:var(--kendo-color-success, #28a745)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
10170
+ `, isInline: true, styles: [".mapping-list{display:flex;flex-direction:column;gap:12px}.mapping-toolbar{display:flex;justify-content:flex-end}.mapping-empty-hint{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.mapping-card{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.mapping-card-header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;font-size:.75rem;font-weight:700;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.mapping-card-header .mapping-name{flex:1}.mapping-card-body{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.mapping-row{display:flex;flex-direction:column;gap:3px}.mapping-row label{font-size:.7rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.target-display{display:flex;align-items:center;gap:8px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);min-height:30px}.target-display .target-info{flex:1;font-size:.85rem;font-family:monospace}.mapping-actions{display:flex;justify-content:flex-end;padding-top:4px}.entity-info-display{display:flex;flex-direction:column;gap:2px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa)}.entity-info-main{display:flex;align-items:center;gap:4px}.entity-name{flex:1;font-size:.85rem;font-weight:600}.entity-info-details{display:flex;align-items:center;gap:2px;font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.entity-detail-separator{color:var(--kendo-color-subtle, #6c757d)}.expression-feedback{font-size:.75rem;padding:2px 0;font-family:monospace}.expression-error{color:var(--kendo-color-error, #dc3545)}.expression-success{color:var(--kendo-color-success, #28a745)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
9916
10171
  }
9917
10172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DataMappingListComponent, decorators: [{
9918
10173
  type: Component,
@@ -9940,7 +10195,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
9940
10195
  <div class="mapping-card">
9941
10196
  <div class="mapping-card-header">
9942
10197
  <span class="mapping-name">{{ mapping.name || ((messages?.mappingHeader ?? 'MAPPING') + ' ' + ($index + 1)) }}</span>
9943
- <button kendoButton fillMode="flat" size="small" [svgIcon]="trashIcon"
10198
+ <button kendoButton fillMode="flat" size="small" themeColor="error" [svgIcon]="trashIcon"
10199
+ [title]="messages?.mappingRemove ?? 'Remove mapping'" data-action="delete"
10200
+ [attr.aria-label]="(messages?.mappingRemove ?? 'Remove mapping') + ' ' + (mapping.name || ((messages?.mappingHeader ?? 'MAPPING') + ' ' + ($index + 1)))"
9944
10201
  (click)="removeMapping.emit(mapping)"></button>
9945
10202
  </div>
9946
10203
  <div class="mapping-card-body">
@@ -9974,7 +10231,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
9974
10231
  <span class="entity-name">{{ mapping.targetName || mapping.targetRtId }}</span>
9975
10232
  @if (mapping.targetRtId) {
9976
10233
  <button kendoButton fillMode="flat" size="small" [svgIcon]="linkIcon"
9977
- title="Navigate to entity"
10234
+ title="Navigate to entity" aria-label="Navigate to entity"
9978
10235
  (click)="navigateToTarget.emit(mapping)"></button>
9979
10236
  }
9980
10237
  </div>
@@ -10015,7 +10272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10015
10272
  </div>
10016
10273
  }
10017
10274
  </div>
10018
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-list{display:flex;flex-direction:column;gap:12px}.mapping-toolbar{display:flex;justify-content:flex-end}.mapping-empty-hint{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.mapping-card{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.mapping-card-header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.mapping-card-header .mapping-name{flex:1}.mapping-card-body{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.mapping-row{display:flex;flex-direction:column;gap:3px}.mapping-row label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.target-display{display:flex;align-items:center;gap:8px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);min-height:30px}.target-display .target-info{flex:1;font-size:.85rem;font-family:monospace}.mapping-actions{display:flex;justify-content:flex-end;padding-top:4px}.entity-info-display{display:flex;flex-direction:column;gap:2px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa)}.entity-info-main{display:flex;align-items:center;gap:4px}.entity-name{flex:1;font-size:.85rem;font-weight:600}.entity-info-details{display:flex;align-items:center;gap:2px;font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.entity-detail-separator{color:var(--kendo-color-subtle, #6c757d)}.expression-feedback{font-size:.75rem;padding:2px 0;font-family:monospace}.expression-error{color:var(--kendo-color-error, #dc3545)}.expression-success{color:var(--kendo-color-success, #28a745)}\n"] }]
10275
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-list{display:flex;flex-direction:column;gap:12px}.mapping-toolbar{display:flex;justify-content:flex-end}.mapping-empty-hint{text-align:center;padding:16px;color:var(--kendo-color-subtle, #6c757d);font-size:.85rem}.mapping-card{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.mapping-card-header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;font-size:.75rem;font-weight:700;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.mapping-card-header .mapping-name{flex:1}.mapping-card-body{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.mapping-row{display:flex;flex-direction:column;gap:3px}.mapping-row label{font-size:.7rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.target-display{display:flex;align-items:center;gap:8px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa);min-height:30px}.target-display .target-info{flex:1;font-size:.85rem;font-family:monospace}.mapping-actions{display:flex;justify-content:flex-end;padding-top:4px}.entity-info-display{display:flex;flex-direction:column;gap:2px;padding:4px 8px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px;background:var(--kendo-color-surface-alt, #f8f9fa)}.entity-info-main{display:flex;align-items:center;gap:4px}.entity-name{flex:1;font-size:.85rem;font-weight:600}.entity-info-details{display:flex;align-items:center;gap:2px;font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.entity-detail-separator{color:var(--kendo-color-subtle, #6c757d)}.expression-feedback{font-size:.75rem;padding:2px 0;font-family:monospace}.expression-error{color:var(--kendo-color-error, #dc3545)}.expression-success{color:var(--kendo-color-success, #28a745)}\n"] }]
10019
10276
  }], propDecorators: { messages: [{
10020
10277
  type: Input
10021
10278
  }], mappings: [{
@@ -10367,7 +10624,7 @@ class EntityDetailViewComponent {
10367
10624
  fillMode="flat"
10368
10625
  size="small"
10369
10626
  [svgIcon]="copyIcon"
10370
- [title]="_messages.copyToClipboard"
10627
+ [title]="_messages.copyToClipboard" [attr.aria-label]="_messages.copyToClipboard"
10371
10628
  (click)="copyToClipboard(entity.rtId, _messages.runtimeId)"
10372
10629
  ></button>
10373
10630
  </div>
@@ -10381,7 +10638,7 @@ class EntityDetailViewComponent {
10381
10638
  fillMode="flat"
10382
10639
  size="small"
10383
10640
  [svgIcon]="copyIcon"
10384
- [title]="_messages.copyToClipboard"
10641
+ [title]="_messages.copyToClipboard" [attr.aria-label]="_messages.copyToClipboard"
10385
10642
  (click)="copyToClipboard(entity.ckTypeId, _messages.typeId)"
10386
10643
  ></button>
10387
10644
  </div>
@@ -10395,7 +10652,7 @@ class EntityDetailViewComponent {
10395
10652
  fillMode="flat"
10396
10653
  size="small"
10397
10654
  [svgIcon]="copyIcon"
10398
- [title]="_messages.copyEntityIdentifierToClipboard"
10655
+ [title]="_messages.copyEntityIdentifierToClipboard" [attr.aria-label]="_messages.copyEntityIdentifierToClipboard"
10399
10656
  (click)="
10400
10657
  copyToClipboard(
10401
10658
  getEntityIdentifier(),
@@ -10566,7 +10823,7 @@ class EntityDetailViewComponent {
10566
10823
  </kendo-tabstrip>
10567
10824
  </div>
10568
10825
  }
10569
- `, isInline: true, styles: [".loading-state,.error-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;text-align:center;min-height:200px}.loading-state .error-message,.error-state .error-message{margin-bottom:16px;font-family:Roboto,sans-serif;color:#e74c3c}.entity-content{flex:1;display:flex;flex-direction:column;gap:24px}.entity-content .basic-info-card{padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.entity-content .basic-info-card:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.entity-content .basic-info-card .basic-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px}.entity-content .basic-info-card .basic-info-grid .info-item{display:flex;flex-direction:column;gap:8px}.entity-content .basic-info-card .basic-info-grid .info-item label{font-family:Montserrat,sans-serif;font-weight:600;font-size:.75rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80)}.entity-content .basic-info-card .basic-info-grid .info-item .value{font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word;background:var(--deep-sea-40);padding:8px 12px;border-radius:4px;border:1px solid var(--octo-mint-15)}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action{display:flex;align-items:center}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action .value{flex:1;font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word}.entity-content .entity-tabs{flex:1;min-height:400px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;overflow:hidden;position:relative}.entity-content .entity-tabs:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);z-index:1}.entity-content .entity-tabs ::ng-deep .k-tabstrip{background:transparent}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{background:linear-gradient(90deg,var(--octo-mint-10),transparent);border-bottom:1px solid var(--octo-mint-20);padding-left:20px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{background:transparent;border:none;color:rgba(var(--octo-text-color),.7);font-family:Montserrat,sans-serif;font-weight:600;font-size:.8rem;letter-spacing:.5px;text-transform:uppercase;padding:12px 20px;margin-right:4px;border-radius:4px 4px 0 0;transition:all .2s ease}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item:hover{background:var(--octo-mint-10);color:var(--octo-mint)}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item.k-active{background:linear-gradient(180deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-bottom:2px solid var(--octo-mint);box-shadow:0 0 10px var(--octo-mint-30)}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-content{background:transparent;border:none;padding:0}.entity-content .entity-tabs .tab-content{padding:20px 24px;height:100%;overflow-y:auto}.entity-content .entity-tabs .tab-content .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 40px;text-align:center}.entity-content .entity-tabs .tab-content .empty-state kendo-svgicon{font-size:64px;margin-bottom:20px;color:var(--octo-mint-40);text-shadow:0 0 20px var(--octo-mint-30)}.entity-content .entity-tabs .tab-content .empty-state p{margin:0;font-family:Montserrat,sans-serif;font-size:.9rem;color:rgba(var(--octo-text-color),.5);letter-spacing:.5px}.entity-content .entity-tabs .tab-content.properties-tab{padding:0;height:100%}.entity-content .entity-tabs .tab-content.properties-tab mm-property-grid{display:block;height:100%;width:100%}.entity-content .entity-tabs .tab-content.associations-tab{display:flex;flex-direction:column;gap:16px;padding:0;height:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:16px;padding:16px 20px;background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{display:flex;align-items:center;gap:10px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group label{font-family:Montserrat,sans-serif;font-weight:600;font-size:.75rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80);white-space:nowrap}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist{width:160px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:220px}.entity-content .entity-tabs .tab-content.associations-tab mm-list-view{flex:1;display:block;height:calc(100% - 70px)}.entity-content .entity-tabs .tab-content.mapping-tab{padding:12px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty{display:flex;flex-direction:column;align-items:center;padding:24px 20px;text-align:center}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty kendo-svgicon{font-size:36px;margin-bottom:10px;opacity:.5}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty p{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-config{display:flex;flex-direction:column;gap:20px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-header{padding:8px 14px;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-body{padding:12px 14px;display:flex;flex-direction:column;gap:10px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field{display:flex;flex-direction:column;gap:4px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display{display:flex;align-items:center;gap:8px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-type{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace;padding:2px 6px;border-radius:3px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-name{font-weight:600;flex:1}.entity-content .entity-tabs .tab-content.mapping-tab .field-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic;line-height:1.3}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker{display:flex;align-items:center;gap:8px;padding:4px 10px;border-radius:4px;border:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface-alt, #f8f9fa);min-height:32px}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker .attribute-value{flex:1;font-family:monospace;font-size:.85rem}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:4px}@media(max-width:768px){.entity-content{gap:16px}.entity-content .basic-info-card{padding:16px 20px}.entity-content .basic-info-card .basic-info-grid{grid-template-columns:1fr;gap:16px}.entity-content .entity-tabs{min-height:300px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{padding-left:12px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{padding:10px 14px;font-size:.75rem}.entity-content .entity-tabs .tab-content{padding:16px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{flex-direction:column;align-items:flex-start;gap:12px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{width:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist,.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TabStripModule }, { kind: "component", type: i1$4.TabStripComponent, selector: "kendo-tabstrip", inputs: ["height", "animate", "tabAlignment", "tabPosition", "keepTabContent", "closable", "scrollable", "size", "closeIcon", "closeIconClass", "closeSVGIcon", "showContentArea"], outputs: ["tabSelect", "tabClose", "tabScroll"], exportAs: ["kendoTabStrip"] }, { kind: "component", type: i1$4.TabStripTabComponent, selector: "kendo-tabstrip-tab", inputs: ["title", "disabled", "cssClass", "cssStyle", "selected", "closable", "closeIcon", "closeIconClass", "closeSVGIcon"], exportAs: ["kendoTabStripTab"] }, { kind: "directive", type: i1$4.TabContentDirective, selector: "[kendoTabContent]" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "ngmodule", type: DropDownListModule }, { kind: "component", type: i3$1.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: PropertyGridComponent, selector: "mm-property-grid", inputs: ["data", "config", "showTypeColumn", "messages"], outputs: ["propertyChange", "saveRequested", "binaryDownload"] }, { kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "collapseCommandsBelow", "rowClass", "messages", "selectable", "columns"], outputs: ["rowClicked", "resetFilters"] }, { kind: "directive", type: EntityAssociationsDataSourceDirective, selector: "[mmEntityAssociationsDataSource]", exportAs: ["mmEntityAssociationsDataSource"] }, { kind: "component", type: DataMappingListComponent, selector: "mm-data-mapping-list", inputs: ["messages", "mappings", "sourceEntity", "expressionValidator"], outputs: ["addMapping", "removeMapping", "selectTarget", "selectSourceAttribute", "selectTargetAttribute", "mappingChanged", "navigateToTarget", "saveAll"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
10826
+ `, isInline: true, styles: [".loading-state,.error-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;text-align:center;min-height:200px}.loading-state .error-message,.error-state .error-message{margin-bottom:16px;font-family:Roboto,sans-serif;color:#e74c3c}.entity-content{flex:1;display:flex;flex-direction:column;gap:24px}.entity-content .basic-info-card{padding:20px 24px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);position:relative;box-shadow:0 4px 20px #0006}.entity-content .basic-info-card:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;border-radius:4px 0 0 4px}.entity-content .basic-info-card .basic-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px}.entity-content .basic-info-card .basic-info-grid .info-item{display:flex;flex-direction:column;gap:8px}.entity-content .basic-info-card .basic-info-grid .info-item label{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.75rem;color:var(--octo-mint-80)}.entity-content .basic-info-card .basic-info-grid .info-item .value{font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word;background:var(--deep-sea-40);padding:8px 12px;border-radius:4px;border:1px solid var(--octo-mint-15)}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action{display:flex;align-items:center}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action .value{flex:1;font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word}.entity-content .entity-tabs{flex:1;min-height:400px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);overflow:hidden;position:relative}.entity-content .entity-tabs:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;z-index:1}.entity-content .entity-tabs ::ng-deep .k-tabstrip{background:transparent}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{background:var(--theme-bg-elevated);border-bottom:1px solid var(--octo-mint-20);padding-left:20px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{background:transparent;border:none;color:rgba(var(--octo-text-color),.7);font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.8rem;padding:12px 20px;margin-right:4px;border-radius:4px 4px 0 0;transition:all .2s ease}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item:hover{background:var(--octo-mint-10);color:var(--theme-text-accent, var(--octo-mint))}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item.k-active{background:var(--theme-bg-elevated);color:var(--theme-text-accent, var(--octo-mint));border-bottom:2px solid var(--octo-mint);box-shadow:none}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-content{background:transparent;border:none;padding:0}.entity-content .entity-tabs .tab-content{padding:20px 24px;height:100%;overflow-y:auto}.entity-content .entity-tabs .tab-content .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 40px;text-align:center}.entity-content .entity-tabs .tab-content .empty-state kendo-svgicon{font-size:64px;margin-bottom:20px;color:var(--octo-mint-40)}.entity-content .entity-tabs .tab-content .empty-state p{margin:0;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:.9rem;color:rgba(var(--octo-text-color),.5)}.entity-content .entity-tabs .tab-content.properties-tab{padding:0;height:100%}.entity-content .entity-tabs .tab-content.properties-tab mm-property-grid{display:block;height:100%;width:100%}.entity-content .entity-tabs .tab-content.associations-tab{display:flex;flex-direction:column;gap:16px;padding:0;height:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:16px;padding:16px 20px;background:var(--theme-bg-elevated);border-bottom:1px solid var(--octo-mint-20)}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{display:flex;align-items:center;gap:10px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group label{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.75rem;color:var(--octo-mint-80);white-space:nowrap}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist{width:160px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:220px}.entity-content .entity-tabs .tab-content.associations-tab mm-list-view{flex:1;display:block;height:calc(100% - 70px)}.entity-content .entity-tabs .tab-content.mapping-tab{padding:12px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty{display:flex;flex-direction:column;align-items:center;padding:24px 20px;text-align:center}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty kendo-svgicon{font-size:36px;margin-bottom:10px;opacity:.5}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty p{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-config{display:flex;flex-direction:column;gap:20px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-header{padding:8px 14px;font-size:.75rem;font-weight:700;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-body{padding:12px 14px;display:flex;flex-direction:column;gap:10px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field{display:flex;flex-direction:column;gap:4px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field label{font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display{display:flex;align-items:center;gap:8px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-type{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace;padding:2px 6px;border-radius:3px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-name{font-weight:600;flex:1}.entity-content .entity-tabs .tab-content.mapping-tab .field-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic;line-height:1.3}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker{display:flex;align-items:center;gap:8px;padding:4px 10px;border-radius:4px;border:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface-alt, #f8f9fa);min-height:32px}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker .attribute-value{flex:1;font-family:monospace;font-size:.85rem}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:4px}@media(max-width:768px){.entity-content{gap:16px}.entity-content .basic-info-card{padding:16px 20px}.entity-content .basic-info-card .basic-info-grid{grid-template-columns:1fr;gap:16px}.entity-content .entity-tabs{min-height:300px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{padding-left:12px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{padding:10px 14px;font-size:.75rem}.entity-content .entity-tabs .tab-content{padding:16px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{flex-direction:column;align-items:flex-start;gap:12px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{width:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist,.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TabStripModule }, { kind: "component", type: i1$4.TabStripComponent, selector: "kendo-tabstrip", inputs: ["height", "animate", "tabAlignment", "tabPosition", "keepTabContent", "closable", "scrollable", "size", "closeIcon", "closeIconClass", "closeSVGIcon", "showContentArea"], outputs: ["tabSelect", "tabClose", "tabScroll"], exportAs: ["kendoTabStrip"] }, { kind: "component", type: i1$4.TabStripTabComponent, selector: "kendo-tabstrip-tab", inputs: ["title", "disabled", "cssClass", "cssStyle", "selected", "closable", "closeIcon", "closeIconClass", "closeSVGIcon"], exportAs: ["kendoTabStripTab"] }, { kind: "directive", type: i1$4.TabContentDirective, selector: "[kendoTabContent]" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "ngmodule", type: DropDownListModule }, { kind: "component", type: i3$1.DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: PropertyGridComponent, selector: "mm-property-grid", inputs: ["data", "config", "showTypeColumn", "messages"], outputs: ["propertyChange", "saveRequested", "binaryDownload"] }, { 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: EntityAssociationsDataSourceDirective, selector: "[mmEntityAssociationsDataSource]", exportAs: ["mmEntityAssociationsDataSource"] }, { kind: "component", type: DataMappingListComponent, selector: "mm-data-mapping-list", inputs: ["messages", "mappings", "sourceEntity", "expressionValidator"], outputs: ["addMapping", "removeMapping", "selectTarget", "selectSourceAttribute", "selectTargetAttribute", "mappingChanged", "navigateToTarget", "saveAll"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
10570
10827
  }
10571
10828
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityDetailViewComponent, decorators: [{
10572
10829
  type: Component,
@@ -10619,7 +10876,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10619
10876
  fillMode="flat"
10620
10877
  size="small"
10621
10878
  [svgIcon]="copyIcon"
10622
- [title]="_messages.copyToClipboard"
10879
+ [title]="_messages.copyToClipboard" [attr.aria-label]="_messages.copyToClipboard"
10623
10880
  (click)="copyToClipboard(entity.rtId, _messages.runtimeId)"
10624
10881
  ></button>
10625
10882
  </div>
@@ -10633,7 +10890,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10633
10890
  fillMode="flat"
10634
10891
  size="small"
10635
10892
  [svgIcon]="copyIcon"
10636
- [title]="_messages.copyToClipboard"
10893
+ [title]="_messages.copyToClipboard" [attr.aria-label]="_messages.copyToClipboard"
10637
10894
  (click)="copyToClipboard(entity.ckTypeId, _messages.typeId)"
10638
10895
  ></button>
10639
10896
  </div>
@@ -10647,7 +10904,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10647
10904
  fillMode="flat"
10648
10905
  size="small"
10649
10906
  [svgIcon]="copyIcon"
10650
- [title]="_messages.copyEntityIdentifierToClipboard"
10907
+ [title]="_messages.copyEntityIdentifierToClipboard" [attr.aria-label]="_messages.copyEntityIdentifierToClipboard"
10651
10908
  (click)="
10652
10909
  copyToClipboard(
10653
10910
  getEntityIdentifier(),
@@ -10818,7 +11075,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10818
11075
  </kendo-tabstrip>
10819
11076
  </div>
10820
11077
  }
10821
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".loading-state,.error-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;text-align:center;min-height:200px}.loading-state .error-message,.error-state .error-message{margin-bottom:16px;font-family:Roboto,sans-serif;color:#e74c3c}.entity-content{flex:1;display:flex;flex-direction:column;gap:24px}.entity-content .basic-info-card{padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.entity-content .basic-info-card:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.entity-content .basic-info-card .basic-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px}.entity-content .basic-info-card .basic-info-grid .info-item{display:flex;flex-direction:column;gap:8px}.entity-content .basic-info-card .basic-info-grid .info-item label{font-family:Montserrat,sans-serif;font-weight:600;font-size:.75rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80)}.entity-content .basic-info-card .basic-info-grid .info-item .value{font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word;background:var(--deep-sea-40);padding:8px 12px;border-radius:4px;border:1px solid var(--octo-mint-15)}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action{display:flex;align-items:center}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action .value{flex:1;font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word}.entity-content .entity-tabs{flex:1;min-height:400px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;overflow:hidden;position:relative}.entity-content .entity-tabs:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);z-index:1}.entity-content .entity-tabs ::ng-deep .k-tabstrip{background:transparent}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{background:linear-gradient(90deg,var(--octo-mint-10),transparent);border-bottom:1px solid var(--octo-mint-20);padding-left:20px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{background:transparent;border:none;color:rgba(var(--octo-text-color),.7);font-family:Montserrat,sans-serif;font-weight:600;font-size:.8rem;letter-spacing:.5px;text-transform:uppercase;padding:12px 20px;margin-right:4px;border-radius:4px 4px 0 0;transition:all .2s ease}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item:hover{background:var(--octo-mint-10);color:var(--octo-mint)}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item.k-active{background:linear-gradient(180deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-bottom:2px solid var(--octo-mint);box-shadow:0 0 10px var(--octo-mint-30)}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-content{background:transparent;border:none;padding:0}.entity-content .entity-tabs .tab-content{padding:20px 24px;height:100%;overflow-y:auto}.entity-content .entity-tabs .tab-content .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 40px;text-align:center}.entity-content .entity-tabs .tab-content .empty-state kendo-svgicon{font-size:64px;margin-bottom:20px;color:var(--octo-mint-40);text-shadow:0 0 20px var(--octo-mint-30)}.entity-content .entity-tabs .tab-content .empty-state p{margin:0;font-family:Montserrat,sans-serif;font-size:.9rem;color:rgba(var(--octo-text-color),.5);letter-spacing:.5px}.entity-content .entity-tabs .tab-content.properties-tab{padding:0;height:100%}.entity-content .entity-tabs .tab-content.properties-tab mm-property-grid{display:block;height:100%;width:100%}.entity-content .entity-tabs .tab-content.associations-tab{display:flex;flex-direction:column;gap:16px;padding:0;height:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:16px;padding:16px 20px;background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{display:flex;align-items:center;gap:10px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group label{font-family:Montserrat,sans-serif;font-weight:600;font-size:.75rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80);white-space:nowrap}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist{width:160px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:220px}.entity-content .entity-tabs .tab-content.associations-tab mm-list-view{flex:1;display:block;height:calc(100% - 70px)}.entity-content .entity-tabs .tab-content.mapping-tab{padding:12px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty{display:flex;flex-direction:column;align-items:center;padding:24px 20px;text-align:center}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty kendo-svgicon{font-size:36px;margin-bottom:10px;opacity:.5}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty p{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-config{display:flex;flex-direction:column;gap:20px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-header{padding:8px 14px;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-body{padding:12px 14px;display:flex;flex-direction:column;gap:10px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field{display:flex;flex-direction:column;gap:4px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display{display:flex;align-items:center;gap:8px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-type{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace;padding:2px 6px;border-radius:3px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-name{font-weight:600;flex:1}.entity-content .entity-tabs .tab-content.mapping-tab .field-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic;line-height:1.3}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker{display:flex;align-items:center;gap:8px;padding:4px 10px;border-radius:4px;border:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface-alt, #f8f9fa);min-height:32px}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker .attribute-value{flex:1;font-family:monospace;font-size:.85rem}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:4px}@media(max-width:768px){.entity-content{gap:16px}.entity-content .basic-info-card{padding:16px 20px}.entity-content .basic-info-card .basic-info-grid{grid-template-columns:1fr;gap:16px}.entity-content .entity-tabs{min-height:300px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{padding-left:12px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{padding:10px 14px;font-size:.75rem}.entity-content .entity-tabs .tab-content{padding:16px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{flex-direction:column;align-items:flex-start;gap:12px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{width:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist,.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:100%}}\n"] }]
11078
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".loading-state,.error-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;text-align:center;min-height:200px}.loading-state .error-message,.error-state .error-message{margin-bottom:16px;font-family:Roboto,sans-serif;color:#e74c3c}.entity-content{flex:1;display:flex;flex-direction:column;gap:24px}.entity-content .basic-info-card{padding:20px 24px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);position:relative;box-shadow:0 4px 20px #0006}.entity-content .basic-info-card:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;border-radius:4px 0 0 4px}.entity-content .basic-info-card .basic-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:20px}.entity-content .basic-info-card .basic-info-grid .info-item{display:flex;flex-direction:column;gap:8px}.entity-content .basic-info-card .basic-info-grid .info-item label{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.75rem;color:var(--octo-mint-80)}.entity-content .basic-info-card .basic-info-grid .info-item .value{font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word;background:var(--deep-sea-40);padding:8px 12px;border-radius:4px;border:1px solid var(--octo-mint-15)}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action{display:flex;align-items:center}.entity-content .basic-info-card .basic-info-grid .info-item.with-action .value-with-action .value{flex:1;font-family:Roboto Mono,monospace;font-size:.875rem;color:rgba(var(--octo-text-color),.9);word-break:break-word}.entity-content .entity-tabs{flex:1;min-height:400px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);overflow:hidden;position:relative}.entity-content .entity-tabs:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;z-index:1}.entity-content .entity-tabs ::ng-deep .k-tabstrip{background:transparent}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{background:var(--theme-bg-elevated);border-bottom:1px solid var(--octo-mint-20);padding-left:20px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{background:transparent;border:none;color:rgba(var(--octo-text-color),.7);font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.8rem;padding:12px 20px;margin-right:4px;border-radius:4px 4px 0 0;transition:all .2s ease}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item:hover{background:var(--octo-mint-10);color:var(--theme-text-accent, var(--octo-mint))}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item.k-active{background:var(--theme-bg-elevated);color:var(--theme-text-accent, var(--octo-mint));border-bottom:2px solid var(--octo-mint);box-shadow:none}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-content{background:transparent;border:none;padding:0}.entity-content .entity-tabs .tab-content{padding:20px 24px;height:100%;overflow-y:auto}.entity-content .entity-tabs .tab-content .empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 40px;text-align:center}.entity-content .entity-tabs .tab-content .empty-state kendo-svgicon{font-size:64px;margin-bottom:20px;color:var(--octo-mint-40)}.entity-content .entity-tabs .tab-content .empty-state p{margin:0;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:.9rem;color:rgba(var(--octo-text-color),.5)}.entity-content .entity-tabs .tab-content.properties-tab{padding:0;height:100%}.entity-content .entity-tabs .tab-content.properties-tab mm-property-grid{display:block;height:100%;width:100%}.entity-content .entity-tabs .tab-content.associations-tab{display:flex;flex-direction:column;gap:16px;padding:0;height:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:16px;padding:16px 20px;background:var(--theme-bg-elevated);border-bottom:1px solid var(--octo-mint-20)}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{display:flex;align-items:center;gap:10px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group label{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-weight:600;font-size:.75rem;color:var(--octo-mint-80);white-space:nowrap}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist{width:160px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:220px}.entity-content .entity-tabs .tab-content.associations-tab mm-list-view{flex:1;display:block;height:calc(100% - 70px)}.entity-content .entity-tabs .tab-content.mapping-tab{padding:12px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty{display:flex;flex-direction:column;align-items:center;padding:24px 20px;text-align:center}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty kendo-svgicon{font-size:36px;margin-bottom:10px;opacity:.5}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-empty p{margin:0 0 12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-config{display:flex;flex-direction:column;gap:20px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;overflow:hidden}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-header{padding:8px 14px;font-size:.75rem;font-weight:700;color:var(--kendo-color-on-primary, #ffffff);background:var(--kendo-color-primary, #ff6358)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-section .section-body{padding:12px 14px;display:flex;flex-direction:column;gap:10px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field{display:flex;flex-direction:column;gap:4px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-field label{font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display{display:flex;align-items:center;gap:8px}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-type{font-size:.75rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace;padding:2px 6px;border-radius:3px;background:var(--kendo-color-surface-alt, #f8f9fa);border:1px solid var(--kendo-color-border, #dee2e6)}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-target-display .target-name{font-weight:600;flex:1}.entity-content .entity-tabs .tab-content.mapping-tab .field-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-style:italic;line-height:1.3}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker{display:flex;align-items:center;gap:8px;padding:4px 10px;border-radius:4px;border:1px solid var(--kendo-color-border, #dee2e6);background:var(--kendo-color-surface-alt, #f8f9fa);min-height:32px}.entity-content .entity-tabs .tab-content.mapping-tab .attribute-picker .attribute-value{flex:1;font-family:monospace;font-size:.85rem}.entity-content .entity-tabs .tab-content.mapping-tab .mapping-actions{display:flex;gap:8px;justify-content:flex-end;padding-top:4px}@media(max-width:768px){.entity-content{gap:16px}.entity-content .basic-info-card{padding:16px 20px}.entity-content .basic-info-card .basic-info-grid{grid-template-columns:1fr;gap:16px}.entity-content .entity-tabs{min-height:300px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper{padding-left:12px}.entity-content .entity-tabs ::ng-deep .k-tabstrip .k-tabstrip-items-wrapper .k-tabstrip-items .k-item{padding:10px 14px;font-size:.75rem}.entity-content .entity-tabs .tab-content{padding:16px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar{flex-direction:column;align-items:flex-start;gap:12px}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group{width:100%}.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-dropdownlist,.entity-content .entity-tabs .tab-content.associations-tab .associations-toolbar .filter-group kendo-textbox{width:100%}}\n"] }]
10822
11079
  }], ctorParameters: () => [], propDecorators: { entity: [{
10823
11080
  type: Input
10824
11081
  }], loading: [{
@@ -10860,18 +11117,424 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
10860
11117
  args: ['associationsDir', { static: false }]
10861
11118
  }] } });
10862
11119
 
11120
+ const GetSecretSafeTypeAttributesDocumentDto = gql `
11121
+ query getSecretSafeTypeAttributes($rtCkTypeId: String!) {
11122
+ constructionKit {
11123
+ types(rtCkId: $rtCkTypeId, first: 1) {
11124
+ items {
11125
+ attributes {
11126
+ items {
11127
+ attributeName
11128
+ attributeValueType
11129
+ isOptional
11130
+ attribute {
11131
+ metaData {
11132
+ key
11133
+ value
11134
+ }
11135
+ ckRecord {
11136
+ ckRecordId {
11137
+ fullName
11138
+ }
11139
+ }
11140
+ }
11141
+ }
11142
+ }
11143
+ }
11144
+ }
11145
+ }
11146
+ }
11147
+ `;
11148
+ class GetSecretSafeTypeAttributesDtoGQL extends i1$3.Query {
11149
+ document = GetSecretSafeTypeAttributesDocumentDto;
11150
+ constructor(apollo) {
11151
+ super(apollo);
11152
+ }
11153
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetSecretSafeTypeAttributesDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
11154
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetSecretSafeTypeAttributesDtoGQL, providedIn: 'root' });
11155
+ }
11156
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetSecretSafeTypeAttributesDtoGQL, decorators: [{
11157
+ type: Injectable,
11158
+ args: [{
11159
+ providedIn: 'root'
11160
+ }]
11161
+ }], ctorParameters: () => [{ type: i1$3.Apollo }] });
11162
+
11163
+ const GetCkAttributesDetailedDocumentDto = gql `
11164
+ query getCkAttributesDetailed($ckId: String!) {
11165
+ constructionKit {
11166
+ types(ckId: $ckId) {
11167
+ items {
11168
+ ckTypeId {
11169
+ fullName
11170
+ }
11171
+ attributes {
11172
+ items {
11173
+ attributeName
11174
+ attributeValueType
11175
+ isOptional
11176
+ autoCompleteValues
11177
+ ckAttributeId {
11178
+ fullName
11179
+ }
11180
+ attribute {
11181
+ ckRecord {
11182
+ ckRecordId {
11183
+ fullName
11184
+ }
11185
+ }
11186
+ ckEnum {
11187
+ ckEnumId {
11188
+ fullName
11189
+ }
11190
+ values {
11191
+ key
11192
+ name
11193
+ }
11194
+ }
11195
+ defaultValues
11196
+ metaData {
11197
+ key
11198
+ value
11199
+ }
11200
+ }
11201
+ }
11202
+ }
11203
+ }
11204
+ }
11205
+ }
11206
+ }
11207
+ `;
11208
+ class GetCkAttributesDetailedDtoGQL extends i1$3.Query {
11209
+ document = GetCkAttributesDetailedDocumentDto;
11210
+ constructor(apollo) {
11211
+ super(apollo);
11212
+ }
11213
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
11214
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, providedIn: 'root' });
11215
+ }
11216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, decorators: [{
11217
+ type: Injectable,
11218
+ args: [{
11219
+ providedIn: 'root'
11220
+ }]
11221
+ }], ctorParameters: () => [{ type: i1$3.Apollo }] });
11222
+
11223
+ const GetCkRecordDetailedDocumentDto = gql `
11224
+ query getCkRecordDetailed($ckId: String) {
11225
+ constructionKit {
11226
+ records(ckId: $ckId) {
11227
+ totalCount
11228
+ items {
11229
+ ckRecordId {
11230
+ fullName
11231
+ }
11232
+ isAbstract
11233
+ attributes {
11234
+ items {
11235
+ ckAttributeId {
11236
+ fullName
11237
+ }
11238
+ isOptional
11239
+ attributeName
11240
+ attributeValueType
11241
+ attribute {
11242
+ ckRecord {
11243
+ ckRecordId {
11244
+ fullName
11245
+ }
11246
+ }
11247
+ ckEnum {
11248
+ ckEnumId {
11249
+ fullName
11250
+ }
11251
+ values {
11252
+ key
11253
+ name
11254
+ }
11255
+ }
11256
+ defaultValues
11257
+ metaData {
11258
+ key
11259
+ value
11260
+ }
11261
+ }
11262
+ }
11263
+ }
11264
+ }
11265
+ }
11266
+ }
11267
+ }
11268
+ `;
11269
+ class GetCkRecordDetailedDtoGQL extends i1$3.Query {
11270
+ document = GetCkRecordDetailedDocumentDto;
11271
+ constructor(apollo) {
11272
+ super(apollo);
11273
+ }
11274
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
11275
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, providedIn: 'root' });
11276
+ }
11277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, decorators: [{
11278
+ type: Injectable,
11279
+ args: [{
11280
+ providedIn: 'root'
11281
+ }]
11282
+ }], ctorParameters: () => [{ type: i1$3.Apollo }] });
11283
+
11284
+ /**
11285
+ * Resolves raw CK attribute definitions for a CK type or CK record by id.
11286
+ *
11287
+ * Extracted from AttributeDataService to break a potential circular dependency:
11288
+ * AttributeMapperService needs to look up nested record attribute definitions when mapping
11289
+ * RECORD / RECORD_ARRAY values to GraphQL, while AttributeDataService already depends on
11290
+ * AttributeMapperService for mapping raw definitions into form-ready Attribute shapes.
11291
+ *
11292
+ * This resolver is intentionally minimal: it fetches and returns raw CkAttributeMetadata[]
11293
+ * with no mapping. Callers that need form-ready Attribute objects should map them via
11294
+ * AttributeMapperService.mapToFormAttribute.
11295
+ *
11296
+ * Apollo's default cache-first fetchPolicy deduplicates repeated lookups for the same ckId,
11297
+ * so callers do not need to memoize externally.
11298
+ */
11299
+ class AttributeMetadataResolverService {
11300
+ getCkAttributesDetailedGQL = inject(GetCkAttributesDetailedDtoGQL);
11301
+ getCkRecordDetailedGQL = inject(GetCkRecordDetailedDtoGQL);
11302
+ /**
11303
+ * Fetches raw attribute metadata for a CK type or CK record.
11304
+ * Returns an empty array when the id is missing or the request fails.
11305
+ */
11306
+ getRawAttributes$(ckId, isRecord = false) {
11307
+ if (!ckId)
11308
+ return of([]);
11309
+ const stream$ = isRecord
11310
+ ? this.fetchCkRecordAttributes(ckId)
11311
+ : this.fetchCkAttributes(ckId);
11312
+ return stream$.pipe(catchError$1((err) => {
11313
+ console.error('AttributeMetadataResolverService error:', err);
11314
+ return of([]);
11315
+ }));
11316
+ }
11317
+ fetchCkAttributes(ckTypeId) {
11318
+ return this.getCkAttributesDetailedGQL
11319
+ .fetch({ variables: { ckId: ckTypeId } })
11320
+ .pipe(map$1((res) => (res.data?.constructionKit?.types?.items?.[0]?.attributes?.items ??
11321
+ []).filter((item) => item != null)));
11322
+ }
11323
+ fetchCkRecordAttributes(ckRecordId) {
11324
+ return this.getCkRecordDetailedGQL
11325
+ .fetch({ variables: { ckId: ckRecordId } })
11326
+ .pipe(map$1((res) => (res.data?.constructionKit?.records?.items?.[0]?.attributes
11327
+ ?.items ?? []).filter((item) => item != null)));
11328
+ }
11329
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11330
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, providedIn: 'root' });
11331
+ }
11332
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, decorators: [{
11333
+ type: Injectable,
11334
+ args: [{
11335
+ providedIn: 'root',
11336
+ }]
11337
+ }] });
11338
+
11339
+ /**
11340
+ * Attributes of a `System.Communication/DataPointMapping` entity that the runtime browser reads
11341
+ * (camelCase, as the `attributeNames` filter expects).
11342
+ */
11343
+ const DATA_POINT_MAPPING_ATTRIBUTE_NAMES = [
11344
+ 'name',
11345
+ 'enabled',
11346
+ 'sourceAttributePath',
11347
+ 'targetAttributePath',
11348
+ 'mappingExpression',
11349
+ ];
11350
+ const RECORD_TYPES$1 = new Set(['RECORD', 'RECORD_ARRAY']);
11351
+ function isRecordType(valueType) {
11352
+ return RECORD_TYPES$1.has((valueType ?? '').toUpperCase());
11353
+ }
11354
+ function isSecret(meta) {
11355
+ return isSecretAttributeCandidate({
11356
+ attributeName: meta.attributeName,
11357
+ attributeValueType: meta.attributeValueType,
11358
+ metaData: meta.attribute?.metaData,
11359
+ });
11360
+ }
11361
+ function recordIdOf(meta) {
11362
+ return isRecordType(meta.attributeValueType) ? meta.attribute?.ckRecord?.ckRecordId?.fullName ?? null : null;
11363
+ }
11364
+ /**
11365
+ * Builds SECRET-safe `attributeNames` lists for the generic runtime documents (AB#5542).
11366
+ *
11367
+ * The generic `attributes` field returns every attribute — credentials included — unless it is
11368
+ * restricted. Screens that show "all attributes" of an arbitrary CK type (property grid, entity
11369
+ * detail, edit form, meshboard widgets) use {@link forCkType}: the CK type's attributes plus the
11370
+ * sub-attributes of its records (the server applies the same filter inside records), minus the
11371
+ * TYPE-AWARE secret candidates (`isSecretAttributeCandidate`: explicit `secret` metadata, or a
11372
+ * textual attribute with a credential-like name). Non-secret attributes are never dropped by name
11373
+ * (`isSecret: BOOLEAN`, a `credentials` RECORD stay in the list). Because one flat list filters
11374
+ * all nesting levels, a name that is a secret anywhere is excluded everywhere; editors must not
11375
+ * write back what was therefore not loaded ({@link SecretSafeAttributeAnalysis.blockedAttributes}).
11376
+ *
11377
+ * All reachable record definitions are loaded first and the "contains a secret / excluded name"
11378
+ * facts are computed over the whole record graph, so recursive record types are handled without
11379
+ * caching a premature "no secret" result for a record reached through a cycle.
11380
+ *
11381
+ * Failures of the type lookup yield an empty list (no attributes) — fail closed. Lookups go
11382
+ * through Apollo's cache, so repeated calls are cheap.
11383
+ */
11384
+ class SecretSafeAttributeNamesService {
11385
+ resolver = inject(AttributeMetadataResolverService);
11386
+ typeAttributesGQL = inject(GetSecretSafeTypeAttributesDtoGQL);
11387
+ /**
11388
+ * camelCase names of all non-secret attributes (incl. record sub-attributes) of a runtime type.
11389
+ * @param rtCkTypeId the type in RtCkTypeId format (`Basic/TreeNode`, as in `RtEntity.ckTypeId`).
11390
+ * @param options.includeSecretState also list the SECRET-typed attributes (safe to read, see
11391
+ * {@link SecretSafeAttributeAnalysis.secretStateNames}) — the document must select `secretIsSet`.
11392
+ */
11393
+ async forCkType(rtCkTypeId, options = {}) {
11394
+ const analysis = await this.analyse(rtCkTypeId);
11395
+ return options.includeSecretState
11396
+ ? toUniqueCamelCaseNames([...analysis.attributeNames, ...analysis.secretStateNames])
11397
+ : analysis.attributeNames;
11398
+ }
11399
+ /**
11400
+ * Type-aware restriction of a requested name list (e.g. widget-configured fields): the requested
11401
+ * names (camelCased) that are non-secret attributes of the type. Names that are unknown to the
11402
+ * type or secret are dropped; a failed CK lookup yields `[]` (fail closed).
11403
+ */
11404
+ async restrict(rtCkTypeId, requested) {
11405
+ const wanted = toUniqueCamelCaseNames(requested);
11406
+ if (wanted.length === 0)
11407
+ return [];
11408
+ const safe = new Set(await this.forCkType(rtCkTypeId));
11409
+ return wanted.filter((n) => safe.has(n));
11410
+ }
11411
+ /** Full analysis: safe names, secret names and the attributes an editor must not write back. */
11412
+ async analyse(rtCkTypeId) {
11413
+ if (!rtCkTypeId)
11414
+ return { attributeNames: [], secretNames: [], secretStateNames: [], blockedAttributes: [] };
11415
+ const topLevel = await this.loadType(rtCkTypeId);
11416
+ const records = await this.loadRecordGraph(topLevel);
11417
+ // 1. Names and secrets over the type and every reachable record.
11418
+ const names = [];
11419
+ const secrets = new Set();
11420
+ const secretValueTypeNames = new Set();
11421
+ const heuristicSecrets = new Set();
11422
+ for (const meta of [...topLevel, ...[...records.values()].flat()]) {
11423
+ if (!meta.attributeName)
11424
+ continue;
11425
+ const camel = toCamelCaseAttributeName(meta.attributeName);
11426
+ if (isSecret(meta)) {
11427
+ secrets.add(camel);
11428
+ (isSecretValueType(meta.attributeValueType) ? secretValueTypeNames : heuristicSecrets).add(camel);
11429
+ }
11430
+ else {
11431
+ names.push(meta.attributeName);
11432
+ }
11433
+ }
11434
+ const attributeNames = toUniqueCamelCaseNames(names).filter((n) => !secrets.has(n));
11435
+ const secretStateNames = [...secretValueTypeNames].filter((n) => !heuristicSecrets.has(n));
11436
+ // SECRET-typed sub-attributes count as loaded: the server carries an omitted record member over
11437
+ // from the stored element with the same record key (records with secrets always declare one),
11438
+ // and an echoed `{ isSet }` marker means "unchanged". Only heuristic secrets block a record.
11439
+ const loaded = new Set([...attributeNames, ...secretStateNames]);
11440
+ // 2. Per record type: is every (transitive) sub-attribute loaded? Fixpoint over the graph —
11441
+ // start optimistic, mark incomplete records, propagate until stable (cycle-safe).
11442
+ const incomplete = new Set();
11443
+ for (const [recordId, subs] of records) {
11444
+ // An unknown (failed / empty) record definition counts as incomplete — fail closed.
11445
+ if (subs.length === 0 || subs.some((m) => !m.attributeName || !loaded.has(toCamelCaseAttributeName(m.attributeName)))) {
11446
+ incomplete.add(recordId);
11447
+ }
11448
+ }
11449
+ let changed = true;
11450
+ while (changed) {
11451
+ changed = false;
11452
+ for (const [recordId, subs] of records) {
11453
+ if (incomplete.has(recordId))
11454
+ continue;
11455
+ if (subs.some((m) => { const id = recordIdOf(m); return !!id && incomplete.has(id); })) {
11456
+ incomplete.add(recordId);
11457
+ changed = true;
11458
+ }
11459
+ }
11460
+ }
11461
+ // 3. Top-level attributes an editor must not write back.
11462
+ const blocked = [];
11463
+ for (const meta of topLevel) {
11464
+ if (!meta.attributeName)
11465
+ continue;
11466
+ const name = toCamelCaseAttributeName(meta.attributeName);
11467
+ const recordId = recordIdOf(meta);
11468
+ const secret = isSecret(meta);
11469
+ if (secret && !recordId && !isRecordType(meta.attributeValueType))
11470
+ continue; // write-only scalar
11471
+ if (!loaded.has(name) || (recordId && incomplete.has(recordId))) {
11472
+ blocked.push(name);
11473
+ }
11474
+ }
11475
+ return {
11476
+ attributeNames,
11477
+ secretNames: [...secrets],
11478
+ secretStateNames,
11479
+ blockedAttributes: toUniqueCamelCaseNames(blocked),
11480
+ };
11481
+ }
11482
+ /** Loads every record definition reachable from the type's attributes (each once). */
11483
+ async loadRecordGraph(topLevel) {
11484
+ const records = new Map();
11485
+ let pending = topLevel.map(recordIdOf).filter((id) => !!id);
11486
+ while (pending.length > 0) {
11487
+ const batch = [...new Set(pending)].filter((id) => !records.has(id));
11488
+ pending = [];
11489
+ const loadedBatch = await Promise.all(batch.map((id) => this.loadRecord(id)));
11490
+ batch.forEach((id, i) => {
11491
+ records.set(id, loadedBatch[i]);
11492
+ for (const meta of loadedBatch[i]) {
11493
+ const sub = recordIdOf(meta);
11494
+ if (sub && !records.has(sub))
11495
+ pending.push(sub);
11496
+ }
11497
+ });
11498
+ }
11499
+ return records;
11500
+ }
11501
+ loadType(rtCkTypeId) {
11502
+ return firstValueFrom(this.typeAttributesGQL.fetch({ variables: { rtCkTypeId } }).pipe(map$1((res) => (res.data?.constructionKit?.types?.items?.[0]?.attributes?.items ?? [])
11503
+ .filter((item) => item != null)), catchError$1((err) => {
11504
+ console.error('SecretSafeAttributeNamesService: CK lookup failed', err);
11505
+ return of([]);
11506
+ })));
11507
+ }
11508
+ /** Record sub-attributes by CkRecordId full name (cached by Apollo, errors yield []). */
11509
+ loadRecord(ckRecordId) {
11510
+ return firstValueFrom(this.resolver.getRawAttributes$(ckRecordId, true));
11511
+ }
11512
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: SecretSafeAttributeNamesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11513
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: SecretSafeAttributeNamesService, providedIn: 'root' });
11514
+ }
11515
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: SecretSafeAttributeNamesService, decorators: [{
11516
+ type: Injectable,
11517
+ args: [{ providedIn: 'root' }]
11518
+ }] });
11519
+
10863
11520
  class EntityDetailDataSource {
10864
11521
  getRuntimeEntityByIdGQL = inject(GetRuntimeEntityByIdDtoGQL);
11522
+ secretSafeNames = inject(SecretSafeAttributeNamesService);
10865
11523
  /**
10866
- * Fetches detailed entity information including attributes and associations
11524
+ * Fetches detailed entity information including attributes and associations.
11525
+ * Attributes are restricted to the type's non-secret attributes (SECRET-safe, AB#5542):
11526
+ * credential-like attributes are never sent to the browser. SECRET-typed attributes (AB#5528)
11527
+ * are read for their state only (`value` null, `secretIsSet`) so the property grid shows a badge.
10867
11528
  */
10868
11529
  async fetchEntityDetails(rtId, ckTypeId) {
10869
11530
  try {
11531
+ const attributeNames = await this.secretSafeNames.forCkType(ckTypeId, { includeSecretState: true });
10870
11532
  const result = await firstValueFrom(this.getRuntimeEntityByIdGQL
10871
11533
  .fetch({
10872
11534
  variables: {
10873
11535
  rtId,
10874
11536
  ckTypeId,
11537
+ attributeNames,
10875
11538
  },
10876
11539
  })
10877
11540
  .pipe(map((response) => response.data?.runtime?.runtimeEntities?.items?.[0])));
@@ -11104,7 +11767,7 @@ class EntityDetailComponent {
11104
11767
  async loadMappingDetails(rtId, ckTypeId) {
11105
11768
  try {
11106
11769
  const entityResult = await firstValueFrom(this.getEntityByIdGQL.fetch({
11107
- variables: { rtId, ckTypeId },
11770
+ variables: { rtId, ckTypeId, attributeNames: [...DATA_POINT_MAPPING_ATTRIBUTE_NAMES] },
11108
11771
  }));
11109
11772
  const mappingEntity = entityResult.data?.runtime?.runtimeEntities?.items?.[0];
11110
11773
  if (!mappingEntity)
@@ -11359,7 +12022,7 @@ class EntityDetailComponent {
11359
12022
  >
11360
12023
  </mm-entity-detail-view>
11361
12024
  </div>
11362
- `, isInline: true, styles: [":host{display:block;height:100%;width:100%}.entity-detail{height:100%;display:flex;flex-direction:column;padding:24px;box-sizing:border-box;overflow-y:auto}.entity-detail .entity-detail-header{display:flex;align-items:center;gap:20px;margin-bottom:24px;padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.entity-detail .entity-detail-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.entity-detail .entity-detail-header .header-info{flex:1}.entity-detail .entity-detail-header .header-info .entity-title h2{margin:0 0 8px;font-family:Montserrat,sans-serif;font-size:1.4rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color);text-shadow:0 0 10px rgba(0,0,0,.3)}.entity-detail .entity-detail-header .header-info .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;background:var(--deep-sea-60);padding:6px 12px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block;color:var(--neo-cyan)}.entity-detail mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}@media(max-width:768px){.entity-detail{padding:16px}.entity-detail .entity-detail-header{flex-direction:column;align-items:flex-start;gap:12px;padding:16px 20px}.entity-detail .entity-detail-header .header-info .entity-title h2{font-size:1.1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: EntityDetailViewComponent, selector: "mm-entity-detail-view", inputs: ["entity", "loading", "error", "showHeader", "messages", "showDataMapping", "dataMappings", "expressionValidator"], outputs: ["retry", "propertyChange", "navigateToEntity", "addMappingRequested", "removeMappingRequested", "selectMappingTarget", "selectSourceAttributeRequested", "selectTargetAttributeRequested", "mappingChanged", "saveAllMappingsRequested"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
12025
+ `, isInline: true, styles: [":host{display:block;height:100%;width:100%}.entity-detail{height:100%;display:flex;flex-direction:column;padding:24px;box-sizing:border-box;overflow-y:auto}.entity-detail .entity-detail-header{display:flex;align-items:center;gap:20px;margin-bottom:24px;padding:20px 24px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);position:relative;box-shadow:0 4px 20px #0006}.entity-detail .entity-detail-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;border-radius:4px 0 0 4px}.entity-detail .entity-detail-header .header-info{flex:1}.entity-detail .entity-detail-header .header-info .entity-title h2{margin:0 0 8px;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1.4rem;font-weight:600;color:var(--octo-text-color)}.entity-detail .entity-detail-header .header-info .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;background:var(--deep-sea-60);padding:6px 12px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block;color:var(--neo-cyan)}.entity-detail mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}@media(max-width:768px){.entity-detail{padding:16px}.entity-detail .entity-detail-header{flex-direction:column;align-items:flex-start;gap:12px;padding:16px 20px}.entity-detail .entity-detail-header .header-info .entity-title h2{font-size:1.1rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: EntityDetailViewComponent, selector: "mm-entity-detail-view", inputs: ["entity", "loading", "error", "showHeader", "messages", "showDataMapping", "dataMappings", "expressionValidator"], outputs: ["retry", "propertyChange", "navigateToEntity", "addMappingRequested", "removeMappingRequested", "selectMappingTarget", "selectSourceAttributeRequested", "selectTargetAttributeRequested", "mappingChanged", "saveAllMappingsRequested"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
11363
12026
  }
11364
12027
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EntityDetailComponent, decorators: [{
11365
12028
  type: Component,
@@ -11410,7 +12073,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
11410
12073
  >
11411
12074
  </mm-entity-detail-view>
11412
12075
  </div>
11413
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:block;height:100%;width:100%}.entity-detail{height:100%;display:flex;flex-direction:column;padding:24px;box-sizing:border-box;overflow-y:auto}.entity-detail .entity-detail-header{display:flex;align-items:center;gap:20px;margin-bottom:24px;padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.entity-detail .entity-detail-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.entity-detail .entity-detail-header .header-info{flex:1}.entity-detail .entity-detail-header .header-info .entity-title h2{margin:0 0 8px;font-family:Montserrat,sans-serif;font-size:1.4rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color);text-shadow:0 0 10px rgba(0,0,0,.3)}.entity-detail .entity-detail-header .header-info .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;background:var(--deep-sea-60);padding:6px 12px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block;color:var(--neo-cyan)}.entity-detail mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}@media(max-width:768px){.entity-detail{padding:16px}.entity-detail .entity-detail-header{flex-direction:column;align-items:flex-start;gap:12px;padding:16px 20px}.entity-detail .entity-detail-header .header-info .entity-title h2{font-size:1.1rem}}\n"] }]
12076
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:block;height:100%;width:100%}.entity-detail{height:100%;display:flex;flex-direction:column;padding:24px;box-sizing:border-box;overflow-y:auto}.entity-detail .entity-detail-header{display:flex;align-items:center;gap:20px;margin-bottom:24px;padding:20px 24px;background:var(--theme-bg-elevated);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);position:relative;box-shadow:0 4px 20px #0006}.entity-detail .entity-detail-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:transparent;box-shadow:none;border-radius:4px 0 0 4px}.entity-detail .entity-detail-header .header-info{flex:1}.entity-detail .entity-detail-header .header-info .entity-title h2{margin:0 0 8px;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1.4rem;font-weight:600;color:var(--octo-text-color)}.entity-detail .entity-detail-header .header-info .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;background:var(--deep-sea-60);padding:6px 12px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block;color:var(--neo-cyan)}.entity-detail mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}@media(max-width:768px){.entity-detail{padding:16px}.entity-detail .entity-detail-header{flex-direction:column;align-items:flex-start;gap:12px;padding:16px 20px}.entity-detail .entity-detail-header .header-info .entity-title h2{font-size:1.1rem}}\n"] }]
11414
12077
  }], propDecorators: { messages: [{
11415
12078
  type: Input
11416
12079
  }] } });
@@ -11774,174 +12437,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
11774
12437
  args: [{ providedIn: 'root' }]
11775
12438
  }] });
11776
12439
 
11777
- const GetCkAttributesDetailedDocumentDto = gql `
11778
- query getCkAttributesDetailed($ckId: String!) {
11779
- constructionKit {
11780
- types(ckId: $ckId) {
11781
- items {
11782
- ckTypeId {
11783
- fullName
11784
- }
11785
- attributes {
11786
- items {
11787
- attributeName
11788
- attributeValueType
11789
- isOptional
11790
- autoCompleteValues
11791
- ckAttributeId {
11792
- fullName
11793
- }
11794
- attribute {
11795
- ckRecord {
11796
- ckRecordId {
11797
- fullName
11798
- }
11799
- }
11800
- ckEnum {
11801
- ckEnumId {
11802
- fullName
11803
- }
11804
- values {
11805
- key
11806
- name
11807
- }
11808
- }
11809
- defaultValues
11810
- }
11811
- }
11812
- }
11813
- }
11814
- }
11815
- }
11816
- }
11817
- `;
11818
- class GetCkAttributesDetailedDtoGQL extends i1$3.Query {
11819
- document = GetCkAttributesDetailedDocumentDto;
11820
- constructor(apollo) {
11821
- super(apollo);
11822
- }
11823
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
11824
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, providedIn: 'root' });
11825
- }
11826
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkAttributesDetailedDtoGQL, decorators: [{
11827
- type: Injectable,
11828
- args: [{
11829
- providedIn: 'root'
11830
- }]
11831
- }], ctorParameters: () => [{ type: i1$3.Apollo }] });
11832
-
11833
- const GetCkRecordDetailedDocumentDto = gql `
11834
- query getCkRecordDetailed($ckId: String) {
11835
- constructionKit {
11836
- records(ckId: $ckId) {
11837
- totalCount
11838
- items {
11839
- ckRecordId {
11840
- fullName
11841
- }
11842
- isAbstract
11843
- attributes {
11844
- items {
11845
- ckAttributeId {
11846
- fullName
11847
- }
11848
- isOptional
11849
- attributeName
11850
- attributeValueType
11851
- attribute {
11852
- ckRecord {
11853
- ckRecordId {
11854
- fullName
11855
- }
11856
- }
11857
- ckEnum {
11858
- ckEnumId {
11859
- fullName
11860
- }
11861
- values {
11862
- key
11863
- name
11864
- }
11865
- }
11866
- defaultValues
11867
- }
11868
- }
11869
- }
11870
- }
11871
- }
11872
- }
11873
- }
11874
- `;
11875
- class GetCkRecordDetailedDtoGQL extends i1$3.Query {
11876
- document = GetCkRecordDetailedDocumentDto;
11877
- constructor(apollo) {
11878
- super(apollo);
11879
- }
11880
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, deps: [{ token: i1$3.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
11881
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, providedIn: 'root' });
11882
- }
11883
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: GetCkRecordDetailedDtoGQL, decorators: [{
11884
- type: Injectable,
11885
- args: [{
11886
- providedIn: 'root'
11887
- }]
11888
- }], ctorParameters: () => [{ type: i1$3.Apollo }] });
11889
-
11890
- /**
11891
- * Resolves raw CK attribute definitions for a CK type or CK record by id.
11892
- *
11893
- * Extracted from AttributeDataService to break a potential circular dependency:
11894
- * AttributeMapperService needs to look up nested record attribute definitions when mapping
11895
- * RECORD / RECORD_ARRAY values to GraphQL, while AttributeDataService already depends on
11896
- * AttributeMapperService for mapping raw definitions into form-ready Attribute shapes.
11897
- *
11898
- * This resolver is intentionally minimal: it fetches and returns raw CkAttributeMetadata[]
11899
- * with no mapping. Callers that need form-ready Attribute objects should map them via
11900
- * AttributeMapperService.mapToFormAttribute.
11901
- *
11902
- * Apollo's default cache-first fetchPolicy deduplicates repeated lookups for the same ckId,
11903
- * so callers do not need to memoize externally.
11904
- */
11905
- class AttributeMetadataResolverService {
11906
- getCkAttributesDetailedGQL = inject(GetCkAttributesDetailedDtoGQL);
11907
- getCkRecordDetailedGQL = inject(GetCkRecordDetailedDtoGQL);
11908
- /**
11909
- * Fetches raw attribute metadata for a CK type or CK record.
11910
- * Returns an empty array when the id is missing or the request fails.
11911
- */
11912
- getRawAttributes$(ckId, isRecord = false) {
11913
- if (!ckId)
11914
- return of([]);
11915
- const stream$ = isRecord
11916
- ? this.fetchCkRecordAttributes(ckId)
11917
- : this.fetchCkAttributes(ckId);
11918
- return stream$.pipe(catchError$1((err) => {
11919
- console.error('AttributeMetadataResolverService error:', err);
11920
- return of([]);
11921
- }));
11922
- }
11923
- fetchCkAttributes(ckTypeId) {
11924
- return this.getCkAttributesDetailedGQL
11925
- .fetch({ variables: { ckId: ckTypeId } })
11926
- .pipe(map$1((res) => (res.data?.constructionKit?.types?.items?.[0]?.attributes?.items ??
11927
- []).filter((item) => item != null)));
11928
- }
11929
- fetchCkRecordAttributes(ckRecordId) {
11930
- return this.getCkRecordDetailedGQL
11931
- .fetch({ variables: { ckId: ckRecordId } })
11932
- .pipe(map$1((res) => (res.data?.constructionKit?.records?.items?.[0]?.attributes
11933
- ?.items ?? []).filter((item) => item != null)));
11934
- }
11935
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
11936
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, providedIn: 'root' });
11937
- }
11938
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributeMetadataResolverService, decorators: [{
11939
- type: Injectable,
11940
- args: [{
11941
- providedIn: 'root',
11942
- }]
11943
- }] });
11944
-
11945
12440
  class AttributeRecognitionService {
11946
12441
  isString(attributeValueType) {
11947
12442
  return attributeValueType === 'STRING';
@@ -12094,6 +12589,9 @@ class AttributeMapperService {
12094
12589
  enumOptions: this.getEnumOptions(attr),
12095
12590
  value: parsedValue,
12096
12591
  };
12592
+ if (isSecretAttributeCandidate({ attributeName, attributeValueType: type, metaData: attr?.attribute?.metaData })) {
12593
+ attribute.secret = true;
12594
+ }
12097
12595
  return attribute;
12098
12596
  }
12099
12597
  /**
@@ -12148,6 +12646,11 @@ class AttributeMapperService {
12148
12646
  if (type === 'BINARY_LINKED') {
12149
12647
  return this.mapBinaryLinkedAttribute(key, value, metadata);
12150
12648
  }
12649
+ // Secrets are write-only (AB#5542): their stored value is never read, so an empty value means
12650
+ // "keep" — omit it instead of sending null/'' that would clear the stored credential.
12651
+ if (metadata?.secret && (value === null || value === undefined || value === '')) {
12652
+ return null;
12653
+ }
12151
12654
  if (value === null || value === undefined) {
12152
12655
  return metadata?.isOptional ? { attributeName: key, value: null } : null;
12153
12656
  }
@@ -12850,6 +13353,7 @@ class AttributeDataService {
12850
13353
  mapper = inject(AttributeMapperService);
12851
13354
  resolver = inject(AttributeMetadataResolverService);
12852
13355
  getRtEntityAttributesGQL = inject(GetRuntimeEntityByIdDtoGQL);
13356
+ secretSafeNames = inject(SecretSafeAttributeNamesService);
12853
13357
  /** Observable of attribute list for a CK type or record. Sorted: required first, optional last. */
12854
13358
  getAttributesDefinition$(ckTypeId, isRecord = false) {
12855
13359
  if (!ckTypeId)
@@ -12872,11 +13376,13 @@ class AttributeDataService {
12872
13376
  return a.isOptional ? 1 : -1;
12873
13377
  });
12874
13378
  }
12875
- /** Fetches runtime entity attribute items by rtId and ckTypeId; returns empty array when absent. */
13379
+ /**
13380
+ * Fetches runtime entity attribute items by rtId and ckTypeId; returns empty array when absent.
13381
+ * Only the type's non-secret attributes are read (SECRET-safe, AB#5542) — secrets stay
13382
+ * write-only in the edit form.
13383
+ */
12876
13384
  fetchRtEntityAttributes(rtId, ckTypeId) {
12877
- return this.getRtEntityAttributesGQL
12878
- .fetch({ variables: { rtId: rtId, ckTypeId: ckTypeId } })
12879
- .pipe(map$1((res) => {
13385
+ return from(this.secretSafeNames.forCkType(ckTypeId)).pipe(switchMap$1((attributeNames) => this.getRtEntityAttributesGQL.fetch({ variables: { rtId, ckTypeId, attributeNames } })), map$1((res) => {
12880
13386
  const items = res.data?.runtime?.runtimeEntities?.items?.[0]?.attributes?.items ??
12881
13387
  [];
12882
13388
  return items
@@ -12966,6 +13472,8 @@ class AttributeFieldComponent {
12966
13472
  (click)="handleUndo()"
12967
13473
  type="button"
12968
13474
  class="undo-button"
13475
+ title="Undo change"
13476
+ aria-label="Undo change"
12969
13477
  ></button>
12970
13478
  }
12971
13479
  </div>
@@ -13005,6 +13513,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13005
13513
  (click)="handleUndo()"
13006
13514
  type="button"
13007
13515
  class="undo-button"
13516
+ title="Undo change"
13517
+ aria-label="Undo change"
13008
13518
  ></button>
13009
13519
  }
13010
13520
  </div>
@@ -13048,6 +13558,12 @@ class AttributesGroupComponent {
13048
13558
  ...(ngDevMode ? [{ debugName: "isRecord" }] : /* istanbul ignore next */ []));
13049
13559
  initialValues = input(/* @ts-ignore */
13050
13560
  ...(ngDevMode ? [undefined, { debugName: "initialValues" }] : /* istanbul ignore next */ []));
13561
+ /**
13562
+ * Edit mode for secrets (AB#5542): secret attributes start empty (their value is never read),
13563
+ * are not required, and an empty value keeps the stored credential.
13564
+ */
13565
+ secretsWriteOnly = input(false, /* @ts-ignore */
13566
+ ...(ngDevMode ? [{ debugName: "secretsWriteOnly" }] : /* istanbul ignore next */ []));
13051
13567
  _messages = { ...DEFAULT_RUNTIME_BROWSER_MESSAGES };
13052
13568
  set messages(value) {
13053
13569
  this._messages = { ...DEFAULT_RUNTIME_BROWSER_MESSAGES, ...(value ?? {}) };
@@ -13096,9 +13612,12 @@ class AttributesGroupComponent {
13096
13612
  const rawValue = rawInitial.find((val) => val.attributeName === attrMetadata.attributeName)?.value;
13097
13613
  // Use parsed initial when entity data exists; otherwise use attribute.value from resource (already has Default or Empty from mapper)
13098
13614
  const hasInitialFromEntity = rawValue !== undefined && rawValue !== null;
13099
- const finalValue = hasInitialFromEntity
13100
- ? this.mapper.getFormValueFromRawInitial(attrMetadata, rawValue)
13101
- : attrMetadata.value;
13615
+ const writeOnlySecret = !!attrMetadata.secret && this.secretsWriteOnly();
13616
+ const finalValue = writeOnlySecret
13617
+ ? null
13618
+ : hasInitialFromEntity
13619
+ ? this.mapper.getFormValueFromRawInitial(attrMetadata, rawValue)
13620
+ : attrMetadata.value;
13102
13621
  if (!form.contains(attrMetadata.attributeName)) {
13103
13622
  this.initializeControl(form, attrMetadata, finalValue);
13104
13623
  }
@@ -13159,8 +13678,9 @@ class AttributesGroupComponent {
13159
13678
  return;
13160
13679
  }
13161
13680
  else {
13162
- // Plain text/numeric/etc. field
13163
- control = new FormControl(initialValue, attr.isOptional ? [] : [Validators.required]);
13681
+ // Plain text/numeric/etc. field. A write-only secret may stay empty (= keep, AB#5542).
13682
+ const required = !attr.isOptional && !(attr.secret && this.secretsWriteOnly());
13683
+ control = new FormControl(initialValue, required ? [Validators.required] : []);
13164
13684
  }
13165
13685
  form.addControl(attr.attributeName, control);
13166
13686
  this.setBaselineForAttr(attr, initialValue);
@@ -13344,7 +13864,7 @@ class AttributesGroupComponent {
13344
13864
  return EMPTY_INITIAL_VALUES;
13345
13865
  }
13346
13866
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributesGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13347
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: AttributesGroupComponent, isStandalone: true, selector: "mm-attributes-group", inputs: { ckId: { classPropertyName: "ckId", publicName: "ckId", isSignal: true, isRequired: true, transformFunction: null }, parentFormGroup: { classPropertyName: "parentFormGroup", publicName: "parentFormGroup", isSignal: true, isRequired: true, transformFunction: null }, isRecord: { classPropertyName: "isRecord", publicName: "isRecord", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: false, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
13867
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: AttributesGroupComponent, isStandalone: true, selector: "mm-attributes-group", inputs: { ckId: { classPropertyName: "ckId", publicName: "ckId", isSignal: true, isRequired: true, transformFunction: null }, parentFormGroup: { classPropertyName: "parentFormGroup", publicName: "parentFormGroup", isSignal: true, isRequired: true, transformFunction: null }, isRecord: { classPropertyName: "isRecord", publicName: "isRecord", isSignal: true, isRequired: false, transformFunction: null }, initialValues: { classPropertyName: "initialValues", publicName: "initialValues", isSignal: true, isRequired: false, transformFunction: null }, secretsWriteOnly: { classPropertyName: "secretsWriteOnly", publicName: "secretsWriteOnly", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: false, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
13348
13868
  <div class="attributes-form-container" [formGroup]="parentFormGroup()">
13349
13869
  <kendo-card [style.margin-bottom.px]="10">
13350
13870
  <kendo-card-header>
@@ -13400,6 +13920,7 @@ class AttributesGroupComponent {
13400
13920
  [isRecord]="true"
13401
13921
  [parentFormGroup]="asFormGroup(item)"
13402
13922
  [initialValues]="getRawInitialValue(attr.attributeName, $index)"
13923
+ [secretsWriteOnly]="secretsWriteOnly()"
13403
13924
  [messages]="_messages"
13404
13925
  />
13405
13926
  </div>
@@ -13456,6 +13977,7 @@ class AttributesGroupComponent {
13456
13977
  asFormGroup(parentFormGroup().get(attr.attributeName)!)
13457
13978
  "
13458
13979
  [initialValues]="getRawInitialValue(attr.attributeName)"
13980
+ [secretsWriteOnly]="secretsWriteOnly()"
13459
13981
  [messages]="_messages"
13460
13982
  />
13461
13983
  </div>
@@ -13552,6 +14074,7 @@ class AttributesGroupComponent {
13552
14074
  [control]="parentFormGroup().get(attr.attributeName)!"
13553
14075
  [baselineValue]="getBaselineValue(attr.attributeName)"
13554
14076
  [fieldId]="attr.attributeName"
14077
+ [hintText]="attr.secret && secretsWriteOnly() ? (_messages.secretWriteOnlyHint ?? '') : ''"
13555
14078
  [errorMessage]="_messages.attributeField?.errorMessage ?? 'This field is required or invalid.'"
13556
14079
  >
13557
14080
  @if (recognition.isNumber(attr.attributeValueType)) {
@@ -13634,6 +14157,13 @@ class AttributesGroupComponent {
13634
14157
  valueField="key"
13635
14158
  [valuePrimitive]="true"
13636
14159
  />
14160
+ } @else if (attr.secret) {
14161
+ <kendo-textbox
14162
+ type="password"
14163
+ autocomplete="new-password"
14164
+ [focusableId]="attr.attributeName"
14165
+ [formControlName]="attr.attributeName"
14166
+ />
13637
14167
  } @else {
13638
14168
  <kendo-textbox
13639
14169
  [focusableId]="attr.attributeName"
@@ -13646,7 +14176,7 @@ class AttributesGroupComponent {
13646
14176
  </kendo-card-body>
13647
14177
  </kendo-card>
13648
14178
  </div>
13649
- `, isInline: true, styles: [".attributes-form-container ::ng-deep kendo-card kendo-card-body{display:flex;flex-direction:column;gap:16px}.attributes-form-container ::ng-deep kendo-label{display:flex;flex-direction:column;gap:4px}.attributes-form-container ::ng-deep kendo-label label{text-transform:uppercase}.header-content{display:flex;flex-direction:column;gap:4px}.record-array-content,.tab-content-wrapper{display:flex;flex-direction:column;gap:16px}.record-actions-info{display:flex;flex-direction:column;gap:12px;padding:16px;background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));border:1px solid var(--kendo-color-border, rgba(0, 0, 0, .1));border-radius:4px;margin-bottom:16px}.record-actions-description{margin:0;font-size:13px;color:var(--kendo-color-subtle, rgba(0, 0, 0, .6));line-height:1.5}.record-array-actions{display:flex;gap:8px;justify-content:flex-start;padding-top:0}.record-actions{margin-top:16px;display:flex;gap:8px;justify-content:flex-start;padding-top:0}.binary-linked-wrap{display:flex;flex-direction:column;gap:6px}.binary-linked-reference-hint{font-size:.75rem;color:var(--kendo-color-primary, #0f6dff);font-style:italic}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => AttributesGroupComponent), selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "messages"] }, { kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i1.FormGroupDirective), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1.FormControlName), selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i0.forwardRef(() => i1.FormGroupName), selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: i0.forwardRef(() => i1$4.CardComponent), selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i0.forwardRef(() => i1$4.CardBodyComponent), selector: "kendo-card-body" }, { kind: "component", type: i0.forwardRef(() => i1$4.CardHeaderComponent), selector: "kendo-card-header" }, { kind: "component", type: i0.forwardRef(() => i1$4.ExpansionPanelComponent), selector: "kendo-expansionpanel", inputs: ["title", "subtitle", "disabled", "expanded", "svgExpandIcon", "svgCollapseIcon", "expandIcon", "collapseIcon", "animation"], outputs: ["expandedChange", "action", "expand", "collapse"], exportAs: ["kendoExpansionPanel"] }, { kind: "directive", type: i0.forwardRef(() => i1$4.ExpansionPanelTitleDirective), selector: "[kendoExpansionPanelTitleDirective]" }, { kind: "component", type: i0.forwardRef(() => i1$4.TabStripComponent), selector: "kendo-tabstrip", inputs: ["height", "animate", "tabAlignment", "tabPosition", "keepTabContent", "closable", "scrollable", "size", "closeIcon", "closeIconClass", "closeSVGIcon", "showContentArea"], outputs: ["tabSelect", "tabClose", "tabScroll"], exportAs: ["kendoTabStrip"] }, { kind: "component", type: i0.forwardRef(() => i1$4.TabStripTabComponent), selector: "kendo-tabstrip-tab", inputs: ["title", "disabled", "cssClass", "cssStyle", "selected", "closable", "closeIcon", "closeIconClass", "closeSVGIcon"], exportAs: ["kendoTabStripTab"] }, { kind: "directive", type: i0.forwardRef(() => i1$4.TabContentDirective), selector: "[kendoTabContent]" }, { kind: "component", type: i0.forwardRef(() => i5.TextBoxComponent), selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i0.forwardRef(() => i5.NumericTextBoxComponent), selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "component", type: i0.forwardRef(() => i5.SwitchComponent), selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "component", type: i0.forwardRef(() => i1$5.LabelComponent), selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }, { kind: "component", type: i0.forwardRef(() => i1$1.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: "component", type: i0.forwardRef(() => i3$1.DropDownListComponent), selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i0.forwardRef(() => i3$1.MultiSelectComponent), selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "component", type: i0.forwardRef(() => i7.DateTimePickerComponent), selector: "kendo-datetimepicker", inputs: ["focusableId", "weekDaysFormat", "showOtherMonthDays", "value", "format", "twoDigitYearMax", "tabindex", "disabledDates", "popupSettings", "adaptiveTitle", "adaptiveSubtitle", "disabled", "readonly", "readOnlyInput", "cancelButton", "formatPlaceholder", "placeholder", "steps", "focusedDate", "calendarType", "animateCalendarNavigation", "weekNumber", "min", "max", "rangeValidation", "disabledDatesValidation", "incompleteDateValidation", "autoCorrectParts", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "clearButton", "autoFill", "adaptiveMode", "inputAttributes", "defaultTab", "size", "rounded", "fillMode", "headerTemplate", "footerTemplate", "footer"], outputs: ["valueChange", "open", "close", "focus", "blur", "escape"], exportAs: ["kendo-datetimepicker"] }, { kind: "component", type: i0.forwardRef(() => i7.TimePickerComponent), selector: "kendo-timepicker", inputs: ["focusableId", "disabled", "readonly", "readOnlyInput", "clearButton", "format", "formatPlaceholder", "placeholder", "min", "max", "incompleteDateValidation", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "cancelButton", "nowButton", "steps", "popupSettings", "tabindex", "tabIndex", "adaptiveTitle", "adaptiveSubtitle", "rangeValidation", "adaptiveMode", "value", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "open", "close", "escape"], exportAs: ["kendo-timepicker"] }, { kind: "component", type: i0.forwardRef(() => i8.FileSelectComponent), selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }, { kind: "component", type: i0.forwardRef(() => i8.CustomMessagesComponent), selector: "kendo-upload-messages, kendo-fileselect-messages, kendo-uploaddropzone-messages" }, { kind: "component", type: i0.forwardRef(() => AttributeFieldComponent), selector: "mm-attribute-field", inputs: ["attribute", "control", "baselineValue", "fieldId", "overrideLabelText", "showUndoButton", "undoButtonSize", "errorMessage", "hintText"], outputs: ["undo"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
14179
+ `, isInline: true, styles: [".attributes-form-container ::ng-deep kendo-card kendo-card-body{display:flex;flex-direction:column;gap:16px}.attributes-form-container ::ng-deep kendo-label{display:flex;flex-direction:column;gap:4px}.header-content{display:flex;flex-direction:column;gap:4px}.record-array-content,.tab-content-wrapper{display:flex;flex-direction:column;gap:16px}.record-actions-info{display:flex;flex-direction:column;gap:12px;padding:16px;background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));border:1px solid var(--kendo-color-border, rgba(0, 0, 0, .1));border-radius:4px;margin-bottom:16px}.record-actions-description{margin:0;font-size:13px;color:var(--kendo-color-subtle, rgba(0, 0, 0, .6));line-height:1.5}.record-array-actions{display:flex;gap:8px;justify-content:flex-start;padding-top:0}.record-actions{margin-top:16px;display:flex;gap:8px;justify-content:flex-start;padding-top:0}.binary-linked-wrap{display:flex;flex-direction:column;gap:6px}.binary-linked-reference-hint{font-size:.75rem;color:var(--kendo-color-primary, #0f6dff);font-style:italic}\n"], dependencies: [{ kind: "component", type: i0.forwardRef(() => AttributesGroupComponent), selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "secretsWriteOnly", "messages"] }, { kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatus), selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i0.forwardRef(() => i1.NgControlStatusGroup), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i0.forwardRef(() => i1.FormGroupDirective), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i0.forwardRef(() => i1.FormControlName), selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i0.forwardRef(() => i1.FormGroupName), selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: i0.forwardRef(() => i1$4.CardComponent), selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i0.forwardRef(() => i1$4.CardBodyComponent), selector: "kendo-card-body" }, { kind: "component", type: i0.forwardRef(() => i1$4.CardHeaderComponent), selector: "kendo-card-header" }, { kind: "component", type: i0.forwardRef(() => i1$4.ExpansionPanelComponent), selector: "kendo-expansionpanel", inputs: ["title", "subtitle", "disabled", "expanded", "svgExpandIcon", "svgCollapseIcon", "expandIcon", "collapseIcon", "animation"], outputs: ["expandedChange", "action", "expand", "collapse"], exportAs: ["kendoExpansionPanel"] }, { kind: "directive", type: i0.forwardRef(() => i1$4.ExpansionPanelTitleDirective), selector: "[kendoExpansionPanelTitleDirective]" }, { kind: "component", type: i0.forwardRef(() => i1$4.TabStripComponent), selector: "kendo-tabstrip", inputs: ["height", "animate", "tabAlignment", "tabPosition", "keepTabContent", "closable", "scrollable", "size", "closeIcon", "closeIconClass", "closeSVGIcon", "showContentArea"], outputs: ["tabSelect", "tabClose", "tabScroll"], exportAs: ["kendoTabStrip"] }, { kind: "component", type: i0.forwardRef(() => i1$4.TabStripTabComponent), selector: "kendo-tabstrip-tab", inputs: ["title", "disabled", "cssClass", "cssStyle", "selected", "closable", "closeIcon", "closeIconClass", "closeSVGIcon"], exportAs: ["kendoTabStripTab"] }, { kind: "directive", type: i0.forwardRef(() => i1$4.TabContentDirective), selector: "[kendoTabContent]" }, { kind: "component", type: i0.forwardRef(() => i5.TextBoxComponent), selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i0.forwardRef(() => i5.NumericTextBoxComponent), selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "component", type: i0.forwardRef(() => i5.SwitchComponent), selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "component", type: i0.forwardRef(() => i1$5.LabelComponent), selector: "kendo-label", inputs: ["text", "for", "optional", "labelCssStyle", "labelCssClass"], exportAs: ["kendoLabel"] }, { kind: "component", type: i0.forwardRef(() => i1$1.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: "component", type: i0.forwardRef(() => i3$1.DropDownListComponent), selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "component", type: i0.forwardRef(() => i3$1.MultiSelectComponent), selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "component", type: i0.forwardRef(() => i7.DateTimePickerComponent), selector: "kendo-datetimepicker", inputs: ["focusableId", "weekDaysFormat", "showOtherMonthDays", "value", "format", "twoDigitYearMax", "tabindex", "disabledDates", "popupSettings", "adaptiveTitle", "adaptiveSubtitle", "disabled", "readonly", "readOnlyInput", "cancelButton", "formatPlaceholder", "placeholder", "steps", "focusedDate", "calendarType", "animateCalendarNavigation", "weekNumber", "min", "max", "rangeValidation", "disabledDatesValidation", "incompleteDateValidation", "autoCorrectParts", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "clearButton", "autoFill", "adaptiveMode", "inputAttributes", "defaultTab", "size", "rounded", "fillMode", "headerTemplate", "footerTemplate", "footer"], outputs: ["valueChange", "open", "close", "focus", "blur", "escape"], exportAs: ["kendo-datetimepicker"] }, { kind: "component", type: i0.forwardRef(() => i7.TimePickerComponent), selector: "kendo-timepicker", inputs: ["focusableId", "disabled", "readonly", "readOnlyInput", "clearButton", "format", "formatPlaceholder", "placeholder", "min", "max", "incompleteDateValidation", "autoSwitchParts", "autoSwitchKeys", "enableMouseWheel", "allowCaretMode", "cancelButton", "nowButton", "steps", "popupSettings", "tabindex", "tabIndex", "adaptiveTitle", "adaptiveSubtitle", "rangeValidation", "adaptiveMode", "value", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "open", "close", "escape"], exportAs: ["kendo-timepicker"] }, { kind: "component", type: i0.forwardRef(() => i8.FileSelectComponent), selector: "kendo-fileselect", inputs: ["name"], outputs: ["valueChange"], exportAs: ["kendoFileSelect"] }, { kind: "component", type: i0.forwardRef(() => i8.CustomMessagesComponent), selector: "kendo-upload-messages, kendo-fileselect-messages, kendo-uploaddropzone-messages" }, { kind: "component", type: i0.forwardRef(() => AttributeFieldComponent), selector: "mm-attribute-field", inputs: ["attribute", "control", "baselineValue", "fieldId", "overrideLabelText", "showUndoButton", "undoButtonSize", "errorMessage", "hintText"], outputs: ["undo"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
13650
14180
  }
13651
14181
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: AttributesGroupComponent, decorators: [{
13652
14182
  type: Component,
@@ -13718,6 +14248,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13718
14248
  [isRecord]="true"
13719
14249
  [parentFormGroup]="asFormGroup(item)"
13720
14250
  [initialValues]="getRawInitialValue(attr.attributeName, $index)"
14251
+ [secretsWriteOnly]="secretsWriteOnly()"
13721
14252
  [messages]="_messages"
13722
14253
  />
13723
14254
  </div>
@@ -13774,6 +14305,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13774
14305
  asFormGroup(parentFormGroup().get(attr.attributeName)!)
13775
14306
  "
13776
14307
  [initialValues]="getRawInitialValue(attr.attributeName)"
14308
+ [secretsWriteOnly]="secretsWriteOnly()"
13777
14309
  [messages]="_messages"
13778
14310
  />
13779
14311
  </div>
@@ -13870,6 +14402,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13870
14402
  [control]="parentFormGroup().get(attr.attributeName)!"
13871
14403
  [baselineValue]="getBaselineValue(attr.attributeName)"
13872
14404
  [fieldId]="attr.attributeName"
14405
+ [hintText]="attr.secret && secretsWriteOnly() ? (_messages.secretWriteOnlyHint ?? '') : ''"
13873
14406
  [errorMessage]="_messages.attributeField?.errorMessage ?? 'This field is required or invalid.'"
13874
14407
  >
13875
14408
  @if (recognition.isNumber(attr.attributeValueType)) {
@@ -13952,6 +14485,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13952
14485
  valueField="key"
13953
14486
  [valuePrimitive]="true"
13954
14487
  />
14488
+ } @else if (attr.secret) {
14489
+ <kendo-textbox
14490
+ type="password"
14491
+ autocomplete="new-password"
14492
+ [focusableId]="attr.attributeName"
14493
+ [formControlName]="attr.attributeName"
14494
+ />
13955
14495
  } @else {
13956
14496
  <kendo-textbox
13957
14497
  [focusableId]="attr.attributeName"
@@ -13964,8 +14504,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
13964
14504
  </kendo-card-body>
13965
14505
  </kendo-card>
13966
14506
  </div>
13967
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".attributes-form-container ::ng-deep kendo-card kendo-card-body{display:flex;flex-direction:column;gap:16px}.attributes-form-container ::ng-deep kendo-label{display:flex;flex-direction:column;gap:4px}.attributes-form-container ::ng-deep kendo-label label{text-transform:uppercase}.header-content{display:flex;flex-direction:column;gap:4px}.record-array-content,.tab-content-wrapper{display:flex;flex-direction:column;gap:16px}.record-actions-info{display:flex;flex-direction:column;gap:12px;padding:16px;background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));border:1px solid var(--kendo-color-border, rgba(0, 0, 0, .1));border-radius:4px;margin-bottom:16px}.record-actions-description{margin:0;font-size:13px;color:var(--kendo-color-subtle, rgba(0, 0, 0, .6));line-height:1.5}.record-array-actions{display:flex;gap:8px;justify-content:flex-start;padding-top:0}.record-actions{margin-top:16px;display:flex;gap:8px;justify-content:flex-start;padding-top:0}.binary-linked-wrap{display:flex;flex-direction:column;gap:6px}.binary-linked-reference-hint{font-size:.75rem;color:var(--kendo-color-primary, #0f6dff);font-style:italic}\n"] }]
13968
- }], ctorParameters: () => [], propDecorators: { ckId: [{ type: i0.Input, args: [{ isSignal: true, alias: "ckId", required: true }] }], parentFormGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentFormGroup", required: true }] }], isRecord: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRecord", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], messages: [{
14507
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".attributes-form-container ::ng-deep kendo-card kendo-card-body{display:flex;flex-direction:column;gap:16px}.attributes-form-container ::ng-deep kendo-label{display:flex;flex-direction:column;gap:4px}.header-content{display:flex;flex-direction:column;gap:4px}.record-array-content,.tab-content-wrapper{display:flex;flex-direction:column;gap:16px}.record-actions-info{display:flex;flex-direction:column;gap:12px;padding:16px;background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));border:1px solid var(--kendo-color-border, rgba(0, 0, 0, .1));border-radius:4px;margin-bottom:16px}.record-actions-description{margin:0;font-size:13px;color:var(--kendo-color-subtle, rgba(0, 0, 0, .6));line-height:1.5}.record-array-actions{display:flex;gap:8px;justify-content:flex-start;padding-top:0}.record-actions{margin-top:16px;display:flex;gap:8px;justify-content:flex-start;padding-top:0}.binary-linked-wrap{display:flex;flex-direction:column;gap:6px}.binary-linked-reference-hint{font-size:.75rem;color:var(--kendo-color-primary, #0f6dff);font-style:italic}\n"] }]
14508
+ }], ctorParameters: () => [], propDecorators: { ckId: [{ type: i0.Input, args: [{ isSignal: true, alias: "ckId", required: true }] }], parentFormGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentFormGroup", required: true }] }], isRecord: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRecord", required: false }] }], initialValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialValues", required: false }] }], secretsWriteOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "secretsWriteOnly", required: false }] }], messages: [{
13969
14509
  type: Input
13970
14510
  }] } });
13971
14511
  /** Stable empty array to avoid new [] references that would retrigger effects (infinite loop). */
@@ -14298,7 +14838,7 @@ class CreateEditorComponent {
14298
14838
  </button>
14299
14839
  </div>
14300
14840
  </div>
14301
- `, isInline: true, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px;text-transform:uppercase}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;text-transform:uppercase;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i1$1.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: "component", type: CkTypeSelectorInputComponent, selector: "mm-ck-type-selector-input", inputs: ["placeholder", "minSearchLength", "maxResults", "debounceMs", "ckModelIds", "allowAbstract", "dialogTitle", "advancedSearchLabel", "derivedFromRtCkTypeId", "messages", "dialogMessages", "disabled", "required"], outputs: ["ckTypeSelected", "ckTypeCleared"] }, { kind: "component", type: AttributesGroupComponent, selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "messages"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
14841
+ `, isInline: true, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i1$1.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: "component", type: CkTypeSelectorInputComponent, selector: "mm-ck-type-selector-input", inputs: ["placeholder", "minSearchLength", "maxResults", "debounceMs", "ckModelIds", "allowAbstract", "dialogTitle", "advancedSearchLabel", "derivedFromRtCkTypeId", "messages", "dialogMessages", "disabled", "required"], outputs: ["ckTypeSelected", "ckTypeCleared"] }, { kind: "component", type: AttributesGroupComponent, selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "secretsWriteOnly", "messages"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
14302
14842
  }
14303
14843
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: CreateEditorComponent, decorators: [{
14304
14844
  type: Component,
@@ -14378,9 +14918,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
14378
14918
  </button>
14379
14919
  </div>
14380
14920
  </div>
14381
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px;text-transform:uppercase}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;text-transform:uppercase;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"] }]
14921
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"] }]
14382
14922
  }], ctorParameters: () => [], propDecorators: { createInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "createInput", required: true }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], createOutput: [{ type: i0.Output, args: ["createOutput"] }], cancelRequested: [{ type: i0.Output, args: ["cancelRequested"] }] } });
14383
14923
 
14924
+ const RECORD_TYPES = new Set(['RECORD', 'RECORD_ARRAY']);
14925
+ /**
14926
+ * Decides what the runtime-browser update editor may write back (AB#5542).
14927
+ *
14928
+ * Only what was loaded completely may be written: an attribute is blocked when the secret-safe
14929
+ * analysis lists it (`blockedAttributes`: records carrying a secret or an excluded sub-attribute,
14930
+ * name collisions) or when it is not part of the loaded `attributeNames` at all (e.g. the CK
14931
+ * lookup failed) — except write-only secret scalars, whose empty value the mapper already omits.
14932
+ */
14933
+ function planSecretSafeUpdate(mapped, definitions, analysis, formValue, initialJson) {
14934
+ const loaded = new Set(analysis.attributeNames.map((n) => n.toLowerCase()));
14935
+ const listed = new Set(analysis.blockedAttributes.map((n) => n.toLowerCase()));
14936
+ const blocked = new Set();
14937
+ for (const def of definitions) {
14938
+ const name = def.attributeName.toLowerCase();
14939
+ const writeOnlySecret = !!def.secret && !RECORD_TYPES.has(def.attributeValueType?.toUpperCase());
14940
+ if (listed.has(name) || (!writeOnlySecret && !loaded.has(name))) {
14941
+ blocked.add(name);
14942
+ }
14943
+ }
14944
+ let initial = {};
14945
+ try {
14946
+ initial = JSON.parse(initialJson ?? '{}');
14947
+ }
14948
+ catch {
14949
+ initial = {};
14950
+ }
14951
+ const changedKeys = Object.keys(formValue).filter((key) => JSON.stringify(formValue[key]) !== JSON.stringify(initial[key]));
14952
+ return {
14953
+ attributes: mapped.filter((a) => !blocked.has(a.attributeName.toLowerCase())),
14954
+ blocked,
14955
+ blockedChanged: changedKeys.some((key) => blocked.has(key.toLowerCase())),
14956
+ otherChanged: changedKeys.some((key) => !blocked.has(key.toLowerCase())),
14957
+ };
14958
+ }
14959
+
14384
14960
  /**
14385
14961
  * Editor for updating an existing runtime entity: loads entity data by rtId/ckTypeId, builds attribute form
14386
14962
  * via mm-attributes-group, and submits updateRuntimeEntities with mapped attributes. Save is enabled only when
@@ -14421,6 +14997,7 @@ class UpdateEditorComponent {
14421
14997
  mapperService = inject(AttributeMapperService);
14422
14998
  coordinatorService = inject(AttributeCoordinatorService);
14423
14999
  sharedEditor = inject(SharedEditor);
15000
+ secretSafeNames = inject(SecretSafeAttributeNamesService);
14424
15001
  dataLoaded = computed(() => !!this.entityData(), /* @ts-ignore */
14425
15002
  ...(ngDevMode ? [{ debugName: "dataLoaded" }] : /* istanbul ignore next */ []));
14426
15003
  isUpdateButtonEnabled = computed(() => {
@@ -14507,7 +15084,20 @@ class UpdateEditorComponent {
14507
15084
  this.isUpdating.set(true);
14508
15085
  try {
14509
15086
  const attributesMetadata = await this.fetchAttributesMetadata(rtCkTypeId);
14510
- const mappedAttributes = await firstValueFrom(this.mapFormToAttributes$(currentForm.getRawValue(), attributesMetadata));
15087
+ const formValue = currentForm.getRawValue();
15088
+ const mapped = await firstValueFrom(this.mapFormToAttributes$(formValue, attributesMetadata));
15089
+ const analysis = await this.secretSafeNames.analyse(input.ckTypeId);
15090
+ const plan = planSecretSafeUpdate(mapped, attributesMetadata, analysis, formValue, this.initialValue());
15091
+ if (plan.blockedChanged) {
15092
+ this.sharedEditor.showErrorNotification(this.resolvedMessages().recordWithSecretNotSaved ??
15093
+ DEFAULT_RUNTIME_BROWSER_MESSAGES.recordWithSecretNotSaved ??
15094
+ '');
15095
+ }
15096
+ if (!plan.otherChanged) {
15097
+ // Nothing that may be written back changed — skip the call (one message, AB#5542).
15098
+ return;
15099
+ }
15100
+ const mappedAttributes = plan.attributes;
14511
15101
  if (!this.hasValidMappedAttributes(mappedAttributes)) {
14512
15102
  this.sharedEditor.showErrorNotification(this.resolvedMessages().failedToUpdateEntity);
14513
15103
  return;
@@ -14608,6 +15198,7 @@ class UpdateEditorComponent {
14608
15198
  [ckId]="updateInput().rtCkTypeId"
14609
15199
  [parentFormGroup]="form()!"
14610
15200
  [initialValues]="$safeNavigationMigration(entityData()?.initial)"
15201
+ [secretsWriteOnly]="true"
14611
15202
  [isRecord]="false"
14612
15203
  [messages]="resolvedMessages()"
14613
15204
  />
@@ -14635,7 +15226,7 @@ class UpdateEditorComponent {
14635
15226
  </button>
14636
15227
  </div>
14637
15228
  </div>
14638
- `, isInline: true, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px;text-transform:uppercase}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;text-transform:uppercase;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i1$1.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: "component", type: AttributesGroupComponent, selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "messages"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
15229
+ `, isInline: true, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: CardModule }, { kind: "component", type: i1$4.CardComponent, selector: "kendo-card", inputs: ["orientation", "width"] }, { kind: "component", type: i1$4.CardBodyComponent, selector: "kendo-card-body" }, { kind: "component", type: i1$4.CardHeaderComponent, selector: "kendo-card-header" }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: i1$1.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: "component", type: AttributesGroupComponent, selector: "mm-attributes-group", inputs: ["ckId", "parentFormGroup", "isRecord", "initialValues", "secretsWriteOnly", "messages"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
14639
15230
  }
14640
15231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: UpdateEditorComponent, decorators: [{
14641
15232
  type: Component,
@@ -14697,6 +15288,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
14697
15288
  [ckId]="updateInput().rtCkTypeId"
14698
15289
  [parentFormGroup]="form()!"
14699
15290
  [initialValues]="$safeNavigationMigration(entityData()?.initial)"
15291
+ [secretsWriteOnly]="true"
14700
15292
  [isRecord]="false"
14701
15293
  [messages]="resolvedMessages()"
14702
15294
  />
@@ -14724,7 +15316,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
14724
15316
  </button>
14725
15317
  </div>
14726
15318
  </div>
14727
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px;text-transform:uppercase}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;text-transform:uppercase;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"] }]
15319
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".entity-editor-container{display:flex;flex-direction:column;gap:16px;width:100%}.entity-editor-container ::ng-deep kendo-card{display:grid;grid-template-rows:auto 1fr;grid-template-columns:1fr 1fr;gap:16px;width:100%!important}.entity-editor-container ::ng-deep kendo-card kendo-card-header{grid-column:span 2;grid-row:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body{grid-row:2;grid-column:span 2;display:grid;grid-template-columns:1fr 1fr;gap:16px}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item{display:flex;flex-direction:column}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :first-child{grid-column:1}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item :nth-child(2){grid-column:2}.entity-editor-container ::ng-deep kendo-card kendo-card-body .info-item label{color:var(--kendo-color-subtle, rgba(0, 0, 0, .7));margin-bottom:8px}.entity-editor-container .attributes-form-container ::ng-deep kendo-card:not(.basic-info-card) kendo-card-body{display:flex;flex-direction:column;gap:16px}.entity-editor-container .select-type-prompt{grid-column:span 2;color:var(--kendo-color-primary, #0f6dff);background-color:var(--kendo-color-surface-alt, rgba(0, 0, 0, .05));padding:16px;border-radius:8px;text-align:center;border:1px dashed var(--kendo-color-border, rgba(0, 0, 0, .1))}.entity-editor-container .entity-editor-actions{display:flex;flex-direction:row;gap:16px}.entity-editor-container .entity-editor-actions button:disabled{opacity:.6}\n"] }]
14728
15320
  }], ctorParameters: () => [], propDecorators: { updateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "updateInput", required: true }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], updateOutput: [{ type: i0.Output, args: ["updateOutput"] }], cancelRequested: [{ type: i0.Output, args: ["cancelRequested"] }] } });
14729
15321
 
14730
15322
  class RuntimeBrowserDetailsComponent {
@@ -14749,6 +15341,7 @@ class RuntimeBrowserDetailsComponent {
14749
15341
  createEntitiesGQL = inject(CreateEntitiesDtoGQL);
14750
15342
  updateEntitiesGQL = inject(UpdateRuntimeEntitiesDtoGQL);
14751
15343
  deleteEntitiesGQL = inject(DeleteEntitiesDtoGQL);
15344
+ confirmation = inject(ConfirmationService);
14752
15345
  entitySelectorDialog = inject(EntitySelectorDialogService);
14753
15346
  attributeSelectorDialog = inject(AttributeSelectorDialogService);
14754
15347
  // Data Mapping state (list of DataPointMapping entities). Source data points
@@ -15126,7 +15719,7 @@ class RuntimeBrowserDetailsComponent {
15126
15719
  try {
15127
15720
  // Load entity attributes
15128
15721
  const entityResult = await firstValueFrom(this.getEntityByIdGQL.fetch({
15129
- variables: { rtId, ckTypeId },
15722
+ variables: { rtId, ckTypeId, attributeNames: [...DATA_POINT_MAPPING_ATTRIBUTE_NAMES] },
15130
15723
  }));
15131
15724
  const mappingEntity = entityResult.data?.runtime?.runtimeEntities?.items?.[0];
15132
15725
  if (!mappingEntity)
@@ -15225,6 +15818,16 @@ class RuntimeBrowserDetailsComponent {
15225
15818
  async onRemoveMapping(mapping) {
15226
15819
  if (!mapping.rtId)
15227
15820
  return;
15821
+ // Danger confirmation naming the mapping (AB#5579): the mapping entity is erased.
15822
+ const name = mapping.name || mapping.rtId;
15823
+ if (!await this.confirmation.showDangerConfirm({
15824
+ title: `Delete mapping ${name}?`,
15825
+ targetName: name,
15826
+ consequence: 'The data point mapping is erased. This cannot be undone.',
15827
+ confirmText: 'Delete mapping',
15828
+ })) {
15829
+ return;
15830
+ }
15228
15831
  try {
15229
15832
  await firstValueFrom(this.deleteEntitiesGQL.mutate({
15230
15833
  variables: {
@@ -15505,7 +16108,7 @@ class RuntimeBrowserDetailsComponent {
15505
16108
  }
15506
16109
  }
15507
16110
  </div>
15508
- `, isInline: true, styles: [":host{display:block;height:100%;width:100%}.runtime-browser-details{display:flex;flex-direction:column;flex:1;min-height:0;padding:24px;box-sizing:border-box;overflow-y:auto;background:linear-gradient(180deg,var(--surface-elevated) 0%,var(--deep-sea) 100%)}.runtime-browser-details .no-selection{display:flex;align-items:center;justify-content:center;flex:1;min-height:0}.runtime-browser-details .no-selection .placeholder-content{text-align:center;max-width:400px;padding:40px;background:linear-gradient(135deg,var(--iron-navy-80),var(--surface-elevated-90));border:1px solid var(--octo-mint-30);border-radius:8px 24px;box-shadow:0 0 30px var(--octo-mint-10),inset 0 0 40px var(--octo-mint-03)}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon{margin-bottom:24px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:64px;color:var(--octo-mint-50);text-shadow:0 0 20px var(--octo-mint-50);animation:lcars-icon-pulse 3s ease-in-out infinite}.runtime-browser-details .no-selection .placeholder-content h3{margin:0 0 12px;font-family:Montserrat,sans-serif;font-size:1.4rem;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:var(--octo-mint);text-shadow:0 0 15px var(--octo-mint-50)}.runtime-browser-details .no-selection .placeholder-content p{margin:0;font-family:Montserrat,sans-serif;font-size:.9rem;line-height:1.6;color:rgba(var(--octo-text-color),.7);letter-spacing:.5px}.runtime-browser-details .entity-details{height:100%;display:flex;flex-direction:column;overflow:hidden}.runtime-browser-details .entity-details .details-header{display:flex;align-items:center;gap:16px;padding:16px 20px 16px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;margin-bottom:20px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.runtime-browser-details .entity-details .details-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.runtime-browser-details .entity-details .details-header .entity-icon{font-size:28px;color:var(--octo-mint);text-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .details-header .entity-title{flex:1}.runtime-browser-details .entity-details .details-header .entity-title h3{margin:0 0 6px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .details-header .entity-title .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;color:var(--neo-cyan);background:var(--deep-sea-60);padding:4px 10px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block}.runtime-browser-details .entity-details mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root{padding:24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative}.runtime-browser-details .entity-details .ck-model-details:before,.runtime-browser-details .entity-details .ck-models-root:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3{margin:0 0 20px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .ck-model-details p,.runtime-browser-details .entity-details .ck-models-root p{margin:0 0 12px;font-family:Roboto,sans-serif;font-size:.9rem;color:rgba(var(--octo-text-color),.85)}.runtime-browser-details .entity-details .ck-model-details p strong,.runtime-browser-details .entity-details .ck-models-root p strong{font-family:Montserrat,sans-serif;font-weight:600;font-size:.8rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80);margin-right:12px}.runtime-browser-details .entity-details .ck-model-details p.info-text,.runtime-browser-details .entity-details .ck-models-root p.info-text{color:rgba(var(--octo-text-color),.6);font-style:italic;margin-top:24px;padding:16px 20px;background:linear-gradient(135deg,var(--neo-cyan-10),var(--neo-cyan-05));border:1px solid var(--neo-cyan-30);border-radius:4px 12px}.runtime-browser-details .entity-details .ck-type-details{display:flex;flex-direction:column;height:100%;padding:0}.runtime-browser-details .entity-details .ck-type-details .type-header{margin-bottom:20px;padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative}.runtime-browser-details .entity-details .ck-type-details .type-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .ck-type-details .type-header h3{margin:0 0 12px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata{display:flex;gap:10px;align-items:center}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge{padding:6px 14px;border-radius:4px;font-family:Montserrat,sans-serif;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.abstract{background:linear-gradient(135deg,var(--royal-violet-30),var(--royal-violet-15));border:1px solid var(--royal-violet-50);color:var(--royal-violet-light-20);box-shadow:0 0 10px var(--royal-violet-30)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.final{background:linear-gradient(135deg,var(--toffee-30),var(--toffee-15));border:1px solid var(--toffee-50);color:var(--toffee);box-shadow:0 0 10px var(--toffee-30)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .base-type{font-family:Roboto Mono,monospace;font-size:.8rem;color:var(--neo-cyan);background:var(--deep-sea-60);padding:4px 10px;border-radius:4px;border:1px solid var(--neo-cyan-30)}.runtime-browser-details .entity-details .ck-type-details .entities-table{flex:1;display:flex;flex-direction:column;overflow:hidden;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;padding:20px}.runtime-browser-details .entity-details .ck-type-details .entities-table h4{margin:0 0 16px;font-family:Montserrat,sans-serif;font-size:1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-mint)}.runtime-browser-details .entity-details .ck-type-details .entities-table mm-list-view{flex:1;display:flex;flex-direction:column;overflow:hidden}@keyframes lcars-icon-pulse{0%,to{opacity:.5;transform:scale(1)}50%{opacity:.8;transform:scale(1.05)}}@media(max-width:768px){.runtime-browser-details{padding:16px}.runtime-browser-details .no-selection .placeholder-content{padding:24px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:48px}.runtime-browser-details .no-selection .placeholder-content h3{font-size:1.1rem}.runtime-browser-details .entity-details .details-header{flex-direction:column;align-items:flex-start;gap:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: EntityDetailViewComponent, selector: "mm-entity-detail-view", inputs: ["entity", "loading", "error", "showHeader", "messages", "showDataMapping", "dataMappings", "expressionValidator"], outputs: ["retry", "propertyChange", "navigateToEntity", "addMappingRequested", "removeMappingRequested", "selectMappingTarget", "selectSourceAttributeRequested", "selectTargetAttributeRequested", "mappingChanged", "saveAllMappingsRequested"] }, { kind: "component", type: ListViewComponent, selector: "mm-list-view", inputs: ["pageSize", "skip", "autoPageSize", "rowIsClickable", "showRowCheckBoxes", "showRowSelectAllCheckBox", "contextMenuType", "leftToolbarActions", "rightToolbarActions", "actionCommandItems", "contextMenuCommandItems", "excelExportFileName", "pdfExportFileName", "pageable", "sortable", "rowFilterEnabled", "searchTextBoxEnabled", "persistListState", "listStateKey", "resizable", "actionsColumnWidth", "hideCheckboxesBelow", "cardModeBelow", "collapseCommandsBelow", "rowClass", "messages", "selectable", "columns"], outputs: ["rowClicked", "resetFilters"] }, { kind: "directive", type: CkTypeEntitiesDataSourceDirective, selector: "[mmCkTypeEntitiesDataSource]", exportAs: ["mmCkTypeEntitiesDataSource"] }, { kind: "component", type: CreateEditorComponent, selector: "mm-create-editor-component", inputs: ["createInput", "messages"], outputs: ["createOutput", "cancelRequested"] }, { kind: "component", type: UpdateEditorComponent, selector: "mm-update-editor-component", inputs: ["updateInput", "messages"], outputs: ["updateOutput", "cancelRequested"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
16111
+ `, isInline: true, styles: [":host{display:block;height:100%;width:100%}.runtime-browser-details .entity-details .ck-type-details .entities-table,.runtime-browser-details .entity-details .ck-type-details .type-header,.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root,.runtime-browser-details .entity-details .details-header{background:var(--theme-bg-elevated, var(--surface-elevated));border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px)}.runtime-browser-details .entity-details .ck-type-details .type-header h3,.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3,.runtime-browser-details .entity-details .details-header .entity-title h3,.runtime-browser-details .no-selection .placeholder-content h3{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1.1rem;font-weight:600;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .base-type,.runtime-browser-details .entity-details .details-header .entity-title .entity-type{font-family:var(--theme-font-mono, \"Roboto Mono\", monospace);font-size:.8rem;color:var(--theme-text-code, var(--octo-text-color));background:var(--theme-bg-sunken, var(--deep-sea-60));padding:2px 8px;border-radius:var(--theme-radius-xs, 2px);border:1px solid var(--theme-border-subtle);display:inline-block}.runtime-browser-details{display:flex;flex-direction:column;flex:1;min-height:0;padding:24px;box-sizing:border-box;overflow-y:auto;background:var(--theme-bg-surface, var(--deep-sea))}.runtime-browser-details .no-selection{display:flex;align-items:center;justify-content:center;flex:1;min-height:0}.runtime-browser-details .no-selection .placeholder-content{text-align:center;max-width:400px;padding:40px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon{margin-bottom:16px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:48px;color:var(--theme-text-muted, var(--ash-blue))}.runtime-browser-details .no-selection .placeholder-content h3{margin:0 0 8px}.runtime-browser-details .no-selection .placeholder-content p{margin:0;font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.9rem;line-height:1.6;color:var(--theme-text-secondary, var(--ash-blue))}.runtime-browser-details .entity-details{height:100%;display:flex;flex-direction:column;overflow:hidden}.runtime-browser-details .entity-details .details-header{display:flex;align-items:center;gap:16px;padding:16px 20px;margin-bottom:20px}.runtime-browser-details .entity-details .details-header .entity-icon{font-size:24px;color:var(--theme-text-secondary, var(--ash-blue))}.runtime-browser-details .entity-details .details-header .entity-title{flex:1}.runtime-browser-details .entity-details .details-header .entity-title h3{margin:0 0 6px}.runtime-browser-details .entity-details .details-header .entity-title .entity-type{margin:0}.runtime-browser-details .entity-details mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root{padding:24px}.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3{margin:0 0 20px}.runtime-browser-details .entity-details .ck-model-details p,.runtime-browser-details .entity-details .ck-models-root p{margin:0 0 12px;font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.9rem;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-model-details p strong,.runtime-browser-details .entity-details .ck-models-root p strong{font-weight:500;font-size:.85rem;color:var(--theme-text-secondary, var(--ash-blue));margin-right:12px}.runtime-browser-details .entity-details .ck-model-details p.info-text,.runtime-browser-details .entity-details .ck-models-root p.info-text{color:var(--theme-text-secondary, var(--ash-blue));margin-top:24px;padding:12px 16px;background:var(--theme-status-info-subtle, var(--neo-cyan-10));border:1px solid var(--theme-border-subtle);border-radius:var(--theme-radius-sm, 4px)}.runtime-browser-details .entity-details .ck-type-details{display:flex;flex-direction:column;height:100%;padding:0}.runtime-browser-details .entity-details .ck-type-details .type-header{margin-bottom:20px;padding:20px 24px}.runtime-browser-details .entity-details .ck-type-details .type-header h3{margin:0 0 12px}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata{display:flex;gap:10px;align-items:center}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge{padding:2px 8px;border-radius:var(--theme-radius-xs, 2px);font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.75rem;font-weight:500}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.abstract{background:var(--theme-ai-subtle, var(--royal-violet-15));border:1px solid transparent;color:var(--theme-ai, var(--royal-violet-light-20))}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.final{background:var(--theme-status-warning-subtle, var(--toffee-15));border:1px solid transparent;color:var(--theme-status-warning, var(--toffee))}.runtime-browser-details .entity-details .ck-type-details .entities-table{flex:1;display:flex;flex-direction:column;overflow:hidden;padding:20px}.runtime-browser-details .entity-details .ck-type-details .entities-table h4{margin:0 0 16px;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1rem;font-weight:600;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-type-details .entities-table mm-list-view{flex:1;display:flex;flex-direction:column;overflow:hidden}@media(max-width:768px){.runtime-browser-details{padding:16px}.runtime-browser-details .no-selection .placeholder-content{padding:24px}.runtime-browser-details .entity-details .details-header{flex-direction:column;align-items:flex-start;gap:12px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: EntityDetailViewComponent, selector: "mm-entity-detail-view", inputs: ["entity", "loading", "error", "showHeader", "messages", "showDataMapping", "dataMappings", "expressionValidator"], outputs: ["retry", "propertyChange", "navigateToEntity", "addMappingRequested", "removeMappingRequested", "selectMappingTarget", "selectSourceAttributeRequested", "selectTargetAttributeRequested", "mappingChanged", "saveAllMappingsRequested"] }, { 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: CkTypeEntitiesDataSourceDirective, selector: "[mmCkTypeEntitiesDataSource]", exportAs: ["mmCkTypeEntitiesDataSource"] }, { kind: "component", type: CreateEditorComponent, selector: "mm-create-editor-component", inputs: ["createInput", "messages"], outputs: ["createOutput", "cancelRequested"] }, { kind: "component", type: UpdateEditorComponent, selector: "mm-update-editor-component", inputs: ["updateInput", "messages"], outputs: ["updateOutput", "cancelRequested"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
15509
16112
  }
15510
16113
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RuntimeBrowserDetailsComponent, decorators: [{
15511
16114
  type: Component,
@@ -15658,7 +16261,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
15658
16261
  }
15659
16262
  }
15660
16263
  </div>
15661
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:block;height:100%;width:100%}.runtime-browser-details{display:flex;flex-direction:column;flex:1;min-height:0;padding:24px;box-sizing:border-box;overflow-y:auto;background:linear-gradient(180deg,var(--surface-elevated) 0%,var(--deep-sea) 100%)}.runtime-browser-details .no-selection{display:flex;align-items:center;justify-content:center;flex:1;min-height:0}.runtime-browser-details .no-selection .placeholder-content{text-align:center;max-width:400px;padding:40px;background:linear-gradient(135deg,var(--iron-navy-80),var(--surface-elevated-90));border:1px solid var(--octo-mint-30);border-radius:8px 24px;box-shadow:0 0 30px var(--octo-mint-10),inset 0 0 40px var(--octo-mint-03)}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon{margin-bottom:24px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:64px;color:var(--octo-mint-50);text-shadow:0 0 20px var(--octo-mint-50);animation:lcars-icon-pulse 3s ease-in-out infinite}.runtime-browser-details .no-selection .placeholder-content h3{margin:0 0 12px;font-family:Montserrat,sans-serif;font-size:1.4rem;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:var(--octo-mint);text-shadow:0 0 15px var(--octo-mint-50)}.runtime-browser-details .no-selection .placeholder-content p{margin:0;font-family:Montserrat,sans-serif;font-size:.9rem;line-height:1.6;color:rgba(var(--octo-text-color),.7);letter-spacing:.5px}.runtime-browser-details .entity-details{height:100%;display:flex;flex-direction:column;overflow:hidden}.runtime-browser-details .entity-details .details-header{display:flex;align-items:center;gap:16px;padding:16px 20px 16px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;margin-bottom:20px;position:relative;box-shadow:0 4px 20px #0006,0 0 15px var(--octo-mint-08)}.runtime-browser-details .entity-details .details-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50);border-radius:4px 0 0 4px}.runtime-browser-details .entity-details .details-header .entity-icon{font-size:28px;color:var(--octo-mint);text-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .details-header .entity-title{flex:1}.runtime-browser-details .entity-details .details-header .entity-title h3{margin:0 0 6px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .details-header .entity-title .entity-type{margin:0;font-family:Roboto Mono,monospace;font-size:.8rem;color:var(--neo-cyan);background:var(--deep-sea-60);padding:4px 10px;border-radius:4px;border:1px solid var(--neo-cyan-30);display:inline-block}.runtime-browser-details .entity-details mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root{padding:24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative}.runtime-browser-details .entity-details .ck-model-details:before,.runtime-browser-details .entity-details .ck-models-root:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3{margin:0 0 20px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .ck-model-details p,.runtime-browser-details .entity-details .ck-models-root p{margin:0 0 12px;font-family:Roboto,sans-serif;font-size:.9rem;color:rgba(var(--octo-text-color),.85)}.runtime-browser-details .entity-details .ck-model-details p strong,.runtime-browser-details .entity-details .ck-models-root p strong{font-family:Montserrat,sans-serif;font-weight:600;font-size:.8rem;letter-spacing:.5px;text-transform:uppercase;color:var(--octo-mint-80);margin-right:12px}.runtime-browser-details .entity-details .ck-model-details p.info-text,.runtime-browser-details .entity-details .ck-models-root p.info-text{color:rgba(var(--octo-text-color),.6);font-style:italic;margin-top:24px;padding:16px 20px;background:linear-gradient(135deg,var(--neo-cyan-10),var(--neo-cyan-05));border:1px solid var(--neo-cyan-30);border-radius:4px 12px}.runtime-browser-details .entity-details .ck-type-details{display:flex;flex-direction:column;height:100%;padding:0}.runtime-browser-details .entity-details .ck-type-details .type-header{margin-bottom:20px;padding:20px 24px;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;position:relative}.runtime-browser-details .entity-details .ck-type-details .type-header:before{content:\"\";position:absolute;top:0;left:0;width:4px;height:100%;background:linear-gradient(180deg,var(--octo-mint),var(--neo-cyan),var(--royal-violet));box-shadow:0 0 10px var(--octo-mint-50)}.runtime-browser-details .entity-details .ck-type-details .type-header h3{margin:0 0 12px;font-family:Montserrat,sans-serif;font-size:1.1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-text-color)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata{display:flex;gap:10px;align-items:center}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge{padding:6px 14px;border-radius:4px;font-family:Montserrat,sans-serif;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.abstract{background:linear-gradient(135deg,var(--royal-violet-30),var(--royal-violet-15));border:1px solid var(--royal-violet-50);color:var(--royal-violet-light-20);box-shadow:0 0 10px var(--royal-violet-30)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.final{background:linear-gradient(135deg,var(--toffee-30),var(--toffee-15));border:1px solid var(--toffee-50);color:var(--toffee);box-shadow:0 0 10px var(--toffee-30)}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .base-type{font-family:Roboto Mono,monospace;font-size:.8rem;color:var(--neo-cyan);background:var(--deep-sea-60);padding:4px 10px;border-radius:4px;border:1px solid var(--neo-cyan-30)}.runtime-browser-details .entity-details .ck-type-details .entities-table{flex:1;display:flex;flex-direction:column;overflow:hidden;background:linear-gradient(180deg,var(--iron-navy),var(--surface-elevated));border:1px solid var(--octo-mint-30);border-radius:4px 16px;padding:20px}.runtime-browser-details .entity-details .ck-type-details .entities-table h4{margin:0 0 16px;font-family:Montserrat,sans-serif;font-size:1rem;font-weight:600;letter-spacing:1px;text-transform:uppercase;color:var(--octo-mint)}.runtime-browser-details .entity-details .ck-type-details .entities-table mm-list-view{flex:1;display:flex;flex-direction:column;overflow:hidden}@keyframes lcars-icon-pulse{0%,to{opacity:.5;transform:scale(1)}50%{opacity:.8;transform:scale(1.05)}}@media(max-width:768px){.runtime-browser-details{padding:16px}.runtime-browser-details .no-selection .placeholder-content{padding:24px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:48px}.runtime-browser-details .no-selection .placeholder-content h3{font-size:1.1rem}.runtime-browser-details .entity-details .details-header{flex-direction:column;align-items:flex-start;gap:12px}}\n"] }]
16264
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:block;height:100%;width:100%}.runtime-browser-details .entity-details .ck-type-details .entities-table,.runtime-browser-details .entity-details .ck-type-details .type-header,.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root,.runtime-browser-details .entity-details .details-header{background:var(--theme-bg-elevated, var(--surface-elevated));border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px)}.runtime-browser-details .entity-details .ck-type-details .type-header h3,.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3,.runtime-browser-details .entity-details .details-header .entity-title h3,.runtime-browser-details .no-selection .placeholder-content h3{font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1.1rem;font-weight:600;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .base-type,.runtime-browser-details .entity-details .details-header .entity-title .entity-type{font-family:var(--theme-font-mono, \"Roboto Mono\", monospace);font-size:.8rem;color:var(--theme-text-code, var(--octo-text-color));background:var(--theme-bg-sunken, var(--deep-sea-60));padding:2px 8px;border-radius:var(--theme-radius-xs, 2px);border:1px solid var(--theme-border-subtle);display:inline-block}.runtime-browser-details{display:flex;flex-direction:column;flex:1;min-height:0;padding:24px;box-sizing:border-box;overflow-y:auto;background:var(--theme-bg-surface, var(--deep-sea))}.runtime-browser-details .no-selection{display:flex;align-items:center;justify-content:center;flex:1;min-height:0}.runtime-browser-details .no-selection .placeholder-content{text-align:center;max-width:400px;padding:40px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon{margin-bottom:16px}.runtime-browser-details .no-selection .placeholder-content .placeholder-icon .k-icon{font-size:48px;color:var(--theme-text-muted, var(--ash-blue))}.runtime-browser-details .no-selection .placeholder-content h3{margin:0 0 8px}.runtime-browser-details .no-selection .placeholder-content p{margin:0;font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.9rem;line-height:1.6;color:var(--theme-text-secondary, var(--ash-blue))}.runtime-browser-details .entity-details{height:100%;display:flex;flex-direction:column;overflow:hidden}.runtime-browser-details .entity-details .details-header{display:flex;align-items:center;gap:16px;padding:16px 20px;margin-bottom:20px}.runtime-browser-details .entity-details .details-header .entity-icon{font-size:24px;color:var(--theme-text-secondary, var(--ash-blue))}.runtime-browser-details .entity-details .details-header .entity-title{flex:1}.runtime-browser-details .entity-details .details-header .entity-title h3{margin:0 0 6px}.runtime-browser-details .entity-details .details-header .entity-title .entity-type{margin:0}.runtime-browser-details .entity-details mm-entity-detail-view{flex:1;display:flex;flex-direction:column;overflow-y:auto}.runtime-browser-details .entity-details .ck-model-details,.runtime-browser-details .entity-details .ck-models-root{padding:24px}.runtime-browser-details .entity-details .ck-model-details h3,.runtime-browser-details .entity-details .ck-models-root h3{margin:0 0 20px}.runtime-browser-details .entity-details .ck-model-details p,.runtime-browser-details .entity-details .ck-models-root p{margin:0 0 12px;font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.9rem;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-model-details p strong,.runtime-browser-details .entity-details .ck-models-root p strong{font-weight:500;font-size:.85rem;color:var(--theme-text-secondary, var(--ash-blue));margin-right:12px}.runtime-browser-details .entity-details .ck-model-details p.info-text,.runtime-browser-details .entity-details .ck-models-root p.info-text{color:var(--theme-text-secondary, var(--ash-blue));margin-top:24px;padding:12px 16px;background:var(--theme-status-info-subtle, var(--neo-cyan-10));border:1px solid var(--theme-border-subtle);border-radius:var(--theme-radius-sm, 4px)}.runtime-browser-details .entity-details .ck-type-details{display:flex;flex-direction:column;height:100%;padding:0}.runtime-browser-details .entity-details .ck-type-details .type-header{margin-bottom:20px;padding:20px 24px}.runtime-browser-details .entity-details .ck-type-details .type-header h3{margin:0 0 12px}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata{display:flex;gap:10px;align-items:center}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge{padding:2px 8px;border-radius:var(--theme-radius-xs, 2px);font-family:var(--theme-font-ui, \"Roboto\", sans-serif);font-size:.75rem;font-weight:500}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.abstract{background:var(--theme-ai-subtle, var(--royal-violet-15));border:1px solid transparent;color:var(--theme-ai, var(--royal-violet-light-20))}.runtime-browser-details .entity-details .ck-type-details .type-header .type-metadata .badge.final{background:var(--theme-status-warning-subtle, var(--toffee-15));border:1px solid transparent;color:var(--theme-status-warning, var(--toffee))}.runtime-browser-details .entity-details .ck-type-details .entities-table{flex:1;display:flex;flex-direction:column;overflow:hidden;padding:20px}.runtime-browser-details .entity-details .ck-type-details .entities-table h4{margin:0 0 16px;font-family:var(--theme-font-display, \"Montserrat\", sans-serif);font-size:1rem;font-weight:600;color:var(--theme-text-primary, var(--octo-text-color))}.runtime-browser-details .entity-details .ck-type-details .entities-table mm-list-view{flex:1;display:flex;flex-direction:column;overflow:hidden}@media(max-width:768px){.runtime-browser-details{padding:16px}.runtime-browser-details .no-selection .placeholder-content{padding:24px}.runtime-browser-details .entity-details .details-header{flex-direction:column;align-items:flex-start;gap:12px}}\n"] }]
15662
16265
  }], propDecorators: { selectedItem: [{
15663
16266
  type: Input
15664
16267
  }], showDataMapping: [{
@@ -15679,6 +16282,7 @@ class RuntimeBrowserComponent {
15679
16282
  dataSource = inject(RuntimeBrowserDataSource);
15680
16283
  getRuntimeEntityByIdGQL = inject(GetRuntimeEntityByIdDtoGQL);
15681
16284
  inputService = inject(InputService);
16285
+ confirmation = inject(ConfirmationService);
15682
16286
  router = inject(Router);
15683
16287
  route = inject(ActivatedRoute);
15684
16288
  stateService = inject(RuntimeBrowserStateService);
@@ -15746,7 +16350,7 @@ class RuntimeBrowserComponent {
15746
16350
  id: 'refresh',
15747
16351
  type: 'link',
15748
16352
  text: messages.refresh,
15749
- svgIcon: arrowRotateCwIcon,
16353
+ svgIcon: MM_ACTION_ICONS.refresh,
15750
16354
  onClick: async () => await this.onRefresh(),
15751
16355
  isDisabled: () => !this.isRefreshButtonEnabled,
15752
16356
  },
@@ -15754,7 +16358,7 @@ class RuntimeBrowserComponent {
15754
16358
  id: 'create',
15755
16359
  type: 'link',
15756
16360
  text: messages.create,
15757
- svgIcon: plusIcon,
16361
+ svgIcon: MM_ACTION_ICONS.add,
15758
16362
  onClick: async () => await this.onCreate(),
15759
16363
  isDisabled: () => !this.isCreateButtonEnabled,
15760
16364
  },
@@ -15762,7 +16366,7 @@ class RuntimeBrowserComponent {
15762
16366
  id: 'edit',
15763
16367
  type: 'link',
15764
16368
  text: messages.edit,
15765
- svgIcon: pencilIcon,
16369
+ svgIcon: MM_ACTION_ICONS.edit,
15766
16370
  onClick: async () => await this.onEdit(),
15767
16371
  isDisabled: () => !this.isEditButtonEnabled,
15768
16372
  },
@@ -15770,7 +16374,8 @@ class RuntimeBrowserComponent {
15770
16374
  id: 'delete',
15771
16375
  type: 'link',
15772
16376
  text: messages.delete,
15773
- svgIcon: xIcon,
16377
+ svgIcon: MM_ACTION_ICONS.delete,
16378
+ danger: true,
15774
16379
  onClick: async () => await this.onDelete(),
15775
16380
  isDisabled: () => !this.isDeleteButtonEnabled,
15776
16381
  },
@@ -16130,14 +16735,27 @@ class RuntimeBrowserComponent {
16130
16735
  console.warn('No node selected; cannot perform delete operation on unknown node');
16131
16736
  return;
16132
16737
  }
16738
+ if (!this.isSelectedItemAnRtEntity) {
16739
+ console.warn('Selected item is not a runtime entity, cannot delete.', this.selectedItem);
16740
+ return;
16741
+ }
16742
+ // Danger confirmation naming the entity (AB#5579): the entity and its children are erased.
16743
+ const selected = this.selectedItem;
16744
+ const runtimeEntity = selected.item;
16745
+ const m = this.resolvedMessages();
16746
+ const name = selected.text || runtimeEntity.rtWellKnownName || runtimeEntity.rtId;
16747
+ const confirmed = await this.confirmation.showDangerConfirm({
16748
+ title: (m.confirmDeleteEntityTitle ?? DEFAULT_RUNTIME_BROWSER_MESSAGES.confirmDeleteEntityTitle).replace('{name}', name),
16749
+ targetName: name,
16750
+ consequence: m.confirmDeleteEntityConsequence ?? DEFAULT_RUNTIME_BROWSER_MESSAGES.confirmDeleteEntityConsequence,
16751
+ confirmText: m.confirmDeleteEntityConfirmText ?? DEFAULT_RUNTIME_BROWSER_MESSAGES.confirmDeleteEntityConfirmText,
16752
+ });
16753
+ if (!confirmed || this.selectedItem !== selected) {
16754
+ return;
16755
+ }
16133
16756
  try {
16134
16757
  this.isLoading = true;
16135
16758
  this.treeDetail.setEnabledState(false);
16136
- if (!this.isSelectedItemAnRtEntity) {
16137
- console.warn('Selected item is not a runtime entity, cannot delete.', this.selectedItem);
16138
- return;
16139
- }
16140
- const runtimeEntity = this.selectedItem.item;
16141
16759
  const parentIdPair = await this.dataSource.getRuntimeEntityParentData(runtimeEntity.ckTypeId, runtimeEntity.rtId);
16142
16760
  const deleteState = await this.dataSource.deleteRtEntityAndChildren(this.selectedItem);
16143
16761
  if (!deleteState) {
@@ -16186,6 +16804,8 @@ class RuntimeBrowserComponent {
16186
16804
  variables: {
16187
16805
  ckTypeId: ckTypeId,
16188
16806
  rtId: rtId,
16807
+ // Existence check only — no attributes (SECRET-safe, AB#5542).
16808
+ attributeNames: [],
16189
16809
  },
16190
16810
  }));
16191
16811
  const entity = result.data?.runtime?.runtimeEntities?.items?.[0];
@@ -16283,32 +16903,8 @@ class RuntimeBrowserComponent {
16283
16903
  }
16284
16904
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RuntimeBrowserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
16285
16905
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: RuntimeBrowserComponent, isStandalone: true, selector: "mm-runtime-browser", inputs: { messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, showDataMapping: { classPropertyName: "showDataMapping", publicName: "showDataMapping", isSignal: true, isRequired: false, transformFunction: null }, expressionValidator: { classPropertyName: "expressionValidator", publicName: "expressionValidator", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "treeDetail", first: true, predicate: ["treeDetail"], descendants: true }, { propertyName: "detailsPanel", first: true, predicate: ["detailsPanel"], descendants: true }], ngImport: i0, template: `
16286
- <div class="runtime-browser-container kendo-theme-provider">
16287
- <!-- LCARS Header -->
16288
- <div class="lcars-page-header">
16289
- <div class="lcars-header-accent"></div>
16290
- <div class="header-content">
16291
- <h1 class="page-title">
16292
- <span class="title-prefix">{{
16293
- resolvedMessages().titlePrefix
16294
- }}</span>
16295
- <span class="title-main">{{ resolvedMessages().title }}</span>
16296
- </h1>
16297
- <div class="header-stats">
16298
- <div class="stat-badge">
16299
- <span class="badge-icon">&#9632;</span>
16300
- <span class="badge-label">{{
16301
- resolvedMessages().badgeLabel
16302
- }}</span>
16303
- </div>
16304
- </div>
16305
- </div>
16306
- <div class="lcars-header-line"></div>
16307
- </div>
16308
-
16309
- <!-- Main Content -->
16310
- <div class="lcars-content-panel">
16311
- <div class="panel-accent-top"></div>
16906
+ <mm-page class="runtime-browser-container kendo-theme-provider" [pageTitle]="resolvedMessages().title">
16907
+ <div class="runtime-browser-panel">
16312
16908
  <mm-perspective-switcher
16313
16909
  [perspectives]="perspectives()"
16314
16910
  [activeKey]="activePerspectiveKey()"
@@ -16335,56 +16931,20 @@ class RuntimeBrowserComponent {
16335
16931
  >
16336
16932
  </mm-runtime-browser-details>
16337
16933
  </mm-base-tree-detail>
16338
- <div class="panel-accent-bottom"></div>
16339
- </div>
16340
-
16341
- <!-- LCARS Footer -->
16342
- <div class="lcars-footer">
16343
- <div class="footer-bar bar-1"></div>
16344
- <div class="footer-bar bar-2"></div>
16345
- <div class="footer-bar bar-3"></div>
16346
- <div class="footer-spacer"></div>
16347
- <div class="footer-indicator">
16348
- <span class="indicator-dot"></span>
16349
- <span class="indicator-text">{{ resolvedMessages().ready }}</span>
16350
- </div>
16351
16934
  </div>
16352
- </div>
16353
- `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"], dependencies: [{ kind: "component", type: BaseTreeDetailComponent, selector: "mm-base-tree-detail", inputs: ["treeDataSource", "leftPaneSize", "leftToolbarActions", "rightToolbarActions"], outputs: ["nodeSelected", "nodeDropped"] }, { kind: "component", type: RuntimeBrowserDetailsComponent, selector: "mm-runtime-browser-details", inputs: ["selectedItem", "showDataMapping", "messages", "expressionValidator"], outputs: ["entitySaved"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
16935
+ </mm-page>
16936
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-panel{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--theme-bg-surface);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);overflow:hidden}.runtime-browser-panel>mm-base-tree-detail{flex:1;display:flex;flex-direction:column;min-height:0}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:var(--theme-border-subtle);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:var(--theme-border-strong)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:var(--theme-font-ui, \"Roboto\", sans-serif);transition:background-color var(--theme-motion-fast, .12s) var(--theme-motion-easing, ease);border-radius:var(--theme-radius-sm, 4px)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--theme-bg-hover)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:var(--theme-bg-selected);color:var(--theme-text-accent)}::ng-deep mm-base-tree-detail .toolbar{background:var(--theme-bg-elevated);border-bottom:1px solid var(--theme-border-subtle)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}\n"], dependencies: [{ kind: "component", type: PageComponent, selector: "mm-page", inputs: ["pageTitle", "pageSubtitle", "headingLevel", "padded"] }, { kind: "component", type: BaseTreeDetailComponent, selector: "mm-base-tree-detail", inputs: ["treeDataSource", "leftPaneSize", "leftToolbarActions", "rightToolbarActions"], outputs: ["nodeSelected", "nodeDropped"] }, { kind: "component", type: RuntimeBrowserDetailsComponent, selector: "mm-runtime-browser-details", inputs: ["selectedItem", "showDataMapping", "messages", "expressionValidator"], outputs: ["entitySaved"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
16354
16937
  }
16355
16938
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RuntimeBrowserComponent, decorators: [{
16356
16939
  type: Component,
16357
16940
  args: [{ selector: 'mm-runtime-browser', imports: [
16941
+ PageComponent,
16358
16942
  BaseTreeDetailComponent,
16359
16943
  RuntimeBrowserDetailsComponent,
16360
16944
  PerspectiveSwitcherComponent,
16361
16945
  ], template: `
16362
- <div class="runtime-browser-container kendo-theme-provider">
16363
- <!-- LCARS Header -->
16364
- <div class="lcars-page-header">
16365
- <div class="lcars-header-accent"></div>
16366
- <div class="header-content">
16367
- <h1 class="page-title">
16368
- <span class="title-prefix">{{
16369
- resolvedMessages().titlePrefix
16370
- }}</span>
16371
- <span class="title-main">{{ resolvedMessages().title }}</span>
16372
- </h1>
16373
- <div class="header-stats">
16374
- <div class="stat-badge">
16375
- <span class="badge-icon">&#9632;</span>
16376
- <span class="badge-label">{{
16377
- resolvedMessages().badgeLabel
16378
- }}</span>
16379
- </div>
16380
- </div>
16381
- </div>
16382
- <div class="lcars-header-line"></div>
16383
- </div>
16384
-
16385
- <!-- Main Content -->
16386
- <div class="lcars-content-panel">
16387
- <div class="panel-accent-top"></div>
16946
+ <mm-page class="runtime-browser-container kendo-theme-provider" [pageTitle]="resolvedMessages().title">
16947
+ <div class="runtime-browser-panel">
16388
16948
  <mm-perspective-switcher
16389
16949
  [perspectives]="perspectives()"
16390
16950
  [activeKey]="activePerspectiveKey()"
@@ -16411,22 +16971,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
16411
16971
  >
16412
16972
  </mm-runtime-browser-details>
16413
16973
  </mm-base-tree-detail>
16414
- <div class="panel-accent-bottom"></div>
16415
16974
  </div>
16416
-
16417
- <!-- LCARS Footer -->
16418
- <div class="lcars-footer">
16419
- <div class="footer-bar bar-1"></div>
16420
- <div class="footer-bar bar-2"></div>
16421
- <div class="footer-bar bar-3"></div>
16422
- <div class="footer-spacer"></div>
16423
- <div class="footer-indicator">
16424
- <span class="indicator-dot"></span>
16425
- <span class="indicator-text">{{ resolvedMessages().ready }}</span>
16426
- </div>
16427
- </div>
16428
- </div>
16429
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-container{display:flex;flex-direction:column;height:100%;padding:16px;gap:16px}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:linear-gradient(180deg,var(--octo-mint-30),transparent);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:linear-gradient(180deg,var(--octo-mint-50),var(--octo-mint-20))}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:Roboto,sans-serif;transition:all .2s ease;border-radius:4px}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--octo-mint-10);color:var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:linear-gradient(90deg,var(--octo-mint-20),transparent);color:var(--octo-mint);border-left:3px solid var(--octo-mint)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected:hover{background:linear-gradient(90deg,var(--octo-mint-25),transparent)}::ng-deep mm-base-tree-detail .toolbar{background:linear-gradient(90deg,var(--octo-mint-05),transparent);border-bottom:1px solid var(--octo-mint-20)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}@media(max-width:1024px){.runtime-browser-container{padding:12px;gap:12px}}@media(max-width:768px){.runtime-browser-container{padding:8px;gap:10px}}\n"] }]
16975
+ </mm-page>
16976
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:flex;flex-direction:column;height:100%;width:100%}.runtime-browser-panel{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--theme-bg-surface);border:1px solid var(--theme-border-default);border-radius:var(--theme-radius-md, 6px);overflow:hidden}.runtime-browser-panel>mm-base-tree-detail{flex:1;display:flex;flex-direction:column;min-height:0}::ng-deep mm-base-tree-detail .k-splitter{background:transparent;border:none}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar{background:var(--theme-border-subtle);width:4px!important}::ng-deep mm-base-tree-detail .k-splitter .k-splitbar:hover{background:var(--theme-border-strong)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf{font-family:var(--theme-font-ui, \"Roboto\", sans-serif);transition:background-color var(--theme-motion-fast, .12s) var(--theme-motion-easing, ease);border-radius:var(--theme-radius-sm, 4px)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf:hover{background:var(--theme-bg-hover)}::ng-deep mm-base-tree-detail kendo-treeview .k-treeview-item .k-treeview-leaf.k-selected{background:var(--theme-bg-selected);color:var(--theme-text-accent)}::ng-deep mm-base-tree-detail .toolbar{background:var(--theme-bg-elevated);border-bottom:1px solid var(--theme-border-subtle)}::ng-deep mm-base-tree-detail .base-tree-detail-container{height:100%;display:flex;flex-direction:column}::ng-deep mm-base-tree-detail .base-tree-detail-container .k-splitter{flex:1;min-height:0}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane{display:flex!important;flex-direction:column!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details{display:flex!important;flex:1!important;min-height:0!important;height:100%!important}::ng-deep mm-base-tree-detail kendo-splitter-pane.detail-pane>mm-runtime-browser-details>.runtime-browser-details{flex:1;display:flex;flex-direction:column;min-height:0}\n"] }]
16430
16977
  }], propDecorators: { messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], showDataMapping: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDataMapping", required: false }] }], expressionValidator: [{ type: i0.Input, args: [{ isSignal: true, alias: "expressionValidator", required: false }] }], treeDetail: [{
16431
16978
  type: ViewChild,
16432
16979
  args: ['treeDetail', { static: false }]
@@ -16714,7 +17261,10 @@ const GetDataPointMappingsDocumentDto = gql `
16714
17261
  rtId
16715
17262
  ckTypeId
16716
17263
  rtWellKnownName
16717
- attributes(resolveEnumValuesToNames: true) {
17264
+ attributes(
17265
+ attributeNames: ["name", "enabled", "sourceAttributePath", "targetAttributePath", "mappingExpression"]
17266
+ resolveEnumValuesToNames: true
17267
+ ) {
16718
17268
  items {
16719
17269
  attributeName
16720
17270
  value
@@ -16757,6 +17307,7 @@ class DataMappingOverviewComponent {
16757
17307
  getEntityByIdGQL = inject(GetRuntimeEntityByIdDtoGQL);
16758
17308
  updateEntitiesGQL = inject(UpdateRuntimeEntitiesDtoGQL);
16759
17309
  deleteEntitiesGQL = inject(DeleteEntitiesDtoGQL);
17310
+ confirmation = inject(ConfirmationService);
16760
17311
  navigateToEntity = new EventEmitter();
16761
17312
  // State
16762
17313
  mappings = signal([], /* @ts-ignore */
@@ -16787,7 +17338,7 @@ class DataMappingOverviewComponent {
16787
17338
  checkIcon = checkCircleIcon;
16788
17339
  warnIcon = exclamationCircleIcon;
16789
17340
  errorIcon = xCircleIcon;
16790
- deleteIcon = trashIcon;
17341
+ deleteIcon = MM_ACTION_ICONS.delete;
16791
17342
  ngOnInit() {
16792
17343
  this.loadMappings();
16793
17344
  }
@@ -16846,6 +17397,16 @@ class DataMappingOverviewComponent {
16846
17397
  }
16847
17398
  }
16848
17399
  async onDeleteMapping(item) {
17400
+ // Danger confirmation naming the mapping (AB#5579): the mapping entity is erased.
17401
+ const name = item.name || item.rtId;
17402
+ if (!await this.confirmation.showDangerConfirm({
17403
+ title: `Delete mapping ${name}?`,
17404
+ targetName: name,
17405
+ consequence: 'The data point mapping is erased. This cannot be undone.',
17406
+ confirmText: 'Delete mapping',
17407
+ })) {
17408
+ return;
17409
+ }
16849
17410
  try {
16850
17411
  await firstValueFrom(this.deleteEntitiesGQL.mutate({
16851
17412
  variables: {
@@ -16866,10 +17427,12 @@ class DataMappingOverviewComponent {
16866
17427
  mapEntityToOverviewItem(entity) {
16867
17428
  const attrs = entity.attributes?.items ?? [];
16868
17429
  const assocs = entity.associations?.definitions?.items ?? [];
16869
- const getAttr = (name) => attrs.find(a => a?.attributeName === name)?.value ?? '';
17430
+ // The server returns camelCase attribute names; compare case-insensitively.
17431
+ const findAttr = (name) => attrs.find(a => a?.attributeName?.toLowerCase() === name.toLowerCase());
17432
+ const getAttr = (name) => findAttr(name)?.value ?? '';
16870
17433
  const mapsFrom = assocs.find(a => a && String(a.ckAssociationRoleId).includes('MapsFrom'));
16871
17434
  const mapsTo = assocs.find(a => a && String(a.ckAssociationRoleId).includes('MapsTo'));
16872
- const enabledRaw = attrs.find(a => a?.attributeName === 'Enabled')?.value;
17435
+ const enabledRaw = findAttr('Enabled')?.value;
16873
17436
  const enabled = enabledRaw === true || enabledRaw === 'true' || enabledRaw === 'True';
16874
17437
  return {
16875
17438
  rtId: String(entity.rtId),
@@ -16938,11 +17501,12 @@ class DataMappingOverviewComponent {
16938
17501
  const loadPromises = [...entityRefs.values()].map(async (ref) => {
16939
17502
  try {
16940
17503
  const result = await firstValueFrom(this.getEntityByIdGQL.fetch({
16941
- variables: { rtId: ref.rtId, ckTypeId: ref.ckTypeId },
17504
+ // Only the display name is needed (SECRET-safe explicit list, AB#5542).
17505
+ variables: { rtId: ref.rtId, ckTypeId: ref.ckTypeId, attributeNames: ['name'] },
16942
17506
  }));
16943
17507
  const entity = result.data?.runtime?.runtimeEntities?.items?.[0];
16944
17508
  if (entity) {
16945
- const nameAttr = entity.attributes?.items?.find(a => a?.attributeName === 'Name');
17509
+ const nameAttr = entity.attributes?.items?.find(a => a?.attributeName?.toLowerCase() === 'name');
16946
17510
  const name = nameAttr?.value
16947
17511
  ?? entity.rtWellKnownName
16948
17512
  ?? '';
@@ -17077,8 +17641,9 @@ class DataMappingOverviewComponent {
17077
17641
 
17078
17642
  <kendo-grid-column title="" [width]="50" [sortable]="false">
17079
17643
  <ng-template kendoGridCellTemplate let-dataItem>
17080
- <button kendoButton fillMode="flat" size="small" [svgIcon]="deleteIcon"
17081
- (click)="onDeleteMapping(dataItem); $event.stopPropagation()">
17644
+ <button kendoButton fillMode="flat" size="small" themeColor="error" [svgIcon]="deleteIcon"
17645
+ title="Delete mapping" [attr.aria-label]="'Delete mapping ' + (dataItem.name || dataItem.rtId)"
17646
+ data-action="delete" (click)="onDeleteMapping(dataItem); $event.stopPropagation()">
17082
17647
  </button>
17083
17648
  </ng-template>
17084
17649
  </kendo-grid-column>
@@ -17142,7 +17707,7 @@ class DataMappingOverviewComponent {
17142
17707
  <div class="loading-overlay">Loading mappings...</div>
17143
17708
  }
17144
17709
  </div>
17145
- `, isInline: true, styles: [".mapping-overview{display:flex;flex-direction:column;gap:12px;padding:16px}.summary-bar{display:flex;gap:16px;align-items:center;padding:8px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;background:var(--kendo-color-surface-alt, #f8f9fa)}.summary-item{display:flex;flex-direction:column;align-items:center;min-width:60px}.summary-count{font-size:1.2rem;font-weight:700}.summary-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.summary-valid .summary-count{color:var(--kendo-color-success, #28a745)}.summary-warnings .summary-count{color:var(--kendo-color-warning, #ffc107)}.summary-errors .summary-count{color:var(--kendo-color-error, #dc3545)}.summary-disabled .summary-count{color:var(--kendo-color-subtle, #6c757d)}.summary-spacer{flex:1}.status-valid{color:var(--kendo-color-success, #28a745)}.status-warning{color:var(--kendo-color-warning, #ffc107)}.status-error{color:var(--kendo-color-error, #dc3545)}.entity-ref{cursor:pointer;color:var(--kendo-color-primary, #ff6358);font-family:monospace;font-size:.85rem}.entity-ref:hover{text-decoration:underline}.no-target{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.entity-type-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.expression-cell{font-size:.85rem;background:var(--kendo-color-surface-alt, #f8f9fa);padding:2px 4px;border-radius:3px}.detail-panel{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;padding:12px 16px}.detail-panel h4{margin:0 0 12px;font-size:.9rem;font-weight:600}.detail-grid{display:grid;grid-template-columns:120px 1fr;gap:6px 12px}.detail-row{display:contents}.detail-row label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d);padding-top:2px}.detail-row span,.detail-row code{font-size:.85rem}.validation-section{margin-top:12px;padding-top:8px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.validation-section h5{margin:0 0 6px;font-size:.8rem;font-weight:600}.validation-msg{font-size:.8rem;padding:2px 0}.validation-error{color:var(--kendo-color-error, #dc3545)}.validation-warning{color:var(--kendo-color-warning, #ffc107)}.validation-info{color:var(--kendo-color-info, #17a2b8)}.loading-overlay{text-align:center;padding:20px;color:var(--kendo-color-subtle, #6c757d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: BadgeModule }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "pipe", type: i1$2.SlicePipe, name: "slice" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
17710
+ `, isInline: true, styles: [".mapping-overview{display:flex;flex-direction:column;gap:12px;padding:16px}.summary-bar{display:flex;gap:16px;align-items:center;padding:8px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;background:var(--kendo-color-surface-alt, #f8f9fa)}.summary-item{display:flex;flex-direction:column;align-items:center;min-width:60px}.summary-count{font-size:1.2rem;font-weight:700}.summary-label{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d)}.summary-valid .summary-count{color:var(--kendo-color-success, #28a745)}.summary-warnings .summary-count{color:var(--kendo-color-warning, #ffc107)}.summary-errors .summary-count{color:var(--kendo-color-error, #dc3545)}.summary-disabled .summary-count{color:var(--kendo-color-subtle, #6c757d)}.summary-spacer{flex:1}.status-valid{color:var(--kendo-color-success, #28a745)}.status-warning{color:var(--kendo-color-warning, #ffc107)}.status-error{color:var(--kendo-color-error, #dc3545)}.entity-ref{cursor:pointer;color:var(--kendo-color-primary, #ff6358);font-family:monospace;font-size:.85rem}.entity-ref:hover{text-decoration:underline}.no-target{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.entity-type-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.expression-cell{font-size:.85rem;background:var(--kendo-color-surface-alt, #f8f9fa);padding:2px 4px;border-radius:3px}.detail-panel{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;padding:12px 16px}.detail-panel h4{margin:0 0 12px;font-size:.9rem;font-weight:600}.detail-grid{display:grid;grid-template-columns:120px 1fr;gap:6px 12px}.detail-row{display:contents}.detail-row label{font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d);padding-top:2px}.detail-row span,.detail-row code{font-size:.85rem}.validation-section{margin-top:12px;padding-top:8px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.validation-section h5{margin:0 0 6px;font-size:.8rem;font-weight:600}.validation-msg{font-size:.8rem;padding:2px 0}.validation-error{color:var(--kendo-color-error, #dc3545)}.validation-warning{color:var(--kendo-color-warning, #ffc107)}.validation-info{color:var(--kendo-color-info, #17a2b8)}.loading-overlay{text-align:center;padding:20px;color:var(--kendo-color-subtle, #6c757d)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i3.GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i3.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i3.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: BadgeModule }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "pipe", type: i1$2.SlicePipe, name: "slice" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
17146
17711
  }
17147
17712
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: DataMappingOverviewComponent, decorators: [{
17148
17713
  type: Component,
@@ -17254,8 +17819,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
17254
17819
 
17255
17820
  <kendo-grid-column title="" [width]="50" [sortable]="false">
17256
17821
  <ng-template kendoGridCellTemplate let-dataItem>
17257
- <button kendoButton fillMode="flat" size="small" [svgIcon]="deleteIcon"
17258
- (click)="onDeleteMapping(dataItem); $event.stopPropagation()">
17822
+ <button kendoButton fillMode="flat" size="small" themeColor="error" [svgIcon]="deleteIcon"
17823
+ title="Delete mapping" [attr.aria-label]="'Delete mapping ' + (dataItem.name || dataItem.rtId)"
17824
+ data-action="delete" (click)="onDeleteMapping(dataItem); $event.stopPropagation()">
17259
17825
  </button>
17260
17826
  </ng-template>
17261
17827
  </kendo-grid-column>
@@ -17319,7 +17885,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
17319
17885
  <div class="loading-overlay">Loading mappings...</div>
17320
17886
  }
17321
17887
  </div>
17322
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-overview{display:flex;flex-direction:column;gap:12px;padding:16px}.summary-bar{display:flex;gap:16px;align-items:center;padding:8px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;background:var(--kendo-color-surface-alt, #f8f9fa)}.summary-item{display:flex;flex-direction:column;align-items:center;min-width:60px}.summary-count{font-size:1.2rem;font-weight:700}.summary-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.summary-valid .summary-count{color:var(--kendo-color-success, #28a745)}.summary-warnings .summary-count{color:var(--kendo-color-warning, #ffc107)}.summary-errors .summary-count{color:var(--kendo-color-error, #dc3545)}.summary-disabled .summary-count{color:var(--kendo-color-subtle, #6c757d)}.summary-spacer{flex:1}.status-valid{color:var(--kendo-color-success, #28a745)}.status-warning{color:var(--kendo-color-warning, #ffc107)}.status-error{color:var(--kendo-color-error, #dc3545)}.entity-ref{cursor:pointer;color:var(--kendo-color-primary, #ff6358);font-family:monospace;font-size:.85rem}.entity-ref:hover{text-decoration:underline}.no-target{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.entity-type-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.expression-cell{font-size:.85rem;background:var(--kendo-color-surface-alt, #f8f9fa);padding:2px 4px;border-radius:3px}.detail-panel{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;padding:12px 16px}.detail-panel h4{margin:0 0 12px;font-size:.9rem;font-weight:600}.detail-grid{display:grid;grid-template-columns:120px 1fr;gap:6px 12px}.detail-row{display:contents}.detail-row label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d);padding-top:2px}.detail-row span,.detail-row code{font-size:.85rem}.validation-section{margin-top:12px;padding-top:8px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.validation-section h5{margin:0 0 6px;font-size:.8rem;font-weight:600}.validation-msg{font-size:.8rem;padding:2px 0}.validation-error{color:var(--kendo-color-error, #dc3545)}.validation-warning{color:var(--kendo-color-warning, #ffc107)}.validation-info{color:var(--kendo-color-info, #17a2b8)}.loading-overlay{text-align:center;padding:20px;color:var(--kendo-color-subtle, #6c757d)}\n"] }]
17888
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-overview{display:flex;flex-direction:column;gap:12px;padding:16px}.summary-bar{display:flex;gap:16px;align-items:center;padding:8px 12px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;background:var(--kendo-color-surface-alt, #f8f9fa)}.summary-item{display:flex;flex-direction:column;align-items:center;min-width:60px}.summary-count{font-size:1.2rem;font-weight:700}.summary-label{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d)}.summary-valid .summary-count{color:var(--kendo-color-success, #28a745)}.summary-warnings .summary-count{color:var(--kendo-color-warning, #ffc107)}.summary-errors .summary-count{color:var(--kendo-color-error, #dc3545)}.summary-disabled .summary-count{color:var(--kendo-color-subtle, #6c757d)}.summary-spacer{flex:1}.status-valid{color:var(--kendo-color-success, #28a745)}.status-warning{color:var(--kendo-color-warning, #ffc107)}.status-error{color:var(--kendo-color-error, #dc3545)}.entity-ref{cursor:pointer;color:var(--kendo-color-primary, #ff6358);font-family:monospace;font-size:.85rem}.entity-ref:hover{text-decoration:underline}.no-target{color:var(--kendo-color-subtle, #6c757d);font-style:italic}.entity-type-hint{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);font-family:monospace}.expression-cell{font-size:.85rem;background:var(--kendo-color-surface-alt, #f8f9fa);padding:2px 4px;border-radius:3px}.detail-panel{border:1px solid var(--kendo-color-border, #dee2e6);border-radius:6px;padding:12px 16px}.detail-panel h4{margin:0 0 12px;font-size:.9rem;font-weight:600}.detail-grid{display:grid;grid-template-columns:120px 1fr;gap:6px 12px}.detail-row{display:contents}.detail-row label{font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #6c757d);padding-top:2px}.detail-row span,.detail-row code{font-size:.85rem}.validation-section{margin-top:12px;padding-top:8px;border-top:1px solid var(--kendo-color-border, #dee2e6)}.validation-section h5{margin:0 0 6px;font-size:.8rem;font-weight:600}.validation-msg{font-size:.8rem;padding:2px 0}.validation-error{color:var(--kendo-color-error, #dc3545)}.validation-warning{color:var(--kendo-color-warning, #ffc107)}.validation-info{color:var(--kendo-color-info, #17a2b8)}.loading-overlay{text-align:center;padding:20px;color:var(--kendo-color-subtle, #6c757d)}\n"] }]
17323
17889
  }], propDecorators: { navigateToEntity: [{
17324
17890
  type: Output
17325
17891
  }] } });
@@ -17342,7 +17908,10 @@ const GetLatestValidationExecutionDocumentDto = gql `
17342
17908
  items {
17343
17909
  rtId
17344
17910
  ckTypeId
17345
- attributes(resolveEnumValuesToNames: true) {
17911
+ attributes(
17912
+ attributeNames: ["outputData", "completedAt"]
17913
+ resolveEnumValuesToNames: true
17914
+ ) {
17346
17915
  items {
17347
17916
  attributeName
17348
17917
  value
@@ -17388,7 +17957,10 @@ const GetNodeMappingsDocumentDto = gql `
17388
17957
  items {
17389
17958
  rtId
17390
17959
  ckTypeId
17391
- attributes(resolveEnumValuesToNames: true) {
17960
+ attributes(
17961
+ attributeNames: ["name", "enabled", "sourceAttributePath", "targetAttributePath", "mappingExpression"]
17962
+ resolveEnumValuesToNames: true
17963
+ ) {
17392
17964
  items {
17393
17965
  attributeName
17394
17966
  value
@@ -17847,7 +18419,7 @@ class BulkMappingDialogComponent {
17847
18419
  [svgIcon]="browseIcon"
17848
18420
  [disabled]="!targetCkTypeId()"
17849
18421
  (click)="browseTargetAttribute()"
17850
- title="Browse all attributes (incl. navigation properties)"></button>
18422
+ title="Browse all attributes (incl. navigation properties)" aria-label="Browse all attributes (incl. navigation properties)"></button>
17851
18423
  </div>
17852
18424
  </div>
17853
18425
  </div>
@@ -17857,7 +18429,7 @@ class BulkMappingDialogComponent {
17857
18429
  [disabled]="!isValid()">Create {{ sources().length }} mappings</button>
17858
18430
  </div>
17859
18431
  </div>
17860
- `, isInline: true, styles: [".bulk-mapping{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.bulk-mapping-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.source-summary{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.source-summary .source-count{font-weight:600;font-size:.85rem}.source-summary .source-preview{font-size:.72rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;letter-spacing:0;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: ComboBoxModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
18432
+ `, isInline: true, styles: [".bulk-mapping{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.bulk-mapping-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.source-summary{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.source-summary .source-count{font-weight:600;font-size:.85rem}.source-summary .source-preview{font-size:.72rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: ComboBoxModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
17861
18433
  }
17862
18434
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: BulkMappingDialogComponent, decorators: [{
17863
18435
  type: Component,
@@ -17973,7 +18545,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
17973
18545
  [svgIcon]="browseIcon"
17974
18546
  [disabled]="!targetCkTypeId()"
17975
18547
  (click)="browseTargetAttribute()"
17976
- title="Browse all attributes (incl. navigation properties)"></button>
18548
+ title="Browse all attributes (incl. navigation properties)" aria-label="Browse all attributes (incl. navigation properties)"></button>
17977
18549
  </div>
17978
18550
  </div>
17979
18551
  </div>
@@ -17983,7 +18555,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
17983
18555
  [disabled]="!isValid()">Create {{ sources().length }} mappings</button>
17984
18556
  </div>
17985
18557
  </div>
17986
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".bulk-mapping{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.bulk-mapping-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.source-summary{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.source-summary .source-count{font-weight:600;font-size:.85rem}.source-summary .source-preview{font-size:.72rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;letter-spacing:0;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}\n"] }]
18558
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".bulk-mapping{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.bulk-mapping-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.source-summary{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.source-summary .source-count{font-weight:600;font-size:.85rem}.source-summary .source-preview{font-size:.72rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}\n"] }]
17987
18559
  }], propDecorators: { sourcePicker: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DataPointPickerComponent), { isSignal: true }] }] } });
17988
18560
 
17989
18561
  const DIALOG_KEY$1 = 'bulk-mapping-dialog';
@@ -18964,7 +19536,7 @@ class MappingEditDialogComponent {
18964
19536
  [svgIcon]="icons.regenerate"
18965
19537
  [disabled]="!canGenerateName()"
18966
19538
  (click)="generateName()"
18967
- title="Generate name from source + target"></button>
19539
+ title="Generate name from source + target" aria-label="Generate name from source + target"></button>
18968
19540
  </div>
18969
19541
  </div>
18970
19542
 
@@ -19101,7 +19673,7 @@ class MappingEditDialogComponent {
19101
19673
  [svgIcon]="icons.browse"
19102
19674
  [disabled]="!effectiveTargetCkTypeId()"
19103
19675
  (click)="browseTargetAttribute()"
19104
- title="Browse all attributes (incl. navigation properties)"></button>
19676
+ title="Browse all attributes (incl. navigation properties)" aria-label="Browse all attributes (incl. navigation properties)"></button>
19105
19677
  </div>
19106
19678
  <span class="hint">
19107
19679
  @if (effectiveTargetCkTypeId(); as t) {
@@ -19120,7 +19692,7 @@ class MappingEditDialogComponent {
19120
19692
  [disabled]="!isValid()">Save</button>
19121
19693
  </div>
19122
19694
  </div>
19123
- `, isInline: true, styles: [".mapping-edit{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.mapping-edit-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.attribute-option{display:flex;justify-content:space-between;align-items:center;width:100%;gap:8px}.attribute-option .attribute-path{flex:1;font-family:monospace;font-size:.85rem}.attribute-option .attribute-type{font-size:.7rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f0f0f0)) 80%,transparent);color:var(--theme-text-secondary, var(--kendo-color-subtle, #888))}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;letter-spacing:0;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: ComboBoxModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "directive", type: i3$1.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "ngmodule", type: SVGIconModule }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
19695
+ `, isInline: true, styles: [".mapping-edit{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.mapping-edit-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.attribute-option{display:flex;justify-content:space-between;align-items:center;width:100%;gap:8px}.attribute-option .attribute-path{flex:1;font-family:monospace;font-size:.85rem}.attribute-option .attribute-type{font-size:.7rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f0f0f0)) 80%,transparent);color:var(--theme-text-secondary, var(--kendo-color-subtle, #888))}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: ComboBoxModule }, { kind: "component", type: i3$1.ComboBoxComponent, selector: "kendo-combobox", inputs: ["icon", "svgIcon", "inputAttributes", "showStickyHeader", "focusableId", "allowCustom", "data", "value", "textField", "valueField", "valuePrimitive", "valueNormalizer", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "loading", "suggest", "clearButton", "disabled", "itemDisabled", "readonly", "tabindex", "tabIndex", "filterable", "virtual", "size", "rounded", "fillMode"], outputs: ["valueChange", "selectionChange", "filterChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "escape"], exportAs: ["kendoComboBox"] }, { kind: "directive", type: i3$1.ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "ngmodule", type: SVGIconModule }, { kind: "ngmodule", type: SwitchModule }, { kind: "component", type: i5.SwitchComponent, selector: "kendo-switch", inputs: ["focusableId", "onLabel", "offLabel", "checked", "disabled", "readonly", "tabindex", "size", "thumbRounded", "trackRounded", "tabIndex"], outputs: ["focus", "blur", "valueChange"], exportAs: ["kendoSwitch"] }, { kind: "ngmodule", type: TextBoxModule }, { kind: "component", type: i5.TextBoxComponent, selector: "kendo-textbox", inputs: ["focusableId", "title", "type", "disabled", "readonly", "tabindex", "value", "selectOnFocus", "showSuccessIcon", "showErrorIcon", "clearButton", "successIcon", "successSvgIcon", "errorIcon", "errorSvgIcon", "clearButtonIcon", "clearButtonSvgIcon", "size", "rounded", "fillMode", "tabIndex", "placeholder", "maxlength", "inputAttributes"], outputs: ["valueChange", "inputFocus", "inputBlur", "focus", "blur"], exportAs: ["kendoTextBox"] }, { kind: "component", type: DataPointPickerComponent, selector: "mm-data-point-picker", inputs: ["entity", "entityRtId", "entityCkTypeId", "value", "placeholder", "disabled"], outputs: ["valueChange", "filterChange"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
19124
19696
  }
19125
19697
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: MappingEditDialogComponent, decorators: [{
19126
19698
  type: Component,
@@ -19146,7 +19718,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
19146
19718
  [svgIcon]="icons.regenerate"
19147
19719
  [disabled]="!canGenerateName()"
19148
19720
  (click)="generateName()"
19149
- title="Generate name from source + target"></button>
19721
+ title="Generate name from source + target" aria-label="Generate name from source + target"></button>
19150
19722
  </div>
19151
19723
  </div>
19152
19724
 
@@ -19283,7 +19855,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
19283
19855
  [svgIcon]="icons.browse"
19284
19856
  [disabled]="!effectiveTargetCkTypeId()"
19285
19857
  (click)="browseTargetAttribute()"
19286
- title="Browse all attributes (incl. navigation properties)"></button>
19858
+ title="Browse all attributes (incl. navigation properties)" aria-label="Browse all attributes (incl. navigation properties)"></button>
19287
19859
  </div>
19288
19860
  <span class="hint">
19289
19861
  @if (effectiveTargetCkTypeId(); as t) {
@@ -19302,7 +19874,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
19302
19874
  [disabled]="!isValid()">Save</button>
19303
19875
  </div>
19304
19876
  </div>
19305
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-edit{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.mapping-edit-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.attribute-option{display:flex;justify-content:space-between;align-items:center;width:100%;gap:8px}.attribute-option .attribute-path{flex:1;font-family:monospace;font-size:.85rem}.attribute-option .attribute-type{font-size:.7rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f0f0f0)) 80%,transparent);color:var(--theme-text-secondary, var(--kendo-color-subtle, #888))}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;letter-spacing:0;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}\n"] }]
19877
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [".mapping-edit{display:flex;flex-direction:column;height:100%;box-sizing:border-box}.mapping-edit-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:14px 18px;display:flex;flex-direction:column;gap:14px}.field-row{display:flex;flex-direction:column;gap:4px}.field-row label{font-size:.72rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.field-row .hint{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.field-row.inline{flex-direction:row;align-items:center;gap:8px}.entity-display{display:flex;flex-direction:column;gap:2px;padding:6px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.entity-display.empty{flex-direction:row;align-items:center;justify-content:space-between}.entity-main{display:flex;align-items:center;gap:8px}.entity-main .entity-name{flex:1;font-weight:600;font-size:.9rem}.entity-meta{display:flex;align-items:center;flex-wrap:wrap;gap:2px;font-size:.7rem;font-family:monospace;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.entity-meta .sep{opacity:.7}.dialog-actions{flex:0 0 auto;display:flex;gap:8px;justify-content:flex-end;padding:10px 18px;border-top:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.combo-row{display:flex;align-items:stretch;gap:4px}.combo-row kendo-combobox{flex:1}.attribute-option{display:flex;justify-content:space-between;align-items:center;width:100%;gap:8px}.attribute-option .attribute-path{flex:1;font-family:monospace;font-size:.85rem}.attribute-option .attribute-type{font-size:.7rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f0f0f0)) 80%,transparent);color:var(--theme-text-secondary, var(--kendo-color-subtle, #888))}.loading-pill{margin-left:6px;font-size:.65rem;padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);color:var(--kendo-color-info, #0dcaf0);text-transform:none;font-style:italic}.expression-preview{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:4px 10px;border-radius:4px;font-size:.75rem;background:color-mix(in srgb,var(--kendo-color-success, #28a745) 10%,transparent)}.expression-preview.expression-preview-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 10%,transparent)}.expression-preview .preview-label{font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview code{font-family:monospace}.expression-preview .preview-arrow{opacity:.7}.expression-preview .preview-note{font-style:italic;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.expression-preview .preview-error-text{color:var(--kendo-color-error, #dc3545)}\n"] }]
19306
19878
  }], propDecorators: { sourcePicker: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DataPointPickerComponent), { isSignal: true }] }] } });
19307
19879
  /**
19308
19880
  * Client-side filter mirroring the substring search Kendo's combobox does
@@ -19477,15 +20049,15 @@ class MappingCoverageTreeComponent {
19477
20049
  expressionEvaluator = null;
19478
20050
  entitySelected = new EventEmitter();
19479
20051
  icons = {
19480
- refresh: arrowRotateCwIcon,
20052
+ refresh: MM_ACTION_ICONS.refresh,
19481
20053
  folderOpen: folderOpenIcon,
19482
- plus: plusIcon,
19483
- pencil: pencilIcon,
19484
- trash: trashIcon,
20054
+ plus: MM_ACTION_ICONS.add,
20055
+ pencil: MM_ACTION_ICONS.edit,
20056
+ trash: MM_ACTION_ICONS.delete,
19485
20057
  link: linkIcon,
19486
20058
  x: xIcon,
19487
- download: downloadIcon,
19488
- upload: uploadIcon,
20059
+ download: MM_ACTION_ICONS.export,
20060
+ upload: MM_ACTION_ICONS.import,
19489
20061
  };
19490
20062
  /** Selectable tree perspectives (built-in Spatial + per-tenant configured). */
19491
20063
  perspectives = signal([
@@ -20428,6 +21000,8 @@ class MappingCoverageTreeComponent {
20428
21000
  .fetch({
20429
21001
  variables: {
20430
21002
  ckTypeId: this.config.validationPipelineCkTypeId,
21003
+ // Only the pipeline definition is read (SECRET-safe explicit list, AB#5542).
21004
+ attributeNames: ['pipelineDefinition'],
20431
21005
  first: 200,
20432
21006
  after: GraphQL.offsetToCursor(0),
20433
21007
  },
@@ -20669,7 +21243,13 @@ class MappingCoverageTreeComponent {
20669
21243
  }
20670
21244
  }
20671
21245
  async deleteMapping(mapping) {
20672
- const confirmed = await this.confirmation.showYesNoConfirmationDialog('Delete Mapping', `Delete mapping '${mapping.name || mapping.rtId}'? This cannot be undone.`);
21246
+ const name = mapping.name || mapping.rtId;
21247
+ const confirmed = await this.confirmation.showDangerConfirm({
21248
+ title: `Delete mapping ${name}?`,
21249
+ targetName: name,
21250
+ consequence: 'The data point mapping is erased. This cannot be undone.',
21251
+ confirmText: 'Delete mapping',
21252
+ });
20673
21253
  if (!confirmed)
20674
21254
  return;
20675
21255
  try {
@@ -20695,6 +21275,8 @@ class MappingCoverageTreeComponent {
20695
21275
  .fetch({
20696
21276
  variables: {
20697
21277
  ckTypeId: this.activeRootCkTypeId(),
21278
+ // Only rt* fields are read (SECRET-safe, AB#5542).
21279
+ attributeNames: [],
20698
21280
  first: 200,
20699
21281
  after: GraphQL.offsetToCursor(0),
20700
21282
  },
@@ -20801,7 +21383,8 @@ class MappingCoverageTreeComponent {
20801
21383
  try {
20802
21384
  const data = await firstValueFrom(this.getRuntimeEntityByIdGQL
20803
21385
  .fetch({
20804
- variables: { rtId: ref.rtId, ckTypeId: ref.ckTypeId },
21386
+ // Only rtDisplayName is read — no attributes (SECRET-safe, AB#5542).
21387
+ variables: { rtId: ref.rtId, ckTypeId: ref.ckTypeId, attributeNames: [] },
20805
21388
  fetchPolicy: 'cache-first',
20806
21389
  })
20807
21390
  .pipe(map(r => r.data?.runtime?.runtimeEntities?.items?.[0])));
@@ -20826,7 +21409,7 @@ class MappingCoverageTreeComponent {
20826
21409
  this.mappings.set(next);
20827
21410
  }
20828
21411
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: MappingCoverageTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20829
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: MappingCoverageTreeComponent, isStandalone: true, selector: "mm-mapping-coverage-tree", inputs: { config: "config", initialRoot: "initialRoot", tenantId: "tenantId", expressionEvaluator: "expressionEvaluator" }, outputs: { entitySelected: "entitySelected" }, providers: [MappingCoverageTreeDataSource], viewQueries: [{ propertyName: "treeView", first: true, predicate: TreeComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"coverage-root\">\n @if (config.sourceCandidateCkTypeIds.length > 0) {\n <div class=\"coverage-tabs\" role=\"tablist\">\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'coverage'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'coverage'\"\n (click)=\"selectTab('coverage')\">Coverage Tree</button>\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'orphans'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'orphans'\"\n (click)=\"selectTab('orphans')\">\n Orphan Sources\n @if (orphanStats(); as s) {\n @if (s.unmapped > 0) { <span class=\"tab-badge\">{{ s.unmapped }}</span> }\n }\n </button>\n </div>\n }\n\n @if (activeTab() === 'coverage') {\n <div class=\"coverage-toolbar\">\n <mm-perspective-switcher\n [perspectives]=\"perspectives()\"\n [activeKey]=\"activePerspectiveKey()\"\n (perspectiveChange)=\"onPerspectiveChange($event)\"></mm-perspective-switcher>\n <label class=\"toolbar-label\">Tree:</label>\n <select class=\"root-select\"\n [value]=\"selectedRoot()?.rtId ?? ''\"\n (change)=\"onRootSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ activeRootCkTypeId() }} \u2014</option>\n @for (root of rootCandidates(); track root.rtId) {\n <option [value]=\"root.rtId\" [title]=\"root.description\">{{ root.name }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshRoots()\" title=\"Refresh tree list\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.folderOpen\"\n (click)=\"pickRoot()\" title=\"Browse for entity\">Browse...</button>\n\n @if (selectedRoot(); as root) {\n <div class=\"toolbar-spacer\"></div>\n <span class=\"toolbar-meta\">\n <span class=\"meta-name\">{{ root.name }}</span>\n <span class=\"meta-type\">{{ root.ckTypeId }}</span>\n </span>\n }\n </div>\n\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Validation:</label>\n <select class=\"root-select\"\n [value]=\"selectedPipeline()?.rtId ?? ''\"\n (change)=\"onPipelineSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ config.validationPipelineCkTypeId }} \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n @if (tenantId) {\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedPipeline() || validationRunning() || validationLoading()\"\n (click)=\"runValidation()\"\n [title]=\"validationRunning() ? 'Validation running\u2026' : 'Run pipeline + load report'\">\n @if (validationRunning()) { Running\u2026 } @else { Run }\n </button>\n }\n <button kendoButton fillMode=\"solid\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!selectedPipeline() || validationLoading() || validationRunning()\"\n (click)=\"refreshValidation()\">Load Report</button>\n @if (validationSummary()) {\n <button kendoButton fillMode=\"flat\" size=\"small\"\n (click)=\"clearValidation()\">Clear</button>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (validationLoading()) {\n <span class=\"toolbar-meta\">Loading\u2026</span>\n } @else if (validationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (validationSummary(); as s) {\n <span class=\"validation-summary\">\n <span class=\"badge badge-error\" title=\"error\">{{ s.error }} err</span>\n <span class=\"badge badge-warning\" title=\"warning\">{{ s.warning }} warn</span>\n <span class=\"badge badge-ok\" title=\"ok\">{{ s.ok }} ok</span>\n <span class=\"badge badge-info\" title=\"info / unscoped\">{{ s.info }} info</span>\n <span class=\"badge\">{{ s.total }} total</span>\n @if (validationExecutedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n }\n </div>\n\n @if (tenantId) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Generation:</label>\n <select class=\"root-select\"\n [value]=\"selectedGenerationPipeline()?.rtId ?? ''\"\n (change)=\"onGenerationSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick an auto-mapping pipeline \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedGenerationPipeline() || generationRunning()\"\n (click)=\"runGeneration()\"\n [title]=\"generationRunning() ? 'Generation running\u2026' : 'Run the auto-mapping pipeline and reload counts'\">\n @if (generationRunning()) { Running\u2026 } @else { Generate }\n </button>\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (generationRunning()) {\n <span class=\"toolbar-meta\">Generating mappings\u2026</span>\n } @else if (generationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (generationStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.totalSuggestions !== undefined) {\n <span class=\"badge badge-ok\" title=\"mapping suggestions produced\">{{ s.totalSuggestions }} mappings</span>\n }\n @if (s.matchedContainers !== undefined && s.totalContainers !== undefined) {\n <span class=\"badge\" title=\"containers (e.g. rooms) matched to a target\">\n {{ s.matchedContainers }}/{{ s.totalContainers }} matched\n </span>\n }\n @if (s.unmatchedContainers) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unmatched: ' + (s.unmatchedContainerNames ?? []).join(', ')\">\n {{ s.unmatchedContainers }} unmatched\n </span>\n }\n @if (generationCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (generationCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n @if (tenantId && (exportBackupPipeline() || importBackupPipeline())) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Backup:</label>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.download\"\n [disabled]=\"!exportBackupPipeline() || backupRunning() !== null\"\n (click)=\"exportMappings()\"\n title=\"Run the export pipeline and download the mapping document as JSON\">\n @if (backupRunning() === 'export') { Exporting\u2026 } @else { Export }\n </button>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.upload\"\n [disabled]=\"!importBackupPipeline() || backupRunning() !== null\"\n (click)=\"importFileInput.click()\"\n title=\"Import a previously exported mapping document (JSON)\">\n @if (backupRunning() === 'import') { Importing\u2026 } @else { Import\u2026 }\n </button>\n <input #importFileInput type=\"file\" accept=\".json,application/json\" hidden\n (change)=\"onImportFileSelected($event)\" />\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (backupRunning() === 'export') {\n <span class=\"toolbar-meta\">Exporting mappings\u2026</span>\n } @else if (backupRunning() === 'import') {\n <span class=\"toolbar-meta\">Importing mappings\u2026</span>\n } @else if (backupError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (importStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.resolved !== undefined) {\n <span class=\"badge badge-ok\" title=\"mappings resolved and imported\">{{ s.resolved }} imported</span>\n }\n @if (s.unresolved) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unresolved: ' + unresolvedImportNames()\">\n {{ s.unresolved }} unresolved\n </span>\n }\n @if (s.total !== undefined) {\n <span class=\"badge\">{{ s.total }} total</span>\n }\n @if (importCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (importCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Import completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n <div class=\"coverage-body\">\n <div class=\"coverage-tree-pane\">\n @if (selectedRoot()) {\n <mm-tree-view\n [dataSource]=\"dataSource\"\n (nodeSelected)=\"onNodeSelected($event)\">\n </mm-tree-view>\n } @else {\n <div class=\"empty-hint\">\n Select a tree to start. Counts in brackets show how many mappings\n point to that node.\n </div>\n }\n </div>\n\n <div class=\"coverage-detail-pane\">\n @if (selectedNode(); as node) {\n <div class=\"detail-header\">\n <div class=\"detail-titles\">\n <h3 class=\"detail-name\">{{ node.name }}</h3>\n <div class=\"detail-subtitle\">{{ node.ckTypeId }}@{{ node.rtId }}</div>\n </div>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshSelected()\" title=\"Refresh\"></button>\n </div>\n\n <div class=\"detail-section-title\">\n <span>Mappings</span>\n @if (summaryLine(); as s) {\n <span class=\"detail-summary\">{{ s }}</span>\n }\n <span class=\"toolbar-spacer\"></span>\n <button kendoButton themeColor=\"primary\" size=\"small\" [svgIcon]=\"icons.plus\"\n (click)=\"addMapping()\">Add</button>\n </div>\n\n @if (mappingsLoading()) {\n <div class=\"empty-hint\">Loading mappings\u2026</div>\n } @else if (mappingsError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (mappings().length === 0) {\n <div class=\"empty-hint\">\n No mappings reference this node yet. Add one using the button above.\n </div>\n } @else {\n <ul class=\"mapping-list\">\n @for (mapping of mappings(); track trackByRtId($index, mapping)) {\n <li class=\"mapping-row\" [class.mapping-disabled]=\"!mapping.enabled\">\n <div class=\"mapping-line\">\n <span class=\"mapping-name\">\n {{ mapping.name || 'Mapping ' + ($index + 1) }}\n </span>\n @if (!mapping.enabled) {\n <span class=\"mapping-badge mapping-badge-off\">disabled</span>\n }\n </div>\n <div class=\"mapping-details\">\n <span class=\"kv\">\n <span class=\"kv-key\">Source:</span>\n <span class=\"kv-val\">\n {{ mapping.sourceName || mapping.sourceRtId || '\u2014 not linked \u2014' }}\n </span>\n </span>\n @if (mapping.sourceAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">Attr:</span>\n <span class=\"kv-val\">{{ mapping.sourceAttributePath }}</span>\n </span>\n }\n @if (mapping.mappingExpression) {\n <span class=\"kv\">\n <span class=\"kv-key\">Expr:</span>\n <code class=\"kv-val\">{{ mapping.mappingExpression }}</code>\n </span>\n }\n @if (mapping.targetAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">\u2192</span>\n <span class=\"kv-val\">{{ mapping.targetAttributePath }}</span>\n </span>\n }\n </div>\n <div class=\"mapping-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.pencil\"\n (click)=\"editMapping(mapping)\"\n title=\"Edit mapping\">Edit\u2026</button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.trash\"\n (click)=\"deleteMapping(mapping)\"\n title=\"Delete mapping\"></button>\n </div>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"empty-hint\">\n Select a node from the tree to view and edit its mappings.\n </div>\n }\n </div>\n </div>\n }\n\n @if (activeTab() === 'orphans') {\n <div class=\"coverage-toolbar\">\n <label class=\"toolbar-label\">Source type:</label>\n <select class=\"root-select\"\n [value]=\"orphanCkType() ?? ''\"\n (change)=\"onOrphanCkTypeChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a source type \u2014</option>\n @for (ckType of config.sourceCandidateCkTypeIds; track ckType) {\n <option [value]=\"ckType\">{{ ckType }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!orphanCkType() || orphanLoading()\"\n (click)=\"refreshOrphans()\" title=\"Reload\"></button>\n <span class=\"orphan-search-wrap\">\n <input type=\"text\" class=\"root-select orphan-search\"\n placeholder=\"Search name, room, description\u2026\"\n [value]=\"orphanSearchText()\"\n (input)=\"orphanSearchText.set($any($event.target).value)\" />\n @if (orphanSearchText()) {\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.x\"\n class=\"orphan-search-clear\"\n (click)=\"orphanSearchText.set('')\"\n title=\"Clear search\" aria-label=\"Clear search\"></button>\n }\n </span>\n <label class=\"orphan-toggle\">\n <input type=\"checkbox\" [checked]=\"orphanHideMapped()\" (change)=\"toggleOrphanHideMapped()\" />\n Hide already-mapped\n </label>\n <label class=\"toolbar-label\">Group by:</label>\n <select class=\"root-select\"\n [value]=\"orphanGroupParentType() ?? ''\"\n (change)=\"onOrphanGroupParentTypeChange($any($event.target).value)\">\n <option value=\"\">(no grouping)</option>\n @for (t of orphanAvailableParentTypes(); track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n @if (orphanGroupParentType()) {\n <kendo-multiselect class=\"orphan-group-filter\"\n [data]=\"orphanAvailableGroupNames()\"\n [value]=\"orphanSelectedGroupNames()\"\n (valueChange)=\"onOrphanGroupNamesChange($event)\"\n [autoClose]=\"false\"\n [clearButton]=\"true\"\n size=\"small\"\n placeholder=\"Filter groups\u2026\"\n title=\"Show only the selected groups (e.g. specific categories)\">\n </kendo-multiselect>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanVisibleList().length === 0\"\n (click)=\"selectAllVisibleOrphans()\"\n title=\"Select every row visible under the current filter\">Select all</button>\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"clearOrphanSelection()\">Clear</button>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"bulkMapSelected()\"\n title=\"Create one mapping per selected source (shared target + paths)\">\n Map {{ orphanSelectedCount() }} selected\u2026\n </button>\n\n @if (orphanStats(); as s) {\n <span class=\"validation-summary\">\n @if (orphanSearchText().trim() || orphanSelectedGroupNames().length > 0) {\n <span class=\"badge badge-info\" title=\"rows matching search + group filter\">{{ orphanVisibleList().length }} shown</span>\n }\n <span class=\"badge badge-error\" title=\"unmapped \u2014 no DataPointMapping yet\">{{ s.unmapped }} unmapped</span>\n <span class=\"badge badge-ok\" title=\"already covered by at least one mapping\">{{ s.mapped }} mapped</span>\n <span class=\"badge\">{{ s.total }} total</span>\n </span>\n }\n </div>\n\n <div class=\"orphan-body\">\n @if (orphanLoading()) {\n <div class=\"empty-hint\">Loading source candidates\u2026</div>\n } @else if (orphanError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (orphanVisibleList().length === 0) {\n <div class=\"empty-hint\">\n @if (orphanSelectedGroupNames().length > 0) {\n No entries in the selected group(s) match the current filters.\n } @else if (orphanSearchText().trim()) {\n No entries match \"{{ orphanSearchText() }}\".\n } @else if (orphanHideMapped()) {\n All {{ orphanCkType() }} entities are mapped at least once. \uD83C\uDF89\n } @else {\n No entities of type {{ orphanCkType() }} found.\n }\n </div>\n } @else if (orphanGroupParentType()) {\n @for (group of orphanGroupedList(); track group.key) {\n <div class=\"orphan-group\">\n <div class=\"orphan-group-header\">\n <span class=\"orphan-group-label\">{{ group.label }}</span>\n <span class=\"orphan-group-count\">{{ group.items.length }}</span>\n </div>\n <ul class=\"orphan-list\">\n @for (item of group.items; track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n </div>\n }\n } @else {\n <ul class=\"orphan-list\">\n @for (item of orphanVisibleList(); track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n }\n\n <ng-template #orphanRowTpl let-item>\n <li class=\"orphan-row\" [class.orphan-mapped]=\"item.mappingCount > 0\">\n <div class=\"orphan-line\">\n <input type=\"checkbox\" class=\"orphan-check\"\n [checked]=\"isOrphanSelected(item.rtId)\"\n (change)=\"toggleOrphanSelected(item.rtId)\"\n [attr.aria-label]=\"'Select ' + item.name\" />\n <span class=\"orphan-name\">{{ item.name }}</span>\n @if (item.mappingCount > 0) {\n <span class=\"orphan-badge orphan-badge-mapped\">\n {{ item.mappingCount }} mapping{{ item.mappingCount === 1 ? '' : 's' }}\n </span>\n } @else {\n <span class=\"orphan-badge orphan-badge-unmapped\">unmapped</span>\n }\n </div>\n @if (item.parentPath.length > 0) {\n <div class=\"orphan-breadcrumb\" [attr.title]=\"'Parent chain (root-first)'\">\n @for (parent of breadcrumbFor(item); track parent.rtId; let last = $last) {\n <span class=\"crumb\">{{ parent.name }}</span>\n @if (!last) { <span class=\"crumb-sep\">\u203A</span> }\n }\n </div>\n }\n <div class=\"orphan-meta\">\n <span class=\"kv-val\">{{ item.ckTypeId }}&#64;{{ item.rtId }}</span>\n </div>\n @if (item.description) {\n <div class=\"orphan-description\">{{ item.description }}</div>\n }\n <div class=\"orphan-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.plus\"\n (click)=\"createMappingFromOrphan(item)\"\n title=\"Create mapping pre-linked to this source\">\n Map\u2026\n </button>\n </div>\n </li>\n </ng-template>\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.coverage-root{display:flex;flex-direction:column;flex:1;min-height:0;gap:12px}.coverage-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 12px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.coverage-toolbar .toolbar-label{flex:0 0 96px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.coverage-toolbar .root-select{flex:0 0 280px;min-width:0;padding:4px 8px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:var(--theme-bg-elevated, var(--kendo-color-surface, #fff));color:var(--theme-text-primary, inherit);font-size:.9rem;height:30px}.coverage-toolbar .orphan-search-wrap{display:inline-flex;align-items:center;gap:2px}.coverage-toolbar .orphan-search-wrap .orphan-search{flex:1 1 220px;min-width:140px}.coverage-toolbar .orphan-group-filter{flex:0 1 320px;min-width:160px}.coverage-toolbar .toolbar-spacer{flex:1}.coverage-toolbar .toolbar-meta{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.coverage-toolbar .toolbar-meta .meta-name{font-size:.85rem;font-weight:600}.coverage-toolbar .toolbar-meta .meta-type{font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.coverage-body{flex:1;display:flex;gap:12px;min-height:0}@media(max-width:900px){.coverage-body{flex-direction:column}.coverage-tree-pane{flex:0 0 38vh;min-width:0;min-height:180px}.coverage-detail-pane{min-height:180px}.coverage-toolbar .toolbar-label{flex:0 0 auto}.coverage-toolbar .root-select{flex:1 1 200px;max-width:100%}}.coverage-tree-pane{flex:0 0 40%;min-width:240px;display:flex;flex-direction:column;min-height:0;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);overflow:auto}.coverage-detail-pane{flex:1;min-width:0;display:flex;flex-direction:column;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);padding:12px 14px;gap:12px;overflow:auto}.detail-header{display:flex;align-items:flex-start;gap:8px}.detail-header .detail-titles{flex:1;min-width:0}.detail-header .detail-name{margin:0;font-size:1.05rem;font-weight:600;word-break:break-word}.detail-header .detail-subtitle{font-size:.72rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d);word-break:break-all}.detail-section-title{display:flex;align-items:center;gap:10px;font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.detail-section-title .toolbar-spacer{flex:1}.detail-section-title .detail-summary{text-transform:none;letter-spacing:0;font-weight:500;color:var(--kendo-color-on-app-surface, inherit);font-size:.78rem}.mapping-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.mapping-row{border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.mapping-row.mapping-disabled{opacity:.55}.mapping-line{display:flex;align-items:center;gap:8px}.mapping-line .mapping-name{font-weight:600;font-size:.9rem}.mapping-badge{font-size:.65rem;text-transform:uppercase;letter-spacing:.5px;padding:1px 6px;border-radius:8px;border:1px solid var(--kendo-color-border, #dee2e6)}.mapping-badge.mapping-badge-off{color:var(--kendo-color-subtle, #6c757d)}.mapping-details{display:flex;flex-wrap:wrap;gap:10px;font-size:.8rem}.mapping-details .kv{display:inline-flex;align-items:baseline;gap:4px}.mapping-details .kv-key{font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.mapping-details code.kv-val{font-family:monospace;background:var(--kendo-color-surface, transparent);padding:1px 4px;border-radius:3px}.mapping-actions{display:flex;gap:6px;justify-content:flex-end}.empty-hint,.error-hint{padding:12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d);text-align:center}.error-hint{color:var(--kendo-color-error, #dc3545)}.coverage-tabs{display:flex;gap:0;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6))}.coverage-tab{padding:8px 16px;border:none;background:transparent;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-size:.85rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px}.coverage-tab:hover{color:var(--theme-text-primary, inherit)}.coverage-tab.active{color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358));border-bottom-color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358))}.coverage-tab .tab-badge{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border-radius:10px;padding:1px 8px;font-size:.7rem;font-weight:700}.orphan-toggle{display:inline-flex;align-items:center;gap:6px;font-size:.8rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));cursor:pointer}.orphan-body{flex:1;min-height:0;overflow:auto;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);padding:8px}.orphan-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.orphan-row{display:flex;flex-direction:column;gap:4px;padding:8px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-left-width:3px;border-left-color:var(--kendo-color-error, #dc3545);border-radius:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.orphan-row.orphan-mapped{border-left-color:var(--kendo-color-success, #28a745);opacity:.7}.orphan-row .orphan-line{display:flex;align-items:center;gap:8px}.orphan-row .orphan-line .orphan-check{flex-shrink:0;margin:0;cursor:pointer;accent-color:var(--kendo-color-primary, #ff6358)}.orphan-row .orphan-line .orphan-name{flex:1;font-weight:600;font-size:.9rem}.orphan-row .orphan-badge{font-size:.7rem;padding:1px 8px;border-radius:10px;text-transform:uppercase;letter-spacing:.5px;font-weight:600}.orphan-row .orphan-badge-unmapped{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border:1px solid var(--kendo-color-error, #dc3545)}.orphan-row .orphan-badge-mapped{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);color:var(--kendo-color-success, #28a745);border:1px solid var(--kendo-color-success, #28a745)}.orphan-row .orphan-meta{font-family:monospace;font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.orphan-row .orphan-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:4px;font-size:.75rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.orphan-row .orphan-breadcrumb .crumb{line-height:1.3}.orphan-row .orphan-breadcrumb .crumb-sep{opacity:.55;font-weight:600}.orphan-row .orphan-description{font-size:.78rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.orphan-row .orphan-actions{display:flex;gap:6px;justify-content:flex-end}.orphan-group{display:flex;flex-direction:column;gap:6px}.orphan-group+.orphan-group{margin-top:14px}.orphan-group .orphan-group-header{display:flex;align-items:baseline;gap:8px;padding:4px 8px;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));font-size:.85rem;font-weight:600;color:var(--theme-text-primary, inherit)}.orphan-group .orphan-group-header .orphan-group-label{flex:1}.orphan-group .orphan-group-header .orphan-group-count{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f1f3f5)) 80%,transparent);border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:10px;padding:0 8px}.validation-summary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.badge{font-size:.7rem;padding:2px 8px;border-radius:10px;background:var(--kendo-color-surface, #f1f3f5);border:1px solid var(--kendo-color-border, #dee2e6)}.badge-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 18%,transparent);border-color:var(--kendo-color-error, #dc3545);color:var(--kendo-color-error, #dc3545);font-weight:600}.badge-warning{background:color-mix(in srgb,var(--kendo-color-warning, #ffc107) 22%,transparent);border-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-warning-on, #6b5500);font-weight:600}.badge-ok{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);border-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-success, #28a745);font-weight:600}.badge-info{background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);border-color:var(--kendo-color-info, #0dcaf0);color:var(--kendo-color-info, #0dcaf0)}.validation-error-text{color:var(--kendo-color-error, #dc3545);font-size:.8rem}.validation-timestamp{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);margin-left:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: LayoutModule }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i3$1.MultiSelectComponent, selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: TreeComponent, selector: "mm-tree-view", inputs: ["dataSource"], outputs: ["nodeSelected", "nodeClick", "nodeDoubleClick", "nodeDrop", "expand", "collapse"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
21412
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: MappingCoverageTreeComponent, isStandalone: true, selector: "mm-mapping-coverage-tree", inputs: { config: "config", initialRoot: "initialRoot", tenantId: "tenantId", expressionEvaluator: "expressionEvaluator" }, outputs: { entitySelected: "entitySelected" }, providers: [MappingCoverageTreeDataSource], viewQueries: [{ propertyName: "treeView", first: true, predicate: TreeComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"coverage-root\">\n @if (config.sourceCandidateCkTypeIds.length > 0) {\n <div class=\"coverage-tabs\" role=\"tablist\">\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'coverage'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'coverage'\"\n (click)=\"selectTab('coverage')\">Coverage Tree</button>\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'orphans'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'orphans'\"\n (click)=\"selectTab('orphans')\">\n Orphan Sources\n @if (orphanStats(); as s) {\n @if (s.unmapped > 0) { <span class=\"tab-badge\">{{ s.unmapped }}</span> }\n }\n </button>\n </div>\n }\n\n @if (activeTab() === 'coverage') {\n <div class=\"coverage-toolbar\">\n <mm-perspective-switcher\n [perspectives]=\"perspectives()\"\n [activeKey]=\"activePerspectiveKey()\"\n (perspectiveChange)=\"onPerspectiveChange($event)\"></mm-perspective-switcher>\n <label class=\"toolbar-label\">Tree:</label>\n <select class=\"root-select\"\n [value]=\"selectedRoot()?.rtId ?? ''\"\n (change)=\"onRootSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ activeRootCkTypeId() }} \u2014</option>\n @for (root of rootCandidates(); track root.rtId) {\n <option [value]=\"root.rtId\" [title]=\"root.description\">{{ root.name }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshRoots()\" title=\"Refresh tree list\" aria-label=\"Refresh tree list\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.folderOpen\"\n (click)=\"pickRoot()\" title=\"Browse for entity\">Browse...</button>\n\n @if (selectedRoot(); as root) {\n <div class=\"toolbar-spacer\"></div>\n <span class=\"toolbar-meta\">\n <span class=\"meta-name\">{{ root.name }}</span>\n <span class=\"meta-type\">{{ root.ckTypeId }}</span>\n </span>\n }\n </div>\n\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Validation:</label>\n <select class=\"root-select\"\n [value]=\"selectedPipeline()?.rtId ?? ''\"\n (change)=\"onPipelineSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ config.validationPipelineCkTypeId }} \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n @if (tenantId) {\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedPipeline() || validationRunning() || validationLoading()\"\n (click)=\"runValidation()\"\n [title]=\"validationRunning() ? 'Validation running\u2026' : 'Run pipeline + load report'\">\n @if (validationRunning()) { Running\u2026 } @else { Run }\n </button>\n }\n <button kendoButton fillMode=\"solid\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!selectedPipeline() || validationLoading() || validationRunning()\"\n (click)=\"refreshValidation()\">Load Report</button>\n @if (validationSummary()) {\n <button kendoButton fillMode=\"flat\" size=\"small\"\n (click)=\"clearValidation()\">Clear</button>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (validationLoading()) {\n <span class=\"toolbar-meta\">Loading\u2026</span>\n } @else if (validationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (validationSummary(); as s) {\n <span class=\"validation-summary\">\n <span class=\"badge badge-error\" title=\"error\">{{ s.error }} err</span>\n <span class=\"badge badge-warning\" title=\"warning\">{{ s.warning }} warn</span>\n <span class=\"badge badge-ok\" title=\"ok\">{{ s.ok }} ok</span>\n <span class=\"badge badge-info\" title=\"info / unscoped\">{{ s.info }} info</span>\n <span class=\"badge\">{{ s.total }} total</span>\n @if (validationExecutedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n }\n </div>\n\n @if (tenantId) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Generation:</label>\n <select class=\"root-select\"\n [value]=\"selectedGenerationPipeline()?.rtId ?? ''\"\n (change)=\"onGenerationSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick an auto-mapping pipeline \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedGenerationPipeline() || generationRunning()\"\n (click)=\"runGeneration()\"\n [title]=\"generationRunning() ? 'Generation running\u2026' : 'Run the auto-mapping pipeline and reload counts'\">\n @if (generationRunning()) { Running\u2026 } @else { Generate }\n </button>\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (generationRunning()) {\n <span class=\"toolbar-meta\">Generating mappings\u2026</span>\n } @else if (generationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (generationStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.totalSuggestions !== undefined) {\n <span class=\"badge badge-ok\" title=\"mapping suggestions produced\">{{ s.totalSuggestions }} mappings</span>\n }\n @if (s.matchedContainers !== undefined && s.totalContainers !== undefined) {\n <span class=\"badge\" title=\"containers (e.g. rooms) matched to a target\">\n {{ s.matchedContainers }}/{{ s.totalContainers }} matched\n </span>\n }\n @if (s.unmatchedContainers) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unmatched: ' + (s.unmatchedContainerNames ?? []).join(', ')\">\n {{ s.unmatchedContainers }} unmatched\n </span>\n }\n @if (generationCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (generationCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n @if (tenantId && (exportBackupPipeline() || importBackupPipeline())) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Backup:</label>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.download\"\n [disabled]=\"!exportBackupPipeline() || backupRunning() !== null\"\n (click)=\"exportMappings()\"\n title=\"Run the export pipeline and download the mapping document as JSON\">\n @if (backupRunning() === 'export') { Exporting\u2026 } @else { Export }\n </button>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.upload\"\n [disabled]=\"!importBackupPipeline() || backupRunning() !== null\"\n (click)=\"importFileInput.click()\"\n title=\"Import a previously exported mapping document (JSON)\">\n @if (backupRunning() === 'import') { Importing\u2026 } @else { Import\u2026 }\n </button>\n <input #importFileInput type=\"file\" accept=\".json,application/json\" hidden\n (change)=\"onImportFileSelected($event)\" />\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (backupRunning() === 'export') {\n <span class=\"toolbar-meta\">Exporting mappings\u2026</span>\n } @else if (backupRunning() === 'import') {\n <span class=\"toolbar-meta\">Importing mappings\u2026</span>\n } @else if (backupError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (importStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.resolved !== undefined) {\n <span class=\"badge badge-ok\" title=\"mappings resolved and imported\">{{ s.resolved }} imported</span>\n }\n @if (s.unresolved) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unresolved: ' + unresolvedImportNames()\">\n {{ s.unresolved }} unresolved\n </span>\n }\n @if (s.total !== undefined) {\n <span class=\"badge\">{{ s.total }} total</span>\n }\n @if (importCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (importCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Import completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n <div class=\"coverage-body\">\n <div class=\"coverage-tree-pane\">\n @if (selectedRoot()) {\n <mm-tree-view\n [dataSource]=\"dataSource\"\n (nodeSelected)=\"onNodeSelected($event)\">\n </mm-tree-view>\n } @else {\n <div class=\"empty-hint\">\n Select a tree to start. Counts in brackets show how many mappings\n point to that node.\n </div>\n }\n </div>\n\n <div class=\"coverage-detail-pane\">\n @if (selectedNode(); as node) {\n <div class=\"detail-header\">\n <div class=\"detail-titles\">\n <h3 class=\"detail-name\">{{ node.name }}</h3>\n <div class=\"detail-subtitle\">{{ node.ckTypeId }}@{{ node.rtId }}</div>\n </div>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshSelected()\" title=\"Refresh\" aria-label=\"Refresh mappings\"></button>\n </div>\n\n <div class=\"detail-section-title\">\n <span>Mappings</span>\n @if (summaryLine(); as s) {\n <span class=\"detail-summary\">{{ s }}</span>\n }\n <span class=\"toolbar-spacer\"></span>\n <button kendoButton themeColor=\"primary\" size=\"small\" [svgIcon]=\"icons.plus\"\n (click)=\"addMapping()\">Add</button>\n </div>\n\n @if (mappingsLoading()) {\n <div class=\"empty-hint\">Loading mappings\u2026</div>\n } @else if (mappingsError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (mappings().length === 0) {\n <div class=\"empty-hint\">\n No mappings reference this node yet. Add one using the button above.\n </div>\n } @else {\n <ul class=\"mapping-list\">\n @for (mapping of mappings(); track trackByRtId($index, mapping)) {\n <li class=\"mapping-row\" [class.mapping-disabled]=\"!mapping.enabled\">\n <div class=\"mapping-line\">\n <span class=\"mapping-name\">\n {{ mapping.name || 'Mapping ' + ($index + 1) }}\n </span>\n @if (!mapping.enabled) {\n <span class=\"mapping-badge mapping-badge-off\">disabled</span>\n }\n </div>\n <div class=\"mapping-details\">\n <span class=\"kv\">\n <span class=\"kv-key\">Source:</span>\n <span class=\"kv-val\">\n {{ mapping.sourceName || mapping.sourceRtId || '\u2014 not linked \u2014' }}\n </span>\n </span>\n @if (mapping.sourceAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">Attr:</span>\n <span class=\"kv-val\">{{ mapping.sourceAttributePath }}</span>\n </span>\n }\n @if (mapping.mappingExpression) {\n <span class=\"kv\">\n <span class=\"kv-key\">Expr:</span>\n <code class=\"kv-val\">{{ mapping.mappingExpression }}</code>\n </span>\n }\n @if (mapping.targetAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">\u2192</span>\n <span class=\"kv-val\">{{ mapping.targetAttributePath }}</span>\n </span>\n }\n </div>\n <div class=\"mapping-actions\">\n <button kendoButton fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.pencil\"\n (click)=\"editMapping(mapping)\"\n title=\"Edit mapping\" [attr.aria-label]=\"'Edit mapping ' + (mapping.name || mapping.rtId)\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" themeColor=\"error\" [svgIcon]=\"icons.trash\"\n (click)=\"deleteMapping(mapping)\" data-action=\"delete\"\n title=\"Delete mapping\" [attr.aria-label]=\"'Delete mapping ' + (mapping.name || mapping.rtId)\"></button>\n </div>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"empty-hint\">\n Select a node from the tree to view and edit its mappings.\n </div>\n }\n </div>\n </div>\n }\n\n @if (activeTab() === 'orphans') {\n <div class=\"coverage-toolbar\">\n <label class=\"toolbar-label\">Source type:</label>\n <select class=\"root-select\"\n [value]=\"orphanCkType() ?? ''\"\n (change)=\"onOrphanCkTypeChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a source type \u2014</option>\n @for (ckType of config.sourceCandidateCkTypeIds; track ckType) {\n <option [value]=\"ckType\">{{ ckType }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!orphanCkType() || orphanLoading()\"\n (click)=\"refreshOrphans()\" title=\"Reload\" aria-label=\"Reload orphans\"></button>\n <span class=\"orphan-search-wrap\">\n <input type=\"text\" class=\"root-select orphan-search\"\n placeholder=\"Search name, room, description\u2026\"\n [value]=\"orphanSearchText()\"\n (input)=\"orphanSearchText.set($any($event.target).value)\" />\n @if (orphanSearchText()) {\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.x\"\n class=\"orphan-search-clear\"\n (click)=\"orphanSearchText.set('')\"\n title=\"Clear search\" aria-label=\"Clear search\"></button>\n }\n </span>\n <label class=\"orphan-toggle\">\n <input type=\"checkbox\" [checked]=\"orphanHideMapped()\" (change)=\"toggleOrphanHideMapped()\" />\n Hide already-mapped\n </label>\n <label class=\"toolbar-label\">Group by:</label>\n <select class=\"root-select\"\n [value]=\"orphanGroupParentType() ?? ''\"\n (change)=\"onOrphanGroupParentTypeChange($any($event.target).value)\">\n <option value=\"\">(no grouping)</option>\n @for (t of orphanAvailableParentTypes(); track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n @if (orphanGroupParentType()) {\n <kendo-multiselect class=\"orphan-group-filter\"\n [data]=\"orphanAvailableGroupNames()\"\n [value]=\"orphanSelectedGroupNames()\"\n (valueChange)=\"onOrphanGroupNamesChange($event)\"\n [autoClose]=\"false\"\n [clearButton]=\"true\"\n size=\"small\"\n placeholder=\"Filter groups\u2026\"\n title=\"Show only the selected groups (e.g. specific categories)\">\n </kendo-multiselect>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanVisibleList().length === 0\"\n (click)=\"selectAllVisibleOrphans()\"\n title=\"Select every row visible under the current filter\">Select all</button>\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"clearOrphanSelection()\">Clear</button>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"bulkMapSelected()\"\n title=\"Create one mapping per selected source (shared target + paths)\">\n Map {{ orphanSelectedCount() }} selected\u2026\n </button>\n\n @if (orphanStats(); as s) {\n <span class=\"validation-summary\">\n @if (orphanSearchText().trim() || orphanSelectedGroupNames().length > 0) {\n <span class=\"badge badge-info\" title=\"rows matching search + group filter\">{{ orphanVisibleList().length }} shown</span>\n }\n <span class=\"badge badge-error\" title=\"unmapped \u2014 no DataPointMapping yet\">{{ s.unmapped }} unmapped</span>\n <span class=\"badge badge-ok\" title=\"already covered by at least one mapping\">{{ s.mapped }} mapped</span>\n <span class=\"badge\">{{ s.total }} total</span>\n </span>\n }\n </div>\n\n <div class=\"orphan-body\">\n @if (orphanLoading()) {\n <div class=\"empty-hint\">Loading source candidates\u2026</div>\n } @else if (orphanError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (orphanVisibleList().length === 0) {\n <div class=\"empty-hint\">\n @if (orphanSelectedGroupNames().length > 0) {\n No entries in the selected group(s) match the current filters.\n } @else if (orphanSearchText().trim()) {\n No entries match \"{{ orphanSearchText() }}\".\n } @else if (orphanHideMapped()) {\n All {{ orphanCkType() }} entities are mapped at least once. \uD83C\uDF89\n } @else {\n No entities of type {{ orphanCkType() }} found.\n }\n </div>\n } @else if (orphanGroupParentType()) {\n @for (group of orphanGroupedList(); track group.key) {\n <div class=\"orphan-group\">\n <div class=\"orphan-group-header\">\n <span class=\"orphan-group-label\">{{ group.label }}</span>\n <span class=\"orphan-group-count\">{{ group.items.length }}</span>\n </div>\n <ul class=\"orphan-list\">\n @for (item of group.items; track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n </div>\n }\n } @else {\n <ul class=\"orphan-list\">\n @for (item of orphanVisibleList(); track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n }\n\n <ng-template #orphanRowTpl let-item>\n <li class=\"orphan-row\" [class.orphan-mapped]=\"item.mappingCount > 0\">\n <div class=\"orphan-line\">\n <input type=\"checkbox\" class=\"orphan-check\"\n [checked]=\"isOrphanSelected(item.rtId)\"\n (change)=\"toggleOrphanSelected(item.rtId)\"\n [attr.aria-label]=\"'Select ' + item.name\" />\n <span class=\"orphan-name\">{{ item.name }}</span>\n @if (item.mappingCount > 0) {\n <span class=\"orphan-badge orphan-badge-mapped\">\n {{ item.mappingCount }} mapping{{ item.mappingCount === 1 ? '' : 's' }}\n </span>\n } @else {\n <span class=\"orphan-badge orphan-badge-unmapped\">unmapped</span>\n }\n </div>\n @if (item.parentPath.length > 0) {\n <div class=\"orphan-breadcrumb\" [attr.title]=\"'Parent chain (root-first)'\">\n @for (parent of breadcrumbFor(item); track parent.rtId; let last = $last) {\n <span class=\"crumb\">{{ parent.name }}</span>\n @if (!last) { <span class=\"crumb-sep\">\u203A</span> }\n }\n </div>\n }\n <div class=\"orphan-meta\">\n <span class=\"kv-val\">{{ item.ckTypeId }}&#64;{{ item.rtId }}</span>\n </div>\n @if (item.description) {\n <div class=\"orphan-description\">{{ item.description }}</div>\n }\n <div class=\"orphan-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.plus\"\n (click)=\"createMappingFromOrphan(item)\"\n title=\"Create mapping pre-linked to this source\">\n Map\u2026\n </button>\n </div>\n </li>\n </ng-template>\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.coverage-root{display:flex;flex-direction:column;flex:1;min-height:0;gap:12px}.coverage-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 12px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.coverage-toolbar .toolbar-label{flex:0 0 96px;font-size:.75rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.coverage-toolbar .root-select{flex:0 0 280px;min-width:0;padding:4px 8px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:var(--theme-bg-elevated, var(--kendo-color-surface, #fff));color:var(--theme-text-primary, inherit);font-size:.9rem;height:30px}.coverage-toolbar .orphan-search-wrap{display:inline-flex;align-items:center;gap:2px}.coverage-toolbar .orphan-search-wrap .orphan-search{flex:1 1 220px;min-width:140px}.coverage-toolbar .orphan-group-filter{flex:0 1 320px;min-width:160px}.coverage-toolbar .toolbar-spacer{flex:1}.coverage-toolbar .toolbar-meta{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.coverage-toolbar .toolbar-meta .meta-name{font-size:.85rem;font-weight:600}.coverage-toolbar .toolbar-meta .meta-type{font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.coverage-body{flex:1;display:flex;gap:12px;min-height:0}@media(max-width:900px){.coverage-body{flex-direction:column}.coverage-tree-pane{flex:0 0 38vh;min-width:0;min-height:180px}.coverage-detail-pane{min-height:180px}.coverage-toolbar .toolbar-label{flex:0 0 auto}.coverage-toolbar .root-select{flex:1 1 200px;max-width:100%}}.coverage-tree-pane{flex:0 0 40%;min-width:240px;display:flex;flex-direction:column;min-height:0;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);overflow:auto}.coverage-detail-pane{flex:1;min-width:0;display:flex;flex-direction:column;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);padding:12px 14px;gap:12px;overflow:auto}.detail-header{display:flex;align-items:flex-start;gap:8px}.detail-header .detail-titles{flex:1;min-width:0}.detail-header .detail-name{margin:0;font-size:1.05rem;font-weight:600;word-break:break-word}.detail-header .detail-subtitle{font-size:.72rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d);word-break:break-all}.detail-section-title{display:flex;align-items:center;gap:10px;font-size:.78rem;font-weight:700;color:var(--kendo-color-subtle, #6c757d)}.detail-section-title .toolbar-spacer{flex:1}.detail-section-title .detail-summary{text-transform:none;font-weight:500;color:var(--kendo-color-on-app-surface, inherit);font-size:.78rem}.mapping-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.mapping-row{border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.mapping-row.mapping-disabled{opacity:.55}.mapping-line{display:flex;align-items:center;gap:8px}.mapping-line .mapping-name{font-weight:600;font-size:.9rem}.mapping-badge{font-size:.65rem;padding:1px 6px;border-radius:8px;border:1px solid var(--kendo-color-border, #dee2e6)}.mapping-badge.mapping-badge-off{color:var(--kendo-color-subtle, #6c757d)}.mapping-details{display:flex;flex-wrap:wrap;gap:10px;font-size:.8rem}.mapping-details .kv{display:inline-flex;align-items:baseline;gap:4px}.mapping-details .kv-key{font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.mapping-details code.kv-val{font-family:monospace;background:var(--kendo-color-surface, transparent);padding:1px 4px;border-radius:3px}.mapping-actions{display:flex;gap:6px;justify-content:flex-end}.empty-hint,.error-hint{padding:12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d);text-align:center}.error-hint{color:var(--kendo-color-error, #dc3545)}.coverage-tabs{display:flex;gap:0;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6))}.coverage-tab{padding:8px 16px;border:none;background:transparent;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-size:.85rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px}.coverage-tab:hover{color:var(--theme-text-primary, inherit)}.coverage-tab.active{color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358));border-bottom-color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358))}.coverage-tab .tab-badge{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border-radius:10px;padding:1px 8px;font-size:.7rem;font-weight:700}.orphan-toggle{display:inline-flex;align-items:center;gap:6px;font-size:.8rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));cursor:pointer}.orphan-body{flex:1;min-height:0;overflow:auto;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);padding:8px}.orphan-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.orphan-row{display:flex;flex-direction:column;gap:4px;padding:8px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-left-width:3px;border-left-color:var(--kendo-color-error, #dc3545);border-radius:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.orphan-row.orphan-mapped{border-left-color:var(--kendo-color-success, #28a745);opacity:.7}.orphan-row .orphan-line{display:flex;align-items:center;gap:8px}.orphan-row .orphan-line .orphan-check{flex-shrink:0;margin:0;cursor:pointer;accent-color:var(--kendo-color-primary, #ff6358)}.orphan-row .orphan-line .orphan-name{flex:1;font-weight:600;font-size:.9rem}.orphan-row .orphan-badge{font-size:.7rem;padding:1px 8px;border-radius:10px;font-weight:600}.orphan-row .orphan-badge-unmapped{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border:1px solid var(--kendo-color-error, #dc3545)}.orphan-row .orphan-badge-mapped{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);color:var(--kendo-color-success, #28a745);border:1px solid var(--kendo-color-success, #28a745)}.orphan-row .orphan-meta{font-family:monospace;font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.orphan-row .orphan-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:4px;font-size:.75rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.orphan-row .orphan-breadcrumb .crumb{line-height:1.3}.orphan-row .orphan-breadcrumb .crumb-sep{opacity:.55;font-weight:600}.orphan-row .orphan-description{font-size:.78rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.orphan-row .orphan-actions{display:flex;gap:6px;justify-content:flex-end}.orphan-group{display:flex;flex-direction:column;gap:6px}.orphan-group+.orphan-group{margin-top:14px}.orphan-group .orphan-group-header{display:flex;align-items:baseline;gap:8px;padding:4px 8px;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));font-size:.85rem;font-weight:600;color:var(--theme-text-primary, inherit)}.orphan-group .orphan-group-header .orphan-group-label{flex:1}.orphan-group .orphan-group-header .orphan-group-count{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f1f3f5)) 80%,transparent);border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:10px;padding:0 8px}.validation-summary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.badge{font-size:.7rem;padding:2px 8px;border-radius:10px;background:var(--kendo-color-surface, #f1f3f5);border:1px solid var(--kendo-color-border, #dee2e6)}.badge-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 18%,transparent);border-color:var(--kendo-color-error, #dc3545);color:var(--kendo-color-error, #dc3545);font-weight:600}.badge-warning{background:color-mix(in srgb,var(--kendo-color-warning, #ffc107) 22%,transparent);border-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-warning-on, #6b5500);font-weight:600}.badge-ok{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);border-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-success, #28a745);font-weight:600}.badge-info{background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);border-color:var(--kendo-color-info, #0dcaf0);color:var(--kendo-color-info, #0dcaf0)}.validation-error-text{color:var(--kendo-color-error, #dc3545);font-size:.8rem}.validation-timestamp{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);margin-left:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$1.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: "ngmodule", type: LayoutModule }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i3$1.MultiSelectComponent, selector: "kendo-multiselect", inputs: ["showStickyHeader", "focusableId", "autoClose", "loading", "data", "value", "valueField", "textField", "tabindex", "tabIndex", "size", "rounded", "fillMode", "placeholder", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "disabled", "itemDisabled", "checkboxes", "readonly", "filterable", "virtual", "popupSettings", "listHeight", "valuePrimitive", "clearButton", "tagMapper", "allowCustom", "valueNormalizer", "inputAttributes"], outputs: ["filterChange", "valueChange", "open", "opened", "close", "closed", "focus", "blur", "inputFocus", "inputBlur", "removeTag"], exportAs: ["kendoMultiSelect"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: TreeComponent, selector: "mm-tree-view", inputs: ["dataSource"], outputs: ["nodeSelected", "nodeClick", "nodeDoubleClick", "nodeDrop", "expand", "collapse"] }, { kind: "component", type: PerspectiveSwitcherComponent, selector: "mm-perspective-switcher", inputs: ["perspectives", "activeKey", "label"], outputs: ["perspectiveChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
20830
21413
  }
20831
21414
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: MappingCoverageTreeComponent, decorators: [{
20832
21415
  type: Component,
@@ -20839,7 +21422,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
20839
21422
  SVGIconModule,
20840
21423
  TreeComponent,
20841
21424
  PerspectiveSwitcherComponent,
20842
- ], providers: [MappingCoverageTreeDataSource], template: "<div class=\"coverage-root\">\n @if (config.sourceCandidateCkTypeIds.length > 0) {\n <div class=\"coverage-tabs\" role=\"tablist\">\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'coverage'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'coverage'\"\n (click)=\"selectTab('coverage')\">Coverage Tree</button>\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'orphans'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'orphans'\"\n (click)=\"selectTab('orphans')\">\n Orphan Sources\n @if (orphanStats(); as s) {\n @if (s.unmapped > 0) { <span class=\"tab-badge\">{{ s.unmapped }}</span> }\n }\n </button>\n </div>\n }\n\n @if (activeTab() === 'coverage') {\n <div class=\"coverage-toolbar\">\n <mm-perspective-switcher\n [perspectives]=\"perspectives()\"\n [activeKey]=\"activePerspectiveKey()\"\n (perspectiveChange)=\"onPerspectiveChange($event)\"></mm-perspective-switcher>\n <label class=\"toolbar-label\">Tree:</label>\n <select class=\"root-select\"\n [value]=\"selectedRoot()?.rtId ?? ''\"\n (change)=\"onRootSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ activeRootCkTypeId() }} \u2014</option>\n @for (root of rootCandidates(); track root.rtId) {\n <option [value]=\"root.rtId\" [title]=\"root.description\">{{ root.name }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshRoots()\" title=\"Refresh tree list\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.folderOpen\"\n (click)=\"pickRoot()\" title=\"Browse for entity\">Browse...</button>\n\n @if (selectedRoot(); as root) {\n <div class=\"toolbar-spacer\"></div>\n <span class=\"toolbar-meta\">\n <span class=\"meta-name\">{{ root.name }}</span>\n <span class=\"meta-type\">{{ root.ckTypeId }}</span>\n </span>\n }\n </div>\n\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Validation:</label>\n <select class=\"root-select\"\n [value]=\"selectedPipeline()?.rtId ?? ''\"\n (change)=\"onPipelineSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ config.validationPipelineCkTypeId }} \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n @if (tenantId) {\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedPipeline() || validationRunning() || validationLoading()\"\n (click)=\"runValidation()\"\n [title]=\"validationRunning() ? 'Validation running\u2026' : 'Run pipeline + load report'\">\n @if (validationRunning()) { Running\u2026 } @else { Run }\n </button>\n }\n <button kendoButton fillMode=\"solid\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!selectedPipeline() || validationLoading() || validationRunning()\"\n (click)=\"refreshValidation()\">Load Report</button>\n @if (validationSummary()) {\n <button kendoButton fillMode=\"flat\" size=\"small\"\n (click)=\"clearValidation()\">Clear</button>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (validationLoading()) {\n <span class=\"toolbar-meta\">Loading\u2026</span>\n } @else if (validationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (validationSummary(); as s) {\n <span class=\"validation-summary\">\n <span class=\"badge badge-error\" title=\"error\">{{ s.error }} err</span>\n <span class=\"badge badge-warning\" title=\"warning\">{{ s.warning }} warn</span>\n <span class=\"badge badge-ok\" title=\"ok\">{{ s.ok }} ok</span>\n <span class=\"badge badge-info\" title=\"info / unscoped\">{{ s.info }} info</span>\n <span class=\"badge\">{{ s.total }} total</span>\n @if (validationExecutedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n }\n </div>\n\n @if (tenantId) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Generation:</label>\n <select class=\"root-select\"\n [value]=\"selectedGenerationPipeline()?.rtId ?? ''\"\n (change)=\"onGenerationSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick an auto-mapping pipeline \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedGenerationPipeline() || generationRunning()\"\n (click)=\"runGeneration()\"\n [title]=\"generationRunning() ? 'Generation running\u2026' : 'Run the auto-mapping pipeline and reload counts'\">\n @if (generationRunning()) { Running\u2026 } @else { Generate }\n </button>\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (generationRunning()) {\n <span class=\"toolbar-meta\">Generating mappings\u2026</span>\n } @else if (generationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (generationStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.totalSuggestions !== undefined) {\n <span class=\"badge badge-ok\" title=\"mapping suggestions produced\">{{ s.totalSuggestions }} mappings</span>\n }\n @if (s.matchedContainers !== undefined && s.totalContainers !== undefined) {\n <span class=\"badge\" title=\"containers (e.g. rooms) matched to a target\">\n {{ s.matchedContainers }}/{{ s.totalContainers }} matched\n </span>\n }\n @if (s.unmatchedContainers) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unmatched: ' + (s.unmatchedContainerNames ?? []).join(', ')\">\n {{ s.unmatchedContainers }} unmatched\n </span>\n }\n @if (generationCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (generationCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n @if (tenantId && (exportBackupPipeline() || importBackupPipeline())) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Backup:</label>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.download\"\n [disabled]=\"!exportBackupPipeline() || backupRunning() !== null\"\n (click)=\"exportMappings()\"\n title=\"Run the export pipeline and download the mapping document as JSON\">\n @if (backupRunning() === 'export') { Exporting\u2026 } @else { Export }\n </button>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.upload\"\n [disabled]=\"!importBackupPipeline() || backupRunning() !== null\"\n (click)=\"importFileInput.click()\"\n title=\"Import a previously exported mapping document (JSON)\">\n @if (backupRunning() === 'import') { Importing\u2026 } @else { Import\u2026 }\n </button>\n <input #importFileInput type=\"file\" accept=\".json,application/json\" hidden\n (change)=\"onImportFileSelected($event)\" />\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (backupRunning() === 'export') {\n <span class=\"toolbar-meta\">Exporting mappings\u2026</span>\n } @else if (backupRunning() === 'import') {\n <span class=\"toolbar-meta\">Importing mappings\u2026</span>\n } @else if (backupError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (importStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.resolved !== undefined) {\n <span class=\"badge badge-ok\" title=\"mappings resolved and imported\">{{ s.resolved }} imported</span>\n }\n @if (s.unresolved) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unresolved: ' + unresolvedImportNames()\">\n {{ s.unresolved }} unresolved\n </span>\n }\n @if (s.total !== undefined) {\n <span class=\"badge\">{{ s.total }} total</span>\n }\n @if (importCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (importCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Import completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n <div class=\"coverage-body\">\n <div class=\"coverage-tree-pane\">\n @if (selectedRoot()) {\n <mm-tree-view\n [dataSource]=\"dataSource\"\n (nodeSelected)=\"onNodeSelected($event)\">\n </mm-tree-view>\n } @else {\n <div class=\"empty-hint\">\n Select a tree to start. Counts in brackets show how many mappings\n point to that node.\n </div>\n }\n </div>\n\n <div class=\"coverage-detail-pane\">\n @if (selectedNode(); as node) {\n <div class=\"detail-header\">\n <div class=\"detail-titles\">\n <h3 class=\"detail-name\">{{ node.name }}</h3>\n <div class=\"detail-subtitle\">{{ node.ckTypeId }}@{{ node.rtId }}</div>\n </div>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshSelected()\" title=\"Refresh\"></button>\n </div>\n\n <div class=\"detail-section-title\">\n <span>Mappings</span>\n @if (summaryLine(); as s) {\n <span class=\"detail-summary\">{{ s }}</span>\n }\n <span class=\"toolbar-spacer\"></span>\n <button kendoButton themeColor=\"primary\" size=\"small\" [svgIcon]=\"icons.plus\"\n (click)=\"addMapping()\">Add</button>\n </div>\n\n @if (mappingsLoading()) {\n <div class=\"empty-hint\">Loading mappings\u2026</div>\n } @else if (mappingsError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (mappings().length === 0) {\n <div class=\"empty-hint\">\n No mappings reference this node yet. Add one using the button above.\n </div>\n } @else {\n <ul class=\"mapping-list\">\n @for (mapping of mappings(); track trackByRtId($index, mapping)) {\n <li class=\"mapping-row\" [class.mapping-disabled]=\"!mapping.enabled\">\n <div class=\"mapping-line\">\n <span class=\"mapping-name\">\n {{ mapping.name || 'Mapping ' + ($index + 1) }}\n </span>\n @if (!mapping.enabled) {\n <span class=\"mapping-badge mapping-badge-off\">disabled</span>\n }\n </div>\n <div class=\"mapping-details\">\n <span class=\"kv\">\n <span class=\"kv-key\">Source:</span>\n <span class=\"kv-val\">\n {{ mapping.sourceName || mapping.sourceRtId || '\u2014 not linked \u2014' }}\n </span>\n </span>\n @if (mapping.sourceAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">Attr:</span>\n <span class=\"kv-val\">{{ mapping.sourceAttributePath }}</span>\n </span>\n }\n @if (mapping.mappingExpression) {\n <span class=\"kv\">\n <span class=\"kv-key\">Expr:</span>\n <code class=\"kv-val\">{{ mapping.mappingExpression }}</code>\n </span>\n }\n @if (mapping.targetAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">\u2192</span>\n <span class=\"kv-val\">{{ mapping.targetAttributePath }}</span>\n </span>\n }\n </div>\n <div class=\"mapping-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.pencil\"\n (click)=\"editMapping(mapping)\"\n title=\"Edit mapping\">Edit\u2026</button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.trash\"\n (click)=\"deleteMapping(mapping)\"\n title=\"Delete mapping\"></button>\n </div>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"empty-hint\">\n Select a node from the tree to view and edit its mappings.\n </div>\n }\n </div>\n </div>\n }\n\n @if (activeTab() === 'orphans') {\n <div class=\"coverage-toolbar\">\n <label class=\"toolbar-label\">Source type:</label>\n <select class=\"root-select\"\n [value]=\"orphanCkType() ?? ''\"\n (change)=\"onOrphanCkTypeChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a source type \u2014</option>\n @for (ckType of config.sourceCandidateCkTypeIds; track ckType) {\n <option [value]=\"ckType\">{{ ckType }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!orphanCkType() || orphanLoading()\"\n (click)=\"refreshOrphans()\" title=\"Reload\"></button>\n <span class=\"orphan-search-wrap\">\n <input type=\"text\" class=\"root-select orphan-search\"\n placeholder=\"Search name, room, description\u2026\"\n [value]=\"orphanSearchText()\"\n (input)=\"orphanSearchText.set($any($event.target).value)\" />\n @if (orphanSearchText()) {\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.x\"\n class=\"orphan-search-clear\"\n (click)=\"orphanSearchText.set('')\"\n title=\"Clear search\" aria-label=\"Clear search\"></button>\n }\n </span>\n <label class=\"orphan-toggle\">\n <input type=\"checkbox\" [checked]=\"orphanHideMapped()\" (change)=\"toggleOrphanHideMapped()\" />\n Hide already-mapped\n </label>\n <label class=\"toolbar-label\">Group by:</label>\n <select class=\"root-select\"\n [value]=\"orphanGroupParentType() ?? ''\"\n (change)=\"onOrphanGroupParentTypeChange($any($event.target).value)\">\n <option value=\"\">(no grouping)</option>\n @for (t of orphanAvailableParentTypes(); track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n @if (orphanGroupParentType()) {\n <kendo-multiselect class=\"orphan-group-filter\"\n [data]=\"orphanAvailableGroupNames()\"\n [value]=\"orphanSelectedGroupNames()\"\n (valueChange)=\"onOrphanGroupNamesChange($event)\"\n [autoClose]=\"false\"\n [clearButton]=\"true\"\n size=\"small\"\n placeholder=\"Filter groups\u2026\"\n title=\"Show only the selected groups (e.g. specific categories)\">\n </kendo-multiselect>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanVisibleList().length === 0\"\n (click)=\"selectAllVisibleOrphans()\"\n title=\"Select every row visible under the current filter\">Select all</button>\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"clearOrphanSelection()\">Clear</button>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"bulkMapSelected()\"\n title=\"Create one mapping per selected source (shared target + paths)\">\n Map {{ orphanSelectedCount() }} selected\u2026\n </button>\n\n @if (orphanStats(); as s) {\n <span class=\"validation-summary\">\n @if (orphanSearchText().trim() || orphanSelectedGroupNames().length > 0) {\n <span class=\"badge badge-info\" title=\"rows matching search + group filter\">{{ orphanVisibleList().length }} shown</span>\n }\n <span class=\"badge badge-error\" title=\"unmapped \u2014 no DataPointMapping yet\">{{ s.unmapped }} unmapped</span>\n <span class=\"badge badge-ok\" title=\"already covered by at least one mapping\">{{ s.mapped }} mapped</span>\n <span class=\"badge\">{{ s.total }} total</span>\n </span>\n }\n </div>\n\n <div class=\"orphan-body\">\n @if (orphanLoading()) {\n <div class=\"empty-hint\">Loading source candidates\u2026</div>\n } @else if (orphanError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (orphanVisibleList().length === 0) {\n <div class=\"empty-hint\">\n @if (orphanSelectedGroupNames().length > 0) {\n No entries in the selected group(s) match the current filters.\n } @else if (orphanSearchText().trim()) {\n No entries match \"{{ orphanSearchText() }}\".\n } @else if (orphanHideMapped()) {\n All {{ orphanCkType() }} entities are mapped at least once. \uD83C\uDF89\n } @else {\n No entities of type {{ orphanCkType() }} found.\n }\n </div>\n } @else if (orphanGroupParentType()) {\n @for (group of orphanGroupedList(); track group.key) {\n <div class=\"orphan-group\">\n <div class=\"orphan-group-header\">\n <span class=\"orphan-group-label\">{{ group.label }}</span>\n <span class=\"orphan-group-count\">{{ group.items.length }}</span>\n </div>\n <ul class=\"orphan-list\">\n @for (item of group.items; track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n </div>\n }\n } @else {\n <ul class=\"orphan-list\">\n @for (item of orphanVisibleList(); track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n }\n\n <ng-template #orphanRowTpl let-item>\n <li class=\"orphan-row\" [class.orphan-mapped]=\"item.mappingCount > 0\">\n <div class=\"orphan-line\">\n <input type=\"checkbox\" class=\"orphan-check\"\n [checked]=\"isOrphanSelected(item.rtId)\"\n (change)=\"toggleOrphanSelected(item.rtId)\"\n [attr.aria-label]=\"'Select ' + item.name\" />\n <span class=\"orphan-name\">{{ item.name }}</span>\n @if (item.mappingCount > 0) {\n <span class=\"orphan-badge orphan-badge-mapped\">\n {{ item.mappingCount }} mapping{{ item.mappingCount === 1 ? '' : 's' }}\n </span>\n } @else {\n <span class=\"orphan-badge orphan-badge-unmapped\">unmapped</span>\n }\n </div>\n @if (item.parentPath.length > 0) {\n <div class=\"orphan-breadcrumb\" [attr.title]=\"'Parent chain (root-first)'\">\n @for (parent of breadcrumbFor(item); track parent.rtId; let last = $last) {\n <span class=\"crumb\">{{ parent.name }}</span>\n @if (!last) { <span class=\"crumb-sep\">\u203A</span> }\n }\n </div>\n }\n <div class=\"orphan-meta\">\n <span class=\"kv-val\">{{ item.ckTypeId }}&#64;{{ item.rtId }}</span>\n </div>\n @if (item.description) {\n <div class=\"orphan-description\">{{ item.description }}</div>\n }\n <div class=\"orphan-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.plus\"\n (click)=\"createMappingFromOrphan(item)\"\n title=\"Create mapping pre-linked to this source\">\n Map\u2026\n </button>\n </div>\n </li>\n </ng-template>\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.coverage-root{display:flex;flex-direction:column;flex:1;min-height:0;gap:12px}.coverage-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 12px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.coverage-toolbar .toolbar-label{flex:0 0 96px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.coverage-toolbar .root-select{flex:0 0 280px;min-width:0;padding:4px 8px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:var(--theme-bg-elevated, var(--kendo-color-surface, #fff));color:var(--theme-text-primary, inherit);font-size:.9rem;height:30px}.coverage-toolbar .orphan-search-wrap{display:inline-flex;align-items:center;gap:2px}.coverage-toolbar .orphan-search-wrap .orphan-search{flex:1 1 220px;min-width:140px}.coverage-toolbar .orphan-group-filter{flex:0 1 320px;min-width:160px}.coverage-toolbar .toolbar-spacer{flex:1}.coverage-toolbar .toolbar-meta{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.coverage-toolbar .toolbar-meta .meta-name{font-size:.85rem;font-weight:600}.coverage-toolbar .toolbar-meta .meta-type{font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.coverage-body{flex:1;display:flex;gap:12px;min-height:0}@media(max-width:900px){.coverage-body{flex-direction:column}.coverage-tree-pane{flex:0 0 38vh;min-width:0;min-height:180px}.coverage-detail-pane{min-height:180px}.coverage-toolbar .toolbar-label{flex:0 0 auto}.coverage-toolbar .root-select{flex:1 1 200px;max-width:100%}}.coverage-tree-pane{flex:0 0 40%;min-width:240px;display:flex;flex-direction:column;min-height:0;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);overflow:auto}.coverage-detail-pane{flex:1;min-width:0;display:flex;flex-direction:column;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);padding:12px 14px;gap:12px;overflow:auto}.detail-header{display:flex;align-items:flex-start;gap:8px}.detail-header .detail-titles{flex:1;min-width:0}.detail-header .detail-name{margin:0;font-size:1.05rem;font-weight:600;word-break:break-word}.detail-header .detail-subtitle{font-size:.72rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d);word-break:break-all}.detail-section-title{display:flex;align-items:center;gap:10px;font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #6c757d)}.detail-section-title .toolbar-spacer{flex:1}.detail-section-title .detail-summary{text-transform:none;letter-spacing:0;font-weight:500;color:var(--kendo-color-on-app-surface, inherit);font-size:.78rem}.mapping-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.mapping-row{border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.mapping-row.mapping-disabled{opacity:.55}.mapping-line{display:flex;align-items:center;gap:8px}.mapping-line .mapping-name{font-weight:600;font-size:.9rem}.mapping-badge{font-size:.65rem;text-transform:uppercase;letter-spacing:.5px;padding:1px 6px;border-radius:8px;border:1px solid var(--kendo-color-border, #dee2e6)}.mapping-badge.mapping-badge-off{color:var(--kendo-color-subtle, #6c757d)}.mapping-details{display:flex;flex-wrap:wrap;gap:10px;font-size:.8rem}.mapping-details .kv{display:inline-flex;align-items:baseline;gap:4px}.mapping-details .kv-key{font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.mapping-details code.kv-val{font-family:monospace;background:var(--kendo-color-surface, transparent);padding:1px 4px;border-radius:3px}.mapping-actions{display:flex;gap:6px;justify-content:flex-end}.empty-hint,.error-hint{padding:12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d);text-align:center}.error-hint{color:var(--kendo-color-error, #dc3545)}.coverage-tabs{display:flex;gap:0;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6))}.coverage-tab{padding:8px 16px;border:none;background:transparent;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-size:.85rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px}.coverage-tab:hover{color:var(--theme-text-primary, inherit)}.coverage-tab.active{color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358));border-bottom-color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358))}.coverage-tab .tab-badge{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border-radius:10px;padding:1px 8px;font-size:.7rem;font-weight:700}.orphan-toggle{display:inline-flex;align-items:center;gap:6px;font-size:.8rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));cursor:pointer}.orphan-body{flex:1;min-height:0;overflow:auto;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);padding:8px}.orphan-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.orphan-row{display:flex;flex-direction:column;gap:4px;padding:8px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-left-width:3px;border-left-color:var(--kendo-color-error, #dc3545);border-radius:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.orphan-row.orphan-mapped{border-left-color:var(--kendo-color-success, #28a745);opacity:.7}.orphan-row .orphan-line{display:flex;align-items:center;gap:8px}.orphan-row .orphan-line .orphan-check{flex-shrink:0;margin:0;cursor:pointer;accent-color:var(--kendo-color-primary, #ff6358)}.orphan-row .orphan-line .orphan-name{flex:1;font-weight:600;font-size:.9rem}.orphan-row .orphan-badge{font-size:.7rem;padding:1px 8px;border-radius:10px;text-transform:uppercase;letter-spacing:.5px;font-weight:600}.orphan-row .orphan-badge-unmapped{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border:1px solid var(--kendo-color-error, #dc3545)}.orphan-row .orphan-badge-mapped{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);color:var(--kendo-color-success, #28a745);border:1px solid var(--kendo-color-success, #28a745)}.orphan-row .orphan-meta{font-family:monospace;font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.orphan-row .orphan-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:4px;font-size:.75rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.orphan-row .orphan-breadcrumb .crumb{line-height:1.3}.orphan-row .orphan-breadcrumb .crumb-sep{opacity:.55;font-weight:600}.orphan-row .orphan-description{font-size:.78rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.orphan-row .orphan-actions{display:flex;gap:6px;justify-content:flex-end}.orphan-group{display:flex;flex-direction:column;gap:6px}.orphan-group+.orphan-group{margin-top:14px}.orphan-group .orphan-group-header{display:flex;align-items:baseline;gap:8px;padding:4px 8px;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));font-size:.85rem;font-weight:600;color:var(--theme-text-primary, inherit)}.orphan-group .orphan-group-header .orphan-group-label{flex:1}.orphan-group .orphan-group-header .orphan-group-count{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f1f3f5)) 80%,transparent);border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:10px;padding:0 8px}.validation-summary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.badge{font-size:.7rem;padding:2px 8px;border-radius:10px;background:var(--kendo-color-surface, #f1f3f5);border:1px solid var(--kendo-color-border, #dee2e6)}.badge-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 18%,transparent);border-color:var(--kendo-color-error, #dc3545);color:var(--kendo-color-error, #dc3545);font-weight:600}.badge-warning{background:color-mix(in srgb,var(--kendo-color-warning, #ffc107) 22%,transparent);border-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-warning-on, #6b5500);font-weight:600}.badge-ok{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);border-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-success, #28a745);font-weight:600}.badge-info{background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);border-color:var(--kendo-color-info, #0dcaf0);color:var(--kendo-color-info, #0dcaf0)}.validation-error-text{color:var(--kendo-color-error, #dc3545);font-size:.8rem}.validation-timestamp{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);margin-left:4px}\n"] }]
21425
+ ], providers: [MappingCoverageTreeDataSource], template: "<div class=\"coverage-root\">\n @if (config.sourceCandidateCkTypeIds.length > 0) {\n <div class=\"coverage-tabs\" role=\"tablist\">\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'coverage'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'coverage'\"\n (click)=\"selectTab('coverage')\">Coverage Tree</button>\n <button class=\"coverage-tab\"\n [class.active]=\"activeTab() === 'orphans'\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab() === 'orphans'\"\n (click)=\"selectTab('orphans')\">\n Orphan Sources\n @if (orphanStats(); as s) {\n @if (s.unmapped > 0) { <span class=\"tab-badge\">{{ s.unmapped }}</span> }\n }\n </button>\n </div>\n }\n\n @if (activeTab() === 'coverage') {\n <div class=\"coverage-toolbar\">\n <mm-perspective-switcher\n [perspectives]=\"perspectives()\"\n [activeKey]=\"activePerspectiveKey()\"\n (perspectiveChange)=\"onPerspectiveChange($event)\"></mm-perspective-switcher>\n <label class=\"toolbar-label\">Tree:</label>\n <select class=\"root-select\"\n [value]=\"selectedRoot()?.rtId ?? ''\"\n (change)=\"onRootSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ activeRootCkTypeId() }} \u2014</option>\n @for (root of rootCandidates(); track root.rtId) {\n <option [value]=\"root.rtId\" [title]=\"root.description\">{{ root.name }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshRoots()\" title=\"Refresh tree list\" aria-label=\"Refresh tree list\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.folderOpen\"\n (click)=\"pickRoot()\" title=\"Browse for entity\">Browse...</button>\n\n @if (selectedRoot(); as root) {\n <div class=\"toolbar-spacer\"></div>\n <span class=\"toolbar-meta\">\n <span class=\"meta-name\">{{ root.name }}</span>\n <span class=\"meta-type\">{{ root.ckTypeId }}</span>\n </span>\n }\n </div>\n\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Validation:</label>\n <select class=\"root-select\"\n [value]=\"selectedPipeline()?.rtId ?? ''\"\n (change)=\"onPipelineSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a {{ config.validationPipelineCkTypeId }} \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n @if (tenantId) {\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedPipeline() || validationRunning() || validationLoading()\"\n (click)=\"runValidation()\"\n [title]=\"validationRunning() ? 'Validation running\u2026' : 'Run pipeline + load report'\">\n @if (validationRunning()) { Running\u2026 } @else { Run }\n </button>\n }\n <button kendoButton fillMode=\"solid\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!selectedPipeline() || validationLoading() || validationRunning()\"\n (click)=\"refreshValidation()\">Load Report</button>\n @if (validationSummary()) {\n <button kendoButton fillMode=\"flat\" size=\"small\"\n (click)=\"clearValidation()\">Clear</button>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (validationLoading()) {\n <span class=\"toolbar-meta\">Loading\u2026</span>\n } @else if (validationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (validationSummary(); as s) {\n <span class=\"validation-summary\">\n <span class=\"badge badge-error\" title=\"error\">{{ s.error }} err</span>\n <span class=\"badge badge-warning\" title=\"warning\">{{ s.warning }} warn</span>\n <span class=\"badge badge-ok\" title=\"ok\">{{ s.ok }} ok</span>\n <span class=\"badge badge-info\" title=\"info / unscoped\">{{ s.info }} info</span>\n <span class=\"badge\">{{ s.total }} total</span>\n @if (validationExecutedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n }\n </div>\n\n @if (tenantId) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Generation:</label>\n <select class=\"root-select\"\n [value]=\"selectedGenerationPipeline()?.rtId ?? ''\"\n (change)=\"onGenerationSelectChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick an auto-mapping pipeline \u2014</option>\n @for (p of validationPipelines(); track p.rtId) {\n <option [value]=\"p.rtId\">{{ p.name }}</option>\n }\n </select>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"!selectedGenerationPipeline() || generationRunning()\"\n (click)=\"runGeneration()\"\n [title]=\"generationRunning() ? 'Generation running\u2026' : 'Run the auto-mapping pipeline and reload counts'\">\n @if (generationRunning()) { Running\u2026 } @else { Generate }\n </button>\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (generationRunning()) {\n <span class=\"toolbar-meta\">Generating mappings\u2026</span>\n } @else if (generationError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (generationStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.totalSuggestions !== undefined) {\n <span class=\"badge badge-ok\" title=\"mapping suggestions produced\">{{ s.totalSuggestions }} mappings</span>\n }\n @if (s.matchedContainers !== undefined && s.totalContainers !== undefined) {\n <span class=\"badge\" title=\"containers (e.g. rooms) matched to a target\">\n {{ s.matchedContainers }}/{{ s.totalContainers }} matched\n </span>\n }\n @if (s.unmatchedContainers) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unmatched: ' + (s.unmatchedContainerNames ?? []).join(', ')\">\n {{ s.unmatchedContainers }} unmatched\n </span>\n }\n @if (generationCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (generationCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n @if (tenantId && (exportBackupPipeline() || importBackupPipeline())) {\n <div class=\"coverage-toolbar coverage-toolbar-validation\">\n <label class=\"toolbar-label\">Backup:</label>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.download\"\n [disabled]=\"!exportBackupPipeline() || backupRunning() !== null\"\n (click)=\"exportMappings()\"\n title=\"Run the export pipeline and download the mapping document as JSON\">\n @if (backupRunning() === 'export') { Exporting\u2026 } @else { Export }\n </button>\n <button kendoButton size=\"small\" [svgIcon]=\"icons.upload\"\n [disabled]=\"!importBackupPipeline() || backupRunning() !== null\"\n (click)=\"importFileInput.click()\"\n title=\"Import a previously exported mapping document (JSON)\">\n @if (backupRunning() === 'import') { Importing\u2026 } @else { Import\u2026 }\n </button>\n <input #importFileInput type=\"file\" accept=\".json,application/json\" hidden\n (change)=\"onImportFileSelected($event)\" />\n\n <div class=\"toolbar-spacer\"></div>\n\n @if (backupRunning() === 'export') {\n <span class=\"toolbar-meta\">Exporting mappings\u2026</span>\n } @else if (backupRunning() === 'import') {\n <span class=\"toolbar-meta\">Importing mappings\u2026</span>\n } @else if (backupError(); as err) {\n <span class=\"toolbar-meta validation-error-text\">{{ err }}</span>\n } @else if (importStats(); as s) {\n <span class=\"validation-summary\">\n @if (s.resolved !== undefined) {\n <span class=\"badge badge-ok\" title=\"mappings resolved and imported\">{{ s.resolved }} imported</span>\n }\n @if (s.unresolved) {\n <span class=\"badge badge-warning\"\n [attr.title]=\"'Unresolved: ' + unresolvedImportNames()\">\n {{ s.unresolved }} unresolved\n </span>\n }\n @if (s.total !== undefined) {\n <span class=\"badge\">{{ s.total }} total</span>\n }\n @if (importCompletedAt(); as ts) {\n <span class=\"validation-timestamp\">{{ ts }}</span>\n }\n </span>\n } @else if (importCompletedAt(); as ts) {\n <span class=\"toolbar-meta\">Import completed {{ ts }} (no statistics in OutputData)</span>\n }\n </div>\n }\n\n <div class=\"coverage-body\">\n <div class=\"coverage-tree-pane\">\n @if (selectedRoot()) {\n <mm-tree-view\n [dataSource]=\"dataSource\"\n (nodeSelected)=\"onNodeSelected($event)\">\n </mm-tree-view>\n } @else {\n <div class=\"empty-hint\">\n Select a tree to start. Counts in brackets show how many mappings\n point to that node.\n </div>\n }\n </div>\n\n <div class=\"coverage-detail-pane\">\n @if (selectedNode(); as node) {\n <div class=\"detail-header\">\n <div class=\"detail-titles\">\n <h3 class=\"detail-name\">{{ node.name }}</h3>\n <div class=\"detail-subtitle\">{{ node.ckTypeId }}@{{ node.rtId }}</div>\n </div>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n (click)=\"refreshSelected()\" title=\"Refresh\" aria-label=\"Refresh mappings\"></button>\n </div>\n\n <div class=\"detail-section-title\">\n <span>Mappings</span>\n @if (summaryLine(); as s) {\n <span class=\"detail-summary\">{{ s }}</span>\n }\n <span class=\"toolbar-spacer\"></span>\n <button kendoButton themeColor=\"primary\" size=\"small\" [svgIcon]=\"icons.plus\"\n (click)=\"addMapping()\">Add</button>\n </div>\n\n @if (mappingsLoading()) {\n <div class=\"empty-hint\">Loading mappings\u2026</div>\n } @else if (mappingsError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (mappings().length === 0) {\n <div class=\"empty-hint\">\n No mappings reference this node yet. Add one using the button above.\n </div>\n } @else {\n <ul class=\"mapping-list\">\n @for (mapping of mappings(); track trackByRtId($index, mapping)) {\n <li class=\"mapping-row\" [class.mapping-disabled]=\"!mapping.enabled\">\n <div class=\"mapping-line\">\n <span class=\"mapping-name\">\n {{ mapping.name || 'Mapping ' + ($index + 1) }}\n </span>\n @if (!mapping.enabled) {\n <span class=\"mapping-badge mapping-badge-off\">disabled</span>\n }\n </div>\n <div class=\"mapping-details\">\n <span class=\"kv\">\n <span class=\"kv-key\">Source:</span>\n <span class=\"kv-val\">\n {{ mapping.sourceName || mapping.sourceRtId || '\u2014 not linked \u2014' }}\n </span>\n </span>\n @if (mapping.sourceAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">Attr:</span>\n <span class=\"kv-val\">{{ mapping.sourceAttributePath }}</span>\n </span>\n }\n @if (mapping.mappingExpression) {\n <span class=\"kv\">\n <span class=\"kv-key\">Expr:</span>\n <code class=\"kv-val\">{{ mapping.mappingExpression }}</code>\n </span>\n }\n @if (mapping.targetAttributePath) {\n <span class=\"kv\">\n <span class=\"kv-key\">\u2192</span>\n <span class=\"kv-val\">{{ mapping.targetAttributePath }}</span>\n </span>\n }\n </div>\n <div class=\"mapping-actions\">\n <button kendoButton fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.pencil\"\n (click)=\"editMapping(mapping)\"\n title=\"Edit mapping\" [attr.aria-label]=\"'Edit mapping ' + (mapping.name || mapping.rtId)\"></button>\n <button kendoButton fillMode=\"flat\" size=\"small\" themeColor=\"error\" [svgIcon]=\"icons.trash\"\n (click)=\"deleteMapping(mapping)\" data-action=\"delete\"\n title=\"Delete mapping\" [attr.aria-label]=\"'Delete mapping ' + (mapping.name || mapping.rtId)\"></button>\n </div>\n </li>\n }\n </ul>\n }\n } @else {\n <div class=\"empty-hint\">\n Select a node from the tree to view and edit its mappings.\n </div>\n }\n </div>\n </div>\n }\n\n @if (activeTab() === 'orphans') {\n <div class=\"coverage-toolbar\">\n <label class=\"toolbar-label\">Source type:</label>\n <select class=\"root-select\"\n [value]=\"orphanCkType() ?? ''\"\n (change)=\"onOrphanCkTypeChange($any($event.target).value)\">\n <option value=\"\" disabled>\u2014 Pick a source type \u2014</option>\n @for (ckType of config.sourceCandidateCkTypeIds; track ckType) {\n <option [value]=\"ckType\">{{ ckType }}</option>\n }\n </select>\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.refresh\"\n [disabled]=\"!orphanCkType() || orphanLoading()\"\n (click)=\"refreshOrphans()\" title=\"Reload\" aria-label=\"Reload orphans\"></button>\n <span class=\"orphan-search-wrap\">\n <input type=\"text\" class=\"root-select orphan-search\"\n placeholder=\"Search name, room, description\u2026\"\n [value]=\"orphanSearchText()\"\n (input)=\"orphanSearchText.set($any($event.target).value)\" />\n @if (orphanSearchText()) {\n <button kendoButton fillMode=\"flat\" size=\"small\" [svgIcon]=\"icons.x\"\n class=\"orphan-search-clear\"\n (click)=\"orphanSearchText.set('')\"\n title=\"Clear search\" aria-label=\"Clear search\"></button>\n }\n </span>\n <label class=\"orphan-toggle\">\n <input type=\"checkbox\" [checked]=\"orphanHideMapped()\" (change)=\"toggleOrphanHideMapped()\" />\n Hide already-mapped\n </label>\n <label class=\"toolbar-label\">Group by:</label>\n <select class=\"root-select\"\n [value]=\"orphanGroupParentType() ?? ''\"\n (change)=\"onOrphanGroupParentTypeChange($any($event.target).value)\">\n <option value=\"\">(no grouping)</option>\n @for (t of orphanAvailableParentTypes(); track t) {\n <option [value]=\"t\">{{ t }}</option>\n }\n </select>\n @if (orphanGroupParentType()) {\n <kendo-multiselect class=\"orphan-group-filter\"\n [data]=\"orphanAvailableGroupNames()\"\n [value]=\"orphanSelectedGroupNames()\"\n (valueChange)=\"onOrphanGroupNamesChange($event)\"\n [autoClose]=\"false\"\n [clearButton]=\"true\"\n size=\"small\"\n placeholder=\"Filter groups\u2026\"\n title=\"Show only the selected groups (e.g. specific categories)\">\n </kendo-multiselect>\n }\n\n <div class=\"toolbar-spacer\"></div>\n\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanVisibleList().length === 0\"\n (click)=\"selectAllVisibleOrphans()\"\n title=\"Select every row visible under the current filter\">Select all</button>\n <button kendoButton size=\"small\" fillMode=\"flat\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"clearOrphanSelection()\">Clear</button>\n <button kendoButton themeColor=\"primary\" size=\"small\"\n [disabled]=\"orphanSelectedCount() === 0\"\n (click)=\"bulkMapSelected()\"\n title=\"Create one mapping per selected source (shared target + paths)\">\n Map {{ orphanSelectedCount() }} selected\u2026\n </button>\n\n @if (orphanStats(); as s) {\n <span class=\"validation-summary\">\n @if (orphanSearchText().trim() || orphanSelectedGroupNames().length > 0) {\n <span class=\"badge badge-info\" title=\"rows matching search + group filter\">{{ orphanVisibleList().length }} shown</span>\n }\n <span class=\"badge badge-error\" title=\"unmapped \u2014 no DataPointMapping yet\">{{ s.unmapped }} unmapped</span>\n <span class=\"badge badge-ok\" title=\"already covered by at least one mapping\">{{ s.mapped }} mapped</span>\n <span class=\"badge\">{{ s.total }} total</span>\n </span>\n }\n </div>\n\n <div class=\"orphan-body\">\n @if (orphanLoading()) {\n <div class=\"empty-hint\">Loading source candidates\u2026</div>\n } @else if (orphanError(); as err) {\n <div class=\"error-hint\">{{ err }}</div>\n } @else if (orphanVisibleList().length === 0) {\n <div class=\"empty-hint\">\n @if (orphanSelectedGroupNames().length > 0) {\n No entries in the selected group(s) match the current filters.\n } @else if (orphanSearchText().trim()) {\n No entries match \"{{ orphanSearchText() }}\".\n } @else if (orphanHideMapped()) {\n All {{ orphanCkType() }} entities are mapped at least once. \uD83C\uDF89\n } @else {\n No entities of type {{ orphanCkType() }} found.\n }\n </div>\n } @else if (orphanGroupParentType()) {\n @for (group of orphanGroupedList(); track group.key) {\n <div class=\"orphan-group\">\n <div class=\"orphan-group-header\">\n <span class=\"orphan-group-label\">{{ group.label }}</span>\n <span class=\"orphan-group-count\">{{ group.items.length }}</span>\n </div>\n <ul class=\"orphan-list\">\n @for (item of group.items; track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n </div>\n }\n } @else {\n <ul class=\"orphan-list\">\n @for (item of orphanVisibleList(); track trackOrphanByRtId($index, item)) {\n <ng-container *ngTemplateOutlet=\"orphanRowTpl; context: { $implicit: item }\"></ng-container>\n }\n </ul>\n }\n\n <ng-template #orphanRowTpl let-item>\n <li class=\"orphan-row\" [class.orphan-mapped]=\"item.mappingCount > 0\">\n <div class=\"orphan-line\">\n <input type=\"checkbox\" class=\"orphan-check\"\n [checked]=\"isOrphanSelected(item.rtId)\"\n (change)=\"toggleOrphanSelected(item.rtId)\"\n [attr.aria-label]=\"'Select ' + item.name\" />\n <span class=\"orphan-name\">{{ item.name }}</span>\n @if (item.mappingCount > 0) {\n <span class=\"orphan-badge orphan-badge-mapped\">\n {{ item.mappingCount }} mapping{{ item.mappingCount === 1 ? '' : 's' }}\n </span>\n } @else {\n <span class=\"orphan-badge orphan-badge-unmapped\">unmapped</span>\n }\n </div>\n @if (item.parentPath.length > 0) {\n <div class=\"orphan-breadcrumb\" [attr.title]=\"'Parent chain (root-first)'\">\n @for (parent of breadcrumbFor(item); track parent.rtId; let last = $last) {\n <span class=\"crumb\">{{ parent.name }}</span>\n @if (!last) { <span class=\"crumb-sep\">\u203A</span> }\n }\n </div>\n }\n <div class=\"orphan-meta\">\n <span class=\"kv-val\">{{ item.ckTypeId }}&#64;{{ item.rtId }}</span>\n </div>\n @if (item.description) {\n <div class=\"orphan-description\">{{ item.description }}</div>\n }\n <div class=\"orphan-actions\">\n <button kendoButton themeColor=\"primary\" fillMode=\"flat\" size=\"small\"\n [svgIcon]=\"icons.plus\"\n (click)=\"createMappingFromOrphan(item)\"\n title=\"Create mapping pre-linked to this source\">\n Map\u2026\n </button>\n </div>\n </li>\n </ng-template>\n </div>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0}.coverage-root{display:flex;flex-direction:column;flex:1;min-height:0;gap:12px}.coverage-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px 12px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface-alt, #f8f9fa)) 70%,transparent)}.coverage-toolbar .toolbar-label{flex:0 0 96px;font-size:.75rem;font-weight:600;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.coverage-toolbar .root-select{flex:0 0 280px;min-width:0;padding:4px 8px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:4px;background:var(--theme-bg-elevated, var(--kendo-color-surface, #fff));color:var(--theme-text-primary, inherit);font-size:.9rem;height:30px}.coverage-toolbar .orphan-search-wrap{display:inline-flex;align-items:center;gap:2px}.coverage-toolbar .orphan-search-wrap .orphan-search{flex:1 1 220px;min-width:140px}.coverage-toolbar .orphan-group-filter{flex:0 1 320px;min-width:160px}.coverage-toolbar .toolbar-spacer{flex:1}.coverage-toolbar .toolbar-meta{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.coverage-toolbar .toolbar-meta .meta-name{font-size:.85rem;font-weight:600}.coverage-toolbar .toolbar-meta .meta-type{font-size:.7rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d)}.coverage-body{flex:1;display:flex;gap:12px;min-height:0}@media(max-width:900px){.coverage-body{flex-direction:column}.coverage-tree-pane{flex:0 0 38vh;min-width:0;min-height:180px}.coverage-detail-pane{min-height:180px}.coverage-toolbar .toolbar-label{flex:0 0 auto}.coverage-toolbar .root-select{flex:1 1 200px;max-width:100%}}.coverage-tree-pane{flex:0 0 40%;min-width:240px;display:flex;flex-direction:column;min-height:0;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);overflow:auto}.coverage-detail-pane{flex:1;min-width:0;display:flex;flex-direction:column;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);color:var(--theme-text-primary, inherit);padding:12px 14px;gap:12px;overflow:auto}.detail-header{display:flex;align-items:flex-start;gap:8px}.detail-header .detail-titles{flex:1;min-width:0}.detail-header .detail-name{margin:0;font-size:1.05rem;font-weight:600;word-break:break-word}.detail-header .detail-subtitle{font-size:.72rem;font-family:monospace;color:var(--kendo-color-subtle, #6c757d);word-break:break-all}.detail-section-title{display:flex;align-items:center;gap:10px;font-size:.78rem;font-weight:700;color:var(--kendo-color-subtle, #6c757d)}.detail-section-title .toolbar-spacer{flex:1}.detail-section-title .detail-summary{text-transform:none;font-weight:500;color:var(--kendo-color-on-app-surface, inherit);font-size:.78rem}.mapping-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.mapping-row{border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;padding:8px 10px;display:flex;flex-direction:column;gap:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.mapping-row.mapping-disabled{opacity:.55}.mapping-line{display:flex;align-items:center;gap:8px}.mapping-line .mapping-name{font-weight:600;font-size:.9rem}.mapping-badge{font-size:.65rem;padding:1px 6px;border-radius:8px;border:1px solid var(--kendo-color-border, #dee2e6)}.mapping-badge.mapping-badge-off{color:var(--kendo-color-subtle, #6c757d)}.mapping-details{display:flex;flex-wrap:wrap;gap:10px;font-size:.8rem}.mapping-details .kv{display:inline-flex;align-items:baseline;gap:4px}.mapping-details .kv-key{font-weight:600;color:var(--kendo-color-subtle, #6c757d)}.mapping-details code.kv-val{font-family:monospace;background:var(--kendo-color-surface, transparent);padding:1px 4px;border-radius:3px}.mapping-actions{display:flex;gap:6px;justify-content:flex-end}.empty-hint,.error-hint{padding:12px;font-size:.85rem;color:var(--kendo-color-subtle, #6c757d);text-align:center}.error-hint{color:var(--kendo-color-error, #dc3545)}.coverage-tabs{display:flex;gap:0;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6))}.coverage-tab{padding:8px 16px;border:none;background:transparent;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-size:.85rem;font-weight:600;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;display:inline-flex;align-items:center;gap:6px}.coverage-tab:hover{color:var(--theme-text-primary, inherit)}.coverage-tab.active{color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358));border-bottom-color:var(--theme-text-accent, var(--kendo-color-primary, #ff6358))}.coverage-tab .tab-badge{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border-radius:10px;padding:1px 8px;font-size:.7rem;font-weight:700}.orphan-toggle{display:inline-flex;align-items:center;gap:6px;font-size:.8rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));cursor:pointer}.orphan-body{flex:1;min-height:0;overflow:auto;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:6px;background:color-mix(in srgb,var(--theme-bg-surface, var(--kendo-color-surface, #fff)) 60%,transparent);padding:8px}.orphan-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.orphan-row{display:flex;flex-direction:column;gap:4px;padding:8px 10px;border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-left-width:3px;border-left-color:var(--kendo-color-error, #dc3545);border-radius:6px;background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f8f9fa)) 65%,transparent)}.orphan-row.orphan-mapped{border-left-color:var(--kendo-color-success, #28a745);opacity:.7}.orphan-row .orphan-line{display:flex;align-items:center;gap:8px}.orphan-row .orphan-line .orphan-check{flex-shrink:0;margin:0;cursor:pointer;accent-color:var(--kendo-color-primary, #ff6358)}.orphan-row .orphan-line .orphan-name{flex:1;font-weight:600;font-size:.9rem}.orphan-row .orphan-badge{font-size:.7rem;padding:1px 8px;border-radius:10px;font-weight:600}.orphan-row .orphan-badge-unmapped{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 22%,transparent);color:var(--kendo-color-error, #dc3545);border:1px solid var(--kendo-color-error, #dc3545)}.orphan-row .orphan-badge-mapped{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);color:var(--kendo-color-success, #28a745);border:1px solid var(--kendo-color-success, #28a745)}.orphan-row .orphan-meta{font-family:monospace;font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));word-break:break-all}.orphan-row .orphan-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;gap:4px;font-size:.75rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d))}.orphan-row .orphan-breadcrumb .crumb{line-height:1.3}.orphan-row .orphan-breadcrumb .crumb-sep{opacity:.55;font-weight:600}.orphan-row .orphan-description{font-size:.78rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));font-style:italic}.orphan-row .orphan-actions{display:flex;gap:6px;justify-content:flex-end}.orphan-group{display:flex;flex-direction:column;gap:6px}.orphan-group+.orphan-group{margin-top:14px}.orphan-group .orphan-group-header{display:flex;align-items:baseline;gap:8px;padding:4px 8px;border-bottom:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));font-size:.85rem;font-weight:600;color:var(--theme-text-primary, inherit)}.orphan-group .orphan-group-header .orphan-group-label{flex:1}.orphan-group .orphan-group-header .orphan-group-count{font-size:.7rem;color:var(--theme-text-secondary, var(--kendo-color-subtle, #6c757d));background:color-mix(in srgb,var(--theme-bg-elevated, var(--kendo-color-surface-alt, #f1f3f5)) 80%,transparent);border:1px solid var(--theme-border-subtle, var(--kendo-color-border, #dee2e6));border-radius:10px;padding:0 8px}.validation-summary{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}.badge{font-size:.7rem;padding:2px 8px;border-radius:10px;background:var(--kendo-color-surface, #f1f3f5);border:1px solid var(--kendo-color-border, #dee2e6)}.badge-error{background:color-mix(in srgb,var(--kendo-color-error, #dc3545) 18%,transparent);border-color:var(--kendo-color-error, #dc3545);color:var(--kendo-color-error, #dc3545);font-weight:600}.badge-warning{background:color-mix(in srgb,var(--kendo-color-warning, #ffc107) 22%,transparent);border-color:var(--kendo-color-warning, #ffc107);color:var(--kendo-color-warning-on, #6b5500);font-weight:600}.badge-ok{background:color-mix(in srgb,var(--kendo-color-success, #28a745) 18%,transparent);border-color:var(--kendo-color-success, #28a745);color:var(--kendo-color-success, #28a745);font-weight:600}.badge-info{background:color-mix(in srgb,var(--kendo-color-info, #0dcaf0) 18%,transparent);border-color:var(--kendo-color-info, #0dcaf0);color:var(--kendo-color-info, #0dcaf0)}.validation-error-text{color:var(--kendo-color-error, #dc3545);font-size:.8rem}.validation-timestamp{font-size:.7rem;color:var(--kendo-color-subtle, #6c757d);margin-left:4px}\n"] }]
20843
21426
  }], ctorParameters: () => [], propDecorators: { treeView: [{
20844
21427
  type: ViewChild,
20845
21428
  args: [TreeComponent, { static: false }]
@@ -21114,7 +21697,7 @@ class TenantSwitcherComponent {
21114
21697
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TenantSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
21115
21698
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: TenantSwitcherComponent, isStandalone: true, selector: "mm-tenant-switcher", inputs: { currentTenantId: "currentTenantId", allowedTenants: "allowedTenants", isDenied: "isDenied" }, outputs: { tenantSelected: "tenantSelected", refreshRequested: "refreshRequested" }, host: { listeners: { "document:keydown": "onKeydown($event)", "document:click": "onDocumentClick($event)" } }, viewQueries: [{ propertyName: "anchor", first: true, predicate: ["badgeEl"], descendants: true, read: ElementRef }, { propertyName: "popup", first: true, predicate: ["popupContent"], descendants: true, read: ElementRef }], ngImport: i0, template: `
21116
21699
  @if (currentTenantId) {
21117
- <div #badgeEl class="tenant-badge" [class.denied]="isDenied" (click)="onToggle()">
21700
+ <div #badgeEl class="tenant-badge" [class.denied]="isDenied" [title]="currentTenantId" (click)="onToggle()">
21118
21701
  <span class="tenant-icon">{{ isDenied ? '\u26A0' : '\u25C6' }}</span>
21119
21702
  <span class="tenant-name">{{ currentTenantId }}</span>
21120
21703
  @if (isDenied) {
@@ -21130,7 +21713,7 @@ class TenantSwitcherComponent {
21130
21713
  <span>Switch Tenant</span>
21131
21714
  <button kendoButton fillMode="flat" size="small" class="refresh-btn"
21132
21715
  [disabled]="isRefreshing"
21133
- title="Refresh tenant list"
21716
+ title="Refresh tenant list" aria-label="Refresh tenant list"
21134
21717
  (click)="onRefresh($event)">
21135
21718
  <kendo-svgicon [icon]="refreshIcon" size="small"
21136
21719
  [class.spinning]="isRefreshing"></kendo-svgicon>
@@ -21149,7 +21732,7 @@ class TenantSwitcherComponent {
21149
21732
  </kendo-popup>
21150
21733
  }
21151
21734
  }
21152
- `, isInline: true, styles: [":host{display:inline-flex;align-items:center}.tenant-badge{display:flex;align-items:center;gap:8px;padding:6px 14px;background:var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent));border:1px solid var(--mm-tenant-switcher-border, var(--kendo-color-border, #dee2e6));border-radius:var(--mm-tenant-switcher-radius, 4px 16px 16px 4px);box-shadow:var(--mm-tenant-switcher-shadow, none);cursor:pointer;transition:all .2s ease}.tenant-badge:hover{background:var(--mm-tenant-switcher-bg-hover, var(--kendo-color-base-hover, rgba(0, 0, 0, .04)));box-shadow:var(--mm-tenant-switcher-shadow-hover, var(--mm-tenant-switcher-shadow, none))}.tenant-icon{font-size:.7rem;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));animation:var(--mm-tenant-switcher-icon-animation, none)}.tenant-name{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.85rem;font-weight:600;letter-spacing:1px;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));text-transform:uppercase;text-shadow:var(--mm-tenant-switcher-text-shadow, none)}.denied{background:var(--mm-tenant-switcher-denied-bg, var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent)));border-color:var(--mm-tenant-switcher-denied-border, var(--kendo-color-error, #d9534f));box-shadow:var(--mm-tenant-switcher-denied-shadow, none)}.denied .tenant-icon,.denied .tenant-name{color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));text-shadow:var(--mm-tenant-switcher-denied-text-shadow, none)}.denied-label{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.55rem;font-weight:700;letter-spacing:1px;color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));background:var(--mm-tenant-switcher-denied-label-bg, color-mix(in srgb, var(--kendo-color-error, #d9534f) 15%, transparent));padding:2px 6px;border-radius:3px}.tenant-popup{min-width:220px;padding:8px 0;background:var(--kendo-color-surface, #fff);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.tenant-popup-header{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #666);border-bottom:1px solid var(--kendo-color-border, #dee2e6);margin-bottom:4px}.refresh-btn{padding:2px;min-width:unset}.spinning{animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tenant-list{list-style:none;margin:0;padding:0}.tenant-list-item{display:flex;align-items:center;gap:10px;padding:8px 16px;cursor:pointer;font-size:.85rem;transition:background .15s ease}.tenant-list-item:hover{background:var(--kendo-color-base-hover, rgba(0, 0, 0, .04))}.tenant-list-item.active{color:var(--kendo-color-primary, #ff6358);font-weight:600}.tenant-list-icon{font-size:.5rem;color:var(--kendo-color-subtle, #666)}.tenant-list-item.active .tenant-list-icon{color:var(--kendo-color-primary, #ff6358)}@keyframes mm-icon-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.1)}}\n"], dependencies: [{ kind: "component", type: PopupComponent, selector: "kendo-popup", inputs: ["animate", "anchor", "anchorAlign", "collision", "popupAlign", "copyAnchorStyles", "popupClass", "positionMode", "offset", "margin"], outputs: ["anchorViewportLeave", "close", "open", "positionChange"], exportAs: ["kendo-popup"] }, { 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: "component", type: SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
21735
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.tenant-badge{display:flex;align-items:center;gap:8px;min-width:0;padding:var(--mm-tenant-switcher-padding, 6px 14px);background:var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent));border:1px solid var(--mm-tenant-switcher-border, var(--kendo-color-border, #dee2e6));border-radius:var(--mm-tenant-switcher-radius, 4px 16px 16px 4px);box-shadow:var(--mm-tenant-switcher-shadow, none);cursor:pointer;transition:all .2s ease}.tenant-badge:hover{background:var(--mm-tenant-switcher-bg-hover, var(--kendo-color-base-hover, rgba(0, 0, 0, .04)));box-shadow:var(--mm-tenant-switcher-shadow-hover, var(--mm-tenant-switcher-shadow, none))}.tenant-icon{flex:none;font-size:.7rem;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));animation:var(--mm-tenant-switcher-icon-animation, none)}.tenant-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mm-tenant-switcher-font, inherit);font-size:.85rem;font-weight:600;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));text-shadow:var(--mm-tenant-switcher-text-shadow, none)}.denied{background:var(--mm-tenant-switcher-denied-bg, var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent)));border-color:var(--mm-tenant-switcher-denied-border, var(--kendo-color-error, #d9534f));box-shadow:var(--mm-tenant-switcher-denied-shadow, none)}.denied .tenant-icon,.denied .tenant-name{color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));text-shadow:var(--mm-tenant-switcher-denied-text-shadow, none)}.denied-label{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.55rem;font-weight:700;color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));background:var(--mm-tenant-switcher-denied-label-bg, color-mix(in srgb, var(--kendo-color-error, #d9534f) 15%, transparent));padding:2px 6px;border-radius:3px}.tenant-popup{min-width:220px;padding:8px 0;background:var(--kendo-color-surface, #fff);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.tenant-popup-header{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #666);border-bottom:1px solid var(--kendo-color-border, #dee2e6);margin-bottom:4px}.refresh-btn{padding:2px;min-width:unset}.spinning{animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tenant-list{list-style:none;margin:0;padding:0}.tenant-list-item{display:flex;align-items:center;gap:10px;padding:8px 16px;cursor:pointer;font-size:.85rem;transition:background .15s ease}.tenant-list-item:hover{background:var(--kendo-color-base-hover, rgba(0, 0, 0, .04))}.tenant-list-item.active{color:var(--kendo-color-primary, #ff6358);font-weight:600}.tenant-list-icon{font-size:.5rem;color:var(--kendo-color-subtle, #666)}.tenant-list-item.active .tenant-list-icon{color:var(--kendo-color-primary, #ff6358)}@keyframes mm-icon-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.1)}}\n"], dependencies: [{ kind: "component", type: PopupComponent, selector: "kendo-popup", inputs: ["animate", "anchor", "anchorAlign", "collision", "popupAlign", "copyAnchorStyles", "popupClass", "positionMode", "offset", "margin"], outputs: ["anchorViewportLeave", "close", "open", "positionChange"], exportAs: ["kendo-popup"] }, { 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: "component", type: SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
21153
21736
  }
21154
21737
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: TenantSwitcherComponent, decorators: [{
21155
21738
  type: Component,
@@ -21159,7 +21742,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
21159
21742
  SVGIconComponent
21160
21743
  ], template: `
21161
21744
  @if (currentTenantId) {
21162
- <div #badgeEl class="tenant-badge" [class.denied]="isDenied" (click)="onToggle()">
21745
+ <div #badgeEl class="tenant-badge" [class.denied]="isDenied" [title]="currentTenantId" (click)="onToggle()">
21163
21746
  <span class="tenant-icon">{{ isDenied ? '\u26A0' : '\u25C6' }}</span>
21164
21747
  <span class="tenant-name">{{ currentTenantId }}</span>
21165
21748
  @if (isDenied) {
@@ -21175,7 +21758,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
21175
21758
  <span>Switch Tenant</span>
21176
21759
  <button kendoButton fillMode="flat" size="small" class="refresh-btn"
21177
21760
  [disabled]="isRefreshing"
21178
- title="Refresh tenant list"
21761
+ title="Refresh tenant list" aria-label="Refresh tenant list"
21179
21762
  (click)="onRefresh($event)">
21180
21763
  <kendo-svgicon [icon]="refreshIcon" size="small"
21181
21764
  [class.spinning]="isRefreshing"></kendo-svgicon>
@@ -21194,7 +21777,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
21194
21777
  </kendo-popup>
21195
21778
  }
21196
21779
  }
21197
- `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:inline-flex;align-items:center}.tenant-badge{display:flex;align-items:center;gap:8px;padding:6px 14px;background:var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent));border:1px solid var(--mm-tenant-switcher-border, var(--kendo-color-border, #dee2e6));border-radius:var(--mm-tenant-switcher-radius, 4px 16px 16px 4px);box-shadow:var(--mm-tenant-switcher-shadow, none);cursor:pointer;transition:all .2s ease}.tenant-badge:hover{background:var(--mm-tenant-switcher-bg-hover, var(--kendo-color-base-hover, rgba(0, 0, 0, .04)));box-shadow:var(--mm-tenant-switcher-shadow-hover, var(--mm-tenant-switcher-shadow, none))}.tenant-icon{font-size:.7rem;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));animation:var(--mm-tenant-switcher-icon-animation, none)}.tenant-name{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.85rem;font-weight:600;letter-spacing:1px;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));text-transform:uppercase;text-shadow:var(--mm-tenant-switcher-text-shadow, none)}.denied{background:var(--mm-tenant-switcher-denied-bg, var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent)));border-color:var(--mm-tenant-switcher-denied-border, var(--kendo-color-error, #d9534f));box-shadow:var(--mm-tenant-switcher-denied-shadow, none)}.denied .tenant-icon,.denied .tenant-name{color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));text-shadow:var(--mm-tenant-switcher-denied-text-shadow, none)}.denied-label{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.55rem;font-weight:700;letter-spacing:1px;color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));background:var(--mm-tenant-switcher-denied-label-bg, color-mix(in srgb, var(--kendo-color-error, #d9534f) 15%, transparent));padding:2px 6px;border-radius:3px}.tenant-popup{min-width:220px;padding:8px 0;background:var(--kendo-color-surface, #fff);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.tenant-popup-header{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--kendo-color-subtle, #666);border-bottom:1px solid var(--kendo-color-border, #dee2e6);margin-bottom:4px}.refresh-btn{padding:2px;min-width:unset}.spinning{animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tenant-list{list-style:none;margin:0;padding:0}.tenant-list-item{display:flex;align-items:center;gap:10px;padding:8px 16px;cursor:pointer;font-size:.85rem;transition:background .15s ease}.tenant-list-item:hover{background:var(--kendo-color-base-hover, rgba(0, 0, 0, .04))}.tenant-list-item.active{color:var(--kendo-color-primary, #ff6358);font-weight:600}.tenant-list-icon{font-size:.5rem;color:var(--kendo-color-subtle, #666)}.tenant-list-item.active .tenant-list-icon{color:var(--kendo-color-primary, #ff6358)}@keyframes mm-icon-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.1)}}\n"] }]
21780
+ `, changeDetection: ChangeDetectionStrategy.Eager, styles: [":host{display:inline-flex;align-items:center;min-width:0;max-width:100%}.tenant-badge{display:flex;align-items:center;gap:8px;min-width:0;padding:var(--mm-tenant-switcher-padding, 6px 14px);background:var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent));border:1px solid var(--mm-tenant-switcher-border, var(--kendo-color-border, #dee2e6));border-radius:var(--mm-tenant-switcher-radius, 4px 16px 16px 4px);box-shadow:var(--mm-tenant-switcher-shadow, none);cursor:pointer;transition:all .2s ease}.tenant-badge:hover{background:var(--mm-tenant-switcher-bg-hover, var(--kendo-color-base-hover, rgba(0, 0, 0, .04)));box-shadow:var(--mm-tenant-switcher-shadow-hover, var(--mm-tenant-switcher-shadow, none))}.tenant-icon{flex:none;font-size:.7rem;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));animation:var(--mm-tenant-switcher-icon-animation, none)}.tenant-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mm-tenant-switcher-font, inherit);font-size:.85rem;font-weight:600;color:var(--mm-tenant-switcher-accent, var(--kendo-color-primary, #ff6358));text-shadow:var(--mm-tenant-switcher-text-shadow, none)}.denied{background:var(--mm-tenant-switcher-denied-bg, var(--mm-tenant-switcher-bg, var(--kendo-color-surface, transparent)));border-color:var(--mm-tenant-switcher-denied-border, var(--kendo-color-error, #d9534f));box-shadow:var(--mm-tenant-switcher-denied-shadow, none)}.denied .tenant-icon,.denied .tenant-name{color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));text-shadow:var(--mm-tenant-switcher-denied-text-shadow, none)}.denied-label{font-family:var(--mm-tenant-switcher-font, inherit);font-size:.55rem;font-weight:700;color:var(--mm-tenant-switcher-denied-accent, var(--kendo-color-error, #d9534f));background:var(--mm-tenant-switcher-denied-label-bg, color-mix(in srgb, var(--kendo-color-error, #d9534f) 15%, transparent));padding:2px 6px;border-radius:3px}.tenant-popup{min-width:220px;padding:8px 0;background:var(--kendo-color-surface, #fff);border:1px solid var(--kendo-color-border, #dee2e6);border-radius:4px}.tenant-popup-header{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;font-size:.75rem;font-weight:600;color:var(--kendo-color-subtle, #666);border-bottom:1px solid var(--kendo-color-border, #dee2e6);margin-bottom:4px}.refresh-btn{padding:2px;min-width:unset}.spinning{animation:spin .8s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tenant-list{list-style:none;margin:0;padding:0}.tenant-list-item{display:flex;align-items:center;gap:10px;padding:8px 16px;cursor:pointer;font-size:.85rem;transition:background .15s ease}.tenant-list-item:hover{background:var(--kendo-color-base-hover, rgba(0, 0, 0, .04))}.tenant-list-item.active{color:var(--kendo-color-primary, #ff6358);font-weight:600}.tenant-list-icon{font-size:.5rem;color:var(--kendo-color-subtle, #666)}.tenant-list-item.active .tenant-list-icon{color:var(--kendo-color-primary, #ff6358)}@keyframes mm-icon-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.1)}}\n"] }]
21198
21781
  }], propDecorators: { currentTenantId: [{
21199
21782
  type: Input
21200
21783
  }], allowedTenants: [{
@@ -21371,5 +21954,5 @@ function provideOctoUi() {
21371
21954
  * Generated bundle index. Do not edit.
21372
21955
  */
21373
21956
 
21374
- export { AssociationValidationService, AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, BulkMappingDialogComponent, BulkMappingDialogService, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DEFAULT_CK_TYPE_SELECTOR_DIALOG_MESSAGES, DEFAULT_CK_TYPE_SELECTOR_INPUT_MESSAGES, DEFAULT_DATA_POINT, DEFAULT_MAPPING_COVERAGE_TREE_CONFIG, DEFAULT_PROPERTY_GRID_MESSAGES, DEFAULT_RUNTIME_BROWSER_MESSAGES, DataMappingOverviewComponent, DataPointPickerComponent, DataPointResolverService, DefaultPropertyCategory, EntityDetailComponent, EntityIdInfoComponent, EntitySelectorDialogComponent, EntitySelectorDialogService, FieldFilterEditorComponent, MAPPING_COVERAGE_CONFIG_CONSTANTS, MappingCoverageConfigService, MappingCoverageTreeComponent, MappingCoverageTreeDataSource, MappingEditDialogComponent, MappingEditDialogService, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, OctoLoaderComponent, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, RUNTIME_BROWSER_MESSAGES, RecordDetailDialogComponent, RtEntityIdHelper, RuntimeBrowserComponent, RuntimeBrowserOutletComponent, RuntimeBrowserPageComponent, RuntimeBrowserStateService, RuntimeEntityVariableDialogComponent, RuntimeEntityVariableDialogService, TREE_NAVIGATION_CONFIG_CONSTANTS, TenantSwitcherComponent, ThemeModeService, ThemeModeToggleComponent, TreeNavigationConfigService, account_tree, add, analytics, app_registration, article, botService, category, chat, checklist, code, coerceDataPointValue, component_exchange, computeExpressionPreview, computer, createRuntimeBrowserRoutes, customer, dashboard, event_list, extractDataPointNames, extractDataPoints, graphic_eq, group, identityService, insert_link, manage_accounts, more_time, notifications, page_info, pages, person_search, playlist_add_check, pool, power, provideOctoUi, publicIcon, query_builder, schedule_send, settings, sort, storage, swagger, swagger_asset, swagger_bot, swagger_communication, swagger_identity, team_dashboard, tenancy, text_snippet, travel_explore, user_diagnostics, webhook, work };
21957
+ export { AssociationValidationService, AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, BulkMappingDialogComponent, BulkMappingDialogService, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DATA_POINT_MAPPING_ATTRIBUTE_NAMES, DEFAULT_CK_TYPE_SELECTOR_DIALOG_MESSAGES, DEFAULT_CK_TYPE_SELECTOR_INPUT_MESSAGES, DEFAULT_DATA_POINT, DEFAULT_MAPPING_COVERAGE_TREE_CONFIG, DEFAULT_PROPERTY_GRID_MESSAGES, DEFAULT_RUNTIME_BROWSER_MESSAGES, DataMappingOverviewComponent, DataPointPickerComponent, DataPointResolverService, DefaultPropertyCategory, EntityDetailComponent, EntityIdInfoComponent, EntitySelectorDialogComponent, EntitySelectorDialogService, FieldFilterEditorComponent, MAPPING_COVERAGE_CONFIG_CONSTANTS, MM_PAGE, MappingCoverageConfigService, MappingCoverageTreeComponent, MappingCoverageTreeDataSource, MappingEditDialogComponent, MappingEditDialogService, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, OctoLoaderComponent, PageActionsDirective, PageComponent, PageSubtitleDirective, PageTitleDirective, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, RUNTIME_BROWSER_MESSAGES, RecordDetailDialogComponent, RtEntityIdHelper, RuntimeBrowserComponent, RuntimeBrowserOutletComponent, RuntimeBrowserPageComponent, RuntimeBrowserStateService, RuntimeEntityVariableDialogComponent, RuntimeEntityVariableDialogService, SecretSafeAttributeNamesService, TREE_NAVIGATION_CONFIG_CONSTANTS, TenantSwitcherComponent, ThemeModeService, ThemeModeToggleComponent, TreeNavigationConfigService, account_tree, add, analytics, app_registration, article, botService, category, chat, checklist, code, coerceDataPointValue, component_exchange, computeExpressionPreview, computer, createRuntimeBrowserRoutes, customer, dashboard, event_list, extractDataPointNames, extractDataPoints, graphic_eq, group, identityService, insert_link, isSecretMarker, manage_accounts, more_time, notifications, page_info, pages, person_search, playlist_add_check, pool, power, provideOctoUi, publicIcon, query_builder, schedule_send, settings, sort, storage, swagger, swagger_asset, swagger_bot, swagger_communication, swagger_identity, team_dashboard, tenancy, text_snippet, travel_explore, user_diagnostics, webhook, work };
21375
21958
  //# sourceMappingURL=meshmakers-octo-ui.mjs.map