@meshmakers/octo-ui 3.3.410 → 3.3.430

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.
@@ -17,7 +17,7 @@ import * as i3$1 from '@progress/kendo-angular-dropdowns';
17
17
  import { DropDownListModule, DropDownsModule, AutoCompleteModule } from '@progress/kendo-angular-dropdowns';
18
18
  import * as i5$1 from '@progress/kendo-angular-icons';
19
19
  import { IconsModule, SVGIconModule } from '@progress/kendo-angular-icons';
20
- import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, filterClearIcon, chevronRightIcon, chevronDownIcon, downloadIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, plusIcon, minusIcon, trashIcon, dollarIcon, copyIcon } from '@progress/kendo-svg-icons';
20
+ import { searchIcon, sortAscSmallIcon, sortDescSmallIcon, chevronRightIcon, chevronDownIcon, downloadIcon, fileIcon, folderIcon, calendarIcon, checkboxCheckedIcon, listUnorderedIcon, filterClearIcon, arrowRightIcon, arrowLeftIcon, chevronDoubleRightIcon, chevronDoubleLeftIcon, arrowUpIcon, arrowDownIcon, plusIcon, minusIcon, trashIcon, dollarIcon, copyIcon } from '@progress/kendo-svg-icons';
21
21
  import * as i5 from '@progress/kendo-angular-dialog';
22
22
  import { DialogContentBase, DialogRef, DialogModule, DialogService } from '@progress/kendo-angular-dialog';
23
23
  import { Subject, firstValueFrom, of, forkJoin, Subscription } from 'rxjs';
@@ -910,485 +910,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
910
910
  }]
911
911
  }] });
912
912
 
913
- class CkTypeSelectorDialogComponent extends DialogContentBase {
914
- ckTypeSelectorService = inject(CkTypeSelectorService);
915
- searchSubject = new Subject();
916
- subscriptions = new Subscription();
917
- searchIcon = searchIcon;
918
- filterClearIcon = filterClearIcon;
919
- dialogTitle = 'Select Construction Kit Type';
920
- allowAbstract = false;
921
- searchText = '';
922
- selectedModel = null;
923
- availableModels = [];
924
- gridData = { data: [], total: 0 };
925
- isLoading = false;
926
- pageSize = 50;
927
- skip = 0;
928
- selectedKeys = [];
929
- selectedType = null;
930
- // Selection key function - returns fullName as unique identifier
931
- selectItemBy = (context) => context.dataItem.fullName;
932
- initialCkModelIds;
933
- constructor() {
934
- super(inject(DialogRef));
935
- }
936
- ngOnInit() {
937
- const data = this.dialog.content?.instance?.data;
938
- if (data) {
939
- this.dialogTitle = data.dialogTitle || 'Select Construction Kit Type';
940
- this.allowAbstract = data.allowAbstract ?? false;
941
- this.initialCkModelIds = data.ckModelIds;
942
- if (data.selectedCkTypeId) {
943
- this.selectedKeys = [data.selectedCkTypeId];
944
- }
945
- }
946
- // Set up search debouncing
947
- this.subscriptions.add(this.searchSubject.pipe(debounceTime(300), distinctUntilChanged()).subscribe(() => {
948
- this.skip = 0;
949
- this.loadTypes();
950
- }));
951
- // Load initial types and extract available models
952
- this.loadTypes();
953
- this.loadAvailableModels();
954
- }
955
- ngOnDestroy() {
956
- this.subscriptions.unsubscribe();
957
- }
958
- loadTypes() {
959
- this.isLoading = true;
960
- const ckModelIds = this.selectedModel
961
- ? [this.selectedModel]
962
- : this.initialCkModelIds;
963
- this.subscriptions.add(this.ckTypeSelectorService.getCkTypes({
964
- ckModelIds,
965
- searchText: this.searchText || undefined,
966
- first: this.pageSize,
967
- skip: this.skip
968
- }).subscribe({
969
- next: result => {
970
- this.gridData = {
971
- data: result.items,
972
- total: result.totalCount
973
- };
974
- // Restore selection if exists
975
- if (this.selectedKeys.length > 0) {
976
- const selectedItem = result.items.find(item => item.fullName === this.selectedKeys[0]);
977
- if (selectedItem) {
978
- this.selectedType = selectedItem;
979
- }
980
- }
981
- this.isLoading = false;
982
- },
983
- error: () => {
984
- this.isLoading = false;
985
- this.gridData = { data: [], total: 0 };
986
- }
987
- }));
988
- }
989
- loadAvailableModels() {
990
- // Load all types to extract unique models
991
- this.subscriptions.add(this.ckTypeSelectorService.getCkTypes({
992
- first: 1000
993
- }).subscribe(result => {
994
- const modelSet = new Set();
995
- result.items.forEach(item => {
996
- // Extract model from fullName (format: "ModelName-Version/TypeName-Version")
997
- const modelMatch = item.fullName.match(/^([^/]+)\//);
998
- if (modelMatch) {
999
- modelSet.add(modelMatch[1]);
1000
- }
1001
- });
1002
- this.availableModels = Array.from(modelSet).sort();
1003
- }));
1004
- }
1005
- onSearchChange(value) {
1006
- this.searchSubject.next(value);
1007
- }
1008
- onModelFilterChange(_value) {
1009
- this.skip = 0;
1010
- this.loadTypes();
1011
- }
1012
- clearFilters() {
1013
- this.searchText = '';
1014
- this.selectedModel = null;
1015
- this.skip = 0;
1016
- this.loadTypes();
1017
- }
1018
- onPageChange(event) {
1019
- this.skip = event.skip;
1020
- this.pageSize = event.take;
1021
- this.loadTypes();
1022
- }
1023
- onSelectionChange(event) {
1024
- const selectedItems = event.selectedRows;
1025
- if (selectedItems && selectedItems.length > 0) {
1026
- this.selectedType = selectedItems[0].dataItem;
1027
- }
1028
- else {
1029
- this.selectedType = null;
1030
- }
1031
- }
1032
- onCancel() {
1033
- this.dialog.close();
1034
- }
1035
- onConfirm() {
1036
- if (this.selectedType) {
1037
- const result = {
1038
- selectedCkType: this.selectedType
1039
- };
1040
- this.dialog.close(result);
1041
- }
1042
- }
1043
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1044
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: CkTypeSelectorDialogComponent, isStandalone: true, selector: "mm-ck-type-selector-dialog", usesInheritance: true, ngImport: i0, template: `
1045
- <div class="ck-type-selector-container">
1046
- <div class="filter-container">
1047
- <div class="filter-row">
1048
- <div class="filter-item">
1049
- <label>Model Filter</label>
1050
- <kendo-combobox
1051
- [data]="availableModels"
1052
- [(ngModel)]="selectedModel"
1053
- (valueChange)="onModelFilterChange($event)"
1054
- [allowCustom]="false"
1055
- [clearButton]="true"
1056
- placeholder="All Models"
1057
- class="filter-input">
1058
- </kendo-combobox>
1059
- </div>
1060
- <div class="filter-item flex-grow">
1061
- <label>Type Search</label>
1062
- <kendo-textbox
1063
- [(ngModel)]="searchText"
1064
- (ngModelChange)="onSearchChange($event)"
1065
- placeholder="Search types..."
1066
- class="filter-input">
1067
- <ng-template kendoTextBoxSuffixTemplate>
1068
- <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
1069
- </ng-template>
1070
- </kendo-textbox>
1071
- </div>
1072
- <div class="filter-item filter-actions">
1073
- <label>&nbsp;</label>
1074
- <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" title="Clear filters"></button>
1075
- </div>
1076
- </div>
1077
- </div>
1078
-
1079
- <div class="grid-container">
1080
- <kendo-grid
1081
- [data]="gridData"
1082
- [loading]="isLoading"
1083
- [height]="400"
1084
- [selectable]="{ mode: 'single' }"
1085
- [pageable]="{ pageSizes: [25, 50, 100] }"
1086
- [pageSize]="pageSize"
1087
- [skip]="skip"
1088
- (pageChange)="onPageChange($event)"
1089
- (selectionChange)="onSelectionChange($event)"
1090
- [kendoGridSelectBy]="selectItemBy"
1091
- [(selectedKeys)]="selectedKeys"
1092
- class="type-grid">
1093
- <kendo-grid-column field="rtCkTypeId" title="Type" [width]="300">
1094
- <ng-template kendoGridCellTemplate let-dataItem>
1095
- <span [class.abstract-type]="dataItem.isAbstract" [class.final-type]="dataItem.isFinal">
1096
- {{ dataItem.rtCkTypeId }}
1097
- </span>
1098
- <span *ngIf="dataItem.isAbstract" class="type-badge abstract">abstract</span>
1099
- <span *ngIf="dataItem.isFinal" class="type-badge final">final</span>
1100
- </ng-template>
1101
- </kendo-grid-column>
1102
- <kendo-grid-column field="baseTypeRtCkTypeId" title="Base Type" [width]="200">
1103
- <ng-template kendoGridCellTemplate let-dataItem>
1104
- {{ dataItem.baseTypeRtCkTypeId || '-' }}
1105
- </ng-template>
1106
- </kendo-grid-column>
1107
- <kendo-grid-column field="description" title="Description">
1108
- <ng-template kendoGridCellTemplate let-dataItem>
1109
- {{ dataItem.description || '-' }}
1110
- </ng-template>
1111
- </kendo-grid-column>
1112
- </kendo-grid>
1113
- </div>
1114
-
1115
- <div class="selection-info" *ngIf="selectedType">
1116
- <strong>Selected:</strong> {{ selectedType.rtCkTypeId }}
1117
- </div>
1118
- </div>
1119
-
1120
- <kendo-dialog-actions>
1121
- <button kendoButton (click)="onCancel()">Cancel</button>
1122
- <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">OK</button>
1123
- </kendo-dialog-actions>
1124
- `, isInline: true, styles: [".ck-type-selector-container{display:flex;flex-direction:column;height:100%;padding:20px;min-width:700px;box-sizing:border-box}.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}.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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i2$1.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"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: i2$1.SelectionDirective, selector: "[kendoGridSelectBy]" }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i2$1.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i3.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i4.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: i4.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: DialogModule }, { kind: "component", type: i5.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }] });
1125
- }
1126
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogComponent, decorators: [{
1127
- type: Component,
1128
- args: [{ selector: 'mm-ck-type-selector-dialog', standalone: true, imports: [
1129
- CommonModule,
1130
- FormsModule,
1131
- GridModule,
1132
- ButtonsModule,
1133
- InputsModule,
1134
- DropDownsModule,
1135
- IconsModule,
1136
- LoaderModule,
1137
- DialogModule
1138
- ], template: `
1139
- <div class="ck-type-selector-container">
1140
- <div class="filter-container">
1141
- <div class="filter-row">
1142
- <div class="filter-item">
1143
- <label>Model Filter</label>
1144
- <kendo-combobox
1145
- [data]="availableModels"
1146
- [(ngModel)]="selectedModel"
1147
- (valueChange)="onModelFilterChange($event)"
1148
- [allowCustom]="false"
1149
- [clearButton]="true"
1150
- placeholder="All Models"
1151
- class="filter-input">
1152
- </kendo-combobox>
1153
- </div>
1154
- <div class="filter-item flex-grow">
1155
- <label>Type Search</label>
1156
- <kendo-textbox
1157
- [(ngModel)]="searchText"
1158
- (ngModelChange)="onSearchChange($event)"
1159
- placeholder="Search types..."
1160
- class="filter-input">
1161
- <ng-template kendoTextBoxSuffixTemplate>
1162
- <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
1163
- </ng-template>
1164
- </kendo-textbox>
1165
- </div>
1166
- <div class="filter-item filter-actions">
1167
- <label>&nbsp;</label>
1168
- <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" title="Clear filters"></button>
1169
- </div>
1170
- </div>
1171
- </div>
1172
-
1173
- <div class="grid-container">
1174
- <kendo-grid
1175
- [data]="gridData"
1176
- [loading]="isLoading"
1177
- [height]="400"
1178
- [selectable]="{ mode: 'single' }"
1179
- [pageable]="{ pageSizes: [25, 50, 100] }"
1180
- [pageSize]="pageSize"
1181
- [skip]="skip"
1182
- (pageChange)="onPageChange($event)"
1183
- (selectionChange)="onSelectionChange($event)"
1184
- [kendoGridSelectBy]="selectItemBy"
1185
- [(selectedKeys)]="selectedKeys"
1186
- class="type-grid">
1187
- <kendo-grid-column field="rtCkTypeId" title="Type" [width]="300">
1188
- <ng-template kendoGridCellTemplate let-dataItem>
1189
- <span [class.abstract-type]="dataItem.isAbstract" [class.final-type]="dataItem.isFinal">
1190
- {{ dataItem.rtCkTypeId }}
1191
- </span>
1192
- <span *ngIf="dataItem.isAbstract" class="type-badge abstract">abstract</span>
1193
- <span *ngIf="dataItem.isFinal" class="type-badge final">final</span>
1194
- </ng-template>
1195
- </kendo-grid-column>
1196
- <kendo-grid-column field="baseTypeRtCkTypeId" title="Base Type" [width]="200">
1197
- <ng-template kendoGridCellTemplate let-dataItem>
1198
- {{ dataItem.baseTypeRtCkTypeId || '-' }}
1199
- </ng-template>
1200
- </kendo-grid-column>
1201
- <kendo-grid-column field="description" title="Description">
1202
- <ng-template kendoGridCellTemplate let-dataItem>
1203
- {{ dataItem.description || '-' }}
1204
- </ng-template>
1205
- </kendo-grid-column>
1206
- </kendo-grid>
1207
- </div>
1208
-
1209
- <div class="selection-info" *ngIf="selectedType">
1210
- <strong>Selected:</strong> {{ selectedType.rtCkTypeId }}
1211
- </div>
1212
- </div>
1213
-
1214
- <kendo-dialog-actions>
1215
- <button kendoButton (click)="onCancel()">Cancel</button>
1216
- <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">OK</button>
1217
- </kendo-dialog-actions>
1218
- `, styles: [".ck-type-selector-container{display:flex;flex-direction:column;height:100%;padding:20px;min-width:700px;box-sizing:border-box}.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}.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}\n"] }]
1219
- }], ctorParameters: () => [] });
1220
-
1221
- class CkTypeSelectorDialogService {
1222
- dialogService = inject(DialogService);
1223
- /**
1224
- * Opens the CkType selector dialog
1225
- * @param options Dialog options
1226
- * @returns Promise that resolves with the result containing selected CkType and confirmation status
1227
- */
1228
- async openCkTypeSelector(options = {}) {
1229
- const data = {
1230
- selectedCkTypeId: options.selectedCkTypeId,
1231
- ckModelIds: options.ckModelIds,
1232
- dialogTitle: options.dialogTitle,
1233
- allowAbstract: options.allowAbstract
1234
- };
1235
- const dialogRef = this.dialogService.open({
1236
- content: CkTypeSelectorDialogComponent,
1237
- width: 900,
1238
- height: 650,
1239
- minWidth: 750,
1240
- minHeight: 550,
1241
- title: options.dialogTitle || 'Select Construction Kit Type'
1242
- });
1243
- // Pass data to the component
1244
- if (dialogRef.content?.instance) {
1245
- dialogRef.content.instance.data = data;
1246
- }
1247
- try {
1248
- const result = await firstValueFrom(dialogRef.result);
1249
- if (result && typeof result === 'object' && 'selectedCkType' in result) {
1250
- // User clicked OK and we have a result
1251
- const dialogResult = result;
1252
- return {
1253
- confirmed: true,
1254
- selectedCkType: dialogResult.selectedCkType
1255
- };
1256
- }
1257
- else {
1258
- // User clicked Cancel or closed dialog
1259
- return {
1260
- confirmed: false,
1261
- selectedCkType: null
1262
- };
1263
- }
1264
- }
1265
- catch {
1266
- // Dialog was closed without result (e.g., ESC key, X button)
1267
- return {
1268
- confirmed: false,
1269
- selectedCkType: null
1270
- };
1271
- }
1272
- }
1273
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1274
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService });
1275
- }
1276
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService, decorators: [{
1277
- type: Injectable
1278
- }] });
1279
-
1280
- // noinspection JSUnusedGlobalSymbols
1281
- class OctoGraphQlDataSource extends DataSourceTyped {
1282
- _searchFilterAttributePaths = [];
1283
- // noinspection JSUnusedGlobalSymbols
1284
- constructor(listViewComponent) {
1285
- super(listViewComponent);
1286
- }
1287
- get searchFilterAttributePaths() {
1288
- return this._searchFilterAttributePaths;
1289
- }
1290
- set searchFilterAttributePaths(value) {
1291
- this._searchFilterAttributePaths = value;
1292
- }
1293
- // noinspection JSUnusedGlobalSymbols
1294
- getFieldFilterDefinitions(state) {
1295
- let fieldFilters = null;
1296
- if (state.filter?.filters) {
1297
- fieldFilters = state.filter.filters.map((f) => {
1298
- if (isCompositeFilterDescriptor(f)) {
1299
- throw new Error('Composite filter descriptor not supported');
1300
- }
1301
- const { operator, value } = OctoGraphQlDataSource.getOperatorAndValue(f.operator, f.value);
1302
- return {
1303
- attributePath: f.field,
1304
- operator: operator,
1305
- comparisonValue: value
1306
- };
1307
- });
1308
- }
1309
- return fieldFilters;
1310
- }
1311
- // noinspection JSUnusedGlobalSymbols
1312
- getSearchFilterDefinitions(textSearchValue) {
1313
- let searchFilterDto = null;
1314
- if (textSearchValue) {
1315
- searchFilterDto = {
1316
- type: SearchFilterTypesDto.AttributeFilterDto,
1317
- attributePaths: this.searchFilterAttributePaths,
1318
- searchTerm: textSearchValue,
1319
- };
1320
- }
1321
- return searchFilterDto;
1322
- }
1323
- // noinspection JSUnusedGlobalSymbols
1324
- getSortDefinitions(state) {
1325
- let sort = null;
1326
- if (state.sort) {
1327
- sort = new Array();
1328
- state.sort.forEach((s) => {
1329
- switch (s.dir) {
1330
- case 'asc':
1331
- sort?.push({
1332
- attributePath: s.field,
1333
- sortOrder: SortOrdersDto.AscendingDto
1334
- });
1335
- break;
1336
- case 'desc':
1337
- sort?.push({
1338
- attributePath: s.field,
1339
- sortOrder: SortOrdersDto.DescendingDto,
1340
- });
1341
- break;
1342
- default:
1343
- sort?.push({
1344
- attributePath: s.field,
1345
- sortOrder: SortOrdersDto.DefaultDto,
1346
- });
1347
- break;
1348
- }
1349
- });
1350
- }
1351
- return sort;
1352
- }
1353
- static getOperatorAndValue(operator, value) {
1354
- switch (operator) {
1355
- case 'eq':
1356
- return { operator: FieldFilterOperatorsDto.EqualsDto, value: value };
1357
- case 'neq':
1358
- return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: value };
1359
- case 'lt':
1360
- return { operator: FieldFilterOperatorsDto.LessThanDto, value: value };
1361
- case 'lte':
1362
- return { operator: FieldFilterOperatorsDto.LessEqualThanDto, value: value };
1363
- case 'gt':
1364
- return { operator: FieldFilterOperatorsDto.GreaterThanDto, value: value };
1365
- case 'gte':
1366
- return { operator: FieldFilterOperatorsDto.GreaterEqualThanDto, value: value };
1367
- case 'contains':
1368
- return { operator: FieldFilterOperatorsDto.LikeDto, value: value };
1369
- case 'doesnotcontain':
1370
- return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: `^(?!.*${value}).*$` };
1371
- case 'startswith':
1372
- return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: value + '.*' };
1373
- case 'endswith':
1374
- return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: '.*' + value };
1375
- case 'isnull':
1376
- return { operator: FieldFilterOperatorsDto.EqualsDto, value: null };
1377
- case 'isnotnull':
1378
- return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: null };
1379
- case 'isempty':
1380
- return { operator: FieldFilterOperatorsDto.EqualsDto, value: "" };
1381
- case 'isnotempty':
1382
- return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: "" };
1383
- default:
1384
- throw new Error('The filter operator is not supported');
1385
- }
1386
- }
1387
- }
1388
-
1389
- class OctoGraphQlHierarchyDataSource extends HierarchyDataSourceBase {
1390
- }
1391
-
1392
913
  /**
1393
914
  * Component for displaying property values with appropriate formatting
1394
915
  */
