@meshmakers/shared-ui 3.5.600 → 3.5.620
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.
- package/README.md +1 -1
- package/fesm2022/meshmakers-shared-ui.mjs +26 -3
- package/fesm2022/meshmakers-shared-ui.mjs.map +1 -1
- package/fonts/fonts.css +179 -0
- package/fonts/licenses/montserrat-OFL.txt +93 -0
- package/fonts/licenses/roboto-OFL.txt +93 -0
- package/fonts/licenses/roboto-mono-OFL.txt +93 -0
- package/fonts/montserrat-latin-300-normal.woff2 +0 -0
- package/fonts/montserrat-latin-400-normal.woff2 +0 -0
- package/fonts/montserrat-latin-500-normal.woff2 +0 -0
- package/fonts/montserrat-latin-600-normal.woff2 +0 -0
- package/fonts/montserrat-latin-700-normal.woff2 +0 -0
- package/fonts/montserrat-latin-ext-300-normal.woff2 +0 -0
- package/fonts/montserrat-latin-ext-400-normal.woff2 +0 -0
- package/fonts/montserrat-latin-ext-500-normal.woff2 +0 -0
- package/fonts/montserrat-latin-ext-600-normal.woff2 +0 -0
- package/fonts/montserrat-latin-ext-700-normal.woff2 +0 -0
- package/fonts/roboto-latin-400-normal.woff2 +0 -0
- package/fonts/roboto-latin-500-normal.woff2 +0 -0
- package/fonts/roboto-latin-700-normal.woff2 +0 -0
- package/fonts/roboto-latin-ext-400-normal.woff2 +0 -0
- package/fonts/roboto-latin-ext-500-normal.woff2 +0 -0
- package/fonts/roboto-latin-ext-700-normal.woff2 +0 -0
- package/fonts/roboto-mono-latin-400-normal.woff2 +0 -0
- package/fonts/roboto-mono-latin-500-normal.woff2 +0 -0
- package/fonts/roboto-mono-latin-ext-400-normal.woff2 +0 -0
- package/fonts/roboto-mono-latin-ext-500-normal.woff2 +0 -0
- package/package.json +1 -1
- package/types/meshmakers-shared-ui.d.ts +10 -2
package/README.md
CHANGED
|
@@ -137,7 +137,7 @@ Configurable data grid with Kendo Grid integration.
|
|
|
137
137
|
|
|
138
138
|
**Features:** Pagination, sorting, filtering, row selection, search, context menus, action menus, Excel/PDF export, toolbar actions, column types (text, numeric, boolean, date, bytes, status icons, cron expressions).
|
|
139
139
|
|
|
140
|
-
Empty state (AB#3444): `[emptyState]="{ title, text }"` shows the shared `mm-empty-state` (OctoBot `idle`) for a list without records and the "no results" variant (OctoBot `look`) while a search or filter is active; `[emptyTemplate]` replaces it. Without either the list keeps the plain "No records available." line.
|
|
140
|
+
Empty state (AB#3444): `[emptyState]="{ title, text }"` shows the shared `mm-empty-state` (OctoBot `idle`) for a list without records and the "no results" variant (OctoBot `look`) while a search or filter is active; `[emptyTemplate]` replaces it. Without either the list keeps the plain "No records available." line. Actions inside the empty state (AB#7628): an `<ng-template mmListViewEmptyActions>` child renders its buttons below the text of the `empty` variant only (not while loading, not in the "no results" variant); without it the block is unchanged.
|
|
141
141
|
|
|
142
142
|
Toolbar actions (`leftToolbarActions` / `rightToolbarActions`, AB#6211) render **flat and neutral** by default: a page has exactly one solid primary action and it sits in the page header (`[mmPageActions]`, Studio action guideline §9). Set `primary: true` on a `CommandItem` only for a list without a page header (the list is the page). A toolbar action with `isDisabled` + `disabledReason` — plain, split or dropdown button — stays focusable (`aria-disabled`), announces the reason (`aria-describedby`), shows it in the tooltip ("Run scripts — No fixup scripts to run") and as a hint bubble on keyboard focus; clicks and the menu are blocked. A `disabledReason` callback receives the current selection.
|
|
143
143
|
|
|
@@ -1660,6 +1660,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
1660
1660
|
}]
|
|
1661
1661
|
}] });
|
|
1662
1662
|
|
|
1663
|
+
class ListViewEmptyActionsDirective {
|
|
1664
|
+
templateRef = inject((TemplateRef));
|
|
1665
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewEmptyActionsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1666
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.5", type: ListViewEmptyActionsDirective, isStandalone: true, selector: "[mmListViewEmptyActions]", ngImport: i0 });
|
|
1667
|
+
}
|
|
1668
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewEmptyActionsDirective, decorators: [{
|
|
1669
|
+
type: Directive,
|
|
1670
|
+
args: [{
|
|
1671
|
+
selector: '[mmListViewEmptyActions]',
|
|
1672
|
+
standalone: true,
|
|
1673
|
+
}]
|
|
1674
|
+
}] });
|
|
1675
|
+
|
|
1663
1676
|
/**
|
|
1664
1677
|
* Default English messages for the ListViewComponent. Complete: every member, including the
|
|
1665
1678
|
* optional ones, has a value.
|
|
@@ -2870,6 +2883,7 @@ class ListViewComponent extends CommandBaseService {
|
|
|
2870
2883
|
* a strip of their own above the grid — see ListViewFiltersDirective.
|
|
2871
2884
|
*/
|
|
2872
2885
|
filtersTemplate;
|
|
2886
|
+
emptyActionsTemplate;
|
|
2873
2887
|
gridComponent;
|
|
2874
2888
|
dataBindingDirective;
|
|
2875
2889
|
gridContextMenu;
|
|
@@ -3111,6 +3125,12 @@ class ListViewComponent extends CommandBaseService {
|
|
|
3111
3125
|
}
|
|
3112
3126
|
return (this.dataBindingDirective?.currentState?.filter?.filters?.length ?? 0) > 0;
|
|
3113
3127
|
}
|
|
3128
|
+
keepEmptyActionKeysFromGrid(event) {
|
|
3129
|
+
const keyForThePage = event.key === 'Escape';
|
|
3130
|
+
if (!keyForThePage) {
|
|
3131
|
+
event.stopPropagation();
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3114
3134
|
get emptyContext() {
|
|
3115
3135
|
const filtered = this.isFiltered;
|
|
3116
3136
|
return { $implicit: filtered, filtered };
|
|
@@ -4167,7 +4187,7 @@ class ListViewComponent extends CommandBaseService {
|
|
|
4167
4187
|
*/
|
|
4168
4188
|
commandsIcon = slidersIcon;
|
|
4169
4189
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4170
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: ListViewComponent, isStandalone: true, selector: "mm-list-view", inputs: { pageSize: "pageSize", skip: "skip", autoPageSize: "autoPageSize", rowIsClickable: "rowIsClickable", showRowCheckBoxes: "showRowCheckBoxes", showRowSelectAllCheckBox: "showRowSelectAllCheckBox", contextMenuType: "contextMenuType", leftToolbarActions: "leftToolbarActions", rightToolbarActions: "rightToolbarActions", actionCommandItems: "actionCommandItems", contextMenuCommandItems: "contextMenuCommandItems", rowActions: "rowActions", maxInlineRowActions: "maxInlineRowActions", excelExportFileName: "excelExportFileName", pdfExportFileName: "pdfExportFileName", pageable: "pageable", sortable: "sortable", rowFilterEnabled: "rowFilterEnabled", searchTextBoxEnabled: "searchTextBoxEnabled", persistListState: "persistListState", listStateKey: "listStateKey", resizable: "resizable", actionsColumnWidth: "actionsColumnWidth", hideCheckboxesBelow: "hideCheckboxesBelow", cardModeBelow: "cardModeBelow", collapseCommandsBelow: "collapseCommandsBelow", hasExternalFilters: "hasExternalFilters", emptyState: "emptyState", emptyTemplate: "emptyTemplate", rowClass: "rowClass", messages: "messages", selectable: "selectable", columns: "columns", rowLabelField: "rowLabelField" }, outputs: { rowClicked: "rowClicked", rowAction: "rowAction", resetFilters: "resetFilters" }, host: { properties: { "class.mm-list-view-narrow": "this.isNarrow", "class.mm-list-view-cards": "this.isCardMode" } }, queries: [{ propertyName: "filtersTemplate", first: true, predicate: ListViewFiltersDirective, descendants: true }], viewQueries: [{ propertyName: "gridComponent", first: true, predicate: GridComponent, descendants: true }, { propertyName: "dataBindingDirective", first: true, predicate: MmListViewDataBindingDirective, descendants: true }, { propertyName: "gridContextMenu", first: true, predicate: ["gridmenu"], descendants: true }, { propertyName: "toolbarHintTemplate", first: true, predicate: ["toolbarHint"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<!-- Shared cell renderer (AB#4930): used by the regular grid columns AND the\n card-mode body lines, so both render every dataType identically. -->\n<ng-template #cellContent let-element=\"element\" let-column=\"column\">\n @if (column.formatter) {\n {{ getFormattedValue(element, column) }}\n } @else {\n @switch (column.dataType) {\n @case ('boolean') {\n <!-- Read-only marker: named after its column so a screen reader says what is checked (AB#5621). -->\n <kendo-checkbox type=\"checkbox\" [checkedState]=\"$any(getValue(element, column))\" [disabled]=\"true\"\n [inputAttributes]=\"booleanCellAttributes(column)\" />\n }\n @case ('booleanIcon') {\n <!-- Boolean as icon (AB#5623): named \"<column>: Yes|No\" like the status icons (G13). -->\n @if (booleanIconState(element, column); as state) {\n @if (booleanIcon(column, state); as icon) {\n <span\n class=\"boolean-icon\"\n [class.boolean-icon--true]=\"state === 'true'\"\n [class.boolean-icon--false]=\"state === 'false'\"\n role=\"img\"\n [title]=\"booleanIconLabel(column, state)\"\n [attr.aria-label]=\"booleanIconLabel(column, state)\"\n [style.color]=\"state === 'true' ? column.booleanIcons?.trueColor : column.booleanIcons?.falseColor\">\n <kendo-svg-icon [icon]=\"icon\"></kendo-svg-icon>\n </span>\n }\n }\n }\n @case ('iso8601') {\n {{ $any(getValue(element, column)) | date:column.format }}\n }\n @case ('bytes') {\n {{ $any(getValue(element, column)) | bytesToSize }}\n }\n @case ('statusIcons') {\n <span class=\"status-icons-cell\">\n @for (fieldConfig of getStatusFields(column); track fieldConfig.field) {\n @if (getStatusIconMapping(element, fieldConfig); as mapping) {\n <!-- Icon-only status: the mapping's tooltip is also its accessible name (AB#5621). -->\n <span\n class=\"status-icon\"\n role=\"img\"\n [title]=\"mapping.tooltip\"\n [attr.aria-label]=\"mapping.tooltip || null\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\"></kendo-svg-icon>\n </span>\n }\n }\n </span>\n }\n @case ('cronExpression') {\n <span class=\"cron-expression-cell\">\n <code class=\"cron-expression\">{{ getValue(element, column) }}</code>\n <span class=\"cron-description\">{{ getCronHumanReadable(getValue(element, column)) }}</span>\n </span>\n }\n @case ('numeric') {\n {{ $any(getValue(element, column)) | number:column.format }}\n }\n @case ('progressBar') {\n <span class=\"progress-bar-cell\">\n <span class=\"progress-bar-track\">\n <span class=\"progress-bar-fill\" [style.width.%]=\"getValue(element, column)\"></span>\n </span>\n <span class=\"progress-bar-label\">{{ getValue(element, column) }}%</span>\n </span>\n }\n @case ('badge') {\n @if (getBadgeMapping(element, column); as badge) {\n <span\n class=\"badge-cell\"\n [title]=\"badge.tooltip ?? ''\"\n [style.color]=\"badge.color\"\n [style.background]=\"badge.backgroundColor\"\n [style.borderColor]=\"badge.borderColor ?? badge.backgroundColor\">\n {{ badge.label ?? getValue(element, column) }}\n </span>\n } @else if (!column.badgeHideUnmapped) {\n <span class=\"badge-cell badge-cell-default\">{{ getValue(element, column) }}</span>\n }\n }\n @case ('component') {\n @if (column.cellComponent) {\n <ng-container *ngComponentOutlet=\"column.cellComponent; inputs: getCellInputs(element, column)\" />\n }\n }\n @default {\n {{ getValue(element, column) }}\n }\n }\n }\n</ng-template>\n\n<!-- Row actions (AB#4930, AB#5572): shared by the actions column and the card header. One MmAction\n per action (CommandItems via adapter): neutral icon buttons, danger colour only for destructive\n actions, max `maxInlineRowActions` slots, the rest (and the context menu) behind \"\u2026\". Disabled\n actions stay focusable and announce their reason (mm-action-button). -->\n<ng-template #rowActions let-dataItem=\"dataItem\">\n @let view = rowActionsView(dataItem);\n @if (view.inline.length > 0 || view.hasMenu) {\n <span class=\"mm-list-view-row-actions\" role=\"group\" [attr.aria-label]=\"rowActionsGroupLabel(dataItem)\">\n @for (entry of view.inline; track entry.action.id) {\n <!-- Clicks never reach the grid (no row selection / row navigation from an action). -->\n <mm-action-button [action]=\"entry.action\" [targetLabel]=\"rowLabel(dataItem)\" context=\"row\" display=\"icon\"\n (click)=\"$event.stopPropagation()\"\n (triggered)=\"onInlineRowAction(entry, dataItem)\" />\n }\n @if (view.hasMenu) {\n <button kendoButton themeColor=\"base\" fillMode=\"flat\" size=\"small\" class=\"mm-list-view-row-actions__more\"\n [svgIcon]=\"moreVerticalIcon\" data-action=\"more\"\n [title]=\"rowActionsLabel(dataItem)\" [attr.aria-label]=\"rowActionsLabel(dataItem)\" aria-haspopup=\"menu\"\n [disabled]=\"isLoading()\" (click)=\"$event.stopPropagation(); onContextMenu(dataItem, $event)\"></button>\n }\n </span>\n }\n</ng-template>\n\n<!-- One host toolbar action (left or right band). Flat + neutral unless `primary` (AB#6211). With\n `isDisabled` + `disabledReason` the control stays focusable (aria-disabled), announces the reason\n (aria-describedby) and shows it as a hint bubble on keyboard focus (guideline \u00A72.5); clicks and\n menu opening are swallowed. Applies to buttons, split and dropdown buttons alike. -->\n<ng-template #toolbarItem let-commandItem let-side=\"side\" let-index=\"index\">\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\n @let reason = toolbarItemDisabledReason(commandItem);\n @let reasonId = toolbarReasonId(side, index);\n <span class=\"mm-list-view-toolbar-action\" [class.mm-list-view-toolbar-action--disabled]=\"!!reason\"\n (pointerdown)=\"onToolbarPointerDown()\"\n (focusin)=\"onToolbarFocusIn($event, reason)\"\n (focusout)=\"closeToolbarHint()\"\n (keydown.escape)=\"closeToolbarHint()\">\n @if (commandItem.children && commandItem.children.length > 0 && commandItem.onClick) {\n <kendo-splitbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (buttonClick)=\"reason ? null : onToolbarCommand(commandItem)\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-splitbutton>\n } @else if (commandItem.children && commandItem.children.length > 0) {\n <kendo-dropdownbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else {\n <button kendoTooltip kendoButton [svgIcon]=\"$any(commandItem.svgIcon)\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [attr.aria-disabled]=\"reason ? 'true' : null\"\n [attr.aria-describedby]=\"reason ? reasonId : null\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n (click)=\"reason ? $event.preventDefault() : onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n @if (reason) {\n <span class=\"mm-list-view-toolbar-reason\" [id]=\"reasonId\">{{ reason }}</span>\n }\n </span>\n }\n @case ('separator') {\n <kendo-separator></kendo-separator>\n }\n }\n }\n</ng-template>\n\n<!-- Disabled reason shown on keyboard focus (AB#6211): opened with the Kendo PopupService under the\n application root, so the grid / toolbar overflow cannot clip it. -->\n<ng-template #toolbarHint>\n <div class=\"mm-list-view-toolbar-hint\" data-toolbar-hint>{{ toolbarHintText() }}</div>\n</ng-template>\n\n<kendo-grid\n mmListViewDataBinding\n [loading]=\"isLoading()\"\n [pageSize]=\"effectivePageSize()\" [selectable]=\"selectable\" (pageChange)=\"onPageChange($event)\"\n [skip]=\"skip\" (selectionChange)=\"onRowSelect($event)\" (cellClick)=\"onCellClick($event)\"\n [pageable]=\"effectivePageable\"\n [sortable]=\"sortable\"\n [filterable]=\"_showRowFilter && !isCardMode\"\n [resizable]=\"resizable\"\n [rowClass]=\"rowClass ?? defaultRowClass\"\n>\n <kendo-grid-messages\n [pagerItemsPerPage]=\"_messages.pagerItemsPerPage\"\n [pagerOf]=\"_messages.pagerOf\"\n [pagerItems]=\"_messages.pagerItems\"\n [pagerPage]=\"_messages.pagerPage\"\n [pagerFirstPage]=\"_messages.pagerFirstPage\"\n [pagerLastPage]=\"_messages.pagerLastPage\"\n [pagerPreviousPage]=\"_messages.pagerPreviousPage\"\n [pagerNextPage]=\"_messages.pagerNextPage\"\n [noRecords]=\"_messages.noRecords\"\n ></kendo-grid-messages>\n <!-- Empty state (AB#3444): one block per list, never per row. -->\n <ng-template kendoGridNoRecordsTemplate>\n @if (emptyTemplate) {\n <ng-container *ngTemplateOutlet=\"emptyTemplate; context: emptyContext\"></ng-container>\n } @else if (emptyState) {\n @if (loadSettled() && !isLoading()) {\n @if (isFiltered) {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"no-results\"\n [heading]=\"emptyState.filteredTitle || _messages.noResultsTitle\"\n [text]=\"emptyState.filteredText || _messages.noResultsText\"></mm-empty-state>\n } @else {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"empty\"\n [heading]=\"emptyState.title\" [text]=\"emptyState.text\"></mm-empty-state>\n }\n }\n } @else {\n {{ _messages.noRecords }}\n }\n </ng-template>\n <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'left', index: i}\" />\n }\n\n <!-- Host scope/filter controls (view switches and the like). They steer the\n table, so they sit in the table's own band instead of a second strip\n stacked above the grid. -->\n @if (filtersTemplate) {\n <!-- A rule between the host's actions and its filters: both sit on the\n left of the same band, but one acts on records and the other changes\n what the list shows. Only drawn when actions precede them. -->\n @if (leftToolbarActions.length > 0) {\n <kendo-separator class=\"mm-toolbar-filters-separator\"></kendo-separator>\n }\n <div class=\"mm-toolbar-filters\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate.templateRef\"></ng-container>\n </div>\n }\n\n <kendo-grid-spacer></kendo-grid-spacer>\n @if (searchTextBoxEnabled) {\n <input\n class=\"k-textbox k-input k-input-md k-rounded-md mm-search-input\"\n [placeholder]=\"_messages.searchPlaceholder\"\n [value]=\"searchValue\"\n (input)=\"onFilter($any($event.target).value || null)\"\n />\n }\n\n @for (commandItem of rightToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'right', index: i}\" />\n }\n\n <!-- Commands: laid out while there is room, collapsed into one menu once\n the list gets narrow. Same behaviour in every host app \u2014 a list this\n wide has space for five buttons, and a list this narrow does not. -->\n @if (commandsCollapsed) {\n <kendo-dropdownbutton class=\"mm-toolbar-commands\" [data]=\"toolbarCommands\" textField=\"text\" [svgIcon]=\"commandsIcon\"\n fillMode=\"flat\" themeColor=\"primary\" [disabled]=\"isLoading()\"\n [title]=\"_messages.commands\"\n [buttonAttributes]=\"commandsMenuButtonAttributes\"\n (itemClick)=\"onCommand($any($event).id)\"></kendo-dropdownbutton>\n } @else {\n @for (command of toolbarCommands; track command.id) {\n @switch (command.id) {\n @case ('excel') {\n <button kendoTooltip kendoGridExcelCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @case ('pdf') {\n <button kendoTooltip kendoGridPDFCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @default {\n <!-- The row filter is a toggle: its on state is shown (k-selected) and announced. -->\n <button kendoTooltip kendoButton themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" (click)=\"onCommand(command.id)\"\n [class.k-selected]=\"command.id === 'rowFilter' && _showRowFilter\"\n [attr.aria-pressed]=\"command.id === 'rowFilter' ? _showRowFilter : null\"\n [attr.data-command]=\"command.id\"\n [disabled]=\"isLoading()\" [title]=\"command.text\" [attr.aria-label]=\"command.text\"></button>\n }\n }\n }\n }\n </ng-template>\n\n @if (showCheckboxColumn()) {\n <kendo-grid-checkbox-column [showSelectAll]=\"showRowSelectAllCheckBox\"\n [width]=\"effectiveCheckboxColumnWidth\"></kendo-grid-checkbox-column>\n }\n\n @if (!isCardMode) {\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\" format=\"{{column.format}}\"\n [width]=\"$any(getEffectiveWidth(column))\"\n [minResizableWidth]=\"column.minWidth ?? 10\"\n [hidden]=\"isColumnHidden(column)\"\n [sortable]=\"column.sortable !== false\"\n [filterable]=\"column.filterable !== false\"\n [class]=\"alignClass(column)\"\n [headerClass]=\"alignClass(column)\"\n [title]=\"getDisplayName(column) | pascalCase\">\n <ng-template kendoGridFilterCellTemplate let-filter let-gridColumn=\"column\">\n @if (hasFilterOptions(column)) {\n <kendo-dropdownlist\n class=\"status-filter-dropdown\"\n [data]=\"column.filterOptions!\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [value]=\"getSelectedFilterValue(column)\"\n [defaultItem]=\"{ text: '', value: null }\"\n [popupSettings]=\"{ width: 'auto' }\"\n (valueChange)=\"onDropdownFilter($event, column)\"\n >\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span class=\"filter-status-item\">\n <span role=\"img\" [attr.aria-label]=\"dataItem.text || mapping.tooltip || null\" [title]=\"dataItem.text || mapping.tooltip\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n </span>\n } @else if (dataItem?.text) {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span style=\"display: inline-flex; align-items: center; gap: 8px;\">\n <span [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n <span>{{ dataItem.text }}</span>\n </span>\n } @else {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n </kendo-dropdownlist>\n } @else if (column.dataType === 'numericRange') {\n <span class=\"numeric-range-filter\">\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'gte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'gte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"From\"\n size=\"small\"\n ></kendo-numerictextbox>\n <span class=\"range-separator\">\u2013</span>\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'lte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'lte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"To\"\n size=\"small\"\n ></kendo-numerictextbox>\n </span>\n } @else {\n @switch (getFilterType(column)) {\n @case ('numeric') {\n <kendo-grid-numeric-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [spinners]=\"!isCompactFilter(column)\" [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-numeric-filter-cell>\n }\n @case ('boolean') {\n <kendo-grid-boolean-filter-cell [column]=\"gridColumn\" [filter]=\"filter\"></kendo-grid-boolean-filter-cell>\n }\n @case ('date') {\n <kendo-grid-date-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-date-filter-cell>\n }\n @default {\n <kendo-grid-string-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"false\"></kendo-grid-string-filter-cell>\n }\n }\n }\n </ng-template>\n <ng-template kendoGridCellTemplate let-dataItem>\n <span\n [class.mm-cell-truncate]=\"column.truncate\"\n [attr.title]=\"column.truncate ? getCellTitle(dataItem, column) : null\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </ng-template>\n </kendo-grid-column>\n }\n\n @if (hasRowActions) {\n <kendo-grid-command-column [title]=\"_messages.actionsColumnTitle\" [width]=\"effectiveActionsColumnWidth\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </ng-template>\n </kendo-grid-command-column>\n }\n } @else {\n <!-- Card mode (AB#4930): one full-width column renders the whole row as a\n stacked card \u2014 title from the first column, labeled lines for the\n rest (empty values skipped), row actions in the card header. -->\n <kendo-grid-column [sortable]=\"false\" [filterable]=\"false\" title=\"\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <div class=\"mm-card\">\n <div class=\"mm-card-header\">\n @if (cardTitleColumn; as titleColumn) {\n <span class=\"mm-card-title\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: titleColumn }\"\n ></ng-container>\n </span>\n }\n <span class=\"mm-card-actions\">\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"mm-card-fields\">\n @for (column of cardBodyColumns; track column.field) {\n @if (hasCardValue(dataItem, column)) {\n <div class=\"mm-card-field\">\n <span class=\"mm-card-label\">{{ getDisplayName(column) | pascalCase }}</span>\n <span class=\"mm-card-value\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n </kendo-grid-column>\n }\n\n <kendo-grid-excel fileName=\"{{excelExportFileName}}\">\n @for (column of columns; track column.field) {\n <kendo-excelexport-column [field]=\"column.field\"\n [title]=\"getDisplayName(column) | pascalCase\">\n </kendo-excelexport-column>\n }\n </kendo-grid-excel>\n\n <kendo-grid-pdf fileName=\"{{pdfExportFileName}}\" paperSize=\"A4\" [repeatHeaders]=\"true\"\n [landscape]=\"true\">\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\"\n [title]=\"getDisplayName(column) | pascalCase\"></kendo-grid-column>\n }\n <kendo-grid-pdf-margin top=\"1.5cm\" left=\"1cm\" right=\"1cm\" bottom=\"1.5cm\"></kendo-grid-pdf-margin>\n <ng-template kendoGridPDFTemplate let-pageNum=\"pageNum\" let-totalPages=\"totalPages\">\n <div class=\"page-template\">\n <div class=\"footer\" style=\"position: absolute; bottom: 0; width: 100%; text-align: center; font-size: 9px; color: #666;\">\n {{ getPdfPageText(pageNum, totalPages) }}\n </div>\n </div>\n </ng-template>\n </kendo-grid-pdf>\n</kendo-grid>\n\n<kendo-contextmenu\n #gridmenu\n [kendoMenuHierarchyBinding]=\"_contextMenuItems\"\n [textField]=\"['text']\"\n childrenField=\"items\"\n svgIconField=\"svgIcon\"\n separatorField=\"separator\"\n disabledField=\"disabled\"\n cssClassField=\"cssClass\"\n (popupClose)=\"onContextMenuClosed($event)\"\n (select)=\"onContextMenuSelect($event)\"\n></kendo-contextmenu>\n", styles: [":host{display:flex;flex-direction:column;min-height:0}:host>kendo-grid{flex:1;min-height:0}.mm-search-input{width:165px}.mm-list-view-toolbar-action{position:relative;display:inline-flex}:host ::ng-deep .mm-list-view-toolbar-action--disabled .k-button{opacity:.45;cursor:not-allowed}.mm-list-view-toolbar-reason{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.mm-list-view-toolbar-hint{max-width:280px;padding:var(--theme-space-1, 4px) var(--theme-space-2, 8px);font-size:.75rem;line-height:1.4;color:var(--theme-text-primary, #0f1c2e);background:var(--theme-bg-overlay, #ffffff);border:1px solid var(--theme-border-default, rgba(7, 23, 43, .12));border-radius:var(--theme-radius-sm, 4px);box-shadow:var(--theme-shadow-popup, 0 8px 24px rgba(7, 23, 43, .14));pointer-events:none}:host ::ng-deep .k-grid th:has(input[type=checkbox]),:host ::ng-deep .k-grid td:has(>kendo-checkbox){text-overflow:clip}:host ::ng-deep .k-command-cell{white-space:nowrap;overflow:hidden;vertical-align:middle}:host ::ng-deep .k-command-cell .k-button{display:inline-flex;vertical-align:middle;margin:0}:host ::ng-deep .k-command-cell .k-button+.k-button{margin-left:4px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar{flex-wrap:wrap;row-gap:6px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-search-input{width:100%;order:10}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar kendo-grid-spacer{display:none}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-toolbar-commands{margin-left:auto}:host ::ng-deep .k-grid td.mm-col-align-right{text-align:right;font-variant-numeric:tabular-nums}:host ::ng-deep .k-grid td.mm-col-align-center{text-align:center}:host ::ng-deep .k-grid th.mm-col-align-right .k-cell-inner>.k-link{justify-content:flex-end}:host ::ng-deep .k-grid th.mm-col-align-center .k-cell-inner>.k-link{justify-content:center}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-wrapper{gap:2px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-datepicker>.k-input-button{display:none}:host ::ng-deep .k-filter-row .mm-filter-compact .k-input-inner{padding-left:4px;padding-right:4px;font-size:12px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator{width:26px;min-width:0}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator .k-input-button{padding:2px}.mm-cell-truncate{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-icons-cell{display:inline-flex;align-items:center;gap:8px}.status-icons-cell .status-icon{display:inline-flex;align-items:center;justify-content:center;cursor:default}.status-icons-cell .status-icon kendo-svg-icon{width:18px;height:18px}:host ::ng-deep .filter-status-item{display:inline-flex;align-items:center;gap:10px}:host ::ng-deep .status-filter-dropdown .k-input-value-text{font-size:0}:host ::ng-deep .status-filter-dropdown .k-input-value-text .filter-status-item,:host ::ng-deep .status-filter-dropdown .k-input-value-text>span{font-size:14px}.numeric-range-filter{display:flex;align-items:center;gap:4px}.numeric-range-filter kendo-numerictextbox{flex:1;min-width:0}.numeric-range-filter .range-separator{flex-shrink:0;opacity:.6}.cron-expression-cell{display:flex;flex-direction:column;gap:2px}.cron-expression-cell .cron-expression{font-family:Roboto Mono,Consolas,monospace;font-size:.85em;background:var(--mm-cron-code-bg, #eeeeee);color:var(--mm-cron-code-text, #333333);padding:2px 6px;border-radius:3px}.cron-expression-cell .cron-description{font-size:.8em;color:var(--mm-cron-text-secondary, #666666)}.badge-cell{display:inline-block;padding:2px 10px;font-size:.75rem;font-weight:600;border-radius:12px;border:1px solid var(--mm-badge-default-border, transparent);background:var(--mm-badge-default-bg, rgba(127, 127, 127, .15));color:var(--mm-badge-default-color, inherit);white-space:nowrap;line-height:1.4}.badge-cell-default{opacity:.7;font-style:italic}.progress-bar-cell{display:inline-flex;align-items:center;gap:8px;width:100%}.progress-bar-cell .progress-bar-track{flex:1;height:8px;background:var(--mm-progress-track-bg, rgba(255, 255, 255, .1));border-radius:4px;overflow:hidden}.progress-bar-cell .progress-bar-fill{display:block;height:100%;background:var(--mm-progress-fill-color, #10b981);border-radius:4px;transition:width .3s ease}.progress-bar-cell .progress-bar-label{min-width:40px;text-align:right;font-size:.85em}:host-context(.k-pdf-export) .k-grid,:host-context(.k-pdf-export) .k-grid-header,:host-context(.k-pdf-export) .k-grid-content,:host-context(.k-pdf-export) .k-grid-header-wrap,:host-context(.k-pdf-export) .k-grid-content-locked,:host-context(.k-pdf-export) .k-grid-header-locked{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border-color:#000!important}:host-context(.k-pdf-export) .k-grid{border:1px solid #000!important;font-family:Arial,sans-serif!important;font-size:10px!important}:host-context(.k-pdf-export) .k-grid-header th,:host-context(.k-pdf-export) .k-header,:host-context(.k-pdf-export) .k-grid th{background:#f0f0f0!important;background-color:#f0f0f0!important;background-image:none!important;color:#000!important;border:1px solid #000!important;font-weight:700!important;padding:6px 8px!important;text-transform:none!important;letter-spacing:normal!important}:host-context(.k-pdf-export) .k-grid td,:host-context(.k-pdf-export) .k-grid-content td,:host-context(.k-pdf-export) .k-master-row td{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border:1px solid #000!important;padding:4px 8px!important}:host-context(.k-pdf-export) .k-grid tr,:host-context(.k-pdf-export) .k-master-row,:host-context(.k-pdf-export) .k-alt{background:#fff!important;background-color:#fff!important;background-image:none!important}:host-context(.k-pdf-export) .k-grid tr:hover,:host-context(.k-pdf-export) .k-grid tr.k-selected,:host-context(.k-pdf-export) .k-grid td:hover{background:#fff!important;background-color:#fff!important}:host-context(.k-pdf-export) .k-grid-toolbar,:host-context(.k-pdf-export) .k-pager,:host-context(.k-pdf-export) .k-grid-pager,:host-context(.k-pdf-export) .k-command-cell,:host-context(.k-pdf-export) .k-checkbox-column,:host-context(.k-pdf-export) kendo-grid-checkbox-column,:host-context(.k-pdf-export) .status-icons-cell,:host-context(.k-pdf-export) .status-icon,:host-context(.k-pdf-export) kendo-svg-icon{display:none!important}:host-context(.k-pdf-export) .badge-cell{background:transparent!important;border:none!important;color:inherit!important;padding:0!important;border-radius:0!important;text-transform:none!important;font-weight:inherit!important;font-size:inherit!important}:host(.mm-list-view-cards) ::ng-deep .k-grid-header{display:none}:host(.mm-list-view-cards) ::ng-deep .k-grid td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td{border:none;background:transparent;padding:4px 2px;white-space:normal}:host(.mm-list-view-cards) ::ng-deep .k-grid td:has(>kendo-checkbox),:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td:has(>kendo-checkbox){padding-left:2px;padding-right:0}:host(.mm-list-view-cards) ::ng-deep .k-grid colgroup>col:first-child:not(:only-child){width:32px!important}:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row:hover,:host(.mm-list-view-cards) ::ng-deep .k-grid tr:hover{background:transparent}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected .mm-card,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected .mm-card{border-color:var(--kendo-color-primary, #ff6358)}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected>td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected>.k-table-td{background:transparent}.mm-card{display:flex;flex-direction:column;gap:6px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:8px;padding:10px 12px}.mm-card-header{display:flex;align-items:center;gap:8px}.mm-card-title{flex:1;min-width:0;font-weight:600;overflow-wrap:anywhere}.mm-card-actions{display:flex;align-items:center;gap:2px;flex-shrink:0}.mm-card-fields{display:flex;flex-direction:column;gap:3px}.mm-card-field{display:flex;align-items:baseline;gap:8px;font-size:.9em}.mm-card-label{flex:0 0 38%;max-width:160px;color:var(--kendo-color-subtle, #666666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mm-card-value{flex:1;min-width:0;overflow-wrap:anywhere}::ng-deep .k-grid-toolbar .mm-toolbar-filters{display:flex;align-items:center;gap:12px;flex-wrap:wrap}::ng-deep .k-grid-toolbar .mm-toolbar-filters-separator{align-self:center;height:22px;margin:0 4px;border-left:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .16));border-top:none;width:0}::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-link,::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-menu-link{color:var(--theme-status-error, #c0385f)}.mm-list-view-row-actions{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;vertical-align:middle}.mm-list-view-row-actions .mm-list-view-row-actions__more:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}.boolean-icon{display:inline-flex;align-items:center}.boolean-icon.boolean-icon--true{color:var(--mm-list-boolean-true-color, var(--kendo-color-success, #2fb37a))}.boolean-icon.boolean-icon--false{color:var(--mm-list-boolean-false-color, var(--kendo-color-subtle, #8a94a0))}\n"], dependencies: [{ kind: "component", type: GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: MmListViewDataBindingDirective, selector: "[mmListViewDataBinding]" }, { kind: "component", type: ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: ToolbarTemplateDirective, selector: "[kendoGridToolbarTemplate]", inputs: ["position"] }, { kind: "component", type: GridSpacerComponent, selector: "kendo-grid-spacer", inputs: ["width"] }, { kind: "ngmodule", type: ExcelModule }, { kind: "component", type: i1$2.ExcelComponent, selector: "kendo-grid-excel", inputs: ["fileName", "filterable", "creator", "date", "forceProxy", "proxyURL", "fetchData", "paddingCellOptions", "headerPaddingCellOptions", "collapsible"], outputs: ["fileCreated"] }, { kind: "component", type: i1$2.ExcelCommandDirective, selector: "[kendoGridExcelCommand]" }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-excelexport-column", inputs: ["field", "cellOptions", "groupHeaderCellOptions", "groupFooterCellOptions", "footerCellOptions"] }, { kind: "ngmodule", type: PDFModule }, { kind: "component", type: i1$2.PDFComponent, selector: "kendo-grid-pdf", inputs: ["allPages", "delay"] }, { kind: "component", type: i1$2.PDFMarginComponent, selector: "kendo-grid-pdf-margin" }, { kind: "component", type: i1$2.PDFCommandDirective, selector: "[kendoGridPDFCommand]" }, { kind: "directive", type: i1$2.PDFTemplateDirective, selector: "[kendoGridPDFTemplate]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }, { kind: "component", type: SplitButtonComponent, selector: "kendo-splitbutton", inputs: ["text", "icon", "svgIcon", "iconClass", "type", "imageUrl", "size", "rounded", "fillMode", "themeColor", "disabled", "popupSettings", "tabIndex", "textField", "data", "arrowButtonClass", "arrowButtonIcon", "arrowButtonSvgIcon", "buttonAttributes"], outputs: ["buttonClick", "itemClick", "focus", "blur", "open", "close"], exportAs: ["kendoSplitButton"] }, { kind: "component", type: CommandColumnComponent, selector: "kendo-grid-command-column" }, { kind: "directive", type: CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "component", type: ContextMenuComponent, selector: "kendo-contextmenu", inputs: ["showOn", "target", "filter", "alignToAnchor", "vertical", "popupAnimate", "popupAlign", "anchorAlign", "collision", "appendTo", "ariaLabel"], outputs: ["popupOpen", "popupClose", "select", "open", "close"], exportAs: ["kendoContextMenu"] }, { kind: "directive", type: HierarchyBindingDirective, selector: "[kendoMenuHierarchyBinding]", inputs: ["kendoMenuHierarchyBinding", "textField", "urlField", "iconField", "svgIconField", "disabledField", "cssClassField", "cssStyleField", "separatorField", "childrenField"], exportAs: ["kendoMenuHierarchyBinding"] }, { kind: "component", type: CheckboxColumnComponent, selector: "kendo-grid-checkbox-column", inputs: ["showSelectAll", "showDisabledCheckbox"] }, { kind: "component", type: CheckBoxComponent, selector: "kendo-checkbox", inputs: ["checkedState", "rounded"], outputs: ["checkedStateChange"], exportAs: ["kendoCheckBox"] }, { kind: "component", type: SeparatorComponent, selector: "kendo-separator", inputs: ["orientation"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i2.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: CustomMessagesComponent, selector: "kendo-grid-messages" }, { kind: "directive", type: FilterCellTemplateDirective, selector: "[kendoGridFilterCellTemplate]" }, { kind: "component", type: StringFilterCellComponent, selector: "kendo-grid-string-filter-cell", inputs: ["filterDelay", "showOperators", "placeholder"] }, { kind: "component", type: NumericFilterCellComponent, selector: "kendo-grid-numeric-filter-cell", inputs: ["filterDelay", "showOperators", "placeholder"] }, { kind: "component", type: BooleanFilterCellComponent, selector: "kendo-grid-boolean-filter-cell" }, { kind: "component", type: DateFilterCellComponent, selector: "kendo-grid-date-filter-cell", inputs: ["showOperators"] }, { kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: ValueTemplateDirective, selector: "[kendoDropDownListValueTemplate],[kendoDropDownTreeValueTemplate]" }, { kind: "directive", type: ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ActionButtonComponent, selector: "mm-action-button", inputs: ["action", "targetLabel", "context", "display", "primary"], outputs: ["triggered"] }, { kind: "directive", type: NoRecordsTemplateDirective, selector: "[kendoGridNoRecordsTemplate]" }, { kind: "component", type: EmptyStateComponent, selector: "mm-empty-state", inputs: ["variant", "heading", "text", "size", "showRetry", "retryLabel"], outputs: ["retry"] }, { kind: "pipe", type: PascalCasePipe, name: "pascalCase" }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: BytesToSizePipe, name: "bytesToSize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4190
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: ListViewComponent, isStandalone: true, selector: "mm-list-view", inputs: { pageSize: "pageSize", skip: "skip", autoPageSize: "autoPageSize", rowIsClickable: "rowIsClickable", showRowCheckBoxes: "showRowCheckBoxes", showRowSelectAllCheckBox: "showRowSelectAllCheckBox", contextMenuType: "contextMenuType", leftToolbarActions: "leftToolbarActions", rightToolbarActions: "rightToolbarActions", actionCommandItems: "actionCommandItems", contextMenuCommandItems: "contextMenuCommandItems", rowActions: "rowActions", maxInlineRowActions: "maxInlineRowActions", excelExportFileName: "excelExportFileName", pdfExportFileName: "pdfExportFileName", pageable: "pageable", sortable: "sortable", rowFilterEnabled: "rowFilterEnabled", searchTextBoxEnabled: "searchTextBoxEnabled", persistListState: "persistListState", listStateKey: "listStateKey", resizable: "resizable", actionsColumnWidth: "actionsColumnWidth", hideCheckboxesBelow: "hideCheckboxesBelow", cardModeBelow: "cardModeBelow", collapseCommandsBelow: "collapseCommandsBelow", hasExternalFilters: "hasExternalFilters", emptyState: "emptyState", emptyTemplate: "emptyTemplate", rowClass: "rowClass", messages: "messages", selectable: "selectable", columns: "columns", rowLabelField: "rowLabelField" }, outputs: { rowClicked: "rowClicked", rowAction: "rowAction", resetFilters: "resetFilters" }, host: { properties: { "class.mm-list-view-narrow": "this.isNarrow", "class.mm-list-view-cards": "this.isCardMode" } }, queries: [{ propertyName: "filtersTemplate", first: true, predicate: ListViewFiltersDirective, descendants: true }, { propertyName: "emptyActionsTemplate", first: true, predicate: ListViewEmptyActionsDirective, descendants: true }], viewQueries: [{ propertyName: "gridComponent", first: true, predicate: GridComponent, descendants: true }, { propertyName: "dataBindingDirective", first: true, predicate: MmListViewDataBindingDirective, descendants: true }, { propertyName: "gridContextMenu", first: true, predicate: ["gridmenu"], descendants: true }, { propertyName: "toolbarHintTemplate", first: true, predicate: ["toolbarHint"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<!-- Shared cell renderer (AB#4930): used by the regular grid columns AND the\n card-mode body lines, so both render every dataType identically. -->\n<ng-template #cellContent let-element=\"element\" let-column=\"column\">\n @if (column.formatter) {\n {{ getFormattedValue(element, column) }}\n } @else {\n @switch (column.dataType) {\n @case ('boolean') {\n <!-- Read-only marker: named after its column so a screen reader says what is checked (AB#5621). -->\n <kendo-checkbox type=\"checkbox\" [checkedState]=\"$any(getValue(element, column))\" [disabled]=\"true\"\n [inputAttributes]=\"booleanCellAttributes(column)\" />\n }\n @case ('booleanIcon') {\n <!-- Boolean as icon (AB#5623): named \"<column>: Yes|No\" like the status icons (G13). -->\n @if (booleanIconState(element, column); as state) {\n @if (booleanIcon(column, state); as icon) {\n <span\n class=\"boolean-icon\"\n [class.boolean-icon--true]=\"state === 'true'\"\n [class.boolean-icon--false]=\"state === 'false'\"\n role=\"img\"\n [title]=\"booleanIconLabel(column, state)\"\n [attr.aria-label]=\"booleanIconLabel(column, state)\"\n [style.color]=\"state === 'true' ? column.booleanIcons?.trueColor : column.booleanIcons?.falseColor\">\n <kendo-svg-icon [icon]=\"icon\"></kendo-svg-icon>\n </span>\n }\n }\n }\n @case ('iso8601') {\n {{ $any(getValue(element, column)) | date:column.format }}\n }\n @case ('bytes') {\n {{ $any(getValue(element, column)) | bytesToSize }}\n }\n @case ('statusIcons') {\n <span class=\"status-icons-cell\">\n @for (fieldConfig of getStatusFields(column); track fieldConfig.field) {\n @if (getStatusIconMapping(element, fieldConfig); as mapping) {\n <!-- Icon-only status: the mapping's tooltip is also its accessible name (AB#5621). -->\n <span\n class=\"status-icon\"\n role=\"img\"\n [title]=\"mapping.tooltip\"\n [attr.aria-label]=\"mapping.tooltip || null\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\"></kendo-svg-icon>\n </span>\n }\n }\n </span>\n }\n @case ('cronExpression') {\n <span class=\"cron-expression-cell\">\n <code class=\"cron-expression\">{{ getValue(element, column) }}</code>\n <span class=\"cron-description\">{{ getCronHumanReadable(getValue(element, column)) }}</span>\n </span>\n }\n @case ('numeric') {\n {{ $any(getValue(element, column)) | number:column.format }}\n }\n @case ('progressBar') {\n <span class=\"progress-bar-cell\">\n <span class=\"progress-bar-track\">\n <span class=\"progress-bar-fill\" [style.width.%]=\"getValue(element, column)\"></span>\n </span>\n <span class=\"progress-bar-label\">{{ getValue(element, column) }}%</span>\n </span>\n }\n @case ('badge') {\n @if (getBadgeMapping(element, column); as badge) {\n <span\n class=\"badge-cell\"\n [title]=\"badge.tooltip ?? ''\"\n [style.color]=\"badge.color\"\n [style.background]=\"badge.backgroundColor\"\n [style.borderColor]=\"badge.borderColor ?? badge.backgroundColor\">\n {{ badge.label ?? getValue(element, column) }}\n </span>\n } @else if (!column.badgeHideUnmapped) {\n <span class=\"badge-cell badge-cell-default\">{{ getValue(element, column) }}</span>\n }\n }\n @case ('component') {\n @if (column.cellComponent) {\n <ng-container *ngComponentOutlet=\"column.cellComponent; inputs: getCellInputs(element, column)\" />\n }\n }\n @default {\n {{ getValue(element, column) }}\n }\n }\n }\n</ng-template>\n\n<!-- Row actions (AB#4930, AB#5572): shared by the actions column and the card header. One MmAction\n per action (CommandItems via adapter): neutral icon buttons, danger colour only for destructive\n actions, max `maxInlineRowActions` slots, the rest (and the context menu) behind \"\u2026\". Disabled\n actions stay focusable and announce their reason (mm-action-button). -->\n<ng-template #rowActions let-dataItem=\"dataItem\">\n @let view = rowActionsView(dataItem);\n @if (view.inline.length > 0 || view.hasMenu) {\n <span class=\"mm-list-view-row-actions\" role=\"group\" [attr.aria-label]=\"rowActionsGroupLabel(dataItem)\">\n @for (entry of view.inline; track entry.action.id) {\n <!-- Clicks never reach the grid (no row selection / row navigation from an action). -->\n <mm-action-button [action]=\"entry.action\" [targetLabel]=\"rowLabel(dataItem)\" context=\"row\" display=\"icon\"\n (click)=\"$event.stopPropagation()\"\n (triggered)=\"onInlineRowAction(entry, dataItem)\" />\n }\n @if (view.hasMenu) {\n <button kendoButton themeColor=\"base\" fillMode=\"flat\" size=\"small\" class=\"mm-list-view-row-actions__more\"\n [svgIcon]=\"moreVerticalIcon\" data-action=\"more\"\n [title]=\"rowActionsLabel(dataItem)\" [attr.aria-label]=\"rowActionsLabel(dataItem)\" aria-haspopup=\"menu\"\n [disabled]=\"isLoading()\" (click)=\"$event.stopPropagation(); onContextMenu(dataItem, $event)\"></button>\n }\n </span>\n }\n</ng-template>\n\n<!-- One host toolbar action (left or right band). Flat + neutral unless `primary` (AB#6211). With\n `isDisabled` + `disabledReason` the control stays focusable (aria-disabled), announces the reason\n (aria-describedby) and shows it as a hint bubble on keyboard focus (guideline \u00A72.5); clicks and\n menu opening are swallowed. Applies to buttons, split and dropdown buttons alike. -->\n<ng-template #toolbarItem let-commandItem let-side=\"side\" let-index=\"index\">\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\n @let reason = toolbarItemDisabledReason(commandItem);\n @let reasonId = toolbarReasonId(side, index);\n <span class=\"mm-list-view-toolbar-action\" [class.mm-list-view-toolbar-action--disabled]=\"!!reason\"\n (pointerdown)=\"onToolbarPointerDown()\"\n (focusin)=\"onToolbarFocusIn($event, reason)\"\n (focusout)=\"closeToolbarHint()\"\n (keydown.escape)=\"closeToolbarHint()\">\n @if (commandItem.children && commandItem.children.length > 0 && commandItem.onClick) {\n <kendo-splitbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (buttonClick)=\"reason ? null : onToolbarCommand(commandItem)\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-splitbutton>\n } @else if (commandItem.children && commandItem.children.length > 0) {\n <kendo-dropdownbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else {\n <button kendoTooltip kendoButton [svgIcon]=\"$any(commandItem.svgIcon)\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [attr.aria-disabled]=\"reason ? 'true' : null\"\n [attr.aria-describedby]=\"reason ? reasonId : null\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n (click)=\"reason ? $event.preventDefault() : onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n @if (reason) {\n <span class=\"mm-list-view-toolbar-reason\" [id]=\"reasonId\">{{ reason }}</span>\n }\n </span>\n }\n @case ('separator') {\n <kendo-separator></kendo-separator>\n }\n }\n }\n</ng-template>\n\n<!-- Disabled reason shown on keyboard focus (AB#6211): opened with the Kendo PopupService under the\n application root, so the grid / toolbar overflow cannot clip it. -->\n<ng-template #toolbarHint>\n <div class=\"mm-list-view-toolbar-hint\" data-toolbar-hint>{{ toolbarHintText() }}</div>\n</ng-template>\n\n<kendo-grid\n mmListViewDataBinding\n [loading]=\"isLoading()\"\n [pageSize]=\"effectivePageSize()\" [selectable]=\"selectable\" (pageChange)=\"onPageChange($event)\"\n [skip]=\"skip\" (selectionChange)=\"onRowSelect($event)\" (cellClick)=\"onCellClick($event)\"\n [pageable]=\"effectivePageable\"\n [sortable]=\"sortable\"\n [filterable]=\"_showRowFilter && !isCardMode\"\n [resizable]=\"resizable\"\n [rowClass]=\"rowClass ?? defaultRowClass\"\n>\n <kendo-grid-messages\n [pagerItemsPerPage]=\"_messages.pagerItemsPerPage\"\n [pagerOf]=\"_messages.pagerOf\"\n [pagerItems]=\"_messages.pagerItems\"\n [pagerPage]=\"_messages.pagerPage\"\n [pagerFirstPage]=\"_messages.pagerFirstPage\"\n [pagerLastPage]=\"_messages.pagerLastPage\"\n [pagerPreviousPage]=\"_messages.pagerPreviousPage\"\n [pagerNextPage]=\"_messages.pagerNextPage\"\n [noRecords]=\"_messages.noRecords\"\n ></kendo-grid-messages>\n <!-- Empty state (AB#3444): one block per list, never per row. -->\n <ng-template kendoGridNoRecordsTemplate>\n @if (emptyTemplate) {\n <ng-container *ngTemplateOutlet=\"emptyTemplate; context: emptyContext\"></ng-container>\n } @else if (emptyState) {\n @if (loadSettled() && !isLoading()) {\n @if (isFiltered) {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"no-results\"\n [heading]=\"emptyState.filteredTitle || _messages.noResultsTitle\"\n [text]=\"emptyState.filteredText || _messages.noResultsText\"></mm-empty-state>\n } @else {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"empty\"\n [heading]=\"emptyState.title\" [text]=\"emptyState.text\">\n @if (emptyActionsTemplate) {\n <div class=\"mm-list-view-empty-actions\" (keydown)=\"keepEmptyActionKeysFromGrid($event)\">\n <ng-container [ngTemplateOutlet]=\"emptyActionsTemplate.templateRef\"></ng-container>\n </div>\n }\n </mm-empty-state>\n }\n }\n } @else {\n {{ _messages.noRecords }}\n }\n </ng-template>\n <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'left', index: i}\" />\n }\n\n <!-- Host scope/filter controls (view switches and the like). They steer the\n table, so they sit in the table's own band instead of a second strip\n stacked above the grid. -->\n @if (filtersTemplate) {\n <!-- A rule between the host's actions and its filters: both sit on the\n left of the same band, but one acts on records and the other changes\n what the list shows. Only drawn when actions precede them. -->\n @if (leftToolbarActions.length > 0) {\n <kendo-separator class=\"mm-toolbar-filters-separator\"></kendo-separator>\n }\n <div class=\"mm-toolbar-filters\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate.templateRef\"></ng-container>\n </div>\n }\n\n <kendo-grid-spacer></kendo-grid-spacer>\n @if (searchTextBoxEnabled) {\n <input\n class=\"k-textbox k-input k-input-md k-rounded-md mm-search-input\"\n [placeholder]=\"_messages.searchPlaceholder\"\n [value]=\"searchValue\"\n (input)=\"onFilter($any($event.target).value || null)\"\n />\n }\n\n @for (commandItem of rightToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'right', index: i}\" />\n }\n\n <!-- Commands: laid out while there is room, collapsed into one menu once\n the list gets narrow. Same behaviour in every host app \u2014 a list this\n wide has space for five buttons, and a list this narrow does not. -->\n @if (commandsCollapsed) {\n <kendo-dropdownbutton class=\"mm-toolbar-commands\" [data]=\"toolbarCommands\" textField=\"text\" [svgIcon]=\"commandsIcon\"\n fillMode=\"flat\" themeColor=\"primary\" [disabled]=\"isLoading()\"\n [title]=\"_messages.commands\"\n [buttonAttributes]=\"commandsMenuButtonAttributes\"\n (itemClick)=\"onCommand($any($event).id)\"></kendo-dropdownbutton>\n } @else {\n @for (command of toolbarCommands; track command.id) {\n @switch (command.id) {\n @case ('excel') {\n <button kendoTooltip kendoGridExcelCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @case ('pdf') {\n <button kendoTooltip kendoGridPDFCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @default {\n <!-- The row filter is a toggle: its on state is shown (k-selected) and announced. -->\n <button kendoTooltip kendoButton themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" (click)=\"onCommand(command.id)\"\n [class.k-selected]=\"command.id === 'rowFilter' && _showRowFilter\"\n [attr.aria-pressed]=\"command.id === 'rowFilter' ? _showRowFilter : null\"\n [attr.data-command]=\"command.id\"\n [disabled]=\"isLoading()\" [title]=\"command.text\" [attr.aria-label]=\"command.text\"></button>\n }\n }\n }\n }\n </ng-template>\n\n @if (showCheckboxColumn()) {\n <kendo-grid-checkbox-column [showSelectAll]=\"showRowSelectAllCheckBox\"\n [width]=\"effectiveCheckboxColumnWidth\"></kendo-grid-checkbox-column>\n }\n\n @if (!isCardMode) {\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\" format=\"{{column.format}}\"\n [width]=\"$any(getEffectiveWidth(column))\"\n [minResizableWidth]=\"column.minWidth ?? 10\"\n [hidden]=\"isColumnHidden(column)\"\n [sortable]=\"column.sortable !== false\"\n [filterable]=\"column.filterable !== false\"\n [class]=\"alignClass(column)\"\n [headerClass]=\"alignClass(column)\"\n [title]=\"getDisplayName(column) | pascalCase\">\n <ng-template kendoGridFilterCellTemplate let-filter let-gridColumn=\"column\">\n @if (hasFilterOptions(column)) {\n <kendo-dropdownlist\n class=\"status-filter-dropdown\"\n [data]=\"column.filterOptions!\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [value]=\"getSelectedFilterValue(column)\"\n [defaultItem]=\"{ text: '', value: null }\"\n [popupSettings]=\"{ width: 'auto' }\"\n (valueChange)=\"onDropdownFilter($event, column)\"\n >\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span class=\"filter-status-item\">\n <span role=\"img\" [attr.aria-label]=\"dataItem.text || mapping.tooltip || null\" [title]=\"dataItem.text || mapping.tooltip\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n </span>\n } @else if (dataItem?.text) {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span style=\"display: inline-flex; align-items: center; gap: 8px;\">\n <span [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n <span>{{ dataItem.text }}</span>\n </span>\n } @else {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n </kendo-dropdownlist>\n } @else if (column.dataType === 'numericRange') {\n <span class=\"numeric-range-filter\">\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'gte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'gte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"From\"\n size=\"small\"\n ></kendo-numerictextbox>\n <span class=\"range-separator\">\u2013</span>\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'lte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'lte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"To\"\n size=\"small\"\n ></kendo-numerictextbox>\n </span>\n } @else {\n @switch (getFilterType(column)) {\n @case ('numeric') {\n <kendo-grid-numeric-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [spinners]=\"!isCompactFilter(column)\" [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-numeric-filter-cell>\n }\n @case ('boolean') {\n <kendo-grid-boolean-filter-cell [column]=\"gridColumn\" [filter]=\"filter\"></kendo-grid-boolean-filter-cell>\n }\n @case ('date') {\n <kendo-grid-date-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-date-filter-cell>\n }\n @default {\n <kendo-grid-string-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"false\"></kendo-grid-string-filter-cell>\n }\n }\n }\n </ng-template>\n <ng-template kendoGridCellTemplate let-dataItem>\n <span\n [class.mm-cell-truncate]=\"column.truncate\"\n [attr.title]=\"column.truncate ? getCellTitle(dataItem, column) : null\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </ng-template>\n </kendo-grid-column>\n }\n\n @if (hasRowActions) {\n <kendo-grid-command-column [title]=\"_messages.actionsColumnTitle\" [width]=\"effectiveActionsColumnWidth\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </ng-template>\n </kendo-grid-command-column>\n }\n } @else {\n <!-- Card mode (AB#4930): one full-width column renders the whole row as a\n stacked card \u2014 title from the first column, labeled lines for the\n rest (empty values skipped), row actions in the card header. -->\n <kendo-grid-column [sortable]=\"false\" [filterable]=\"false\" title=\"\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <div class=\"mm-card\">\n <div class=\"mm-card-header\">\n @if (cardTitleColumn; as titleColumn) {\n <span class=\"mm-card-title\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: titleColumn }\"\n ></ng-container>\n </span>\n }\n <span class=\"mm-card-actions\">\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"mm-card-fields\">\n @for (column of cardBodyColumns; track column.field) {\n @if (hasCardValue(dataItem, column)) {\n <div class=\"mm-card-field\">\n <span class=\"mm-card-label\">{{ getDisplayName(column) | pascalCase }}</span>\n <span class=\"mm-card-value\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n </kendo-grid-column>\n }\n\n <kendo-grid-excel fileName=\"{{excelExportFileName}}\">\n @for (column of columns; track column.field) {\n <kendo-excelexport-column [field]=\"column.field\"\n [title]=\"getDisplayName(column) | pascalCase\">\n </kendo-excelexport-column>\n }\n </kendo-grid-excel>\n\n <kendo-grid-pdf fileName=\"{{pdfExportFileName}}\" paperSize=\"A4\" [repeatHeaders]=\"true\"\n [landscape]=\"true\">\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\"\n [title]=\"getDisplayName(column) | pascalCase\"></kendo-grid-column>\n }\n <kendo-grid-pdf-margin top=\"1.5cm\" left=\"1cm\" right=\"1cm\" bottom=\"1.5cm\"></kendo-grid-pdf-margin>\n <ng-template kendoGridPDFTemplate let-pageNum=\"pageNum\" let-totalPages=\"totalPages\">\n <div class=\"page-template\">\n <div class=\"footer\" style=\"position: absolute; bottom: 0; width: 100%; text-align: center; font-size: 9px; color: #666;\">\n {{ getPdfPageText(pageNum, totalPages) }}\n </div>\n </div>\n </ng-template>\n </kendo-grid-pdf>\n</kendo-grid>\n\n<kendo-contextmenu\n #gridmenu\n [kendoMenuHierarchyBinding]=\"_contextMenuItems\"\n [textField]=\"['text']\"\n childrenField=\"items\"\n svgIconField=\"svgIcon\"\n separatorField=\"separator\"\n disabledField=\"disabled\"\n cssClassField=\"cssClass\"\n (popupClose)=\"onContextMenuClosed($event)\"\n (select)=\"onContextMenuSelect($event)\"\n></kendo-contextmenu>\n", styles: [":host{display:flex;flex-direction:column;min-height:0}:host>kendo-grid{flex:1;min-height:0}.mm-search-input{width:165px}.mm-list-view-toolbar-action{position:relative;display:inline-flex}:host ::ng-deep .mm-list-view-toolbar-action--disabled .k-button{opacity:.45;cursor:not-allowed}.mm-list-view-toolbar-reason{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.mm-list-view-toolbar-hint{max-width:280px;padding:var(--theme-space-1, 4px) var(--theme-space-2, 8px);font-size:.75rem;line-height:1.4;color:var(--theme-text-primary, #0f1c2e);background:var(--theme-bg-overlay, #ffffff);border:1px solid var(--theme-border-default, rgba(7, 23, 43, .12));border-radius:var(--theme-radius-sm, 4px);box-shadow:var(--theme-shadow-popup, 0 8px 24px rgba(7, 23, 43, .14));pointer-events:none}:host ::ng-deep .k-grid th:has(input[type=checkbox]),:host ::ng-deep .k-grid td:has(>kendo-checkbox){text-overflow:clip}:host ::ng-deep .k-command-cell{white-space:nowrap;overflow:hidden;vertical-align:middle}:host ::ng-deep .k-command-cell .k-button{display:inline-flex;vertical-align:middle;margin:0}:host ::ng-deep .k-command-cell .k-button+.k-button{margin-left:4px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar{flex-wrap:wrap;row-gap:6px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-search-input{width:100%;order:10}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar kendo-grid-spacer{display:none}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-toolbar-commands{margin-left:auto}:host ::ng-deep .k-grid td.mm-col-align-right{text-align:right;font-variant-numeric:tabular-nums}:host ::ng-deep .k-grid td.mm-col-align-center{text-align:center}:host ::ng-deep .k-grid th.mm-col-align-right .k-cell-inner>.k-link{justify-content:flex-end}:host ::ng-deep .k-grid th.mm-col-align-center .k-cell-inner>.k-link{justify-content:center}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-wrapper{gap:2px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-datepicker>.k-input-button{display:none}:host ::ng-deep .k-filter-row .mm-filter-compact .k-input-inner{padding-left:4px;padding-right:4px;font-size:12px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator{width:26px;min-width:0}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator .k-input-button{padding:2px}.mm-cell-truncate{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-icons-cell{display:inline-flex;align-items:center;gap:8px}.status-icons-cell .status-icon{display:inline-flex;align-items:center;justify-content:center;cursor:default}.status-icons-cell .status-icon kendo-svg-icon{width:18px;height:18px}:host ::ng-deep .filter-status-item{display:inline-flex;align-items:center;gap:10px}:host ::ng-deep .status-filter-dropdown .k-input-value-text{font-size:0}:host ::ng-deep .status-filter-dropdown .k-input-value-text .filter-status-item,:host ::ng-deep .status-filter-dropdown .k-input-value-text>span{font-size:14px}.numeric-range-filter{display:flex;align-items:center;gap:4px}.numeric-range-filter kendo-numerictextbox{flex:1;min-width:0}.numeric-range-filter .range-separator{flex-shrink:0;opacity:.6}.cron-expression-cell{display:flex;flex-direction:column;gap:2px}.cron-expression-cell .cron-expression{font-family:Roboto Mono,Consolas,monospace;font-size:.85em;background:var(--mm-cron-code-bg, #eeeeee);color:var(--mm-cron-code-text, #333333);padding:2px 6px;border-radius:3px}.cron-expression-cell .cron-description{font-size:.8em;color:var(--mm-cron-text-secondary, #666666)}.badge-cell{display:inline-block;padding:2px 10px;font-size:.75rem;font-weight:600;border-radius:12px;border:1px solid var(--mm-badge-default-border, transparent);background:var(--mm-badge-default-bg, rgba(127, 127, 127, .15));color:var(--mm-badge-default-color, inherit);white-space:nowrap;line-height:1.4}.badge-cell-default{opacity:.7;font-style:italic}.progress-bar-cell{display:inline-flex;align-items:center;gap:8px;width:100%}.progress-bar-cell .progress-bar-track{flex:1;height:8px;background:var(--mm-progress-track-bg, rgba(255, 255, 255, .1));border-radius:4px;overflow:hidden}.progress-bar-cell .progress-bar-fill{display:block;height:100%;background:var(--mm-progress-fill-color, #10b981);border-radius:4px;transition:width .3s ease}.progress-bar-cell .progress-bar-label{min-width:40px;text-align:right;font-size:.85em}:host-context(.k-pdf-export) .k-grid,:host-context(.k-pdf-export) .k-grid-header,:host-context(.k-pdf-export) .k-grid-content,:host-context(.k-pdf-export) .k-grid-header-wrap,:host-context(.k-pdf-export) .k-grid-content-locked,:host-context(.k-pdf-export) .k-grid-header-locked{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border-color:#000!important}:host-context(.k-pdf-export) .k-grid{border:1px solid #000!important;font-family:Arial,sans-serif!important;font-size:10px!important}:host-context(.k-pdf-export) .k-grid-header th,:host-context(.k-pdf-export) .k-header,:host-context(.k-pdf-export) .k-grid th{background:#f0f0f0!important;background-color:#f0f0f0!important;background-image:none!important;color:#000!important;border:1px solid #000!important;font-weight:700!important;padding:6px 8px!important;text-transform:none!important;letter-spacing:normal!important}:host-context(.k-pdf-export) .k-grid td,:host-context(.k-pdf-export) .k-grid-content td,:host-context(.k-pdf-export) .k-master-row td{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border:1px solid #000!important;padding:4px 8px!important}:host-context(.k-pdf-export) .k-grid tr,:host-context(.k-pdf-export) .k-master-row,:host-context(.k-pdf-export) .k-alt{background:#fff!important;background-color:#fff!important;background-image:none!important}:host-context(.k-pdf-export) .k-grid tr:hover,:host-context(.k-pdf-export) .k-grid tr.k-selected,:host-context(.k-pdf-export) .k-grid td:hover{background:#fff!important;background-color:#fff!important}:host-context(.k-pdf-export) .k-grid-toolbar,:host-context(.k-pdf-export) .k-pager,:host-context(.k-pdf-export) .k-grid-pager,:host-context(.k-pdf-export) .k-command-cell,:host-context(.k-pdf-export) .k-checkbox-column,:host-context(.k-pdf-export) kendo-grid-checkbox-column,:host-context(.k-pdf-export) .status-icons-cell,:host-context(.k-pdf-export) .status-icon,:host-context(.k-pdf-export) kendo-svg-icon{display:none!important}:host-context(.k-pdf-export) .badge-cell{background:transparent!important;border:none!important;color:inherit!important;padding:0!important;border-radius:0!important;text-transform:none!important;font-weight:inherit!important;font-size:inherit!important}:host(.mm-list-view-cards) ::ng-deep .k-grid-header{display:none}:host(.mm-list-view-cards) ::ng-deep .k-grid td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td{border:none;background:transparent;padding:4px 2px;white-space:normal}:host(.mm-list-view-cards) ::ng-deep .k-grid td:has(>kendo-checkbox),:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td:has(>kendo-checkbox){padding-left:2px;padding-right:0}:host(.mm-list-view-cards) ::ng-deep .k-grid colgroup>col:first-child:not(:only-child){width:32px!important}:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row:hover,:host(.mm-list-view-cards) ::ng-deep .k-grid tr:hover{background:transparent}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected .mm-card,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected .mm-card{border-color:var(--kendo-color-primary, #ff6358)}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected>td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected>.k-table-td{background:transparent}.mm-card{display:flex;flex-direction:column;gap:6px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:8px;padding:10px 12px}.mm-card-header{display:flex;align-items:center;gap:8px}.mm-card-title{flex:1;min-width:0;font-weight:600;overflow-wrap:anywhere}.mm-card-actions{display:flex;align-items:center;gap:2px;flex-shrink:0}.mm-card-fields{display:flex;flex-direction:column;gap:3px}.mm-card-field{display:flex;align-items:baseline;gap:8px;font-size:.9em}.mm-card-label{flex:0 0 38%;max-width:160px;color:var(--kendo-color-subtle, #666666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mm-card-value{flex:1;min-width:0;overflow-wrap:anywhere}::ng-deep .k-grid-toolbar .mm-toolbar-filters{display:flex;align-items:center;gap:12px;flex-wrap:wrap}::ng-deep .k-grid-toolbar .mm-toolbar-filters-separator{align-self:center;height:22px;margin:0 4px;border-left:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .16));border-top:none;width:0}::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-link,::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-menu-link{color:var(--theme-status-error, #c0385f)}.mm-list-view-row-actions{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;vertical-align:middle}.mm-list-view-row-actions .mm-list-view-row-actions__more:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}.boolean-icon{display:inline-flex;align-items:center}.boolean-icon.boolean-icon--true{color:var(--mm-list-boolean-true-color, var(--kendo-color-success, #2fb37a))}.boolean-icon.boolean-icon--false{color:var(--mm-list-boolean-false-color, var(--kendo-color-subtle, #8a94a0))}.mm-list-view-empty-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--theme-space-2, 8px);margin-top:var(--theme-space-1, 4px)}\n"], dependencies: [{ kind: "component", type: GridComponent, selector: "kendo-grid", inputs: ["data", "pageSize", "height", "rowHeight", "adaptiveMode", "detailRowHeight", "skip", "scrollable", "selectable", "sort", "size", "trackBy", "filter", "group", "virtualColumns", "filterable", "sortable", "pageable", "groupable", "gridResizable", "rowReorderable", "navigable", "autoSize", "rowClass", "rowSticky", "rowSelected", "isRowSelectable", "cellSelected", "resizable", "reorderable", "loading", "columnMenu", "hideHeader", "showInactiveTools", "isDetailExpanded", "isGroupExpanded", "dataLayoutMode", "pinnable", "pinnedTopRows", "pinnedBottomRows", "isRowPinnable"], outputs: ["filterChange", "pageChange", "groupChange", "sortChange", "selectionChange", "rowReorder", "rowPinChange", "dataStateChange", "gridStateChange", "groupExpand", "groupCollapse", "detailExpand", "detailCollapse", "edit", "cancel", "save", "remove", "add", "cellClose", "cellClick", "pdfExport", "excelExport", "csvExport", "columnResize", "columnReorder", "columnVisibilityChange", "columnLockedChange", "columnStickyChange", "scrollBottom", "contentScroll"], exportAs: ["kendoGrid"] }, { kind: "directive", type: MmListViewDataBindingDirective, selector: "[mmListViewDataBinding]" }, { kind: "component", type: ColumnComponent, selector: "kendo-grid-column", inputs: ["field", "format", "sortable", "groupable", "editor", "filter", "filterVariant", "filterable", "editable"] }, { kind: "directive", type: ToolbarTemplateDirective, selector: "[kendoGridToolbarTemplate]", inputs: ["position"] }, { kind: "component", type: GridSpacerComponent, selector: "kendo-grid-spacer", inputs: ["width"] }, { kind: "ngmodule", type: ExcelModule }, { kind: "component", type: i1$2.ExcelComponent, selector: "kendo-grid-excel", inputs: ["fileName", "filterable", "creator", "date", "forceProxy", "proxyURL", "fetchData", "paddingCellOptions", "headerPaddingCellOptions", "collapsible"], outputs: ["fileCreated"] }, { kind: "component", type: i1$2.ExcelCommandDirective, selector: "[kendoGridExcelCommand]" }, { kind: "component", type: i2$1.ColumnComponent, selector: "kendo-excelexport-column", inputs: ["field", "cellOptions", "groupHeaderCellOptions", "groupFooterCellOptions", "footerCellOptions"] }, { kind: "ngmodule", type: PDFModule }, { kind: "component", type: i1$2.PDFComponent, selector: "kendo-grid-pdf", inputs: ["allPages", "delay"] }, { kind: "component", type: i1$2.PDFMarginComponent, selector: "kendo-grid-pdf-margin" }, { kind: "component", type: i1$2.PDFCommandDirective, selector: "[kendoGridPDFCommand]" }, { kind: "directive", type: i1$2.PDFTemplateDirective, selector: "[kendoGridPDFTemplate]" }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconPosition", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "component", type: DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }, { kind: "component", type: SplitButtonComponent, selector: "kendo-splitbutton", inputs: ["text", "icon", "svgIcon", "iconClass", "type", "imageUrl", "size", "rounded", "fillMode", "themeColor", "disabled", "popupSettings", "tabIndex", "textField", "data", "arrowButtonClass", "arrowButtonIcon", "arrowButtonSvgIcon", "buttonAttributes"], outputs: ["buttonClick", "itemClick", "focus", "blur", "open", "close"], exportAs: ["kendoSplitButton"] }, { kind: "component", type: CommandColumnComponent, selector: "kendo-grid-command-column" }, { kind: "directive", type: CellTemplateDirective, selector: "[kendoGridCellTemplate]" }, { kind: "component", type: ContextMenuComponent, selector: "kendo-contextmenu", inputs: ["showOn", "target", "filter", "alignToAnchor", "vertical", "popupAnimate", "popupAlign", "anchorAlign", "collision", "appendTo", "ariaLabel"], outputs: ["popupOpen", "popupClose", "select", "open", "close"], exportAs: ["kendoContextMenu"] }, { kind: "directive", type: HierarchyBindingDirective, selector: "[kendoMenuHierarchyBinding]", inputs: ["kendoMenuHierarchyBinding", "textField", "urlField", "iconField", "svgIconField", "disabledField", "cssClassField", "cssStyleField", "separatorField", "childrenField"], exportAs: ["kendoMenuHierarchyBinding"] }, { kind: "component", type: CheckboxColumnComponent, selector: "kendo-grid-checkbox-column", inputs: ["showSelectAll", "showDisabledCheckbox"] }, { kind: "component", type: CheckBoxComponent, selector: "kendo-checkbox", inputs: ["checkedState", "rounded"], outputs: ["checkedStateChange"], exportAs: ["kendoCheckBox"] }, { kind: "component", type: SeparatorComponent, selector: "kendo-separator", inputs: ["orientation"] }, { kind: "ngmodule", type: SVGIconModule }, { kind: "component", type: i2.SVGIconComponent, selector: "kendo-svg-icon, kendo-svgicon", inputs: ["icon", "variant"], exportAs: ["kendoSVGIcon"] }, { kind: "component", type: CustomMessagesComponent, selector: "kendo-grid-messages" }, { kind: "directive", type: FilterCellTemplateDirective, selector: "[kendoGridFilterCellTemplate]" }, { kind: "component", type: StringFilterCellComponent, selector: "kendo-grid-string-filter-cell", inputs: ["filterDelay", "showOperators", "placeholder"] }, { kind: "component", type: NumericFilterCellComponent, selector: "kendo-grid-numeric-filter-cell", inputs: ["filterDelay", "showOperators", "placeholder"] }, { kind: "component", type: BooleanFilterCellComponent, selector: "kendo-grid-boolean-filter-cell" }, { kind: "component", type: DateFilterCellComponent, selector: "kendo-grid-date-filter-cell", inputs: ["showOperators"] }, { kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: ValueTemplateDirective, selector: "[kendoDropDownListValueTemplate],[kendoDropDownTreeValueTemplate]" }, { kind: "directive", type: ItemTemplateDirective, selector: "[kendoDropDownListItemTemplate],[kendoComboBoxItemTemplate],[kendoAutoCompleteItemTemplate],[kendoMultiSelectItemTemplate]" }, { kind: "component", type: NumericTextBoxComponent, selector: "kendo-numerictextbox", inputs: ["focusableId", "disabled", "readonly", "title", "autoCorrect", "format", "max", "min", "decimals", "placeholder", "step", "spinners", "rangeValidation", "tabindex", "tabIndex", "changeValueOnScroll", "selectOnFocus", "value", "maxlength", "size", "rounded", "fillMode", "inputAttributes"], outputs: ["valueChange", "focus", "blur", "inputFocus", "inputBlur"], exportAs: ["kendoNumericTextBox"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ActionButtonComponent, selector: "mm-action-button", inputs: ["action", "targetLabel", "context", "display", "primary"], outputs: ["triggered"] }, { kind: "directive", type: NoRecordsTemplateDirective, selector: "[kendoGridNoRecordsTemplate]" }, { kind: "component", type: EmptyStateComponent, selector: "mm-empty-state", inputs: ["variant", "heading", "text", "size", "showRetry", "retryLabel"], outputs: ["retry"] }, { kind: "pipe", type: PascalCasePipe, name: "pascalCase" }, { kind: "pipe", type: DatePipe, name: "date" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: BytesToSizePipe, name: "bytesToSize" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4171
4191
|
}
|
|
4172
4192
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewComponent, decorators: [{
|
|
4173
4193
|
type: Component,
|
|
@@ -4209,10 +4229,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
4209
4229
|
ActionButtonComponent,
|
|
4210
4230
|
NoRecordsTemplateDirective,
|
|
4211
4231
|
EmptyStateComponent
|
|
4212
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Shared cell renderer (AB#4930): used by the regular grid columns AND the\n card-mode body lines, so both render every dataType identically. -->\n<ng-template #cellContent let-element=\"element\" let-column=\"column\">\n @if (column.formatter) {\n {{ getFormattedValue(element, column) }}\n } @else {\n @switch (column.dataType) {\n @case ('boolean') {\n <!-- Read-only marker: named after its column so a screen reader says what is checked (AB#5621). -->\n <kendo-checkbox type=\"checkbox\" [checkedState]=\"$any(getValue(element, column))\" [disabled]=\"true\"\n [inputAttributes]=\"booleanCellAttributes(column)\" />\n }\n @case ('booleanIcon') {\n <!-- Boolean as icon (AB#5623): named \"<column>: Yes|No\" like the status icons (G13). -->\n @if (booleanIconState(element, column); as state) {\n @if (booleanIcon(column, state); as icon) {\n <span\n class=\"boolean-icon\"\n [class.boolean-icon--true]=\"state === 'true'\"\n [class.boolean-icon--false]=\"state === 'false'\"\n role=\"img\"\n [title]=\"booleanIconLabel(column, state)\"\n [attr.aria-label]=\"booleanIconLabel(column, state)\"\n [style.color]=\"state === 'true' ? column.booleanIcons?.trueColor : column.booleanIcons?.falseColor\">\n <kendo-svg-icon [icon]=\"icon\"></kendo-svg-icon>\n </span>\n }\n }\n }\n @case ('iso8601') {\n {{ $any(getValue(element, column)) | date:column.format }}\n }\n @case ('bytes') {\n {{ $any(getValue(element, column)) | bytesToSize }}\n }\n @case ('statusIcons') {\n <span class=\"status-icons-cell\">\n @for (fieldConfig of getStatusFields(column); track fieldConfig.field) {\n @if (getStatusIconMapping(element, fieldConfig); as mapping) {\n <!-- Icon-only status: the mapping's tooltip is also its accessible name (AB#5621). -->\n <span\n class=\"status-icon\"\n role=\"img\"\n [title]=\"mapping.tooltip\"\n [attr.aria-label]=\"mapping.tooltip || null\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\"></kendo-svg-icon>\n </span>\n }\n }\n </span>\n }\n @case ('cronExpression') {\n <span class=\"cron-expression-cell\">\n <code class=\"cron-expression\">{{ getValue(element, column) }}</code>\n <span class=\"cron-description\">{{ getCronHumanReadable(getValue(element, column)) }}</span>\n </span>\n }\n @case ('numeric') {\n {{ $any(getValue(element, column)) | number:column.format }}\n }\n @case ('progressBar') {\n <span class=\"progress-bar-cell\">\n <span class=\"progress-bar-track\">\n <span class=\"progress-bar-fill\" [style.width.%]=\"getValue(element, column)\"></span>\n </span>\n <span class=\"progress-bar-label\">{{ getValue(element, column) }}%</span>\n </span>\n }\n @case ('badge') {\n @if (getBadgeMapping(element, column); as badge) {\n <span\n class=\"badge-cell\"\n [title]=\"badge.tooltip ?? ''\"\n [style.color]=\"badge.color\"\n [style.background]=\"badge.backgroundColor\"\n [style.borderColor]=\"badge.borderColor ?? badge.backgroundColor\">\n {{ badge.label ?? getValue(element, column) }}\n </span>\n } @else if (!column.badgeHideUnmapped) {\n <span class=\"badge-cell badge-cell-default\">{{ getValue(element, column) }}</span>\n }\n }\n @case ('component') {\n @if (column.cellComponent) {\n <ng-container *ngComponentOutlet=\"column.cellComponent; inputs: getCellInputs(element, column)\" />\n }\n }\n @default {\n {{ getValue(element, column) }}\n }\n }\n }\n</ng-template>\n\n<!-- Row actions (AB#4930, AB#5572): shared by the actions column and the card header. One MmAction\n per action (CommandItems via adapter): neutral icon buttons, danger colour only for destructive\n actions, max `maxInlineRowActions` slots, the rest (and the context menu) behind \"\u2026\". Disabled\n actions stay focusable and announce their reason (mm-action-button). -->\n<ng-template #rowActions let-dataItem=\"dataItem\">\n @let view = rowActionsView(dataItem);\n @if (view.inline.length > 0 || view.hasMenu) {\n <span class=\"mm-list-view-row-actions\" role=\"group\" [attr.aria-label]=\"rowActionsGroupLabel(dataItem)\">\n @for (entry of view.inline; track entry.action.id) {\n <!-- Clicks never reach the grid (no row selection / row navigation from an action). -->\n <mm-action-button [action]=\"entry.action\" [targetLabel]=\"rowLabel(dataItem)\" context=\"row\" display=\"icon\"\n (click)=\"$event.stopPropagation()\"\n (triggered)=\"onInlineRowAction(entry, dataItem)\" />\n }\n @if (view.hasMenu) {\n <button kendoButton themeColor=\"base\" fillMode=\"flat\" size=\"small\" class=\"mm-list-view-row-actions__more\"\n [svgIcon]=\"moreVerticalIcon\" data-action=\"more\"\n [title]=\"rowActionsLabel(dataItem)\" [attr.aria-label]=\"rowActionsLabel(dataItem)\" aria-haspopup=\"menu\"\n [disabled]=\"isLoading()\" (click)=\"$event.stopPropagation(); onContextMenu(dataItem, $event)\"></button>\n }\n </span>\n }\n</ng-template>\n\n<!-- One host toolbar action (left or right band). Flat + neutral unless `primary` (AB#6211). With\n `isDisabled` + `disabledReason` the control stays focusable (aria-disabled), announces the reason\n (aria-describedby) and shows it as a hint bubble on keyboard focus (guideline \u00A72.5); clicks and\n menu opening are swallowed. Applies to buttons, split and dropdown buttons alike. -->\n<ng-template #toolbarItem let-commandItem let-side=\"side\" let-index=\"index\">\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\n @let reason = toolbarItemDisabledReason(commandItem);\n @let reasonId = toolbarReasonId(side, index);\n <span class=\"mm-list-view-toolbar-action\" [class.mm-list-view-toolbar-action--disabled]=\"!!reason\"\n (pointerdown)=\"onToolbarPointerDown()\"\n (focusin)=\"onToolbarFocusIn($event, reason)\"\n (focusout)=\"closeToolbarHint()\"\n (keydown.escape)=\"closeToolbarHint()\">\n @if (commandItem.children && commandItem.children.length > 0 && commandItem.onClick) {\n <kendo-splitbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (buttonClick)=\"reason ? null : onToolbarCommand(commandItem)\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-splitbutton>\n } @else if (commandItem.children && commandItem.children.length > 0) {\n <kendo-dropdownbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else {\n <button kendoTooltip kendoButton [svgIcon]=\"$any(commandItem.svgIcon)\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [attr.aria-disabled]=\"reason ? 'true' : null\"\n [attr.aria-describedby]=\"reason ? reasonId : null\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n (click)=\"reason ? $event.preventDefault() : onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n @if (reason) {\n <span class=\"mm-list-view-toolbar-reason\" [id]=\"reasonId\">{{ reason }}</span>\n }\n </span>\n }\n @case ('separator') {\n <kendo-separator></kendo-separator>\n }\n }\n }\n</ng-template>\n\n<!-- Disabled reason shown on keyboard focus (AB#6211): opened with the Kendo PopupService under the\n application root, so the grid / toolbar overflow cannot clip it. -->\n<ng-template #toolbarHint>\n <div class=\"mm-list-view-toolbar-hint\" data-toolbar-hint>{{ toolbarHintText() }}</div>\n</ng-template>\n\n<kendo-grid\n mmListViewDataBinding\n [loading]=\"isLoading()\"\n [pageSize]=\"effectivePageSize()\" [selectable]=\"selectable\" (pageChange)=\"onPageChange($event)\"\n [skip]=\"skip\" (selectionChange)=\"onRowSelect($event)\" (cellClick)=\"onCellClick($event)\"\n [pageable]=\"effectivePageable\"\n [sortable]=\"sortable\"\n [filterable]=\"_showRowFilter && !isCardMode\"\n [resizable]=\"resizable\"\n [rowClass]=\"rowClass ?? defaultRowClass\"\n>\n <kendo-grid-messages\n [pagerItemsPerPage]=\"_messages.pagerItemsPerPage\"\n [pagerOf]=\"_messages.pagerOf\"\n [pagerItems]=\"_messages.pagerItems\"\n [pagerPage]=\"_messages.pagerPage\"\n [pagerFirstPage]=\"_messages.pagerFirstPage\"\n [pagerLastPage]=\"_messages.pagerLastPage\"\n [pagerPreviousPage]=\"_messages.pagerPreviousPage\"\n [pagerNextPage]=\"_messages.pagerNextPage\"\n [noRecords]=\"_messages.noRecords\"\n ></kendo-grid-messages>\n <!-- Empty state (AB#3444): one block per list, never per row. -->\n <ng-template kendoGridNoRecordsTemplate>\n @if (emptyTemplate) {\n <ng-container *ngTemplateOutlet=\"emptyTemplate; context: emptyContext\"></ng-container>\n } @else if (emptyState) {\n @if (loadSettled() && !isLoading()) {\n @if (isFiltered) {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"no-results\"\n [heading]=\"emptyState.filteredTitle || _messages.noResultsTitle\"\n [text]=\"emptyState.filteredText || _messages.noResultsText\"></mm-empty-state>\n } @else {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"empty\"\n [heading]=\"emptyState.title\" [text]=\"emptyState.text\"></mm-empty-state>\n }\n }\n } @else {\n {{ _messages.noRecords }}\n }\n </ng-template>\n <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'left', index: i}\" />\n }\n\n <!-- Host scope/filter controls (view switches and the like). They steer the\n table, so they sit in the table's own band instead of a second strip\n stacked above the grid. -->\n @if (filtersTemplate) {\n <!-- A rule between the host's actions and its filters: both sit on the\n left of the same band, but one acts on records and the other changes\n what the list shows. Only drawn when actions precede them. -->\n @if (leftToolbarActions.length > 0) {\n <kendo-separator class=\"mm-toolbar-filters-separator\"></kendo-separator>\n }\n <div class=\"mm-toolbar-filters\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate.templateRef\"></ng-container>\n </div>\n }\n\n <kendo-grid-spacer></kendo-grid-spacer>\n @if (searchTextBoxEnabled) {\n <input\n class=\"k-textbox k-input k-input-md k-rounded-md mm-search-input\"\n [placeholder]=\"_messages.searchPlaceholder\"\n [value]=\"searchValue\"\n (input)=\"onFilter($any($event.target).value || null)\"\n />\n }\n\n @for (commandItem of rightToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'right', index: i}\" />\n }\n\n <!-- Commands: laid out while there is room, collapsed into one menu once\n the list gets narrow. Same behaviour in every host app \u2014 a list this\n wide has space for five buttons, and a list this narrow does not. -->\n @if (commandsCollapsed) {\n <kendo-dropdownbutton class=\"mm-toolbar-commands\" [data]=\"toolbarCommands\" textField=\"text\" [svgIcon]=\"commandsIcon\"\n fillMode=\"flat\" themeColor=\"primary\" [disabled]=\"isLoading()\"\n [title]=\"_messages.commands\"\n [buttonAttributes]=\"commandsMenuButtonAttributes\"\n (itemClick)=\"onCommand($any($event).id)\"></kendo-dropdownbutton>\n } @else {\n @for (command of toolbarCommands; track command.id) {\n @switch (command.id) {\n @case ('excel') {\n <button kendoTooltip kendoGridExcelCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @case ('pdf') {\n <button kendoTooltip kendoGridPDFCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @default {\n <!-- The row filter is a toggle: its on state is shown (k-selected) and announced. -->\n <button kendoTooltip kendoButton themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" (click)=\"onCommand(command.id)\"\n [class.k-selected]=\"command.id === 'rowFilter' && _showRowFilter\"\n [attr.aria-pressed]=\"command.id === 'rowFilter' ? _showRowFilter : null\"\n [attr.data-command]=\"command.id\"\n [disabled]=\"isLoading()\" [title]=\"command.text\" [attr.aria-label]=\"command.text\"></button>\n }\n }\n }\n }\n </ng-template>\n\n @if (showCheckboxColumn()) {\n <kendo-grid-checkbox-column [showSelectAll]=\"showRowSelectAllCheckBox\"\n [width]=\"effectiveCheckboxColumnWidth\"></kendo-grid-checkbox-column>\n }\n\n @if (!isCardMode) {\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\" format=\"{{column.format}}\"\n [width]=\"$any(getEffectiveWidth(column))\"\n [minResizableWidth]=\"column.minWidth ?? 10\"\n [hidden]=\"isColumnHidden(column)\"\n [sortable]=\"column.sortable !== false\"\n [filterable]=\"column.filterable !== false\"\n [class]=\"alignClass(column)\"\n [headerClass]=\"alignClass(column)\"\n [title]=\"getDisplayName(column) | pascalCase\">\n <ng-template kendoGridFilterCellTemplate let-filter let-gridColumn=\"column\">\n @if (hasFilterOptions(column)) {\n <kendo-dropdownlist\n class=\"status-filter-dropdown\"\n [data]=\"column.filterOptions!\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [value]=\"getSelectedFilterValue(column)\"\n [defaultItem]=\"{ text: '', value: null }\"\n [popupSettings]=\"{ width: 'auto' }\"\n (valueChange)=\"onDropdownFilter($event, column)\"\n >\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span class=\"filter-status-item\">\n <span role=\"img\" [attr.aria-label]=\"dataItem.text || mapping.tooltip || null\" [title]=\"dataItem.text || mapping.tooltip\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n </span>\n } @else if (dataItem?.text) {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span style=\"display: inline-flex; align-items: center; gap: 8px;\">\n <span [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n <span>{{ dataItem.text }}</span>\n </span>\n } @else {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n </kendo-dropdownlist>\n } @else if (column.dataType === 'numericRange') {\n <span class=\"numeric-range-filter\">\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'gte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'gte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"From\"\n size=\"small\"\n ></kendo-numerictextbox>\n <span class=\"range-separator\">\u2013</span>\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'lte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'lte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"To\"\n size=\"small\"\n ></kendo-numerictextbox>\n </span>\n } @else {\n @switch (getFilterType(column)) {\n @case ('numeric') {\n <kendo-grid-numeric-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [spinners]=\"!isCompactFilter(column)\" [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-numeric-filter-cell>\n }\n @case ('boolean') {\n <kendo-grid-boolean-filter-cell [column]=\"gridColumn\" [filter]=\"filter\"></kendo-grid-boolean-filter-cell>\n }\n @case ('date') {\n <kendo-grid-date-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-date-filter-cell>\n }\n @default {\n <kendo-grid-string-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"false\"></kendo-grid-string-filter-cell>\n }\n }\n }\n </ng-template>\n <ng-template kendoGridCellTemplate let-dataItem>\n <span\n [class.mm-cell-truncate]=\"column.truncate\"\n [attr.title]=\"column.truncate ? getCellTitle(dataItem, column) : null\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </ng-template>\n </kendo-grid-column>\n }\n\n @if (hasRowActions) {\n <kendo-grid-command-column [title]=\"_messages.actionsColumnTitle\" [width]=\"effectiveActionsColumnWidth\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </ng-template>\n </kendo-grid-command-column>\n }\n } @else {\n <!-- Card mode (AB#4930): one full-width column renders the whole row as a\n stacked card \u2014 title from the first column, labeled lines for the\n rest (empty values skipped), row actions in the card header. -->\n <kendo-grid-column [sortable]=\"false\" [filterable]=\"false\" title=\"\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <div class=\"mm-card\">\n <div class=\"mm-card-header\">\n @if (cardTitleColumn; as titleColumn) {\n <span class=\"mm-card-title\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: titleColumn }\"\n ></ng-container>\n </span>\n }\n <span class=\"mm-card-actions\">\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"mm-card-fields\">\n @for (column of cardBodyColumns; track column.field) {\n @if (hasCardValue(dataItem, column)) {\n <div class=\"mm-card-field\">\n <span class=\"mm-card-label\">{{ getDisplayName(column) | pascalCase }}</span>\n <span class=\"mm-card-value\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n </kendo-grid-column>\n }\n\n <kendo-grid-excel fileName=\"{{excelExportFileName}}\">\n @for (column of columns; track column.field) {\n <kendo-excelexport-column [field]=\"column.field\"\n [title]=\"getDisplayName(column) | pascalCase\">\n </kendo-excelexport-column>\n }\n </kendo-grid-excel>\n\n <kendo-grid-pdf fileName=\"{{pdfExportFileName}}\" paperSize=\"A4\" [repeatHeaders]=\"true\"\n [landscape]=\"true\">\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\"\n [title]=\"getDisplayName(column) | pascalCase\"></kendo-grid-column>\n }\n <kendo-grid-pdf-margin top=\"1.5cm\" left=\"1cm\" right=\"1cm\" bottom=\"1.5cm\"></kendo-grid-pdf-margin>\n <ng-template kendoGridPDFTemplate let-pageNum=\"pageNum\" let-totalPages=\"totalPages\">\n <div class=\"page-template\">\n <div class=\"footer\" style=\"position: absolute; bottom: 0; width: 100%; text-align: center; font-size: 9px; color: #666;\">\n {{ getPdfPageText(pageNum, totalPages) }}\n </div>\n </div>\n </ng-template>\n </kendo-grid-pdf>\n</kendo-grid>\n\n<kendo-contextmenu\n #gridmenu\n [kendoMenuHierarchyBinding]=\"_contextMenuItems\"\n [textField]=\"['text']\"\n childrenField=\"items\"\n svgIconField=\"svgIcon\"\n separatorField=\"separator\"\n disabledField=\"disabled\"\n cssClassField=\"cssClass\"\n (popupClose)=\"onContextMenuClosed($event)\"\n (select)=\"onContextMenuSelect($event)\"\n></kendo-contextmenu>\n", styles: [":host{display:flex;flex-direction:column;min-height:0}:host>kendo-grid{flex:1;min-height:0}.mm-search-input{width:165px}.mm-list-view-toolbar-action{position:relative;display:inline-flex}:host ::ng-deep .mm-list-view-toolbar-action--disabled .k-button{opacity:.45;cursor:not-allowed}.mm-list-view-toolbar-reason{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.mm-list-view-toolbar-hint{max-width:280px;padding:var(--theme-space-1, 4px) var(--theme-space-2, 8px);font-size:.75rem;line-height:1.4;color:var(--theme-text-primary, #0f1c2e);background:var(--theme-bg-overlay, #ffffff);border:1px solid var(--theme-border-default, rgba(7, 23, 43, .12));border-radius:var(--theme-radius-sm, 4px);box-shadow:var(--theme-shadow-popup, 0 8px 24px rgba(7, 23, 43, .14));pointer-events:none}:host ::ng-deep .k-grid th:has(input[type=checkbox]),:host ::ng-deep .k-grid td:has(>kendo-checkbox){text-overflow:clip}:host ::ng-deep .k-command-cell{white-space:nowrap;overflow:hidden;vertical-align:middle}:host ::ng-deep .k-command-cell .k-button{display:inline-flex;vertical-align:middle;margin:0}:host ::ng-deep .k-command-cell .k-button+.k-button{margin-left:4px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar{flex-wrap:wrap;row-gap:6px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-search-input{width:100%;order:10}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar kendo-grid-spacer{display:none}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-toolbar-commands{margin-left:auto}:host ::ng-deep .k-grid td.mm-col-align-right{text-align:right;font-variant-numeric:tabular-nums}:host ::ng-deep .k-grid td.mm-col-align-center{text-align:center}:host ::ng-deep .k-grid th.mm-col-align-right .k-cell-inner>.k-link{justify-content:flex-end}:host ::ng-deep .k-grid th.mm-col-align-center .k-cell-inner>.k-link{justify-content:center}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-wrapper{gap:2px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-datepicker>.k-input-button{display:none}:host ::ng-deep .k-filter-row .mm-filter-compact .k-input-inner{padding-left:4px;padding-right:4px;font-size:12px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator{width:26px;min-width:0}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator .k-input-button{padding:2px}.mm-cell-truncate{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-icons-cell{display:inline-flex;align-items:center;gap:8px}.status-icons-cell .status-icon{display:inline-flex;align-items:center;justify-content:center;cursor:default}.status-icons-cell .status-icon kendo-svg-icon{width:18px;height:18px}:host ::ng-deep .filter-status-item{display:inline-flex;align-items:center;gap:10px}:host ::ng-deep .status-filter-dropdown .k-input-value-text{font-size:0}:host ::ng-deep .status-filter-dropdown .k-input-value-text .filter-status-item,:host ::ng-deep .status-filter-dropdown .k-input-value-text>span{font-size:14px}.numeric-range-filter{display:flex;align-items:center;gap:4px}.numeric-range-filter kendo-numerictextbox{flex:1;min-width:0}.numeric-range-filter .range-separator{flex-shrink:0;opacity:.6}.cron-expression-cell{display:flex;flex-direction:column;gap:2px}.cron-expression-cell .cron-expression{font-family:Roboto Mono,Consolas,monospace;font-size:.85em;background:var(--mm-cron-code-bg, #eeeeee);color:var(--mm-cron-code-text, #333333);padding:2px 6px;border-radius:3px}.cron-expression-cell .cron-description{font-size:.8em;color:var(--mm-cron-text-secondary, #666666)}.badge-cell{display:inline-block;padding:2px 10px;font-size:.75rem;font-weight:600;border-radius:12px;border:1px solid var(--mm-badge-default-border, transparent);background:var(--mm-badge-default-bg, rgba(127, 127, 127, .15));color:var(--mm-badge-default-color, inherit);white-space:nowrap;line-height:1.4}.badge-cell-default{opacity:.7;font-style:italic}.progress-bar-cell{display:inline-flex;align-items:center;gap:8px;width:100%}.progress-bar-cell .progress-bar-track{flex:1;height:8px;background:var(--mm-progress-track-bg, rgba(255, 255, 255, .1));border-radius:4px;overflow:hidden}.progress-bar-cell .progress-bar-fill{display:block;height:100%;background:var(--mm-progress-fill-color, #10b981);border-radius:4px;transition:width .3s ease}.progress-bar-cell .progress-bar-label{min-width:40px;text-align:right;font-size:.85em}:host-context(.k-pdf-export) .k-grid,:host-context(.k-pdf-export) .k-grid-header,:host-context(.k-pdf-export) .k-grid-content,:host-context(.k-pdf-export) .k-grid-header-wrap,:host-context(.k-pdf-export) .k-grid-content-locked,:host-context(.k-pdf-export) .k-grid-header-locked{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border-color:#000!important}:host-context(.k-pdf-export) .k-grid{border:1px solid #000!important;font-family:Arial,sans-serif!important;font-size:10px!important}:host-context(.k-pdf-export) .k-grid-header th,:host-context(.k-pdf-export) .k-header,:host-context(.k-pdf-export) .k-grid th{background:#f0f0f0!important;background-color:#f0f0f0!important;background-image:none!important;color:#000!important;border:1px solid #000!important;font-weight:700!important;padding:6px 8px!important;text-transform:none!important;letter-spacing:normal!important}:host-context(.k-pdf-export) .k-grid td,:host-context(.k-pdf-export) .k-grid-content td,:host-context(.k-pdf-export) .k-master-row td{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border:1px solid #000!important;padding:4px 8px!important}:host-context(.k-pdf-export) .k-grid tr,:host-context(.k-pdf-export) .k-master-row,:host-context(.k-pdf-export) .k-alt{background:#fff!important;background-color:#fff!important;background-image:none!important}:host-context(.k-pdf-export) .k-grid tr:hover,:host-context(.k-pdf-export) .k-grid tr.k-selected,:host-context(.k-pdf-export) .k-grid td:hover{background:#fff!important;background-color:#fff!important}:host-context(.k-pdf-export) .k-grid-toolbar,:host-context(.k-pdf-export) .k-pager,:host-context(.k-pdf-export) .k-grid-pager,:host-context(.k-pdf-export) .k-command-cell,:host-context(.k-pdf-export) .k-checkbox-column,:host-context(.k-pdf-export) kendo-grid-checkbox-column,:host-context(.k-pdf-export) .status-icons-cell,:host-context(.k-pdf-export) .status-icon,:host-context(.k-pdf-export) kendo-svg-icon{display:none!important}:host-context(.k-pdf-export) .badge-cell{background:transparent!important;border:none!important;color:inherit!important;padding:0!important;border-radius:0!important;text-transform:none!important;font-weight:inherit!important;font-size:inherit!important}:host(.mm-list-view-cards) ::ng-deep .k-grid-header{display:none}:host(.mm-list-view-cards) ::ng-deep .k-grid td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td{border:none;background:transparent;padding:4px 2px;white-space:normal}:host(.mm-list-view-cards) ::ng-deep .k-grid td:has(>kendo-checkbox),:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td:has(>kendo-checkbox){padding-left:2px;padding-right:0}:host(.mm-list-view-cards) ::ng-deep .k-grid colgroup>col:first-child:not(:only-child){width:32px!important}:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row:hover,:host(.mm-list-view-cards) ::ng-deep .k-grid tr:hover{background:transparent}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected .mm-card,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected .mm-card{border-color:var(--kendo-color-primary, #ff6358)}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected>td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected>.k-table-td{background:transparent}.mm-card{display:flex;flex-direction:column;gap:6px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:8px;padding:10px 12px}.mm-card-header{display:flex;align-items:center;gap:8px}.mm-card-title{flex:1;min-width:0;font-weight:600;overflow-wrap:anywhere}.mm-card-actions{display:flex;align-items:center;gap:2px;flex-shrink:0}.mm-card-fields{display:flex;flex-direction:column;gap:3px}.mm-card-field{display:flex;align-items:baseline;gap:8px;font-size:.9em}.mm-card-label{flex:0 0 38%;max-width:160px;color:var(--kendo-color-subtle, #666666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mm-card-value{flex:1;min-width:0;overflow-wrap:anywhere}::ng-deep .k-grid-toolbar .mm-toolbar-filters{display:flex;align-items:center;gap:12px;flex-wrap:wrap}::ng-deep .k-grid-toolbar .mm-toolbar-filters-separator{align-self:center;height:22px;margin:0 4px;border-left:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .16));border-top:none;width:0}::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-link,::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-menu-link{color:var(--theme-status-error, #c0385f)}.mm-list-view-row-actions{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;vertical-align:middle}.mm-list-view-row-actions .mm-list-view-row-actions__more:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}.boolean-icon{display:inline-flex;align-items:center}.boolean-icon.boolean-icon--true{color:var(--mm-list-boolean-true-color, var(--kendo-color-success, #2fb37a))}.boolean-icon.boolean-icon--false{color:var(--mm-list-boolean-false-color, var(--kendo-color-subtle, #8a94a0))}\n"] }]
|
|
4232
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Shared cell renderer (AB#4930): used by the regular grid columns AND the\n card-mode body lines, so both render every dataType identically. -->\n<ng-template #cellContent let-element=\"element\" let-column=\"column\">\n @if (column.formatter) {\n {{ getFormattedValue(element, column) }}\n } @else {\n @switch (column.dataType) {\n @case ('boolean') {\n <!-- Read-only marker: named after its column so a screen reader says what is checked (AB#5621). -->\n <kendo-checkbox type=\"checkbox\" [checkedState]=\"$any(getValue(element, column))\" [disabled]=\"true\"\n [inputAttributes]=\"booleanCellAttributes(column)\" />\n }\n @case ('booleanIcon') {\n <!-- Boolean as icon (AB#5623): named \"<column>: Yes|No\" like the status icons (G13). -->\n @if (booleanIconState(element, column); as state) {\n @if (booleanIcon(column, state); as icon) {\n <span\n class=\"boolean-icon\"\n [class.boolean-icon--true]=\"state === 'true'\"\n [class.boolean-icon--false]=\"state === 'false'\"\n role=\"img\"\n [title]=\"booleanIconLabel(column, state)\"\n [attr.aria-label]=\"booleanIconLabel(column, state)\"\n [style.color]=\"state === 'true' ? column.booleanIcons?.trueColor : column.booleanIcons?.falseColor\">\n <kendo-svg-icon [icon]=\"icon\"></kendo-svg-icon>\n </span>\n }\n }\n }\n @case ('iso8601') {\n {{ $any(getValue(element, column)) | date:column.format }}\n }\n @case ('bytes') {\n {{ $any(getValue(element, column)) | bytesToSize }}\n }\n @case ('statusIcons') {\n <span class=\"status-icons-cell\">\n @for (fieldConfig of getStatusFields(column); track fieldConfig.field) {\n @if (getStatusIconMapping(element, fieldConfig); as mapping) {\n <!-- Icon-only status: the mapping's tooltip is also its accessible name (AB#5621). -->\n <span\n class=\"status-icon\"\n role=\"img\"\n [title]=\"mapping.tooltip\"\n [attr.aria-label]=\"mapping.tooltip || null\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\"></kendo-svg-icon>\n </span>\n }\n }\n </span>\n }\n @case ('cronExpression') {\n <span class=\"cron-expression-cell\">\n <code class=\"cron-expression\">{{ getValue(element, column) }}</code>\n <span class=\"cron-description\">{{ getCronHumanReadable(getValue(element, column)) }}</span>\n </span>\n }\n @case ('numeric') {\n {{ $any(getValue(element, column)) | number:column.format }}\n }\n @case ('progressBar') {\n <span class=\"progress-bar-cell\">\n <span class=\"progress-bar-track\">\n <span class=\"progress-bar-fill\" [style.width.%]=\"getValue(element, column)\"></span>\n </span>\n <span class=\"progress-bar-label\">{{ getValue(element, column) }}%</span>\n </span>\n }\n @case ('badge') {\n @if (getBadgeMapping(element, column); as badge) {\n <span\n class=\"badge-cell\"\n [title]=\"badge.tooltip ?? ''\"\n [style.color]=\"badge.color\"\n [style.background]=\"badge.backgroundColor\"\n [style.borderColor]=\"badge.borderColor ?? badge.backgroundColor\">\n {{ badge.label ?? getValue(element, column) }}\n </span>\n } @else if (!column.badgeHideUnmapped) {\n <span class=\"badge-cell badge-cell-default\">{{ getValue(element, column) }}</span>\n }\n }\n @case ('component') {\n @if (column.cellComponent) {\n <ng-container *ngComponentOutlet=\"column.cellComponent; inputs: getCellInputs(element, column)\" />\n }\n }\n @default {\n {{ getValue(element, column) }}\n }\n }\n }\n</ng-template>\n\n<!-- Row actions (AB#4930, AB#5572): shared by the actions column and the card header. One MmAction\n per action (CommandItems via adapter): neutral icon buttons, danger colour only for destructive\n actions, max `maxInlineRowActions` slots, the rest (and the context menu) behind \"\u2026\". Disabled\n actions stay focusable and announce their reason (mm-action-button). -->\n<ng-template #rowActions let-dataItem=\"dataItem\">\n @let view = rowActionsView(dataItem);\n @if (view.inline.length > 0 || view.hasMenu) {\n <span class=\"mm-list-view-row-actions\" role=\"group\" [attr.aria-label]=\"rowActionsGroupLabel(dataItem)\">\n @for (entry of view.inline; track entry.action.id) {\n <!-- Clicks never reach the grid (no row selection / row navigation from an action). -->\n <mm-action-button [action]=\"entry.action\" [targetLabel]=\"rowLabel(dataItem)\" context=\"row\" display=\"icon\"\n (click)=\"$event.stopPropagation()\"\n (triggered)=\"onInlineRowAction(entry, dataItem)\" />\n }\n @if (view.hasMenu) {\n <button kendoButton themeColor=\"base\" fillMode=\"flat\" size=\"small\" class=\"mm-list-view-row-actions__more\"\n [svgIcon]=\"moreVerticalIcon\" data-action=\"more\"\n [title]=\"rowActionsLabel(dataItem)\" [attr.aria-label]=\"rowActionsLabel(dataItem)\" aria-haspopup=\"menu\"\n [disabled]=\"isLoading()\" (click)=\"$event.stopPropagation(); onContextMenu(dataItem, $event)\"></button>\n }\n </span>\n }\n</ng-template>\n\n<!-- One host toolbar action (left or right band). Flat + neutral unless `primary` (AB#6211). With\n `isDisabled` + `disabledReason` the control stays focusable (aria-disabled), announces the reason\n (aria-describedby) and shows it as a hint bubble on keyboard focus (guideline \u00A72.5); clicks and\n menu opening are swallowed. Applies to buttons, split and dropdown buttons alike. -->\n<ng-template #toolbarItem let-commandItem let-side=\"side\" let-index=\"index\">\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\n @let reason = toolbarItemDisabledReason(commandItem);\n @let reasonId = toolbarReasonId(side, index);\n <span class=\"mm-list-view-toolbar-action\" [class.mm-list-view-toolbar-action--disabled]=\"!!reason\"\n (pointerdown)=\"onToolbarPointerDown()\"\n (focusin)=\"onToolbarFocusIn($event, reason)\"\n (focusout)=\"closeToolbarHint()\"\n (keydown.escape)=\"closeToolbarHint()\">\n @if (commandItem.children && commandItem.children.length > 0 && commandItem.onClick) {\n <kendo-splitbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (buttonClick)=\"reason ? null : onToolbarCommand(commandItem)\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-splitbutton>\n } @else if (commandItem.children && commandItem.children.length > 0) {\n <kendo-dropdownbutton\n [data]=\"commandItem.children\"\n [svgIcon]=\"$any(commandItem.svgIcon)\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n [textField]=\"'text'\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem, reason ? reasonId : null)\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n (open)=\"reason ? $event.preventDefault() : null\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else {\n <button kendoTooltip kendoButton [svgIcon]=\"$any(commandItem.svgIcon)\"\n [themeColor]=\"toolbarItemThemeColor(commandItem)\"\n [fillMode]=\"$any(toolbarItemFillMode(commandItem))\"\n [attr.data-toolbar-action]=\"commandItem.id\"\n [title]=\"toolbarItemTitle(commandItem, reason)\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [attr.aria-disabled]=\"reason ? 'true' : null\"\n [attr.aria-describedby]=\"reason ? reasonId : null\"\n [disabled]=\"(getToolbarItemDisabled(commandItem) && !reason) || isLoading()\"\n (click)=\"reason ? $event.preventDefault() : onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n @if (reason) {\n <span class=\"mm-list-view-toolbar-reason\" [id]=\"reasonId\">{{ reason }}</span>\n }\n </span>\n }\n @case ('separator') {\n <kendo-separator></kendo-separator>\n }\n }\n }\n</ng-template>\n\n<!-- Disabled reason shown on keyboard focus (AB#6211): opened with the Kendo PopupService under the\n application root, so the grid / toolbar overflow cannot clip it. -->\n<ng-template #toolbarHint>\n <div class=\"mm-list-view-toolbar-hint\" data-toolbar-hint>{{ toolbarHintText() }}</div>\n</ng-template>\n\n<kendo-grid\n mmListViewDataBinding\n [loading]=\"isLoading()\"\n [pageSize]=\"effectivePageSize()\" [selectable]=\"selectable\" (pageChange)=\"onPageChange($event)\"\n [skip]=\"skip\" (selectionChange)=\"onRowSelect($event)\" (cellClick)=\"onCellClick($event)\"\n [pageable]=\"effectivePageable\"\n [sortable]=\"sortable\"\n [filterable]=\"_showRowFilter && !isCardMode\"\n [resizable]=\"resizable\"\n [rowClass]=\"rowClass ?? defaultRowClass\"\n>\n <kendo-grid-messages\n [pagerItemsPerPage]=\"_messages.pagerItemsPerPage\"\n [pagerOf]=\"_messages.pagerOf\"\n [pagerItems]=\"_messages.pagerItems\"\n [pagerPage]=\"_messages.pagerPage\"\n [pagerFirstPage]=\"_messages.pagerFirstPage\"\n [pagerLastPage]=\"_messages.pagerLastPage\"\n [pagerPreviousPage]=\"_messages.pagerPreviousPage\"\n [pagerNextPage]=\"_messages.pagerNextPage\"\n [noRecords]=\"_messages.noRecords\"\n ></kendo-grid-messages>\n <!-- Empty state (AB#3444): one block per list, never per row. -->\n <ng-template kendoGridNoRecordsTemplate>\n @if (emptyTemplate) {\n <ng-container *ngTemplateOutlet=\"emptyTemplate; context: emptyContext\"></ng-container>\n } @else if (emptyState) {\n @if (loadSettled() && !isLoading()) {\n @if (isFiltered) {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"no-results\"\n [heading]=\"emptyState.filteredTitle || _messages.noResultsTitle\"\n [text]=\"emptyState.filteredText || _messages.noResultsText\"></mm-empty-state>\n } @else {\n <mm-empty-state class=\"mm-list-view-empty\" variant=\"empty\"\n [heading]=\"emptyState.title\" [text]=\"emptyState.text\">\n @if (emptyActionsTemplate) {\n <div class=\"mm-list-view-empty-actions\" (keydown)=\"keepEmptyActionKeysFromGrid($event)\">\n <ng-container [ngTemplateOutlet]=\"emptyActionsTemplate.templateRef\"></ng-container>\n </div>\n }\n </mm-empty-state>\n }\n }\n } @else {\n {{ _messages.noRecords }}\n }\n </ng-template>\n <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'left', index: i}\" />\n }\n\n <!-- Host scope/filter controls (view switches and the like). They steer the\n table, so they sit in the table's own band instead of a second strip\n stacked above the grid. -->\n @if (filtersTemplate) {\n <!-- A rule between the host's actions and its filters: both sit on the\n left of the same band, but one acts on records and the other changes\n what the list shows. Only drawn when actions precede them. -->\n @if (leftToolbarActions.length > 0) {\n <kendo-separator class=\"mm-toolbar-filters-separator\"></kendo-separator>\n }\n <div class=\"mm-toolbar-filters\">\n <ng-container [ngTemplateOutlet]=\"filtersTemplate.templateRef\"></ng-container>\n </div>\n }\n\n <kendo-grid-spacer></kendo-grid-spacer>\n @if (searchTextBoxEnabled) {\n <input\n class=\"k-textbox k-input k-input-md k-rounded-md mm-search-input\"\n [placeholder]=\"_messages.searchPlaceholder\"\n [value]=\"searchValue\"\n (input)=\"onFilter($any($event.target).value || null)\"\n />\n }\n\n @for (commandItem of rightToolbarActions; track commandItem.id; let i = $index) {\n <ng-container [ngTemplateOutlet]=\"toolbarItem\" [ngTemplateOutletContext]=\"{$implicit: commandItem, side: 'right', index: i}\" />\n }\n\n <!-- Commands: laid out while there is room, collapsed into one menu once\n the list gets narrow. Same behaviour in every host app \u2014 a list this\n wide has space for five buttons, and a list this narrow does not. -->\n @if (commandsCollapsed) {\n <kendo-dropdownbutton class=\"mm-toolbar-commands\" [data]=\"toolbarCommands\" textField=\"text\" [svgIcon]=\"commandsIcon\"\n fillMode=\"flat\" themeColor=\"primary\" [disabled]=\"isLoading()\"\n [title]=\"_messages.commands\"\n [buttonAttributes]=\"commandsMenuButtonAttributes\"\n (itemClick)=\"onCommand($any($event).id)\"></kendo-dropdownbutton>\n } @else {\n @for (command of toolbarCommands; track command.id) {\n @switch (command.id) {\n @case ('excel') {\n <button kendoTooltip kendoGridExcelCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @case ('pdf') {\n <button kendoTooltip kendoGridPDFCommand themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" [disabled]=\"isLoading()\" [title]=\"command.text\"\n [attr.aria-label]=\"command.text\" [attr.data-command]=\"command.id\"></button>\n }\n @default {\n <!-- The row filter is a toggle: its on state is shown (k-selected) and announced. -->\n <button kendoTooltip kendoButton themeColor=\"primary\" fillMode=\"flat\"\n [svgIcon]=\"command.svgIcon\" (click)=\"onCommand(command.id)\"\n [class.k-selected]=\"command.id === 'rowFilter' && _showRowFilter\"\n [attr.aria-pressed]=\"command.id === 'rowFilter' ? _showRowFilter : null\"\n [attr.data-command]=\"command.id\"\n [disabled]=\"isLoading()\" [title]=\"command.text\" [attr.aria-label]=\"command.text\"></button>\n }\n }\n }\n }\n </ng-template>\n\n @if (showCheckboxColumn()) {\n <kendo-grid-checkbox-column [showSelectAll]=\"showRowSelectAllCheckBox\"\n [width]=\"effectiveCheckboxColumnWidth\"></kendo-grid-checkbox-column>\n }\n\n @if (!isCardMode) {\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\" format=\"{{column.format}}\"\n [width]=\"$any(getEffectiveWidth(column))\"\n [minResizableWidth]=\"column.minWidth ?? 10\"\n [hidden]=\"isColumnHidden(column)\"\n [sortable]=\"column.sortable !== false\"\n [filterable]=\"column.filterable !== false\"\n [class]=\"alignClass(column)\"\n [headerClass]=\"alignClass(column)\"\n [title]=\"getDisplayName(column) | pascalCase\">\n <ng-template kendoGridFilterCellTemplate let-filter let-gridColumn=\"column\">\n @if (hasFilterOptions(column)) {\n <kendo-dropdownlist\n class=\"status-filter-dropdown\"\n [data]=\"column.filterOptions!\"\n textField=\"text\"\n valueField=\"value\"\n [valuePrimitive]=\"true\"\n [value]=\"getSelectedFilterValue(column)\"\n [defaultItem]=\"{ text: '', value: null }\"\n [popupSettings]=\"{ width: 'auto' }\"\n (valueChange)=\"onDropdownFilter($event, column)\"\n >\n <ng-template kendoDropDownListValueTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span class=\"filter-status-item\">\n <span role=\"img\" [attr.aria-label]=\"dataItem.text || mapping.tooltip || null\" [title]=\"dataItem.text || mapping.tooltip\"\n [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n </span>\n } @else if (dataItem?.text) {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n <ng-template kendoDropDownListItemTemplate let-dataItem>\n @if (dataItem?.value && column.statusMapping?.[dataItem.value]; as mapping) {\n <span style=\"display: inline-flex; align-items: center; gap: 8px;\">\n <span [style.color]=\"mapping.color\">\n <kendo-svg-icon [icon]=\"mapping.icon\" [size]=\"'small'\"></kendo-svg-icon>\n </span>\n <span>{{ dataItem.text }}</span>\n </span>\n } @else {\n <span>{{ dataItem.text }}</span>\n }\n </ng-template>\n </kendo-dropdownlist>\n } @else if (column.dataType === 'numericRange') {\n <span class=\"numeric-range-filter\">\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'gte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'gte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"From\"\n size=\"small\"\n ></kendo-numerictextbox>\n <span class=\"range-separator\">\u2013</span>\n <kendo-numerictextbox\n [value]=\"$any(getRangeFilterValue(column, 'lte'))\"\n (valueChange)=\"onRangeFilterChange($event, column, 'lte')\"\n [spinners]=\"false\"\n [decimals]=\"2\"\n placeholder=\"To\"\n size=\"small\"\n ></kendo-numerictextbox>\n </span>\n } @else {\n @switch (getFilterType(column)) {\n @case ('numeric') {\n <kendo-grid-numeric-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [spinners]=\"!isCompactFilter(column)\" [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-numeric-filter-cell>\n }\n @case ('boolean') {\n <kendo-grid-boolean-filter-cell [column]=\"gridColumn\" [filter]=\"filter\"></kendo-grid-boolean-filter-cell>\n }\n @case ('date') {\n <kendo-grid-date-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"true\" [operator]=\"column.filterOperator || 'eq'\"\n [class.mm-filter-compact]=\"isCompactFilter(column)\"></kendo-grid-date-filter-cell>\n }\n @default {\n <kendo-grid-string-filter-cell [column]=\"gridColumn\" [filter]=\"filter\" [showOperators]=\"false\"></kendo-grid-string-filter-cell>\n }\n }\n }\n </ng-template>\n <ng-template kendoGridCellTemplate let-dataItem>\n <span\n [class.mm-cell-truncate]=\"column.truncate\"\n [attr.title]=\"column.truncate ? getCellTitle(dataItem, column) : null\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </ng-template>\n </kendo-grid-column>\n }\n\n @if (hasRowActions) {\n <kendo-grid-command-column [title]=\"_messages.actionsColumnTitle\" [width]=\"effectiveActionsColumnWidth\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </ng-template>\n </kendo-grid-command-column>\n }\n } @else {\n <!-- Card mode (AB#4930): one full-width column renders the whole row as a\n stacked card \u2014 title from the first column, labeled lines for the\n rest (empty values skipped), row actions in the card header. -->\n <kendo-grid-column [sortable]=\"false\" [filterable]=\"false\" title=\"\">\n <ng-template kendoGridCellTemplate let-dataItem>\n <div class=\"mm-card\">\n <div class=\"mm-card-header\">\n @if (cardTitleColumn; as titleColumn) {\n <span class=\"mm-card-title\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: titleColumn }\"\n ></ng-container>\n </span>\n }\n <span class=\"mm-card-actions\">\n <ng-container\n [ngTemplateOutlet]=\"rowActions\"\n [ngTemplateOutletContext]=\"{ dataItem: dataItem }\"\n ></ng-container>\n </span>\n </div>\n <div class=\"mm-card-fields\">\n @for (column of cardBodyColumns; track column.field) {\n @if (hasCardValue(dataItem, column)) {\n <div class=\"mm-card-field\">\n <span class=\"mm-card-label\">{{ getDisplayName(column) | pascalCase }}</span>\n <span class=\"mm-card-value\">\n <ng-container\n [ngTemplateOutlet]=\"cellContent\"\n [ngTemplateOutletContext]=\"{ element: dataItem, column: column }\"\n ></ng-container>\n </span>\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n </kendo-grid-column>\n }\n\n <kendo-grid-excel fileName=\"{{excelExportFileName}}\">\n @for (column of columns; track column.field) {\n <kendo-excelexport-column [field]=\"column.field\"\n [title]=\"getDisplayName(column) | pascalCase\">\n </kendo-excelexport-column>\n }\n </kendo-grid-excel>\n\n <kendo-grid-pdf fileName=\"{{pdfExportFileName}}\" paperSize=\"A4\" [repeatHeaders]=\"true\"\n [landscape]=\"true\">\n @for (column of columns; track column.field) {\n <kendo-grid-column [field]=\"column.field\"\n [filter]=\"getFilterType(column)\"\n [title]=\"getDisplayName(column) | pascalCase\"></kendo-grid-column>\n }\n <kendo-grid-pdf-margin top=\"1.5cm\" left=\"1cm\" right=\"1cm\" bottom=\"1.5cm\"></kendo-grid-pdf-margin>\n <ng-template kendoGridPDFTemplate let-pageNum=\"pageNum\" let-totalPages=\"totalPages\">\n <div class=\"page-template\">\n <div class=\"footer\" style=\"position: absolute; bottom: 0; width: 100%; text-align: center; font-size: 9px; color: #666;\">\n {{ getPdfPageText(pageNum, totalPages) }}\n </div>\n </div>\n </ng-template>\n </kendo-grid-pdf>\n</kendo-grid>\n\n<kendo-contextmenu\n #gridmenu\n [kendoMenuHierarchyBinding]=\"_contextMenuItems\"\n [textField]=\"['text']\"\n childrenField=\"items\"\n svgIconField=\"svgIcon\"\n separatorField=\"separator\"\n disabledField=\"disabled\"\n cssClassField=\"cssClass\"\n (popupClose)=\"onContextMenuClosed($event)\"\n (select)=\"onContextMenuSelect($event)\"\n></kendo-contextmenu>\n", styles: [":host{display:flex;flex-direction:column;min-height:0}:host>kendo-grid{flex:1;min-height:0}.mm-search-input{width:165px}.mm-list-view-toolbar-action{position:relative;display:inline-flex}:host ::ng-deep .mm-list-view-toolbar-action--disabled .k-button{opacity:.45;cursor:not-allowed}.mm-list-view-toolbar-reason{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.mm-list-view-toolbar-hint{max-width:280px;padding:var(--theme-space-1, 4px) var(--theme-space-2, 8px);font-size:.75rem;line-height:1.4;color:var(--theme-text-primary, #0f1c2e);background:var(--theme-bg-overlay, #ffffff);border:1px solid var(--theme-border-default, rgba(7, 23, 43, .12));border-radius:var(--theme-radius-sm, 4px);box-shadow:var(--theme-shadow-popup, 0 8px 24px rgba(7, 23, 43, .14));pointer-events:none}:host ::ng-deep .k-grid th:has(input[type=checkbox]),:host ::ng-deep .k-grid td:has(>kendo-checkbox){text-overflow:clip}:host ::ng-deep .k-command-cell{white-space:nowrap;overflow:hidden;vertical-align:middle}:host ::ng-deep .k-command-cell .k-button{display:inline-flex;vertical-align:middle;margin:0}:host ::ng-deep .k-command-cell .k-button+.k-button{margin-left:4px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar{flex-wrap:wrap;row-gap:6px}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-search-input{width:100%;order:10}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar kendo-grid-spacer{display:none}:host(.mm-list-view-narrow) ::ng-deep .k-grid-toolbar .mm-toolbar-commands{margin-left:auto}:host ::ng-deep .k-grid td.mm-col-align-right{text-align:right;font-variant-numeric:tabular-nums}:host ::ng-deep .k-grid td.mm-col-align-center{text-align:center}:host ::ng-deep .k-grid th.mm-col-align-right .k-cell-inner>.k-link{justify-content:flex-end}:host ::ng-deep .k-grid th.mm-col-align-center .k-cell-inner>.k-link{justify-content:center}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-wrapper{gap:2px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-datepicker>.k-input-button{display:none}:host ::ng-deep .k-filter-row .mm-filter-compact .k-input-inner{padding-left:4px;padding-right:4px;font-size:12px}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator{width:26px;min-width:0}:host ::ng-deep .k-filter-row .mm-filter-compact .k-filtercell-operator .k-dropdown-operator .k-input-button{padding:2px}.mm-cell-truncate{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-icons-cell{display:inline-flex;align-items:center;gap:8px}.status-icons-cell .status-icon{display:inline-flex;align-items:center;justify-content:center;cursor:default}.status-icons-cell .status-icon kendo-svg-icon{width:18px;height:18px}:host ::ng-deep .filter-status-item{display:inline-flex;align-items:center;gap:10px}:host ::ng-deep .status-filter-dropdown .k-input-value-text{font-size:0}:host ::ng-deep .status-filter-dropdown .k-input-value-text .filter-status-item,:host ::ng-deep .status-filter-dropdown .k-input-value-text>span{font-size:14px}.numeric-range-filter{display:flex;align-items:center;gap:4px}.numeric-range-filter kendo-numerictextbox{flex:1;min-width:0}.numeric-range-filter .range-separator{flex-shrink:0;opacity:.6}.cron-expression-cell{display:flex;flex-direction:column;gap:2px}.cron-expression-cell .cron-expression{font-family:Roboto Mono,Consolas,monospace;font-size:.85em;background:var(--mm-cron-code-bg, #eeeeee);color:var(--mm-cron-code-text, #333333);padding:2px 6px;border-radius:3px}.cron-expression-cell .cron-description{font-size:.8em;color:var(--mm-cron-text-secondary, #666666)}.badge-cell{display:inline-block;padding:2px 10px;font-size:.75rem;font-weight:600;border-radius:12px;border:1px solid var(--mm-badge-default-border, transparent);background:var(--mm-badge-default-bg, rgba(127, 127, 127, .15));color:var(--mm-badge-default-color, inherit);white-space:nowrap;line-height:1.4}.badge-cell-default{opacity:.7;font-style:italic}.progress-bar-cell{display:inline-flex;align-items:center;gap:8px;width:100%}.progress-bar-cell .progress-bar-track{flex:1;height:8px;background:var(--mm-progress-track-bg, rgba(255, 255, 255, .1));border-radius:4px;overflow:hidden}.progress-bar-cell .progress-bar-fill{display:block;height:100%;background:var(--mm-progress-fill-color, #10b981);border-radius:4px;transition:width .3s ease}.progress-bar-cell .progress-bar-label{min-width:40px;text-align:right;font-size:.85em}:host-context(.k-pdf-export) .k-grid,:host-context(.k-pdf-export) .k-grid-header,:host-context(.k-pdf-export) .k-grid-content,:host-context(.k-pdf-export) .k-grid-header-wrap,:host-context(.k-pdf-export) .k-grid-content-locked,:host-context(.k-pdf-export) .k-grid-header-locked{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border-color:#000!important}:host-context(.k-pdf-export) .k-grid{border:1px solid #000!important;font-family:Arial,sans-serif!important;font-size:10px!important}:host-context(.k-pdf-export) .k-grid-header th,:host-context(.k-pdf-export) .k-header,:host-context(.k-pdf-export) .k-grid th{background:#f0f0f0!important;background-color:#f0f0f0!important;background-image:none!important;color:#000!important;border:1px solid #000!important;font-weight:700!important;padding:6px 8px!important;text-transform:none!important;letter-spacing:normal!important}:host-context(.k-pdf-export) .k-grid td,:host-context(.k-pdf-export) .k-grid-content td,:host-context(.k-pdf-export) .k-master-row td{background:#fff!important;background-color:#fff!important;background-image:none!important;color:#000!important;border:1px solid #000!important;padding:4px 8px!important}:host-context(.k-pdf-export) .k-grid tr,:host-context(.k-pdf-export) .k-master-row,:host-context(.k-pdf-export) .k-alt{background:#fff!important;background-color:#fff!important;background-image:none!important}:host-context(.k-pdf-export) .k-grid tr:hover,:host-context(.k-pdf-export) .k-grid tr.k-selected,:host-context(.k-pdf-export) .k-grid td:hover{background:#fff!important;background-color:#fff!important}:host-context(.k-pdf-export) .k-grid-toolbar,:host-context(.k-pdf-export) .k-pager,:host-context(.k-pdf-export) .k-grid-pager,:host-context(.k-pdf-export) .k-command-cell,:host-context(.k-pdf-export) .k-checkbox-column,:host-context(.k-pdf-export) kendo-grid-checkbox-column,:host-context(.k-pdf-export) .status-icons-cell,:host-context(.k-pdf-export) .status-icon,:host-context(.k-pdf-export) kendo-svg-icon{display:none!important}:host-context(.k-pdf-export) .badge-cell{background:transparent!important;border:none!important;color:inherit!important;padding:0!important;border-radius:0!important;text-transform:none!important;font-weight:inherit!important;font-size:inherit!important}:host(.mm-list-view-cards) ::ng-deep .k-grid-header{display:none}:host(.mm-list-view-cards) ::ng-deep .k-grid td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td{border:none;background:transparent;padding:4px 2px;white-space:normal}:host(.mm-list-view-cards) ::ng-deep .k-grid td:has(>kendo-checkbox),:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-td:has(>kendo-checkbox){padding-left:2px;padding-right:0}:host(.mm-list-view-cards) ::ng-deep .k-grid colgroup>col:first-child:not(:only-child){width:32px!important}:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row:hover,:host(.mm-list-view-cards) ::ng-deep .k-grid tr:hover{background:transparent}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected .mm-card,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected .mm-card{border-color:var(--kendo-color-primary, #ff6358)}:host(.mm-list-view-cards) ::ng-deep .k-grid tr.k-selected>td,:host(.mm-list-view-cards) ::ng-deep .k-grid .k-table-row.k-selected>.k-table-td{background:transparent}.mm-card{display:flex;flex-direction:column;gap:6px;border:1px solid var(--kendo-color-border, #dee2e6);border-radius:8px;padding:10px 12px}.mm-card-header{display:flex;align-items:center;gap:8px}.mm-card-title{flex:1;min-width:0;font-weight:600;overflow-wrap:anywhere}.mm-card-actions{display:flex;align-items:center;gap:2px;flex-shrink:0}.mm-card-fields{display:flex;flex-direction:column;gap:3px}.mm-card-field{display:flex;align-items:baseline;gap:8px;font-size:.9em}.mm-card-label{flex:0 0 38%;max-width:160px;color:var(--kendo-color-subtle, #666666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.mm-card-value{flex:1;min-width:0;overflow-wrap:anywhere}::ng-deep .k-grid-toolbar .mm-toolbar-filters{display:flex;align-items:center;gap:12px;flex-wrap:wrap}::ng-deep .k-grid-toolbar .mm-toolbar-filters-separator{align-self:center;height:22px;margin:0 4px;border-left:1px solid var(--theme-border-subtle, rgba(0, 0, 0, .16));border-top:none;width:0}::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-link,::ng-deep .k-menu-group .mm-list-view-menu-item--danger>.k-menu-link{color:var(--theme-status-error, #c0385f)}.mm-list-view-row-actions{display:inline-flex;align-items:center;gap:4px;white-space:nowrap;vertical-align:middle}.mm-list-view-row-actions .mm-list-view-row-actions__more:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}.boolean-icon{display:inline-flex;align-items:center}.boolean-icon.boolean-icon--true{color:var(--mm-list-boolean-true-color, var(--kendo-color-success, #2fb37a))}.boolean-icon.boolean-icon--false{color:var(--mm-list-boolean-false-color, var(--kendo-color-subtle, #8a94a0))}.mm-list-view-empty-actions{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--theme-space-2, 8px);margin-top:var(--theme-space-1, 4px)}\n"] }]
|
|
4213
4233
|
}], ctorParameters: () => [], propDecorators: { filtersTemplate: [{
|
|
4214
4234
|
type: ContentChild,
|
|
4215
4235
|
args: [ListViewFiltersDirective]
|
|
4236
|
+
}], emptyActionsTemplate: [{
|
|
4237
|
+
type: ContentChild,
|
|
4238
|
+
args: [ListViewEmptyActionsDirective]
|
|
4216
4239
|
}], gridComponent: [{
|
|
4217
4240
|
type: ViewChild,
|
|
4218
4241
|
args: [GridComponent]
|
|
@@ -8333,5 +8356,5 @@ function provideMmSharedUi() {
|
|
|
8333
8356
|
* Generated bundle index. Do not edit.
|
|
8334
8357
|
*/
|
|
8335
8358
|
|
|
8336
|
-
export { ActionButtonComponent, BaseFormComponent, BaseTreeDetailComponent, ButtonTypes, BytesToSizePipe, CRON_PRESETS, ConfirmationService, ConfirmationWindowComponent, ConfirmationWindowResult, CopyableTextComponent, CronBuilderComponent, CronHumanizerService, CronParserService, DANGER_CONFIRM_ENVIRONMENT, DANGER_CONFIRM_FALLBACK_WORD, DANGER_CONFIRM_SAFE_FOCUS, DEFAULT_CONFIRMATION_WINDOW_MESSAGES, DEFAULT_CRON_BUILDER_CONFIG, DEFAULT_DANGER_CONFIRMATION_MESSAGES, DEFAULT_EMPTY_STATE_RETRY_LABEL, DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES, DEFAULT_ENTITY_SELECT_INPUT_MESSAGES, DEFAULT_INPUT_DIALOG_MESSAGES, DEFAULT_LIST_VIEW_MESSAGES, DEFAULT_MESSAGE_DETAILS_DIALOG_MESSAGES, DEFAULT_NOTIFICATION_DISPLAY_MESSAGES, DEFAULT_PROGRESS_WINDOW_MESSAGES, DEFAULT_RESPONSIVE_COLSPAN, DEFAULT_ROW_ACTIONS_MESSAGES, DEFAULT_SAVE_AS_DIALOG_MESSAGES, DEFAULT_TIME_RANGE_LABELS, DangerConfirmationResult, DangerConfirmationWindowComponent, DataSourceBase, DataSourceTyped, DialogType, EmptyStateComponent, EntitySelectDialogComponent, EntitySelectDialogService, EntitySelectInputComponent, FetchResultBase, FetchResultTyped, FileUploadResult, FileUploadService, FormTitleExtraDirective, HAS_UNSAVED_CHANGES, HOUR_INTERVALS, HierarchyDataSource, HierarchyDataSourceBase, ImportStrategyDialogComponent, ImportStrategyDialogResult, ImportStrategyDialogService, ImportStrategyDto, InputDialogComponent, InputService, ListStateService, ListViewComponent, ListViewFiltersDirective, MINUTE_INTERVALS, MM_ACTION_ICONS, MM_DIALOG_ACTIONS_CLASS, MM_LANGUAGE, MM_ROW_ACTIONS_MAX_INLINE, MM_ROW_ACTIONS_MESSAGES, MM_TRANSLATE, MM_TRANSLATE_DEFAULTS, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmDialogActionsDirective, MmListViewDataBindingDirective, MmTranslatePipe, NOTIFICATION_DISPLAY_OPTIONS, NotificationDisplayService, OCTOBOT_ASSET_BASE_URL, OCTOBOT_FORCE_STILL, OCTOBOT_LOOP_MS, OCTOBOT_SIZE_PX, OctoBotComponent, PascalCasePipe, ProgressValue, ProgressWindowComponent, ProgressWindowService, RELATIVE_WEEKS, RowActionsComponent, SECOND_INTERVALS, SaveAsDialogComponent, SaveAsDialogService, TimeRangePickerComponent, TimeRangeUtils, TreeComponent, UnsavedChangesDirective, UnsavedChangesGuard, UploadFileDialogComponent, WEEKDAYS, WEEKDAY_ABBREVIATIONS, WindowStateService, actionAccessibleName, actionTooltip, applyDangerConfirmEnvironment, dangerConfirmNameMatches, dangerConfirmTypingToken, generateDayOfMonthOptions, generateHourOptions, generateMinuteOptions, injectMmLanguage, injectMmT, interpolateMm, isActionDisabled, isActionVisible, liveMessages, lookupMmTable, messagesFromTranslate, provideMmSharedUi, provideMmTranslateDefaults, resolveListRowAction, resolveListRowLabel, resolveListViewMessages, resolveMmTranslation, resolveRowActionsMessages, sameAction, splitRowActions };
|
|
8359
|
+
export { ActionButtonComponent, BaseFormComponent, BaseTreeDetailComponent, ButtonTypes, BytesToSizePipe, CRON_PRESETS, ConfirmationService, ConfirmationWindowComponent, ConfirmationWindowResult, CopyableTextComponent, CronBuilderComponent, CronHumanizerService, CronParserService, DANGER_CONFIRM_ENVIRONMENT, DANGER_CONFIRM_FALLBACK_WORD, DANGER_CONFIRM_SAFE_FOCUS, DEFAULT_CONFIRMATION_WINDOW_MESSAGES, DEFAULT_CRON_BUILDER_CONFIG, DEFAULT_DANGER_CONFIRMATION_MESSAGES, DEFAULT_EMPTY_STATE_RETRY_LABEL, DEFAULT_ENTITY_SELECT_DIALOG_MESSAGES, DEFAULT_ENTITY_SELECT_INPUT_MESSAGES, DEFAULT_INPUT_DIALOG_MESSAGES, DEFAULT_LIST_VIEW_MESSAGES, DEFAULT_MESSAGE_DETAILS_DIALOG_MESSAGES, DEFAULT_NOTIFICATION_DISPLAY_MESSAGES, DEFAULT_PROGRESS_WINDOW_MESSAGES, DEFAULT_RESPONSIVE_COLSPAN, DEFAULT_ROW_ACTIONS_MESSAGES, DEFAULT_SAVE_AS_DIALOG_MESSAGES, DEFAULT_TIME_RANGE_LABELS, DangerConfirmationResult, DangerConfirmationWindowComponent, DataSourceBase, DataSourceTyped, DialogType, EmptyStateComponent, EntitySelectDialogComponent, EntitySelectDialogService, EntitySelectInputComponent, FetchResultBase, FetchResultTyped, FileUploadResult, FileUploadService, FormTitleExtraDirective, HAS_UNSAVED_CHANGES, HOUR_INTERVALS, HierarchyDataSource, HierarchyDataSourceBase, ImportStrategyDialogComponent, ImportStrategyDialogResult, ImportStrategyDialogService, ImportStrategyDto, InputDialogComponent, InputService, ListStateService, ListViewComponent, ListViewEmptyActionsDirective, ListViewFiltersDirective, MINUTE_INTERVALS, MM_ACTION_ICONS, MM_DIALOG_ACTIONS_CLASS, MM_LANGUAGE, MM_ROW_ACTIONS_MAX_INLINE, MM_ROW_ACTIONS_MESSAGES, MM_TRANSLATE, MM_TRANSLATE_DEFAULTS, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmDialogActionsDirective, MmListViewDataBindingDirective, MmTranslatePipe, NOTIFICATION_DISPLAY_OPTIONS, NotificationDisplayService, OCTOBOT_ASSET_BASE_URL, OCTOBOT_FORCE_STILL, OCTOBOT_LOOP_MS, OCTOBOT_SIZE_PX, OctoBotComponent, PascalCasePipe, ProgressValue, ProgressWindowComponent, ProgressWindowService, RELATIVE_WEEKS, RowActionsComponent, SECOND_INTERVALS, SaveAsDialogComponent, SaveAsDialogService, TimeRangePickerComponent, TimeRangeUtils, TreeComponent, UnsavedChangesDirective, UnsavedChangesGuard, UploadFileDialogComponent, WEEKDAYS, WEEKDAY_ABBREVIATIONS, WindowStateService, actionAccessibleName, actionTooltip, applyDangerConfirmEnvironment, dangerConfirmNameMatches, dangerConfirmTypingToken, generateDayOfMonthOptions, generateHourOptions, generateMinuteOptions, injectMmLanguage, injectMmT, interpolateMm, isActionDisabled, isActionVisible, liveMessages, lookupMmTable, messagesFromTranslate, provideMmSharedUi, provideMmTranslateDefaults, resolveListRowAction, resolveListRowLabel, resolveListViewMessages, resolveMmTranslation, resolveRowActionsMessages, sameAction, splitRowActions };
|
|
8337
8360
|
//# sourceMappingURL=meshmakers-shared-ui.mjs.map
|