@@ -1837,502 +1358,981 @@ class PropertyValueDisplayComponent {
1837
1358
  </div>
1838
1359
  }
1839
1360
  </div>
1840
- }
1841
- </div>
1842
- } @else if (isBinaryLinkedWithDownload()) {
1843
- <!-- Binary Linked with download capability -->
1844
- <div class="binary-linked-display">
1845
- <div class="binary-info">
1846
- @if (getBinaryFilename()) {
1847
- <span class="filename">{{ getBinaryFilename() }}</span>
1848
- }
1849
- @if (getBinarySize()) {
1850
- <span class="file-size">({{ formatFileSize(getBinarySize()) }})</span>
1851
- }
1852
- @if (getBinaryContentType()) {
1853
- <span class="content-type">{{ getBinaryContentType() }}</span>
1854
- }
1855
- </div>
1856
- <button
1857
- kendoButton
1858
- size="small"
1859
- fillMode="flat"
1860
- [svgIcon]="downloadIcon"
1861
- title="Download file"
1862
- (click)="onDownload()">
1863
- Download
1864
- </button>
1865
- </div>
1866
- } @else {
1867
- <!-- Non-expandable value display -->
1868
- @switch (displayMode) {
1869
- @case (PropertyDisplayMode.Json) {
1870
- <pre class="json-display">{{ getFormattedValue() }}</pre>
1871
- }
1872
- @case (PropertyDisplayMode.Text) {
1873
- <span class="text-display" [innerHTML]="getFormattedValue()"></span>
1874
- }
1875
- @default {
1876
- <span class="default-display">{{ getFormattedValue() }}</span>
1877
- }
1878
- }
1361
+ }
1362
+ </div>
1363
+ } @else if (isBinaryLinkedWithDownload()) {
1364
+ <!-- Binary Linked with download capability -->
1365
+ <div class="binary-linked-display">
1366
+ <div class="binary-info">
1367
+ @if (getBinaryFilename()) {
1368
+ <span class="filename">{{ getBinaryFilename() }}</span>
1369
+ }
1370
+ @if (getBinarySize()) {
1371
+ <span class="file-size">({{ formatFileSize(getBinarySize()) }})</span>
1372
+ }
1373
+ @if (getBinaryContentType()) {
1374
+ <span class="content-type">{{ getBinaryContentType() }}</span>
1375
+ }
1376
+ </div>
1377
+ <button
1378
+ kendoButton
1379
+ size="small"
1380
+ fillMode="flat"
1381
+ [svgIcon]="downloadIcon"
1382
+ title="Download file"
1383
+ (click)="onDownload()">
1384
+ Download
1385
+ </button>
1386
+ </div>
1387
+ } @else {
1388
+ <!-- Non-expandable value display -->
1389
+ @switch (displayMode) {
1390
+ @case (PropertyDisplayMode.Json) {
1391
+ <pre class="json-display">{{ getFormattedValue() }}</pre>
1392
+ }
1393
+ @case (PropertyDisplayMode.Text) {
1394
+ <span class="text-display" [innerHTML]="getFormattedValue()"></span>
1395
+ }
1396
+ @default {
1397
+ <span class="default-display">{{ getFormattedValue() }}</span>
1398
+ }
1399
+ }
1400
+
1401
+ @if (isComplexType() && !isExpandableRecord()) {
1402
+ <span class="type-indicator" [title]="getTypeDescription()">
1403
+ {{ getTypeIndicator() }}
1404
+ </span>
1405
+ }
1406
+ }
1407
+ </div>
1408
+ `, isInline: true, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;min-height:20px;font-family:inherit;width:100%}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.record-header:hover{background:var(--kendo-color-base-subtle)}.expand-icon{width:16px;height:16px;flex-shrink:0;transition:transform .2s}.record-summary{flex:1;font-size:.9em}.record-content{margin-left:22px;margin-top:8px;border-left:2px solid var(--kendo-color-border);padding-left:12px;background:var(--kendo-color-base-subtle);border-radius:0 4px 4px 0}.nested-properties{display:flex;flex-direction:column;gap:6px;padding:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;min-height:24px}.property-key{font-weight:500;color:var(--kendo-color-primary);min-width:100px;flex-shrink:0;font-size:.9em}.array-item{border:1px solid var(--kendo-color-border);border-radius:4px;margin-bottom:8px;background:transparent}.array-index{display:inline-block;background:var(--kendo-color-primary);color:#fff;padding:2px 8px;font-size:.8em;font-weight:700;border-radius:4px 0;margin-bottom:4px}.json-display{font-family:Courier New,monospace;font-size:12px;margin:0;padding:4px 8px;background:var(--kendo-color-base-subtle);border-radius:4px;max-width:300px;overflow:auto}.text-display,.default-display{flex:1;word-break:break-word;overflow-wrap:anywhere}.type-boolean .default-display{font-weight:500}.type-boolean .default-display.value-true{color:#28a745}.type-boolean .default-display.value-false{color:#dc3545}:is(.type-datetime,.type-datetimeoffset) .default-display{font-family:monospace;font-size:.9em}:is(.type-int,.type-integer,.type-double) .default-display{font-family:monospace;text-align:right}.type-indicator{font-size:.75em;padding:2px 6px;background:var(--kendo-color-primary);color:#fff;border-radius:3px;text-transform:uppercase;font-weight:500;flex-shrink:0}.empty-value{color:var(--kendo-color-subtle);font-style:italic}.null-value{color:var(--kendo-color-error);font-style:italic}.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;color:var(--kendo-color-on-app-surface);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"], outputs: ["binaryDownload"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
1409
+ }
1410
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyValueDisplayComponent, decorators: [{
1411
+ type: Component,
1412
+ args: [{ selector: 'mm-property-value-display', standalone: true, imports: [CommonModule, SVGIconModule, ButtonModule], template: `
1413
+ <div class="property-value-display" [ngClass]="'type-' + type.toLowerCase()">
1414
+
1415
+ @if (isExpandableRecord()) {
1416
+ <div class="expandable-record">
1417
+ <!-- Expand/Collapse Button and Summary -->
1418
+ <div class="record-header" (click)="toggleExpansion()">
1419
+ <kendo-svgicon
1420
+ [icon]="isExpanded ? chevronDownIcon : chevronRightIcon"
1421
+ class="expand-icon">
1422
+ </kendo-svgicon>
1423
+ <span class="record-summary">{{ getRecordSummary() }}</span>
1424
+ <span class="type-indicator" [title]="getTypeDescription()">
1425
+ {{ getTypeIndicator() }}
1426
+ </span>
1427
+ </div>
1428
+
1429
+ <!-- Expanded Content -->
1430
+ @if (isExpanded) {
1431
+ <div class="record-content">
1432
+ @if (type === AttributeValueTypeDto.RecordArrayDto && Array.isArray(value)) {
1433
+ @for (item of value; track $index) {
1434
+ <div class="array-item">
1435
+ <span class="array-index">[{{ $index }}]</span>
1436
+ <div class="nested-properties">
1437
+ @for (prop of getObjectProperties(item); track prop.key) {
1438
+ <div class="nested-property">
1439
+ <span class="property-key">{{ prop.key }}:</span>
1440
+ <mm-property-value-display
1441
+ [value]="prop.value"
1442
+ [type]="getPropertyType(prop.value)">
1443
+ </mm-property-value-display>
1444
+ </div>
1445
+ }
1446
+ </div>
1447
+ </div>
1448
+ }
1449
+ } @else {
1450
+ <div class="nested-properties">
1451
+ @for (prop of getObjectProperties(value); track prop.key) {
1452
+ <div class="nested-property">
1453
+ <span class="property-key">{{ prop.key }}:</span>
1454
+ <mm-property-value-display
1455
+ [value]="prop.value"
1456
+ [type]="getPropertyType(prop.value)">
1457
+ </mm-property-value-display>
1458
+ </div>
1459
+ }
1460
+ </div>
1461
+ }
1462
+ </div>
1463
+ }
1464
+ </div>
1465
+ } @else if (isBinaryLinkedWithDownload()) {
1466
+ <!-- Binary Linked with download capability -->
1467
+ <div class="binary-linked-display">
1468
+ <div class="binary-info">
1469
+ @if (getBinaryFilename()) {
1470
+ <span class="filename">{{ getBinaryFilename() }}</span>
1471
+ }
1472
+ @if (getBinarySize()) {
1473
+ <span class="file-size">({{ formatFileSize(getBinarySize()) }})</span>
1474
+ }
1475
+ @if (getBinaryContentType()) {
1476
+ <span class="content-type">{{ getBinaryContentType() }}</span>
1477
+ }
1478
+ </div>
1479
+ <button
1480
+ kendoButton
1481
+ size="small"
1482
+ fillMode="flat"
1483
+ [svgIcon]="downloadIcon"
1484
+ title="Download file"
1485
+ (click)="onDownload()">
1486
+ Download
1487
+ </button>
1488
+ </div>
1489
+ } @else {
1490
+ <!-- Non-expandable value display -->
1491
+ @switch (displayMode) {
1492
+ @case (PropertyDisplayMode.Json) {
1493
+ <pre class="json-display">{{ getFormattedValue() }}</pre>
1494
+ }
1495
+ @case (PropertyDisplayMode.Text) {
1496
+ <span class="text-display" [innerHTML]="getFormattedValue()"></span>
1497
+ }
1498
+ @default {
1499
+ <span class="default-display">{{ getFormattedValue() }}</span>
1500
+ }
1501
+ }
1502
+
1503
+ @if (isComplexType() && !isExpandableRecord()) {
1504
+ <span class="type-indicator" [title]="getTypeDescription()">
1505
+ {{ getTypeIndicator() }}
1506
+ </span>
1507
+ }
1508
+ }
1509
+ </div>
1510
+ `, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;min-height:20px;font-family:inherit;width:100%}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.record-header:hover{background:var(--kendo-color-base-subtle)}.expand-icon{width:16px;height:16px;flex-shrink:0;transition:transform .2s}.record-summary{flex:1;font-size:.9em}.record-content{margin-left:22px;margin-top:8px;border-left:2px solid var(--kendo-color-border);padding-left:12px;background:var(--kendo-color-base-subtle);border-radius:0 4px 4px 0}.nested-properties{display:flex;flex-direction:column;gap:6px;padding:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;min-height:24px}.property-key{font-weight:500;color:var(--kendo-color-primary);min-width:100px;flex-shrink:0;font-size:.9em}.array-item{border:1px solid var(--kendo-color-border);border-radius:4px;margin-bottom:8px;background:transparent}.array-index{display:inline-block;background:var(--kendo-color-primary);color:#fff;padding:2px 8px;font-size:.8em;font-weight:700;border-radius:4px 0;margin-bottom:4px}.json-display{font-family:Courier New,monospace;font-size:12px;margin:0;padding:4px 8px;background:var(--kendo-color-base-subtle);border-radius:4px;max-width:300px;overflow:auto}.text-display,.default-display{flex:1;word-break:break-word;overflow-wrap:anywhere}.type-boolean .default-display{font-weight:500}.type-boolean .default-display.value-true{color:#28a745}.type-boolean .default-display.value-false{color:#dc3545}:is(.type-datetime,.type-datetimeoffset) .default-display{font-family:monospace;font-size:.9em}:is(.type-int,.type-integer,.type-double) .default-display{font-family:monospace;text-align:right}.type-indicator{font-size:.75em;padding:2px 6px;background:var(--kendo-color-primary);color:#fff;border-radius:3px;text-transform:uppercase;font-weight:500;flex-shrink:0}.empty-value{color:var(--kendo-color-subtle);font-style:italic}.null-value{color:var(--kendo-color-error);font-style:italic}.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;color:var(--kendo-color-on-app-surface);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"] }]
1511
+ }], propDecorators: { value: [{
1512
+ type: Input
1513
+ }], type: [{
1514
+ type: Input
1515
+ }], displayMode: [{
1516
+ type: Input
1517
+ }], binaryDownload: [{
1518
+ type: Output
1519
+ }] } });
1520
+
1521
+ /**
1522
+ * Generic property grid component for OctoMesh
1523
+ */
1524
+ class PropertyGridComponent {
1525
+ data = [];
1526
+ config = {};
1527
+ showTypeColumn = false;
1528
+ propertyChange = new EventEmitter();
1529
+ saveRequested = new EventEmitter();
1530
+ binaryDownload = new EventEmitter();
1531
+ // Component state
1532
+ filteredData = [];
1533
+ searchTerm = '';
1534
+ hasChanges = false;
1535
+ pendingChanges = [];
1536
+ // Icons
1537
+ fileIcon = fileIcon;
1538
+ folderIcon = folderIcon;
1539
+ calendarIcon = calendarIcon;
1540
+ checkboxCheckedIcon = checkboxCheckedIcon;
1541
+ listUnorderedIcon = listUnorderedIcon;
1542
+ // Enum reference
1543
+ AttributeValueTypeDto = AttributeValueTypeDto;
1544
+ ngOnInit() {
1545
+ this.updateFilteredData();
1546
+ }
1547
+ ngOnChanges(changes) {
1548
+ if (changes['data']) {
1549
+ this.updateFilteredData();
1550
+ this.hasChanges = false;
1551
+ this.pendingChanges = [];
1552
+ }
1553
+ }
1554
+ get gridHeight() {
1555
+ const baseHeight = this.config.height || '400px';
1556
+ const searchHeight = this.config.showSearch ? 40 : 0;
1557
+ const toolbarHeight = !this.config.readOnlyMode ? 50 : 0;
1558
+ const totalOffset = searchHeight + toolbarHeight;
1559
+ if (baseHeight.includes('px')) {
1560
+ const px = parseInt(baseHeight) - totalOffset;
1561
+ return `${Math.max(px, 200)}px`;
1562
+ }
1563
+ return baseHeight;
1564
+ }
1565
+ /**
1566
+ * Update filtered data based on search term
1567
+ */
1568
+ updateFilteredData() {
1569
+ if (!this.searchTerm.trim()) {
1570
+ this.filteredData = [...this.data];
1571
+ return;
1572
+ }
1573
+ const term = this.searchTerm.toLowerCase();
1574
+ this.filteredData = this.data.filter(item => item.name.toLowerCase().includes(term) ||
1575
+ (item.displayName?.toLowerCase().includes(term)) ||
1576
+ (item.description?.toLowerCase().includes(term)) ||
1577
+ String(item.value).toLowerCase().includes(term));
1578
+ }
1579
+ /**
1580
+ * Handle search input
1581
+ */
1582
+ onSearch() {
1583
+ this.updateFilteredData();
1584
+ }
1585
+ /**
1586
+ * Get appropriate icon for property type
1587
+ */
1588
+ getTypeIcon(type) {
1589
+ switch (type) {
1590
+ case AttributeValueTypeDto.BooleanDto:
1591
+ return checkboxCheckedIcon;
1592
+ case AttributeValueTypeDto.IntDto:
1593
+ case AttributeValueTypeDto.IntegerDto:
1594
+ case AttributeValueTypeDto.DoubleDto:
1595
+ return fileIcon;
1596
+ case AttributeValueTypeDto.DateTimeDto:
1597
+ case AttributeValueTypeDto.DateTimeOffsetDto:
1598
+ return calendarIcon;
1599
+ case AttributeValueTypeDto.StringArrayDto:
1600
+ case AttributeValueTypeDto.IntegerArrayDto:
1601
+ return listUnorderedIcon;
1602
+ case AttributeValueTypeDto.RecordDto:
1603
+ case AttributeValueTypeDto.RecordArrayDto:
1604
+ return folderIcon;
1605
+ default:
1606
+ return fileIcon;
1607
+ }
1608
+ }
1609
+ /**
1610
+ * Format type name for display
1611
+ */
1612
+ formatTypeName(type) {
1613
+ return type.replace('_DTO', '').replace('DTO', '').replace('_', ' ');
1614
+ }
1615
+ /**
1616
+ * Save pending changes
1617
+ */
1618
+ saveChanges() {
1619
+ if (this.pendingChanges.length > 0) {
1620
+ const updatedData = this.data.map(item => {
1621
+ const change = this.pendingChanges.find(c => c.property.id === item.id);
1622
+ return change ? { ...item, value: change.newValue } : item;
1623
+ });
1624
+ this.saveRequested.emit(updatedData);
1625
+ this.hasChanges = false;
1626
+ this.pendingChanges = [];
1627
+ }
1628
+ }
1629
+ /**
1630
+ * Discard pending changes
1631
+ */
1632
+ discardChanges() {
1633
+ this.hasChanges = false;
1634
+ this.pendingChanges = [];
1635
+ this.updateFilteredData();
1636
+ }
1637
+ /**
1638
+ * Handle property value change
1639
+ */
1640
+ onPropertyChange(property, oldValue, newValue) {
1641
+ const changeEvent = {
1642
+ property,
1643
+ oldValue,
1644
+ newValue
1645
+ };
1646
+ // Update or add to pending changes
1647
+ const existingIndex = this.pendingChanges.findIndex(c => c.property.id === property.id);
1648
+ if (existingIndex >= 0) {
1649
+ this.pendingChanges[existingIndex] = changeEvent;
1650
+ }
1651
+ else {
1652
+ this.pendingChanges.push(changeEvent);
1653
+ }
1654
+ this.hasChanges = this.pendingChanges.length > 0;
1655
+ this.propertyChange.emit(changeEvent);
1656
+ }
1657
+ /**
1658
+ * Handle binary download request from property value display
1659
+ */
1660
+ onBinaryDownload(event) {
1661
+ this.binaryDownload.emit(event);
1662
+ }
1663
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1664
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: PropertyGridComponent, isStandalone: true, selector: "mm-property-grid", inputs: { data: "data", config: "config", showTypeColumn: "showTypeColumn" }, outputs: { propertyChange: "propertyChange", saveRequested: "saveRequested", binaryDownload: "binaryDownload" }, usesOnChanges: true, ngImport: i0, template: `
1665
+ <div class="mm-property-grid" [style.height]="config.height || '400px'">
1666
+
1667
+ @if (config.showSearch) {
1668
+ <div class="search-toolbar">
1669
+ <kendo-textbox
1670
+ [(ngModel)]="searchTerm"
1671
+ placeholder="Search attributes..."
1672
+ (input)="onSearch()"
1673
+ [clearButton]="true">
1674
+ </kendo-textbox>
1675
+ </div>
1676
+ }
1677
+
1678
+ <kendo-grid
1679
+ [data]="filteredData"
1680
+ [sortable]="true"
1681
+ [resizable]="true"
1682
+ [style.height]="gridHeight"
1683
+ [selectable]="{mode: 'single'}"
1684
+ class="property-grid">
1685
+
1686
+ <!-- Property Name Column -->
1687
+ <kendo-grid-column
1688
+ field="displayName"
1689
+ title="Property"
1690
+ [width]="200"
1691
+ [sortable]="true">
1692
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1693
+ <div class="property-name-cell">
1694
+ @if (config.showTypeIcons !== false) {
1695
+ <kendo-svgicon
1696
+ [icon]="getTypeIcon(dataItem.type)"
1697
+ class="type-icon">
1698
+ </kendo-svgicon>
1699
+ }
1700
+ <div class="property-info">
1701
+ <span class="property-name" [title]="dataItem.description">
1702
+ {{ dataItem.displayName || dataItem.name }}
1703
+ </span>
1704
+ @if (dataItem.required) {
1705
+ <span class="required-indicator">*</span>
1706
+ }
1707
+ @if (dataItem.readOnly) {
1708
+ <span class="readonly-indicator" title="Read-only">🔒</span>
1709
+ }
1710
+ </div>
1711
+ </div>
1712
+ </ng-template>
1713
+ </kendo-grid-column>
1879
1714
 
1880
- @if (isComplexType() && !isExpandableRecord()) {
1881
- <span class="type-indicator" [title]="getTypeDescription()">
1882
- {{ getTypeIndicator() }}
1883
- </span>
1715
+ <!-- Property Value Column -->
1716
+ <kendo-grid-column
1717
+ field="value"
1718
+ title="Value"
1719
+ [sortable]="false">
1720
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1721
+ <mm-property-value-display
1722
+ [value]="dataItem.value"
1723
+ [type]="dataItem.type"
1724
+ (binaryDownload)="onBinaryDownload($event)">
1725
+ </mm-property-value-display>
1726
+ </ng-template>
1727
+ </kendo-grid-column>
1728
+
1729
+ <!-- Type Column (optional) -->
1730
+ @if (showTypeColumn) {
1731
+ <kendo-grid-column
1732
+ field="type"
1733
+ title="Type"
1734
+ [width]="120"
1735
+ [sortable]="true">
1736
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1737
+ <span class="type-badge" [ngClass]="'type-' + dataItem.type.toLowerCase()">
1738
+ {{ formatTypeName(dataItem.type) }}
1739
+ </span>
1740
+ </ng-template>
1741
+ </kendo-grid-column>
1884
1742
  }
1885
- }
1743
+
1744
+ </kendo-grid>
1886
1745
  </div>
1887
- `, isInline: true, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;min-height:20px;font-family:inherit;width:100%}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.record-header:hover{background:var(--kendo-color-base-subtle)}.expand-icon{width:16px;height:16px;flex-shrink:0;transition:transform .2s}.record-summary{flex:1;font-size:.9em}.record-content{margin-left:22px;margin-top:8px;border-left:2px solid var(--kendo-color-border);padding-left:12px;background:var(--kendo-color-base-subtle);border-radius:0 4px 4px 0}.nested-properties{display:flex;flex-direction:column;gap:6px;padding:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;min-height:24px}.property-key{font-weight:500;color:var(--kendo-color-primary);min-width:100px;flex-shrink:0;font-size:.9em}.array-item{border:1px solid var(--kendo-color-border);border-radius:4px;margin-bottom:8px;background:transparent}.array-index{display:inline-block;background:var(--kendo-color-primary);color:#fff;padding:2px 8px;font-size:.8em;font-weight:700;border-radius:4px 0;margin-bottom:4px}.json-display{font-family:Courier New,monospace;font-size:12px;margin:0;padding:4px 8px;background:var(--kendo-color-base-subtle);border-radius:4px;max-width:300px;overflow:auto}.text-display,.default-display{flex:1;word-break:break-word;overflow-wrap:anywhere}.type-boolean .default-display{font-weight:500}.type-boolean .default-display.value-true{color:#28a745}.type-boolean .default-display.value-false{color:#dc3545}:is(.type-datetime,.type-datetimeoffset) .default-display{font-family:monospace;font-size:.9em}:is(.type-int,.type-integer,.type-double) .default-display{font-family:monospace;text-align:right}.type-indicator{font-size:.75em;padding:2px 6px;background:var(--kendo-color-primary);color:#fff;border-radius:3px;text-transform:uppercase;font-weight:500;flex-shrink:0}.empty-value{color:var(--kendo-color-subtle);font-style:italic}.null-value{color:var(--kendo-color-error);font-style:italic}.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;color:var(--kendo-color-on-app-surface);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"], outputs: ["binaryDownload"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i5$1.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon"], exportAs: ["kendoSVGIcon"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }] });
1746
+ `, 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.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i2$1.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"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i2$1.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i4.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"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode"], outputs: ["binaryDownload"] }] });
1888
1747
  }
1889
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyValueDisplayComponent, decorators: [{
1748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyGridComponent, decorators: [{
1890
1749
  type: Component,
1891
- args: [{ selector: 'mm-property-value-display', standalone: true, imports: [CommonModule, SVGIconModule, ButtonModule], template: `
1892
- <div class="property-value-display" [ngClass]="'type-' + type.toLowerCase()">
1750
+ args: [{ selector: 'mm-property-grid', standalone: true, imports: [
1751
+ CommonModule,
1752
+ FormsModule,
1753
+ GridModule,
1754
+ InputsModule,
1755
+ DropDownsModule,
1756
+ ButtonsModule,
1757
+ SVGIconModule,
1758
+ PropertyValueDisplayComponent
1759
+ ], template: `
1760
+ <div class="mm-property-grid" [style.height]="config.height || '400px'">
1893
1761
 
1894
- @if (isExpandableRecord()) {
1895
- <div class="expandable-record">
1896
- <!-- Expand/Collapse Button and Summary -->
1897
- <div class="record-header" (click)="toggleExpansion()">
1898
- <kendo-svgicon
1899
- [icon]="isExpanded ? chevronDownIcon : chevronRightIcon"
1900
- class="expand-icon">
1901
- </kendo-svgicon>
1902
- <span class="record-summary">{{ getRecordSummary() }}</span>
1903
- <span class="type-indicator" [title]="getTypeDescription()">
1904
- {{ getTypeIndicator() }}
1905
- </span>
1906
- </div>
1762
+ @if (config.showSearch) {
1763
+ <div class="search-toolbar">
1764
+ <kendo-textbox
1765
+ [(ngModel)]="searchTerm"
1766
+ placeholder="Search attributes..."
1767
+ (input)="onSearch()"
1768
+ [clearButton]="true">
1769
+ </kendo-textbox>
1770
+ </div>
1771
+ }
1907
1772
 
1908
- <!-- Expanded Content -->
1909
- @if (isExpanded) {
1910
- <div class="record-content">
1911
- @if (type === AttributeValueTypeDto.RecordArrayDto && Array.isArray(value)) {
1912
- @for (item of value; track $index) {
1913
- <div class="array-item">
1914
- <span class="array-index">[{{ $index }}]</span>
1915
- <div class="nested-properties">
1916
- @for (prop of getObjectProperties(item); track prop.key) {
1917
- <div class="nested-property">
1918
- <span class="property-key">{{ prop.key }}:</span>
1919
- <mm-property-value-display
1920
- [value]="prop.value"
1921
- [type]="getPropertyType(prop.value)">
1922
- </mm-property-value-display>
1923
- </div>
1924
- }
1925
- </div>
1926
- </div>
1927
- }
1928
- } @else {
1929
- <div class="nested-properties">
1930
- @for (prop of getObjectProperties(value); track prop.key) {
1931
- <div class="nested-property">
1932
- <span class="property-key">{{ prop.key }}:</span>
1933
- <mm-property-value-display
1934
- [value]="prop.value"
1935
- [type]="getPropertyType(prop.value)">
1936
- </mm-property-value-display>
1937
- </div>
1938
- }
1939
- </div>
1773
+ <kendo-grid
1774
+ [data]="filteredData"
1775
+ [sortable]="true"
1776
+ [resizable]="true"
1777
+ [style.height]="gridHeight"
1778
+ [selectable]="{mode: 'single'}"
1779
+ class="property-grid">
1780
+
1781
+ <!-- Property Name Column -->
1782
+ <kendo-grid-column
1783
+ field="displayName"
1784
+ title="Property"
1785
+ [width]="200"
1786
+ [sortable]="true">
1787
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1788
+ <div class="property-name-cell">
1789
+ @if (config.showTypeIcons !== false) {
1790
+ <kendo-svgicon
1791
+ [icon]="getTypeIcon(dataItem.type)"
1792
+ class="type-icon">
1793
+ </kendo-svgicon>
1940
1794
  }
1795
+ <div class="property-info">
1796
+ <span class="property-name" [title]="dataItem.description">
1797
+ {{ dataItem.displayName || dataItem.name }}
1798
+ </span>
1799
+ @if (dataItem.required) {
1800
+ <span class="required-indicator">*</span>
1801
+ }
1802
+ @if (dataItem.readOnly) {
1803
+ <span class="readonly-indicator" title="Read-only">🔒</span>
1804
+ }
1805
+ </div>
1941
1806
  </div>
1942
- }
1943
- </div>
1944
- } @else if (isBinaryLinkedWithDownload()) {
1945
- <!-- Binary Linked with download capability -->
1946
- <div class="binary-linked-display">
1947
- <div class="binary-info">
1948
- @if (getBinaryFilename()) {
1949
- <span class="filename">{{ getBinaryFilename() }}</span>
1950
- }
1951
- @if (getBinarySize()) {
1952
- <span class="file-size">({{ formatFileSize(getBinarySize()) }})</span>
1953
- }
1954
- @if (getBinaryContentType()) {
1955
- <span class="content-type">{{ getBinaryContentType() }}</span>
1956
- }
1957
- </div>
1958
- <button
1959
- kendoButton
1960
- size="small"
1961
- fillMode="flat"
1962
- [svgIcon]="downloadIcon"
1963
- title="Download file"
1964
- (click)="onDownload()">
1965
- Download
1966
- </button>
1967
- </div>
1968
- } @else {
1969
- <!-- Non-expandable value display -->
1970
- @switch (displayMode) {
1971
- @case (PropertyDisplayMode.Json) {
1972
- <pre class="json-display">{{ getFormattedValue() }}</pre>
1973
- }
1974
- @case (PropertyDisplayMode.Text) {
1975
- <span class="text-display" [innerHTML]="getFormattedValue()"></span>
1976
- }
1977
- @default {
1978
- <span class="default-display">{{ getFormattedValue() }}</span>
1979
- }
1980
- }
1807
+ </ng-template>
1808
+ </kendo-grid-column>
1981
1809
 
1982
- @if (isComplexType() && !isExpandableRecord()) {
1983
- <span class="type-indicator" [title]="getTypeDescription()">
1984
- {{ getTypeIndicator() }}
1985
- </span>
1810
+ <!-- Property Value Column -->
1811
+ <kendo-grid-column
1812
+ field="value"
1813
+ title="Value"
1814
+ [sortable]="false">
1815
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1816
+ <mm-property-value-display
1817
+ [value]="dataItem.value"
1818
+ [type]="dataItem.type"
1819
+ (binaryDownload)="onBinaryDownload($event)">
1820
+ </mm-property-value-display>
1821
+ </ng-template>
1822
+ </kendo-grid-column>
1823
+
1824
+ <!-- Type Column (optional) -->
1825
+ @if (showTypeColumn) {
1826
+ <kendo-grid-column
1827
+ field="type"
1828
+ title="Type"
1829
+ [width]="120"
1830
+ [sortable]="true">
1831
+ <ng-template kendoGridCellTemplate let-dataItem="dataItem">
1832
+ <span class="type-badge" [ngClass]="'type-' + dataItem.type.toLowerCase()">
1833
+ {{ formatTypeName(dataItem.type) }}
1834
+ </span>
1835
+ </ng-template>
1836
+ </kendo-grid-column>
1986
1837
  }
1987
- }
1838
+
1839
+ </kendo-grid>
1988
1840
  </div>
1989
- `, styles: [".property-value-display{display:flex;align-items:flex-start;gap:8px;min-height:20px;font-family:inherit;width:100%}.expandable-record{width:100%}.record-header{display:flex;align-items:center;gap:6px;cursor:pointer;padding:4px;border-radius:4px;transition:background-color .2s}.record-header:hover{background:var(--kendo-color-base-subtle)}.expand-icon{width:16px;height:16px;flex-shrink:0;transition:transform .2s}.record-summary{flex:1;font-size:.9em}.record-content{margin-left:22px;margin-top:8px;border-left:2px solid var(--kendo-color-border);padding-left:12px;background:var(--kendo-color-base-subtle);border-radius:0 4px 4px 0}.nested-properties{display:flex;flex-direction:column;gap:6px;padding:8px}.nested-property{display:flex;align-items:flex-start;gap:8px;min-height:24px}.property-key{font-weight:500;color:var(--kendo-color-primary);min-width:100px;flex-shrink:0;font-size:.9em}.array-item{border:1px solid var(--kendo-color-border);border-radius:4px;margin-bottom:8px;background:transparent}.array-index{display:inline-block;background:var(--kendo-color-primary);color:#fff;padding:2px 8px;font-size:.8em;font-weight:700;border-radius:4px 0;margin-bottom:4px}.json-display{font-family:Courier New,monospace;font-size:12px;margin:0;padding:4px 8px;background:var(--kendo-color-base-subtle);border-radius:4px;max-width:300px;overflow:auto}.text-display,.default-display{flex:1;word-break:break-word;overflow-wrap:anywhere}.type-boolean .default-display{font-weight:500}.type-boolean .default-display.value-true{color:#28a745}.type-boolean .default-display.value-false{color:#dc3545}:is(.type-datetime,.type-datetimeoffset) .default-display{font-family:monospace;font-size:.9em}:is(.type-int,.type-integer,.type-double) .default-display{font-family:monospace;text-align:right}.type-indicator{font-size:.75em;padding:2px 6px;background:var(--kendo-color-primary);color:#fff;border-radius:3px;text-transform:uppercase;font-weight:500;flex-shrink:0}.empty-value{color:var(--kendo-color-subtle);font-style:italic}.null-value{color:var(--kendo-color-error);font-style:italic}.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;color:var(--kendo-color-on-app-surface);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"] }]
1990
- }], propDecorators: { value: [{
1841
+ `, 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"] }]
1842
+ }], propDecorators: { data: [{
1991
1843
  type: Input
1992
- }], type: [{
1844
+ }], config: [{
1993
1845
  type: Input
1994
- }], displayMode: [{
1846
+ }], showTypeColumn: [{
1995
1847
  type: Input
1848
+ }], propertyChange: [{
1849
+ type: Output
1850
+ }], saveRequested: [{
1851
+ type: Output
1996
1852
  }], binaryDownload: [{
1997
1853
  type: Output
1998
1854
  }] } });
1999
1855
 
2000
- /**
2001
- * Generic property grid component for OctoMesh
2002
- */
2003
- class PropertyGridComponent {
2004
- data = [];
2005
- config = {};
2006
- showTypeColumn = false;
2007
- propertyChange = new EventEmitter();
2008
- saveRequested = new EventEmitter();
2009
- binaryDownload = new EventEmitter();
2010
- // Component state
2011
- filteredData = [];
2012
- searchTerm = '';
2013
- hasChanges = false;
2014
- pendingChanges = [];
2015
- // Icons
2016
- fileIcon = fileIcon;
2017
- folderIcon = folderIcon;
2018
- calendarIcon = calendarIcon;
2019
- checkboxCheckedIcon = checkboxCheckedIcon;
2020
- listUnorderedIcon = listUnorderedIcon;
2021
- // Enum reference
2022
- AttributeValueTypeDto = AttributeValueTypeDto;
2023
- ngOnInit() {
2024
- this.updateFilteredData();
1856
+ // Models
1857
+
1858
+ class CkTypeSelectorDialogComponent extends DialogContentBase {
1859
+ ckTypeSelectorService = inject(CkTypeSelectorService);
1860
+ searchSubject = new Subject();
1861
+ subscriptions = new Subscription();
1862
+ searchIcon = searchIcon;
1863
+ filterClearIcon = filterClearIcon;
1864
+ dialogTitle = 'Select Construction Kit Type';
1865
+ allowAbstract = false;
1866
+ searchText = '';
1867
+ selectedModel = null;
1868
+ availableModels = [];
1869
+ gridData = { data: [], total: 0 };
1870
+ isLoading = false;
1871
+ pageSize = 50;
1872
+ skip = 0;
1873
+ selectedKeys = [];
1874
+ selectedType = null;
1875
+ // Selection key function - returns fullName as unique identifier
1876
+ selectItemBy = (context) => context.dataItem.fullName;
1877
+ initialCkModelIds;
1878
+ constructor() {
1879
+ super(inject(DialogRef));
2025
1880
  }
2026
- ngOnChanges(changes) {
2027
- if (changes['data']) {
2028
- this.updateFilteredData();
2029
- this.hasChanges = false;
2030
- this.pendingChanges = [];
1881
+ ngOnInit() {
1882
+ const data = this.dialog.content?.instance?.data;
1883
+ if (data) {
1884
+ this.dialogTitle = data.dialogTitle || 'Select Construction Kit Type';
1885
+ this.allowAbstract = data.allowAbstract ?? false;
1886
+ this.initialCkModelIds = data.ckModelIds;
1887
+ if (data.selectedCkTypeId) {
1888
+ this.selectedKeys = [data.selectedCkTypeId];
1889
+ }
2031
1890
  }
1891
+ // Set up search debouncing
1892
+ this.subscriptions.add(this.searchSubject.pipe(debounceTime(300), distinctUntilChanged()).subscribe(() => {
1893
+ this.skip = 0;
1894
+ this.loadTypes();
1895
+ }));
1896
+ // Load initial types and extract available models
1897
+ this.loadTypes();
1898
+ this.loadAvailableModels();
2032
1899
  }
2033
- get gridHeight() {
2034
- const baseHeight = this.config.height || '400px';
2035
- const searchHeight = this.config.showSearch ? 40 : 0;
2036
- const toolbarHeight = !this.config.readOnlyMode ? 50 : 0;
2037
- const totalOffset = searchHeight + toolbarHeight;
2038
- if (baseHeight.includes('px')) {
2039
- const px = parseInt(baseHeight) - totalOffset;
2040
- return `${Math.max(px, 200)}px`;
2041
- }
2042
- return baseHeight;
1900
+ ngOnDestroy() {
1901
+ this.subscriptions.unsubscribe();
2043
1902
  }
2044
- /**
2045
- * Update filtered data based on search term
2046
- */
2047
- updateFilteredData() {
2048
- if (!this.searchTerm.trim()) {
2049
- this.filteredData = [...this.data];
2050
- return;
2051
- }
2052
- const term = this.searchTerm.toLowerCase();
2053
- this.filteredData = this.data.filter(item => item.name.toLowerCase().includes(term) ||
2054
- (item.displayName?.toLowerCase().includes(term)) ||
2055
- (item.description?.toLowerCase().includes(term)) ||
2056
- String(item.value).toLowerCase().includes(term));
1903
+ loadTypes() {
1904
+ this.isLoading = true;
1905
+ const ckModelIds = this.selectedModel
1906
+ ? [this.selectedModel]
1907
+ : this.initialCkModelIds;
1908
+ this.subscriptions.add(this.ckTypeSelectorService.getCkTypes({
1909
+ ckModelIds,
1910
+ searchText: this.searchText || undefined,
1911
+ first: this.pageSize,
1912
+ skip: this.skip
1913
+ }).subscribe({
1914
+ next: result => {
1915
+ this.gridData = {
1916
+ data: result.items,
1917
+ total: result.totalCount
1918
+ };
1919
+ // Restore selection if exists
1920
+ if (this.selectedKeys.length > 0) {
1921
+ const selectedItem = result.items.find(item => item.fullName === this.selectedKeys[0]);
1922
+ if (selectedItem) {
1923
+ this.selectedType = selectedItem;
1924
+ }
1925
+ }
1926
+ this.isLoading = false;
1927
+ },
1928
+ error: () => {
1929
+ this.isLoading = false;
1930
+ this.gridData = { data: [], total: 0 };
1931
+ }
1932
+ }));
2057
1933
  }
2058
- /**
2059
- * Handle search input
2060
- */
2061
- onSearch() {
2062
- this.updateFilteredData();
1934
+ loadAvailableModels() {
1935
+ // Load all types to extract unique models
1936
+ this.subscriptions.add(this.ckTypeSelectorService.getCkTypes({
1937
+ first: 1000
1938
+ }).subscribe(result => {
1939
+ const modelSet = new Set();
1940
+ result.items.forEach(item => {
1941
+ // Extract model from fullName (format: "ModelName-Version/TypeName-Version")
1942
+ const modelMatch = item.fullName.match(/^([^/]+)\//);
1943
+ if (modelMatch) {
1944
+ modelSet.add(modelMatch[1]);
1945
+ }
1946
+ });
1947
+ this.availableModels = Array.from(modelSet).sort();
1948
+ }));
2063
1949
  }
2064
- /**
2065
- * Get appropriate icon for property type
2066
- */
2067
- getTypeIcon(type) {
2068
- switch (type) {
2069
- case AttributeValueTypeDto.BooleanDto:
2070
- return checkboxCheckedIcon;
2071
- case AttributeValueTypeDto.IntDto:
2072
- case AttributeValueTypeDto.IntegerDto:
2073
- case AttributeValueTypeDto.DoubleDto:
2074
- return fileIcon;
2075
- case AttributeValueTypeDto.DateTimeDto:
2076
- case AttributeValueTypeDto.DateTimeOffsetDto:
2077
- return calendarIcon;
2078
- case AttributeValueTypeDto.StringArrayDto:
2079
- case AttributeValueTypeDto.IntegerArrayDto:
2080
- return listUnorderedIcon;
2081
- case AttributeValueTypeDto.RecordDto:
2082
- case AttributeValueTypeDto.RecordArrayDto:
2083
- return folderIcon;
2084
- default:
2085
- return fileIcon;
2086
- }
1950
+ onSearchChange(value) {
1951
+ this.searchSubject.next(value);
2087
1952
  }
2088
- /**
2089
- * Format type name for display
2090
- */
2091
- formatTypeName(type) {
2092
- return type.replace('_DTO', '').replace('DTO', '').replace('_', ' ');
1953
+ onModelFilterChange(_value) {
1954
+ this.skip = 0;
1955
+ this.loadTypes();
2093
1956
  }
2094
- /**
2095
- * Save pending changes
2096
- */
2097
- saveChanges() {
2098
- if (this.pendingChanges.length > 0) {
2099
- const updatedData = this.data.map(item => {
2100
- const change = this.pendingChanges.find(c => c.property.id === item.id);
2101
- return change ? { ...item, value: change.newValue } : item;
2102
- });
2103
- this.saveRequested.emit(updatedData);
2104
- this.hasChanges = false;
2105
- this.pendingChanges = [];
2106
- }
1957
+ clearFilters() {
1958
+ this.searchText = '';
1959
+ this.selectedModel = null;
1960
+ this.skip = 0;
1961
+ this.loadTypes();
2107
1962
  }
2108
- /**
2109
- * Discard pending changes
2110
- */
2111
- discardChanges() {
2112
- this.hasChanges = false;
2113
- this.pendingChanges = [];
2114
- this.updateFilteredData();
1963
+ onPageChange(event) {
1964
+ this.skip = event.skip;
1965
+ this.pageSize = event.take;
1966
+ this.loadTypes();
2115
1967
  }
2116
- /**
2117
- * Handle property value change
2118
- */
2119
- onPropertyChange(property, oldValue, newValue) {
2120
- const changeEvent = {
2121
- property,
2122
- oldValue,
2123
- newValue
2124
- };
2125
- // Update or add to pending changes
2126
- const existingIndex = this.pendingChanges.findIndex(c => c.property.id === property.id);
2127
- if (existingIndex >= 0) {
2128
- this.pendingChanges[existingIndex] = changeEvent;
1968
+ onSelectionChange(event) {
1969
+ const selectedItems = event.selectedRows;
1970
+ if (selectedItems && selectedItems.length > 0) {
1971
+ this.selectedType = selectedItems[0].dataItem;
2129
1972
  }
2130
1973
  else {
2131
- this.pendingChanges.push(changeEvent);
1974
+ this.selectedType = null;
2132
1975
  }
2133
- this.hasChanges = this.pendingChanges.length > 0;
2134
- this.propertyChange.emit(changeEvent);
2135
1976
  }
2136
- /**
2137
- * Handle binary download request from property value display
2138
- */
2139
- onBinaryDownload(event) {
2140
- this.binaryDownload.emit(event);
1977
+ onCancel() {
1978
+ this.dialog.close();
1979
+ }
1980
+ onConfirm() {
1981
+ if (this.selectedType) {
1982
+ const result = {
1983
+ selectedCkType: this.selectedType
1984
+ };
1985
+ this.dialog.close(result);
1986
+ }
2141
1987
  }
2142
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2143
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: PropertyGridComponent, isStandalone: true, selector: "mm-property-grid", inputs: { data: "data", config: "config", showTypeColumn: "showTypeColumn" }, outputs: { propertyChange: "propertyChange", saveRequested: "saveRequested", binaryDownload: "binaryDownload" }, usesOnChanges: true, ngImport: i0, template: `
2144
- <div class="mm-property-grid" [style.height]="config.height || '400px'">
2145
-
2146
- @if (config.showSearch) {
2147
- <div class="search-toolbar">
2148
- <kendo-textbox
2149
- [(ngModel)]="searchTerm"
2150
- placeholder="Search attributes..."
2151
- (input)="onSearch()"
2152
- [clearButton]="true">
2153
- </kendo-textbox>
1988
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1989
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: CkTypeSelectorDialogComponent, isStandalone: true, selector: "mm-ck-type-selector-dialog", usesInheritance: true, ngImport: i0, template: `
1990
+ <div class="ck-type-selector-container">
1991
+ <div class="filter-container">
1992
+ <div class="filter-row">
1993
+ <div class="filter-item">
1994
+ <label>Model Filter</label>
1995
+ <kendo-combobox
1996
+ [data]="availableModels"
1997
+ [(ngModel)]="selectedModel"
1998
+ (valueChange)="onModelFilterChange($event)"
1999
+ [allowCustom]="false"
2000
+ [clearButton]="true"
2001
+ placeholder="All Models"
2002
+ class="filter-input">
2003
+ </kendo-combobox>
2004
+ </div>
2005
+ <div class="filter-item flex-grow">
2006
+ <label>Type Search</label>
2007
+ <kendo-textbox
2008
+ [(ngModel)]="searchText"
2009
+ (ngModelChange)="onSearchChange($event)"
2010
+ placeholder="Search types..."
2011
+ class="filter-input">
2012
+ <ng-template kendoTextBoxSuffixTemplate>
2013
+ <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
2014
+ </ng-template>
2015
+ </kendo-textbox>
2016
+ </div>
2017
+ <div class="filter-item filter-actions">
2018
+ <label>&nbsp;</label>
2019
+ <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" title="Clear filters"></button>
2020
+ </div>
2154
2021
  </div>
2155
- }
2156
-
2157
- <kendo-grid
2158
- [data]="filteredData"
2159
- [sortable]="true"
2160
- [resizable]="true"
2161
- [style.height]="gridHeight"
2162
- [selectable]="{mode: 'single'}"
2163
- class="property-grid">
2164
-
2165
- <!-- Property Name Column -->
2166
- <kendo-grid-column
2167
- field="displayName"
2168
- title="Property"
2169
- [width]="200"
2170
- [sortable]="true">
2171
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2172
- <div class="property-name-cell">
2173
- @if (config.showTypeIcons !== false) {
2174
- <kendo-svgicon
2175
- [icon]="getTypeIcon(dataItem.type)"
2176
- class="type-icon">
2177
- </kendo-svgicon>
2178
- }
2179
- <div class="property-info">
2180
- <span class="property-name" [title]="dataItem.description">
2181
- {{ dataItem.displayName || dataItem.name }}
2182
- </span>
2183
- @if (dataItem.required) {
2184
- <span class="required-indicator">*</span>
2185
- }
2186
- @if (dataItem.readOnly) {
2187
- <span class="readonly-indicator" title="Read-only">🔒</span>
2188
- }
2189
- </div>
2190
- </div>
2191
- </ng-template>
2192
- </kendo-grid-column>
2193
-
2194
- <!-- Property Value Column -->
2195
- <kendo-grid-column
2196
- field="value"
2197
- title="Value"
2198
- [sortable]="false">
2199
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2200
- <mm-property-value-display
2201
- [value]="dataItem.value"
2202
- [type]="dataItem.type"
2203
- (binaryDownload)="onBinaryDownload($event)">
2204
- </mm-property-value-display>
2205
- </ng-template>
2206
- </kendo-grid-column>
2022
+ </div>
2207
2023
 
2208
- <!-- Type Column (optional) -->
2209
- @if (showTypeColumn) {
2210
- <kendo-grid-column
2211
- field="type"
2212
- title="Type"
2213
- [width]="120"
2214
- [sortable]="true">
2215
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2216
- <span class="type-badge" [ngClass]="'type-' + dataItem.type.toLowerCase()">
2217
- {{ formatTypeName(dataItem.type) }}
2024
+ <div class="grid-container">
2025
+ <kendo-grid
2026
+ [data]="gridData"
2027
+ [loading]="isLoading"
2028
+ [height]="400"
2029
+ [selectable]="{ mode: 'single' }"
2030
+ [pageable]="{ pageSizes: [25, 50, 100] }"
2031
+ [pageSize]="pageSize"
2032
+ [skip]="skip"
2033
+ (pageChange)="onPageChange($event)"
2034
+ (selectionChange)="onSelectionChange($event)"
2035
+ [kendoGridSelectBy]="selectItemBy"
2036
+ [(selectedKeys)]="selectedKeys"
2037
+ class="type-grid">
2038
+ <kendo-grid-column field="rtCkTypeId" title="Type" [width]="300">
2039
+ <ng-template kendoGridCellTemplate let-dataItem>
2040
+ <span [class.abstract-type]="dataItem.isAbstract" [class.final-type]="dataItem.isFinal">
2041
+ {{ dataItem.rtCkTypeId }}
2218
2042
  </span>
2043
+ <span *ngIf="dataItem.isAbstract" class="type-badge abstract">abstract</span>
2044
+ <span *ngIf="dataItem.isFinal" class="type-badge final">final</span>
2219
2045
  </ng-template>
2220
2046
  </kendo-grid-column>
2221
- }
2047
+ <kendo-grid-column field="baseTypeRtCkTypeId" title="Base Type" [width]="200">
2048
+ <ng-template kendoGridCellTemplate let-dataItem>
2049
+ {{ dataItem.baseTypeRtCkTypeId || '-' }}
2050
+ </ng-template>
2051
+ </kendo-grid-column>
2052
+ <kendo-grid-column field="description" title="Description">
2053
+ <ng-template kendoGridCellTemplate let-dataItem>
2054
+ {{ dataItem.description || '-' }}
2055
+ </ng-template>
2056
+ </kendo-grid-column>
2057
+ </kendo-grid>
2058
+ </div>
2222
2059
 
2223
- </kendo-grid>
2060
+ <div class="selection-info" *ngIf="selectedType">
2061
+ <strong>Selected:</strong> {{ selectedType.rtCkTypeId }}
2062
+ </div>
2224
2063
  </div>
2225
- `, 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.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i2$1.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"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i2$1.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i4.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"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: PropertyValueDisplayComponent, selector: "mm-property-value-display", inputs: ["value", "type", "displayMode"], outputs: ["binaryDownload"] }] });
2064
+
2065
+ <kendo-dialog-actions>
2066
+ <button kendoButton (click)="onCancel()">Cancel</button>
2067
+ <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">OK</button>
2068
+ </kendo-dialog-actions>
2069
+ `, isInline: true, styles: [".ck-type-selector-container{display:flex;flex-direction:column;height:100%;padding:20px;min-width:700px;box-sizing:border-box}.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}.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}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: GridModule }, { kind: "component", type: i2$1.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"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: i2$1.SelectionDirective, selector: "[kendoGridSelectBy]" }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: i2$1.CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "ngmodule", type: ButtonsModule }, { kind: "component", type: i3.ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "ngmodule", type: InputsModule }, { kind: "component", type: i4.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: i4.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: DialogModule }, { kind: "component", type: i5.DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }] });
2226
2070
  }
2227
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PropertyGridComponent, decorators: [{
2071
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogComponent, decorators: [{
2228
2072
  type: Component,
2229
- args: [{ selector: 'mm-property-grid', standalone: true, imports: [
2073
+ args: [{ selector: 'mm-ck-type-selector-dialog', standalone: true, imports: [
2230
2074
  CommonModule,
2231
2075
  FormsModule,
2232
2076
  GridModule,
2077
+ ButtonsModule,
2233
2078
  InputsModule,
2234
2079
  DropDownsModule,
2235
- ButtonsModule,
2236
- SVGIconModule,
2237
- PropertyValueDisplayComponent
2080
+ IconsModule,
2081
+ LoaderModule,
2082
+ DialogModule
2238
2083
  ], template: `
2239
- <div class="mm-property-grid" [style.height]="config.height || '400px'">
2240
-
2241
- @if (config.showSearch) {
2242
- <div class="search-toolbar">
2243
- <kendo-textbox
2244
- [(ngModel)]="searchTerm"
2245
- placeholder="Search attributes..."
2246
- (input)="onSearch()"
2247
- [clearButton]="true">
2248
- </kendo-textbox>
2249
- </div>
2250
- }
2251
-
2252
- <kendo-grid
2253
- [data]="filteredData"
2254
- [sortable]="true"
2255
- [resizable]="true"
2256
- [style.height]="gridHeight"
2257
- [selectable]="{mode: 'single'}"
2258
- class="property-grid">
2259
-
2260
- <!-- Property Name Column -->
2261
- <kendo-grid-column
2262
- field="displayName"
2263
- title="Property"
2264
- [width]="200"
2265
- [sortable]="true">
2266
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2267
- <div class="property-name-cell">
2268
- @if (config.showTypeIcons !== false) {
2269
- <kendo-svgicon
2270
- [icon]="getTypeIcon(dataItem.type)"
2271
- class="type-icon">
2272
- </kendo-svgicon>
2273
- }
2274
- <div class="property-info">
2275
- <span class="property-name" [title]="dataItem.description">
2276
- {{ dataItem.displayName || dataItem.name }}
2277
- </span>
2278
- @if (dataItem.required) {
2279
- <span class="required-indicator">*</span>
2280
- }
2281
- @if (dataItem.readOnly) {
2282
- <span class="readonly-indicator" title="Read-only">🔒</span>
2283
- }
2284
- </div>
2285
- </div>
2286
- </ng-template>
2287
- </kendo-grid-column>
2288
-
2289
- <!-- Property Value Column -->
2290
- <kendo-grid-column
2291
- field="value"
2292
- title="Value"
2293
- [sortable]="false">
2294
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2295
- <mm-property-value-display
2296
- [value]="dataItem.value"
2297
- [type]="dataItem.type"
2298
- (binaryDownload)="onBinaryDownload($event)">
2299
- </mm-property-value-display>
2300
- </ng-template>
2301
- </kendo-grid-column>
2084
+ <div class="ck-type-selector-container">
2085
+ <div class="filter-container">
2086
+ <div class="filter-row">
2087
+ <div class="filter-item">
2088
+ <label>Model Filter</label>
2089
+ <kendo-combobox
2090
+ [data]="availableModels"
2091
+ [(ngModel)]="selectedModel"
2092
+ (valueChange)="onModelFilterChange($event)"
2093
+ [allowCustom]="false"
2094
+ [clearButton]="true"
2095
+ placeholder="All Models"
2096
+ class="filter-input">
2097
+ </kendo-combobox>
2098
+ </div>
2099
+ <div class="filter-item flex-grow">
2100
+ <label>Type Search</label>
2101
+ <kendo-textbox
2102
+ [(ngModel)]="searchText"
2103
+ (ngModelChange)="onSearchChange($event)"
2104
+ placeholder="Search types..."
2105
+ class="filter-input">
2106
+ <ng-template kendoTextBoxSuffixTemplate>
2107
+ <button kendoButton [svgIcon]="searchIcon" fillMode="clear" size="small"></button>
2108
+ </ng-template>
2109
+ </kendo-textbox>
2110
+ </div>
2111
+ <div class="filter-item filter-actions">
2112
+ <label>&nbsp;</label>
2113
+ <button kendoButton [svgIcon]="filterClearIcon" (click)="clearFilters()" title="Clear filters"></button>
2114
+ </div>
2115
+ </div>
2116
+ </div>
2302
2117
 
2303
- <!-- Type Column (optional) -->
2304
- @if (showTypeColumn) {
2305
- <kendo-grid-column
2306
- field="type"
2307
- title="Type"
2308
- [width]="120"
2309
- [sortable]="true">
2310
- <ng-template kendoGridCellTemplate let-dataItem="dataItem">
2311
- <span class="type-badge" [ngClass]="'type-' + dataItem.type.toLowerCase()">
2312
- {{ formatTypeName(dataItem.type) }}
2118
+ <div class="grid-container">
2119
+ <kendo-grid
2120
+ [data]="gridData"
2121
+ [loading]="isLoading"
2122
+ [height]="400"
2123
+ [selectable]="{ mode: 'single' }"
2124
+ [pageable]="{ pageSizes: [25, 50, 100] }"
2125
+ [pageSize]="pageSize"
2126
+ [skip]="skip"
2127
+ (pageChange)="onPageChange($event)"
2128
+ (selectionChange)="onSelectionChange($event)"
2129
+ [kendoGridSelectBy]="selectItemBy"
2130
+ [(selectedKeys)]="selectedKeys"
2131
+ class="type-grid">
2132
+ <kendo-grid-column field="rtCkTypeId" title="Type" [width]="300">
2133
+ <ng-template kendoGridCellTemplate let-dataItem>
2134
+ <span [class.abstract-type]="dataItem.isAbstract" [class.final-type]="dataItem.isFinal">
2135
+ {{ dataItem.rtCkTypeId }}
2313
2136
  </span>
2137
+ <span *ngIf="dataItem.isAbstract" class="type-badge abstract">abstract</span>
2138
+ <span *ngIf="dataItem.isFinal" class="type-badge final">final</span>
2314
2139
  </ng-template>
2315
2140
  </kendo-grid-column>
2316
- }
2141
+ <kendo-grid-column field="baseTypeRtCkTypeId" title="Base Type" [width]="200">
2142
+ <ng-template kendoGridCellTemplate let-dataItem>
2143
+ {{ dataItem.baseTypeRtCkTypeId || '-' }}
2144
+ </ng-template>
2145
+ </kendo-grid-column>
2146
+ <kendo-grid-column field="description" title="Description">
2147
+ <ng-template kendoGridCellTemplate let-dataItem>
2148
+ {{ dataItem.description || '-' }}
2149
+ </ng-template>
2150
+ </kendo-grid-column>
2151
+ </kendo-grid>
2152
+ </div>
2317
2153
 
2318
- </kendo-grid>
2154
+ <div class="selection-info" *ngIf="selectedType">
2155
+ <strong>Selected:</strong> {{ selectedType.rtCkTypeId }}
2156
+ </div>
2319
2157
  </div>
2320
- `, 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"] }]
2321
- }], propDecorators: { data: [{
2322
- type: Input
2323
- }], config: [{
2324
- type: Input
2325
- }], showTypeColumn: [{
2326
- type: Input
2327
- }], propertyChange: [{
2328
- type: Output
2329
- }], saveRequested: [{
2330
- type: Output
2331
- }], binaryDownload: [{
2332
- type: Output
2333
- }] } });
2334
2158
 
2335
- // Models
2159
+ <kendo-dialog-actions>
2160
+ <button kendoButton (click)="onCancel()">Cancel</button>
2161
+ <button kendoButton themeColor="primary" [disabled]="!selectedType || (selectedType.isAbstract && !allowAbstract)" (click)="onConfirm()">OK</button>
2162
+ </kendo-dialog-actions>
2163
+ `, styles: [".ck-type-selector-container{display:flex;flex-direction:column;height:100%;padding:20px;min-width:700px;box-sizing:border-box}.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}.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}\n"] }]
2164
+ }], ctorParameters: () => [] });
2165
+
2166
+ class CkTypeSelectorDialogService {
2167
+ dialogService = inject(DialogService);
2168
+ /**
2169
+ * Opens the CkType selector dialog
2170
+ * @param options Dialog options
2171
+ * @returns Promise that resolves with the result containing selected CkType and confirmation status
2172
+ */
2173
+ async openCkTypeSelector(options = {}) {
2174
+ const data = {
2175
+ selectedCkTypeId: options.selectedCkTypeId,
2176
+ ckModelIds: options.ckModelIds,
2177
+ dialogTitle: options.dialogTitle,
2178
+ allowAbstract: options.allowAbstract
2179
+ };
2180
+ const dialogRef = this.dialogService.open({
2181
+ content: CkTypeSelectorDialogComponent,
2182
+ width: 900,
2183
+ height: 650,
2184
+ minWidth: 750,
2185
+ minHeight: 550,
2186
+ title: options.dialogTitle || 'Select Construction Kit Type'
2187
+ });
2188
+ // Pass data to the component
2189
+ if (dialogRef.content?.instance) {
2190
+ dialogRef.content.instance.data = data;
2191
+ }
2192
+ try {
2193
+ const result = await firstValueFrom(dialogRef.result);
2194
+ if (result && typeof result === 'object' && 'selectedCkType' in result) {
2195
+ // User clicked OK and we have a result
2196
+ const dialogResult = result;
2197
+ return {
2198
+ confirmed: true,
2199
+ selectedCkType: dialogResult.selectedCkType
2200
+ };
2201
+ }
2202
+ else {
2203
+ // User clicked Cancel or closed dialog
2204
+ return {
2205
+ confirmed: false,
2206
+ selectedCkType: null
2207
+ };
2208
+ }
2209
+ }
2210
+ catch {
2211
+ // Dialog was closed without result (e.g., ESC key, X button)
2212
+ return {
2213
+ confirmed: false,
2214
+ selectedCkType: null
2215
+ };
2216
+ }
2217
+ }
2218
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2219
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService });
2220
+ }
2221
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: CkTypeSelectorDialogService, decorators: [{
2222
+ type: Injectable
2223
+ }] });
2224
+
2225
+ // noinspection JSUnusedGlobalSymbols
2226
+ class OctoGraphQlDataSource extends DataSourceTyped {
2227
+ _searchFilterAttributePaths = [];
2228
+ // noinspection JSUnusedGlobalSymbols
2229
+ constructor(listViewComponent) {
2230
+ super(listViewComponent);
2231
+ }
2232
+ get searchFilterAttributePaths() {
2233
+ return this._searchFilterAttributePaths;
2234
+ }
2235
+ set searchFilterAttributePaths(value) {
2236
+ this._searchFilterAttributePaths = value;
2237
+ }
2238
+ // noinspection JSUnusedGlobalSymbols
2239
+ getFieldFilterDefinitions(state) {
2240
+ let fieldFilters = null;
2241
+ if (state.filter?.filters) {
2242
+ fieldFilters = state.filter.filters.map((f) => {
2243
+ if (isCompositeFilterDescriptor(f)) {
2244
+ throw new Error('Composite filter descriptor not supported');
2245
+ }
2246
+ const { operator, value } = OctoGraphQlDataSource.getOperatorAndValue(f.operator, f.value);
2247
+ return {
2248
+ attributePath: f.field,
2249
+ operator: operator,
2250
+ comparisonValue: value
2251
+ };
2252
+ });
2253
+ }
2254
+ return fieldFilters;
2255
+ }
2256
+ // noinspection JSUnusedGlobalSymbols
2257
+ getSearchFilterDefinitions(textSearchValue) {
2258
+ let searchFilterDto = null;
2259
+ if (textSearchValue) {
2260
+ searchFilterDto = {
2261
+ type: SearchFilterTypesDto.AttributeFilterDto,
2262
+ attributePaths: this.searchFilterAttributePaths,
2263
+ searchTerm: textSearchValue,
2264
+ };
2265
+ }
2266
+ return searchFilterDto;
2267
+ }
2268
+ // noinspection JSUnusedGlobalSymbols
2269
+ getSortDefinitions(state) {
2270
+ let sort = null;
2271
+ if (state.sort) {
2272
+ sort = new Array();
2273
+ state.sort.forEach((s) => {
2274
+ switch (s.dir) {
2275
+ case 'asc':
2276
+ sort?.push({
2277
+ attributePath: s.field,
2278
+ sortOrder: SortOrdersDto.AscendingDto
2279
+ });
2280
+ break;
2281
+ case 'desc':
2282
+ sort?.push({
2283
+ attributePath: s.field,
2284
+ sortOrder: SortOrdersDto.DescendingDto,
2285
+ });
2286
+ break;
2287
+ default:
2288
+ sort?.push({
2289
+ attributePath: s.field,
2290
+ sortOrder: SortOrdersDto.DefaultDto,
2291
+ });
2292
+ break;
2293
+ }
2294
+ });
2295
+ }
2296
+ return sort;
2297
+ }
2298
+ static getOperatorAndValue(operator, value) {
2299
+ switch (operator) {
2300
+ case 'eq':
2301
+ return { operator: FieldFilterOperatorsDto.EqualsDto, value: value };
2302
+ case 'neq':
2303
+ return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: value };
2304
+ case 'lt':
2305
+ return { operator: FieldFilterOperatorsDto.LessThanDto, value: value };
2306
+ case 'lte':
2307
+ return { operator: FieldFilterOperatorsDto.LessEqualThanDto, value: value };
2308
+ case 'gt':
2309
+ return { operator: FieldFilterOperatorsDto.GreaterThanDto, value: value };
2310
+ case 'gte':
2311
+ return { operator: FieldFilterOperatorsDto.GreaterEqualThanDto, value: value };
2312
+ case 'contains':
2313
+ return { operator: FieldFilterOperatorsDto.LikeDto, value: value };
2314
+ case 'doesnotcontain':
2315
+ return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: `^(?!.*${value}).*$` };
2316
+ case 'startswith':
2317
+ return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: value + '.*' };
2318
+ case 'endswith':
2319
+ return { operator: FieldFilterOperatorsDto.MatchRegExDto, value: '.*' + value };
2320
+ case 'isnull':
2321
+ return { operator: FieldFilterOperatorsDto.EqualsDto, value: null };
2322
+ case 'isnotnull':
2323
+ return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: null };
2324
+ case 'isempty':
2325
+ return { operator: FieldFilterOperatorsDto.EqualsDto, value: "" };
2326
+ case 'isnotempty':
2327
+ return { operator: FieldFilterOperatorsDto.NotEqualsDto, value: "" };
2328
+ default:
2329
+ throw new Error('The filter operator is not supported');
2330
+ }
2331
+ }
2332
+ }
2333
+
2334
+ class OctoGraphQlHierarchyDataSource extends HierarchyDataSourceBase {
2335
+ }
2336
2336
 
2337
2337
  class AttributeSelectorDialogComponent extends DialogContentBase {
2338
2338
  attributeService = inject(AttributeSelectorService);
@@ -4202,6 +4202,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
4202
4202
  type: Input
4203
4203
  }] } });
4204
4204
 
4205
+ /**
4206
+ * Animated OctoMesh logo loader component.
4207
+ * Displays the OctoMesh octopus SVG with a tentacle wave animation,
4208
+ * gentle bob, and pulsing glow effect.
4209
+ *
4210
+ * Uses `--kendo-color-primary` for theme-independent coloring.
4211
+ * Override the color via CSS `color` property on the host element.
4212
+ *
4213
+ * @example
4214
+ * ```html
4215
+ * <mm-octo-loader [size]="'medium'"></mm-octo-loader>
4216
+ * <mm-octo-loader [size]="'small'"></mm-octo-loader>
4217
+ * ```
4218
+ */
4219
+ class OctoLoaderComponent {
4220
+ size = 'medium';
4221
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: OctoLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4222
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.5", type: OctoLoaderComponent, isStandalone: true, selector: "mm-octo-loader", inputs: { size: "size" }, ngImport: i0, template: `
4223
+ <div class="octo-loader" [class.octo-loader--small]="size === 'small'" [class.octo-loader--medium]="size === 'medium'">
4224
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 97" class="octo-loader__svg" overflow="visible">
4225
+ <!-- Body + head + outer arms -->
4226
+ <polygon fill="currentColor"
4227
+ points="58.19 72.13 53.34 72.13 53.34 52.74 63.04 52.74 63.04 43.04 63.04 38.19 63.04 28.49 67.89 0 43.64 4.24 34.01 4.24 14.61 4.24 0 4.24 0 18.79 0 28.49 0 40.61 0 52.74 9.7 52.74 9.7 72.13 4.85 72.13 4.85 67.28 0 67.28 0 72.13 0 76.98 4.85 76.98 14.55 76.98 14.55 72.13 14.55 52.74 14.55 52.13 14.55 47.89 4.85 47.89 4.85 43.04 4.85 36.37 4.85 23.64 4.85 17.58 4.85 9.09 19.4 9.09 33.94 9.09 43.64 9.09 62.01 6.02 58.19 28.49 58.19 33.34 58.19 38.19 58.19 43.04 58.19 47.89 48.49 47.89 48.49 52.13 48.49 52.74 48.49 72.13 48.49 76.98 58.19 76.98 63.04 76.98 63.04 76.98 63.04 67.28 58.19 67.28 58.19 72.13"/>
4228
+ <!-- Eyes -->
4229
+ <rect fill="currentColor" x="18.79" y="19.4" width="4.85" height="13.94"/>
4230
+ <rect fill="currentColor" x="38.79" y="19.4" width="4.85" height="13.94"/>
4231
+ <!-- Left tentacle pair -->
4232
+ <polygon class="octo-leg octo-leg--left" fill="currentColor"
4233
+ points="19.4 91.53 14.55 91.53 14.55 81.83 9.7 81.83 9.7 91.53 9.7 96.38 14.55 96.38 19.4 96.38 24.25 96.38 24.25 91.53 24.25 52.74 19.4 52.74 19.4 91.53"/>
4234
+ <!-- Center tentacle -->
4235
+ <rect class="octo-leg octo-leg--center" fill="currentColor"
4236
+ x="29.1" y="52.74" width="4.85" height="33.94"/>
4237
+ <!-- Right tentacle pair -->
4238
+ <polygon class="octo-leg octo-leg--right" fill="currentColor"
4239
+ points="48.49 91.53 43.64 91.53 43.64 52.74 38.79 52.74 38.79 91.53 38.79 96.38 43.64 96.38 48.49 96.38 53.34 96.38 53.34 91.53 53.34 81.83 48.49 81.83 48.49 91.53"/>
4240
+ </svg>
4241
+ </div>
4242
+ `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;color:var(--kendo-color-primary, #64ceb9)}.octo-loader{display:inline-flex;align-items:center;justify-content:center;animation:octo-spin 6s ease-in-out infinite}.octo-loader--small .octo-loader__svg{width:24px;height:24px}.octo-loader--medium .octo-loader__svg{width:48px;height:48px}.octo-loader__svg{animation:octo-glow 6s ease-in-out infinite}.octo-leg{transform-box:fill-box;transform-origin:50% 0%}.octo-leg--left{animation:octo-wiggle-left 6s ease-in-out infinite}.octo-leg--center{animation:octo-wiggle-center 6s ease-in-out infinite}.octo-leg--right{animation:octo-wiggle-right 6s ease-in-out infinite}@keyframes octo-spin{0%{transform:rotate(0) scale(1)}5%{transform:rotate(0) scale(1)}15%{transform:rotate(360deg) scale(.85)}20%{transform:rotate(360deg) scale(1)}25%{transform:rotate(360deg) scale(1)}40%{transform:rotate(0) scale(.85)}45%{transform:rotate(0) scale(1)}to{transform:rotate(0) scale(1)}}@keyframes octo-glow{0%,5%{filter:drop-shadow(0 0 2px currentColor)}15%{filter:drop-shadow(0 0 14px currentColor)}20%,25%{filter:drop-shadow(0 0 6px currentColor)}40%{filter:drop-shadow(0 0 14px currentColor)}50%,to{filter:drop-shadow(0 0 2px currentColor)}}@keyframes octo-wiggle-left{0%,47%{transform:rotate(0)}50%{transform:rotate(12deg)}53%{transform:rotate(-10deg)}56%{transform:rotate(10deg)}59%{transform:rotate(-8deg)}62%{transform:rotate(6deg)}65%{transform:rotate(-3deg)}68%{transform:rotate(0)}to{transform:rotate(0)}}@keyframes octo-wiggle-center{0%,48%{transform:rotate(0)}51%{transform:rotate(-10deg)}54%{transform:rotate(9deg)}57%{transform:rotate(-8deg)}60%{transform:rotate(7deg)}63%{transform:rotate(-4deg)}66%{transform:rotate(2deg)}69%{transform:rotate(0)}to{transform:rotate(0)}}@keyframes octo-wiggle-right{0%,49%{transform:rotate(0)}52%{transform:rotate(-12deg)}55%{transform:rotate(10deg)}58%{transform:rotate(-10deg)}61%{transform:rotate(8deg)}64%{transform:rotate(-6deg)}67%{transform:rotate(3deg)}70%{transform:rotate(0)}to{transform:rotate(0)}}\n"] });
4243
+ }
4244
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: OctoLoaderComponent, decorators: [{
4245
+ type: Component,
4246
+ args: [{ selector: 'mm-octo-loader', standalone: true, template: `
4247
+ <div class="octo-loader" [class.octo-loader--small]="size === 'small'" [class.octo-loader--medium]="size === 'medium'">
4248
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 97" class="octo-loader__svg" overflow="visible">
4249
+ <!-- Body + head + outer arms -->
4250
+ <polygon fill="currentColor"
4251
+ points="58.19 72.13 53.34 72.13 53.34 52.74 63.04 52.74 63.04 43.04 63.04 38.19 63.04 28.49 67.89 0 43.64 4.24 34.01 4.24 14.61 4.24 0 4.24 0 18.79 0 28.49 0 40.61 0 52.74 9.7 52.74 9.7 72.13 4.85 72.13 4.85 67.28 0 67.28 0 72.13 0 76.98 4.85 76.98 14.55 76.98 14.55 72.13 14.55 52.74 14.55 52.13 14.55 47.89 4.85 47.89 4.85 43.04 4.85 36.37 4.85 23.64 4.85 17.58 4.85 9.09 19.4 9.09 33.94 9.09 43.64 9.09 62.01 6.02 58.19 28.49 58.19 33.34 58.19 38.19 58.19 43.04 58.19 47.89 48.49 47.89 48.49 52.13 48.49 52.74 48.49 72.13 48.49 76.98 58.19 76.98 63.04 76.98 63.04 76.98 63.04 67.28 58.19 67.28 58.19 72.13"/>
4252
+ <!-- Eyes -->
4253
+ <rect fill="currentColor" x="18.79" y="19.4" width="4.85" height="13.94"/>
4254
+ <rect fill="currentColor" x="38.79" y="19.4" width="4.85" height="13.94"/>
4255
+ <!-- Left tentacle pair -->
4256
+ <polygon class="octo-leg octo-leg--left" fill="currentColor"
4257
+ points="19.4 91.53 14.55 91.53 14.55 81.83 9.7 81.83 9.7 91.53 9.7 96.38 14.55 96.38 19.4 96.38 24.25 96.38 24.25 91.53 24.25 52.74 19.4 52.74 19.4 91.53"/>
4258
+ <!-- Center tentacle -->
4259
+ <rect class="octo-leg octo-leg--center" fill="currentColor"
4260
+ x="29.1" y="52.74" width="4.85" height="33.94"/>
4261
+ <!-- Right tentacle pair -->
4262
+ <polygon class="octo-leg octo-leg--right" fill="currentColor"
4263
+ points="48.49 91.53 43.64 91.53 43.64 52.74 38.79 52.74 38.79 91.53 38.79 96.38 43.64 96.38 48.49 96.38 53.34 96.38 53.34 91.53 53.34 81.83 48.49 81.83 48.49 91.53"/>
4264
+ </svg>
4265
+ </div>
4266
+ `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;color:var(--kendo-color-primary, #64ceb9)}.octo-loader{display:inline-flex;align-items:center;justify-content:center;animation:octo-spin 6s ease-in-out infinite}.octo-loader--small .octo-loader__svg{width:24px;height:24px}.octo-loader--medium .octo-loader__svg{width:48px;height:48px}.octo-loader__svg{animation:octo-glow 6s ease-in-out infinite}.octo-leg{transform-box:fill-box;transform-origin:50% 0%}.octo-leg--left{animation:octo-wiggle-left 6s ease-in-out infinite}.octo-leg--center{animation:octo-wiggle-center 6s ease-in-out infinite}.octo-leg--right{animation:octo-wiggle-right 6s ease-in-out infinite}@keyframes octo-spin{0%{transform:rotate(0) scale(1)}5%{transform:rotate(0) scale(1)}15%{transform:rotate(360deg) scale(.85)}20%{transform:rotate(360deg) scale(1)}25%{transform:rotate(360deg) scale(1)}40%{transform:rotate(0) scale(.85)}45%{transform:rotate(0) scale(1)}to{transform:rotate(0) scale(1)}}@keyframes octo-glow{0%,5%{filter:drop-shadow(0 0 2px currentColor)}15%{filter:drop-shadow(0 0 14px currentColor)}20%,25%{filter:drop-shadow(0 0 6px currentColor)}40%{filter:drop-shadow(0 0 14px currentColor)}50%,to{filter:drop-shadow(0 0 2px currentColor)}}@keyframes octo-wiggle-left{0%,47%{transform:rotate(0)}50%{transform:rotate(12deg)}53%{transform:rotate(-10deg)}56%{transform:rotate(10deg)}59%{transform:rotate(-8deg)}62%{transform:rotate(6deg)}65%{transform:rotate(-3deg)}68%{transform:rotate(0)}to{transform:rotate(0)}}@keyframes octo-wiggle-center{0%,48%{transform:rotate(0)}51%{transform:rotate(-10deg)}54%{transform:rotate(9deg)}57%{transform:rotate(-8deg)}60%{transform:rotate(7deg)}63%{transform:rotate(-4deg)}66%{transform:rotate(2deg)}69%{transform:rotate(0)}to{transform:rotate(0)}}@keyframes octo-wiggle-right{0%,49%{transform:rotate(0)}52%{transform:rotate(-12deg)}55%{transform:rotate(10deg)}58%{transform:rotate(-10deg)}61%{transform:rotate(8deg)}64%{transform:rotate(-6deg)}67%{transform:rotate(3deg)}70%{transform:rotate(0)}to{transform:rotate(0)}}\n"] }]
4267
+ }], propDecorators: { size: [{
4268
+ type: Input
4269
+ }] } });
4270
+
4205
4271
  /*
4206
4272
  * Public API Surface of octo-ui
4207
4273
  */
@@ -4224,5 +4290,5 @@ function provideOctoUi() {
4224
4290
  * Generated bundle index. Do not edit.
4225
4291
  */
4226
4292
 
4227
- export { AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DefaultPropertyCategory, EntityIdInfoComponent, FieldFilterEditorComponent, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, provideOctoUi };
4293
+ export { AttributeSelectorDialogComponent, AttributeSelectorDialogService, AttributeSortSelectorDialogComponent, AttributeSortSelectorDialogService, AttributeValueTypeDto, CkTypeSelectorDialogComponent, CkTypeSelectorDialogService, CkTypeSelectorInputComponent, DefaultPropertyCategory, EntityIdInfoComponent, FieldFilterEditorComponent, OctoGraphQlDataSource, OctoGraphQlHierarchyDataSource, OctoLoaderComponent, PropertyConverterService, PropertyDisplayMode, PropertyGridComponent, PropertyValueDisplayComponent, provideOctoUi };
4228
4294
  //# sourceMappingURL=meshmakers-octo-ui.mjs.map