@meshmakers/shared-ui 3.4.1490 → 3.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/assets/octobot/lg/octo_blink.webp +0 -0
- package/assets/octobot/lg/octo_blink_still.png +0 -0
- package/assets/octobot/lg/octo_idle.webp +0 -0
- package/assets/octobot/lg/octo_idle_still.png +0 -0
- package/assets/octobot/lg/octo_look.webp +0 -0
- package/assets/octobot/lg/octo_look_still.png +0 -0
- package/assets/octobot/lg/octo_swim.webp +0 -0
- package/assets/octobot/lg/octo_swim_still.png +0 -0
- package/assets/octobot/lg/octo_thinking.webp +0 -0
- package/assets/octobot/lg/octo_thinking_still.png +0 -0
- package/assets/octobot/lg/octo_wave.webp +0 -0
- package/assets/octobot/lg/octo_wave_still.png +0 -0
- package/assets/octobot/md/octo_blink.webp +0 -0
- package/assets/octobot/md/octo_blink_still.png +0 -0
- package/assets/octobot/md/octo_idle.webp +0 -0
- package/assets/octobot/md/octo_idle_still.png +0 -0
- package/assets/octobot/md/octo_look.webp +0 -0
- package/assets/octobot/md/octo_look_still.png +0 -0
- package/assets/octobot/md/octo_swim.webp +0 -0
- package/assets/octobot/md/octo_swim_still.png +0 -0
- package/assets/octobot/md/octo_thinking.webp +0 -0
- package/assets/octobot/md/octo_thinking_still.png +0 -0
- package/assets/octobot/md/octo_wave.webp +0 -0
- package/assets/octobot/md/octo_wave_still.png +0 -0
- package/assets/octobot/sm/octo_blink.webp +0 -0
- package/assets/octobot/sm/octo_blink_still.png +0 -0
- package/assets/octobot/sm/octo_idle.webp +0 -0
- package/assets/octobot/sm/octo_idle_still.png +0 -0
- package/assets/octobot/sm/octo_look.webp +0 -0
- package/assets/octobot/sm/octo_look_still.png +0 -0
- package/assets/octobot/sm/octo_swim.webp +0 -0
- package/assets/octobot/sm/octo_swim_still.png +0 -0
- package/assets/octobot/sm/octo_thinking.webp +0 -0
- package/assets/octobot/sm/octo_thinking_still.png +0 -0
- package/assets/octobot/sm/octo_wave.webp +0 -0
- package/assets/octobot/sm/octo_wave_still.png +0 -0
- package/fesm2022/meshmakers-shared-ui-assistant-core.mjs +2 -0
- package/fesm2022/meshmakers-shared-ui-assistant-core.mjs.map +1 -1
- package/fesm2022/meshmakers-shared-ui-assistant.mjs +28 -5
- package/fesm2022/meshmakers-shared-ui-assistant.mjs.map +1 -1
- package/fesm2022/meshmakers-shared-ui.mjs +402 -21
- package/fesm2022/meshmakers-shared-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/meshmakers-shared-ui-assistant-core.d.ts +4 -0
- package/types/meshmakers-shared-ui-assistant.d.ts +11 -0
- package/types/meshmakers-shared-ui.d.ts +270 -6
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, ViewChild, Input, ChangeDetectionStrategy, Component, Injectable, ElementRef, InjectionToken, computed, NgZone, TemplateRef, Directive, Pipe, EventEmitter, ChangeDetectorRef, input, booleanAttribute, output, ViewEncapsulation, Output, HostBinding, ContentChild, HostListener, forwardRef,
|
|
2
|
+
import { inject, signal, ViewChild, Input, ChangeDetectionStrategy, Component, Injectable, ElementRef, InjectionToken, computed, NgZone, TemplateRef, Directive, Pipe, EventEmitter, ChangeDetectorRef, input, booleanAttribute, output, ViewEncapsulation, DestroyRef, effect, PLATFORM_ID, Output, HostBinding, ContentChild, HostListener, forwardRef, numberAttribute, makeEnvironmentProviders } from '@angular/core';
|
|
3
3
|
import * as i3$1 from '@progress/kendo-angular-dialog';
|
|
4
4
|
import { DialogContentBase, DialogRef, DialogActionsComponent, DialogService, WindowRef, WindowService, WindowModule, WindowCloseResult, DialogModule } from '@progress/kendo-angular-dialog';
|
|
5
5
|
import { NotificationService } from '@progress/kendo-angular-notification';
|
|
6
6
|
import * as i1$1 from '@progress/kendo-angular-buttons';
|
|
7
7
|
import { ButtonComponent, ButtonModule, DropDownButtonComponent, SplitButtonComponent, ButtonsModule, ButtonGroupModule, DropDownButtonModule } from '@progress/kendo-angular-buttons';
|
|
8
8
|
import * as i1$3 from '@angular/common';
|
|
9
|
-
import { NgIf, CommonModule, NgComponentOutlet, NgTemplateOutlet, DatePipe, DecimalPipe, AsyncPipe, NgClass } from '@angular/common';
|
|
9
|
+
import { NgIf, CommonModule, isPlatformBrowser, NgComponentOutlet, NgTemplateOutlet, DatePipe, DecimalPipe, AsyncPipe, NgClass } from '@angular/common';
|
|
10
10
|
import * as i2 from '@progress/kendo-angular-icons';
|
|
11
11
|
import { SVGIconComponent, SVGIconModule, IconsModule } from '@progress/kendo-angular-icons';
|
|
12
12
|
import { firstValueFrom, fromEvent, BehaviorSubject, of, Subject, asyncScheduler, from, Subscription } from 'rxjs';
|
|
@@ -17,12 +17,12 @@ import { LabelComponent, LabelModule } from '@progress/kendo-angular-label';
|
|
|
17
17
|
import * as i5 from '@progress/kendo-angular-inputs';
|
|
18
18
|
import { TextBoxComponent, CheckBoxComponent, SeparatorComponent, NumericTextBoxComponent, InputsModule, NumericTextBoxModule } from '@progress/kendo-angular-inputs';
|
|
19
19
|
import { ProgressBarComponent } from '@progress/kendo-angular-progressbar';
|
|
20
|
-
import { copyIcon, xIcon, undoIcon, fileReportIcon, downloadIcon, importIcon, exportIcon, stopIcon, playIcon, xCircleIcon, uploadIcon, arrowRotateCwIcon, fileDataIcon, eraserIcon, trashIcon, hyperlinkOpenIcon, eyeIcon, pencilIcon, plusIcon, filterIcon, filePdfIcon, fileExcelIcon, filterClearIcon, moreVerticalIcon, slidersIcon, saveIcon, cancelIcon, searchIcon, clockIcon
|
|
20
|
+
import { copyIcon, xIcon, calculatorIcon, clockArrowRotateIcon, passwordIcon, cellsMergeIcon, unpinIcon, pinIcon, undoIcon, fileReportIcon, downloadIcon, importIcon, exportIcon, stopIcon, playIcon, xCircleIcon, uploadIcon, arrowRotateCwIcon, fileDataIcon, eraserIcon, trashIcon, hyperlinkOpenIcon, eyeIcon, pencilIcon, plusIcon, checkIcon, filterIcon, filePdfIcon, fileExcelIcon, filterClearIcon, moreVerticalIcon, slidersIcon, saveIcon, cancelIcon, searchIcon, clockIcon } from '@progress/kendo-svg-icons';
|
|
21
21
|
import { Router, NavigationEnd, RouterLink, ActivatedRoute } from '@angular/router';
|
|
22
22
|
import { filter, debounceTime, distinctUntilChanged, takeUntil, observeOn, tap, switchMap, catchError } from 'rxjs/operators';
|
|
23
23
|
import { MessageService, CommandBaseService, CommandSettingsService, provideMmSharedServices } from '@meshmakers/shared-services';
|
|
24
24
|
import * as i1$2 from '@progress/kendo-angular-grid';
|
|
25
|
-
import { DataBindingDirective, GridComponent, ColumnComponent, ToolbarTemplateDirective, GridSpacerComponent, ExcelModule, PDFModule, CommandColumnComponent, CellTemplateDirective, CheckboxColumnComponent, CustomMessagesComponent, FilterCellTemplateDirective, StringFilterCellComponent, NumericFilterCellComponent, BooleanFilterCellComponent, DateFilterCellComponent } from '@progress/kendo-angular-grid';
|
|
25
|
+
import { DataBindingDirective, GridComponent, ColumnComponent, ToolbarTemplateDirective, GridSpacerComponent, ExcelModule, PDFModule, CommandColumnComponent, CellTemplateDirective, CheckboxColumnComponent, CustomMessagesComponent, FilterCellTemplateDirective, StringFilterCellComponent, NumericFilterCellComponent, BooleanFilterCellComponent, DateFilterCellComponent, NoRecordsTemplateDirective } from '@progress/kendo-angular-grid';
|
|
26
26
|
import * as i3 from '@progress/kendo-angular-dropdowns';
|
|
27
27
|
import { DropDownListComponent, ValueTemplateDirective, ItemTemplateDirective, AutoCompleteModule, DropDownListModule } from '@progress/kendo-angular-dropdowns';
|
|
28
28
|
import { isCompositeFilterDescriptor } from '@progress/kendo-data-query';
|
|
@@ -1627,6 +1627,11 @@ const DEFAULT_LIST_VIEW_MESSAGES = {
|
|
|
1627
1627
|
pagerPreviousPage: 'Go to the previous page',
|
|
1628
1628
|
pagerNextPage: 'Go to the next page',
|
|
1629
1629
|
noRecords: 'No records available.',
|
|
1630
|
+
noResultsTitle: 'No results',
|
|
1631
|
+
noResultsText: 'Nothing matches the current search or filter.',
|
|
1632
|
+
booleanYes: 'Yes',
|
|
1633
|
+
booleanNo: 'No',
|
|
1634
|
+
booleanIconLabel: '{column}: {value}',
|
|
1630
1635
|
};
|
|
1631
1636
|
/**
|
|
1632
1637
|
* Merges app-supplied list-view messages over {@link DEFAULT_LIST_VIEW_MESSAGES}. Members that
|
|
@@ -2091,6 +2096,18 @@ const MM_ACTION_ICONS = {
|
|
|
2091
2096
|
report: fileReportIcon,
|
|
2092
2097
|
/** Restore / roll back to a stored state (e.g. restore a dump); destructive restores are `danger`. */
|
|
2093
2098
|
restore: undoIcon,
|
|
2099
|
+
/** Pin to a start page / favourites ("Pin to Home"). */
|
|
2100
|
+
pin: pinIcon,
|
|
2101
|
+
/** Remove a pin ("Unpin from Home"). */
|
|
2102
|
+
unpin: unpinIcon,
|
|
2103
|
+
/** Merge one item into another (e.g. merge users); usually `danger`. */
|
|
2104
|
+
merge: cellsMergeIcon,
|
|
2105
|
+
/** Reset / set a password. */
|
|
2106
|
+
resetPassword: passwordIcon,
|
|
2107
|
+
/** Fill a past time range from the source data (e.g. rollup backfill). */
|
|
2108
|
+
backfill: clockArrowRotateIcon,
|
|
2109
|
+
/** Recalculate derived values for a range (e.g. rollup recompute); not the same as `refresh`. */
|
|
2110
|
+
recompute: calculatorIcon,
|
|
2094
2111
|
};
|
|
2095
2112
|
/** True when the action is disabled (non-empty {@link MmAction.disabledReason}). */
|
|
2096
2113
|
function isActionDisabled(action) {
|
|
@@ -2289,6 +2306,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
2289
2306
|
`, styles: [".mm-action-button-host{display:inline-flex;position:relative}.mm-action-button--toolbar.mm-action-button--icon-only .k-svg-icon{width:20px;height:20px}.mm-action-button--disabled{opacity:.45;cursor:not-allowed}.mm-action-button-host .mm-action-button:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}.mm-action-button__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-action-button-host--disabled:has(.mm-action-button:focus-visible) .mm-action-button__reason{top:calc(100% + 4px);left:0;z-index:20;width:max-content;max-width:280px;height:auto;margin:0;overflow:visible;clip:auto;padding:var(--theme-space-1, 4px) var(--theme-space-2, 8px);white-space:normal;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}\n"] }]
|
|
2290
2307
|
}], propDecorators: { action: [{ type: i0.Input, args: [{ isSignal: true, alias: "action", required: true }] }], targetLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "targetLabel", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], display: [{ type: i0.Input, args: [{ isSignal: true, alias: "display", required: false }] }], primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }], triggered: [{ type: i0.Output, args: ["triggered"] }] } });
|
|
2291
2308
|
|
|
2309
|
+
/**
|
|
2310
|
+
* Human label of a list row (AB#5623) — the row's name in row action names ("Actions for <label>"),
|
|
2311
|
+
* dialog titles and danger confirmations. Reads `field` (a dotted path such as `contact.displayName`
|
|
2312
|
+
* also works, a flat key with dots wins), then each of `fallbacks` (default `rtWellKnownName`,
|
|
2313
|
+
* `rtId`); the first non-blank value wins. `''` when none is set.
|
|
2314
|
+
*/
|
|
2315
|
+
function resolveListRowLabel(row, field, fallbacks = ['rtWellKnownName', 'rtId']) {
|
|
2316
|
+
const record = (row ?? {});
|
|
2317
|
+
for (const key of field ? [field, ...fallbacks] : fallbacks) {
|
|
2318
|
+
const value = readRowPath(record, key);
|
|
2319
|
+
if (value !== null && value !== undefined && typeof value !== 'object' && typeof value !== 'function' && String(value).trim() !== '') {
|
|
2320
|
+
return String(value);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
return '';
|
|
2324
|
+
}
|
|
2325
|
+
function readRowPath(row, path) {
|
|
2326
|
+
if (path in row || path.indexOf('.') === -1) {
|
|
2327
|
+
return row[path];
|
|
2328
|
+
}
|
|
2329
|
+
let value = row;
|
|
2330
|
+
for (const key of path.split('.')) {
|
|
2331
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
2332
|
+
return undefined;
|
|
2333
|
+
}
|
|
2334
|
+
value = value[key];
|
|
2335
|
+
}
|
|
2336
|
+
return value;
|
|
2337
|
+
}
|
|
2292
2338
|
/** Resolves the per-row callbacks of a {@link MmListRowAction}. */
|
|
2293
2339
|
function resolveListRowAction(definition, row) {
|
|
2294
2340
|
const { disabledReason, visible, link, run: _run, ...rest } = definition;
|
|
@@ -2452,6 +2498,235 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
2452
2498
|
}]
|
|
2453
2499
|
}] });
|
|
2454
2500
|
|
|
2501
|
+
/** Pixel edge length of each {@link OctoBotSize}. */
|
|
2502
|
+
const OCTOBOT_SIZE_PX = { sm: 60, md: 120, lg: 240 };
|
|
2503
|
+
/**
|
|
2504
|
+
* Length of one loop of each animation in ms (identical for all sizes; read from the WebP frame
|
|
2505
|
+
* durations). Used by `playOnce`.
|
|
2506
|
+
*/
|
|
2507
|
+
const OCTOBOT_LOOP_MS = {
|
|
2508
|
+
idle: 1900, blink: 2140, look: 2320, swim: 1750, thinking: 3520, wave: 2210
|
|
2509
|
+
};
|
|
2510
|
+
/**
|
|
2511
|
+
* Base URL of the OctoBot images, with a trailing slash. Default `assets/octobot/` (relative to
|
|
2512
|
+
* the document base). The files ship as library assets in
|
|
2513
|
+
* `node_modules/@meshmakers/shared-ui/assets/octobot`; a host app copies them with an
|
|
2514
|
+
* `angular.json` assets entry:
|
|
2515
|
+
*
|
|
2516
|
+
* ```json
|
|
2517
|
+
* { "glob": "**\/*", "input": "node_modules/@meshmakers/shared-ui/assets/octobot", "output": "/assets/octobot" }
|
|
2518
|
+
* ```
|
|
2519
|
+
*
|
|
2520
|
+
* Provide a different value when the app serves them elsewhere (a CDN, a sub path).
|
|
2521
|
+
*/
|
|
2522
|
+
const OCTOBOT_ASSET_BASE_URL = new InjectionToken('OCTOBOT_ASSET_BASE_URL', {
|
|
2523
|
+
providedIn: 'root',
|
|
2524
|
+
factory: () => 'assets/octobot/'
|
|
2525
|
+
});
|
|
2526
|
+
/**
|
|
2527
|
+
* App-wide "show stills only" switch, e.g. bound to a user setting "Reduce animations". When
|
|
2528
|
+
* `true`, every `mm-octobot` shows its still frame regardless of `prefers-reduced-motion`.
|
|
2529
|
+
*/
|
|
2530
|
+
const OCTOBOT_FORCE_STILL = new InjectionToken('OCTOBOT_FORCE_STILL', {
|
|
2531
|
+
providedIn: 'root',
|
|
2532
|
+
factory: () => false
|
|
2533
|
+
});
|
|
2534
|
+
const REDUCED_MOTION_QUERY = '(prefers-reduced-motion: reduce)';
|
|
2535
|
+
/**
|
|
2536
|
+
* `mm-octobot` — the meshmakers OctoBot mascot as a small animated pixel-art image (AB#3444).
|
|
2537
|
+
*
|
|
2538
|
+
* Renders one `<img>` with a fixed width and height (no layout shift), `loading="lazy"` (or
|
|
2539
|
+
* `eager` via the `loading` input),
|
|
2540
|
+
* `decoding="async"` and `image-rendering: pixelated`. The image is an 8-frame animated WebP
|
|
2541
|
+
* loaded by URL from {@link OCTOBOT_ASSET_BASE_URL} — nothing lands in the JS bundle.
|
|
2542
|
+
*
|
|
2543
|
+
* **Reduced motion:** while the user prefers reduced motion (`prefers-reduced-motion: reduce`,
|
|
2544
|
+
* followed live via `matchMedia`), when {@link OCTOBOT_FORCE_STILL} is `true` or when the `still`
|
|
2545
|
+
* input is set, the first frame is shown as a static PNG instead.
|
|
2546
|
+
*
|
|
2547
|
+
* **Accessibility:** without a `label` the figure is decorative (`alt=""`, `aria-hidden="true"`);
|
|
2548
|
+
* the surrounding text must carry the meaning (e.g. "Thinking…" next to `thinking`). With a
|
|
2549
|
+
* `label` the host gets `role="img"` and `aria-label`.
|
|
2550
|
+
*
|
|
2551
|
+
* **Placement rules (host responsibility, see `docs/actions.md` › OctoBot):** at most one
|
|
2552
|
+
* animated OctoBot per view — empty states (once per page), page loading, the assistant panel,
|
|
2553
|
+
* 404 / turned-off pages, onboarding. Never inside repeated elements (list rows, table cells,
|
|
2554
|
+
* cockpit tiles, buttons) and never in toasts or error messages (a still frame is acceptable
|
|
2555
|
+
* there if a figure is wanted at all).
|
|
2556
|
+
*
|
|
2557
|
+
* @example
|
|
2558
|
+
* ```html
|
|
2559
|
+
* <mm-octobot animation="idle" size="md" />
|
|
2560
|
+
* <mm-octobot animation="thinking" size="sm" label="The assistant is thinking" />
|
|
2561
|
+
* ```
|
|
2562
|
+
*/
|
|
2563
|
+
class OctoBotComponent {
|
|
2564
|
+
baseUrl = inject(OCTOBOT_ASSET_BASE_URL);
|
|
2565
|
+
forceStill = inject(OCTOBOT_FORCE_STILL);
|
|
2566
|
+
/** Which animation to play. Default `idle`. */
|
|
2567
|
+
animation = input('idle', /* @ts-ignore */
|
|
2568
|
+
...(ngDevMode ? [{ debugName: "animation" }] : /* istanbul ignore next */ []));
|
|
2569
|
+
/** Rendered size. Default `md` (120 px). */
|
|
2570
|
+
size = input('md', /* @ts-ignore */
|
|
2571
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2572
|
+
/** Accessible name; when empty the figure is decorative. */
|
|
2573
|
+
label = input(null, /* @ts-ignore */
|
|
2574
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
2575
|
+
/** Image loading strategy; `eager` where the figure is visible right away. Default `lazy`. */
|
|
2576
|
+
loading = input('lazy', /* @ts-ignore */
|
|
2577
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
2578
|
+
/** Show the still frame instead of the animation (e.g. after the assistant finished). */
|
|
2579
|
+
still = input(false, { ...(ngDevMode ? { debugName: "still" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2580
|
+
/**
|
|
2581
|
+
* Plays the animation once ({@link OCTOBOT_LOOP_MS}) and then rests on the still frame — for
|
|
2582
|
+
* greetings (`wave`) that should not loop forever. The WebPs themselves loop endlessly.
|
|
2583
|
+
*/
|
|
2584
|
+
playOnce = input(false, { ...(ngDevMode ? { debugName: "playOnce" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2585
|
+
prefersReducedMotion = signal(false, /* @ts-ignore */
|
|
2586
|
+
...(ngDevMode ? [{ debugName: "prefersReducedMotion" }] : /* istanbul ignore next */ []));
|
|
2587
|
+
played = signal(false, /* @ts-ignore */
|
|
2588
|
+
...(ngDevMode ? [{ debugName: "played" }] : /* istanbul ignore next */ []));
|
|
2589
|
+
px = computed(() => OCTOBOT_SIZE_PX[this.size()] ?? OCTOBOT_SIZE_PX.md, /* @ts-ignore */
|
|
2590
|
+
...(ngDevMode ? [{ debugName: "px" }] : /* istanbul ignore next */ []));
|
|
2591
|
+
showStill = computed(() => this.still() || this.forceStill || this.prefersReducedMotion() || this.played(), /* @ts-ignore */
|
|
2592
|
+
...(ngDevMode ? [{ debugName: "showStill" }] : /* istanbul ignore next */ []));
|
|
2593
|
+
src = computed(() => {
|
|
2594
|
+
const base = this.baseUrl.endsWith('/') ? this.baseUrl : `${this.baseUrl}/`;
|
|
2595
|
+
const file = this.showStill() ? `octo_${this.animation()}_still.png` : `octo_${this.animation()}.webp`;
|
|
2596
|
+
return `${base}${this.size()}/${file}`;
|
|
2597
|
+
}, /* @ts-ignore */
|
|
2598
|
+
...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
|
|
2599
|
+
constructor() {
|
|
2600
|
+
const destroyRef = inject(DestroyRef);
|
|
2601
|
+
// Restart the single loop whenever the animation changes while playOnce is set.
|
|
2602
|
+
effect((onCleanup) => {
|
|
2603
|
+
const animation = this.animation();
|
|
2604
|
+
this.played.set(false);
|
|
2605
|
+
if (!this.playOnce()) {
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
const timer = setTimeout(() => this.played.set(true), OCTOBOT_LOOP_MS[animation] ?? 2000);
|
|
2609
|
+
onCleanup(() => clearTimeout(timer));
|
|
2610
|
+
});
|
|
2611
|
+
if (!isPlatformBrowser(inject(PLATFORM_ID)) || typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
2612
|
+
return;
|
|
2613
|
+
}
|
|
2614
|
+
const query = window.matchMedia(REDUCED_MOTION_QUERY);
|
|
2615
|
+
if (!query) {
|
|
2616
|
+
// Stubbed or partial matchMedia (tests, embedded webviews): keep the animation, no live updates.
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2619
|
+
this.prefersReducedMotion.set(!!query.matches);
|
|
2620
|
+
const listener = (event) => this.prefersReducedMotion.set(event.matches);
|
|
2621
|
+
query.addEventListener?.('change', listener);
|
|
2622
|
+
destroyRef.onDestroy(() => query.removeEventListener?.('change', listener));
|
|
2623
|
+
}
|
|
2624
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: OctoBotComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2625
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.5", type: OctoBotComponent, isStandalone: true, selector: "mm-octobot", inputs: { animation: { classPropertyName: "animation", publicName: "animation", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, still: { classPropertyName: "still", publicName: "still", isSignal: true, isRequired: false, transformFunction: null }, playOnce: { classPropertyName: "playOnce", publicName: "playOnce", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-size": "size()", "attr.role": "label() ? \"img\" : null", "attr.aria-label": "label() || null", "attr.aria-hidden": "label() ? null : \"true\"", "attr.data-animation": "animation()", "attr.data-still": "showStill() ? \"true\" : null" }, classAttribute: "mm-octobot" }, ngImport: i0, template: `<img
|
|
2626
|
+
class="mm-octobot__img"
|
|
2627
|
+
[attr.loading]="loading()"
|
|
2628
|
+
[src]="src()"
|
|
2629
|
+
[attr.width]="px()"
|
|
2630
|
+
[attr.height]="px()"
|
|
2631
|
+
alt=""
|
|
2632
|
+
decoding="async"
|
|
2633
|
+
draggable="false" />`, isInline: true, styles: [":host{display:inline-block;flex:none;line-height:0}.mm-octobot__img{display:block;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2634
|
+
}
|
|
2635
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: OctoBotComponent, decorators: [{
|
|
2636
|
+
type: Component,
|
|
2637
|
+
args: [{ selector: 'mm-octobot', template: `<img
|
|
2638
|
+
class="mm-octobot__img"
|
|
2639
|
+
[attr.loading]="loading()"
|
|
2640
|
+
[src]="src()"
|
|
2641
|
+
[attr.width]="px()"
|
|
2642
|
+
[attr.height]="px()"
|
|
2643
|
+
alt=""
|
|
2644
|
+
decoding="async"
|
|
2645
|
+
draggable="false" />`, host: {
|
|
2646
|
+
'class': 'mm-octobot',
|
|
2647
|
+
'[attr.data-size]': 'size()',
|
|
2648
|
+
'[attr.role]': 'label() ? "img" : null',
|
|
2649
|
+
'[attr.aria-label]': 'label() || null',
|
|
2650
|
+
'[attr.aria-hidden]': 'label() ? null : "true"',
|
|
2651
|
+
'[attr.data-animation]': 'animation()',
|
|
2652
|
+
'[attr.data-still]': 'showStill() ? "true" : null'
|
|
2653
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:inline-block;flex:none;line-height:0}.mm-octobot__img{display:block;max-width:none;image-rendering:pixelated;-webkit-user-select:none;user-select:none}\n"] }]
|
|
2654
|
+
}], ctorParameters: () => [], propDecorators: { animation: [{ type: i0.Input, args: [{ isSignal: true, alias: "animation", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], still: [{ type: i0.Input, args: [{ isSignal: true, alias: "still", required: false }] }], playOnce: [{ type: i0.Input, args: [{ isSignal: true, alias: "playOnce", required: false }] }] } });
|
|
2655
|
+
|
|
2656
|
+
/** Default English "Try again" label of {@link EmptyStateComponent}. */
|
|
2657
|
+
const DEFAULT_EMPTY_STATE_RETRY_LABEL = 'Try again';
|
|
2658
|
+
/**
|
|
2659
|
+
* `mm-empty-state` — the shared empty / no-results / error block of a page or list (AB#3444).
|
|
2660
|
+
*
|
|
2661
|
+
* One per page or list, never per row. The `empty` and `no-results` variants show one OctoBot
|
|
2662
|
+
* (`idle` / `look`, decorative) above the title; the `error` variant shows no figure and announces
|
|
2663
|
+
* itself as an alert. Project extra actions (e.g. "New data flow") as content.
|
|
2664
|
+
*
|
|
2665
|
+
* @example
|
|
2666
|
+
* ```html
|
|
2667
|
+
* <mm-empty-state heading="No data flows yet" text="Create your first data flow to start processing data." />
|
|
2668
|
+
* <mm-empty-state variant="error" heading="The blueprints could not be loaded." showRetry (retry)="load()" />
|
|
2669
|
+
* ```
|
|
2670
|
+
*/
|
|
2671
|
+
class EmptyStateComponent {
|
|
2672
|
+
variant = input('empty', /* @ts-ignore */
|
|
2673
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
2674
|
+
heading = input.required(/* @ts-ignore */
|
|
2675
|
+
...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
|
|
2676
|
+
text = input(null, /* @ts-ignore */
|
|
2677
|
+
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
2678
|
+
/** OctoBot size of the `empty` / `no-results` variants. Default `md`. */
|
|
2679
|
+
size = input('md', /* @ts-ignore */
|
|
2680
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
2681
|
+
/** Shows the "Try again" button (error variant only). */
|
|
2682
|
+
showRetry = input(false, { ...(ngDevMode ? { debugName: "showRetry" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
2683
|
+
retryLabel = input(DEFAULT_EMPTY_STATE_RETRY_LABEL, /* @ts-ignore */
|
|
2684
|
+
...(ngDevMode ? [{ debugName: "retryLabel" }] : /* istanbul ignore next */ []));
|
|
2685
|
+
/** Emitted by the "Try again" button. */
|
|
2686
|
+
retry = output();
|
|
2687
|
+
figure = computed(() => {
|
|
2688
|
+
switch (this.variant()) {
|
|
2689
|
+
case 'empty': return 'idle';
|
|
2690
|
+
case 'no-results': return 'look';
|
|
2691
|
+
default: return null;
|
|
2692
|
+
}
|
|
2693
|
+
}, /* @ts-ignore */
|
|
2694
|
+
...(ngDevMode ? [{ debugName: "figure" }] : /* istanbul ignore next */ []));
|
|
2695
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2696
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: EmptyStateComponent, isStandalone: true, selector: "mm-empty-state", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: true, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showRetry: { classPropertyName: "showRetry", publicName: "showRetry", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry" }, host: { properties: { "attr.data-variant": "variant()" }, classAttribute: "mm-empty-state" }, ngImport: i0, template: `
|
|
2697
|
+
@if (figure(); as animation) {
|
|
2698
|
+
<mm-octobot class="mm-empty-state__figure" [animation]="animation" [size]="size()" loading="eager" />
|
|
2699
|
+
}
|
|
2700
|
+
<p class="mm-empty-state__title" [attr.role]="variant() === 'error' ? 'alert' : null">{{ heading() }}</p>
|
|
2701
|
+
@if (text()) {
|
|
2702
|
+
<p class="mm-empty-state__text">{{ text() }}</p>
|
|
2703
|
+
}
|
|
2704
|
+
@if (variant() === 'error' && showRetry()) {
|
|
2705
|
+
<button kendoButton type="button" class="mm-empty-state__retry" (click)="retry.emit()">{{ retryLabel() }}</button>
|
|
2706
|
+
}
|
|
2707
|
+
<ng-content />
|
|
2708
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:center;gap:var(--theme-space-2, 8px);padding:var(--theme-space-6, 24px) var(--theme-space-4, 16px);text-align:center;color:var(--theme-text-secondary)}.mm-empty-state__title{margin:0;color:var(--theme-text-primary);font-weight:600}:host([data-variant=\"error\"]) .mm-empty-state__title{color:var(--theme-status-error)}.mm-empty-state__text{margin:0;max-width:48ch}.mm-empty-state__retry{margin-top:var(--theme-space-1, 4px)}\n"], dependencies: [{ kind: "component", type: OctoBotComponent, selector: "mm-octobot", inputs: ["animation", "size", "label", "loading", "still", "playOnce"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2709
|
+
}
|
|
2710
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: EmptyStateComponent, decorators: [{
|
|
2711
|
+
type: Component,
|
|
2712
|
+
args: [{ selector: 'mm-empty-state', imports: [OctoBotComponent, ButtonComponent], template: `
|
|
2713
|
+
@if (figure(); as animation) {
|
|
2714
|
+
<mm-octobot class="mm-empty-state__figure" [animation]="animation" [size]="size()" loading="eager" />
|
|
2715
|
+
}
|
|
2716
|
+
<p class="mm-empty-state__title" [attr.role]="variant() === 'error' ? 'alert' : null">{{ heading() }}</p>
|
|
2717
|
+
@if (text()) {
|
|
2718
|
+
<p class="mm-empty-state__text">{{ text() }}</p>
|
|
2719
|
+
}
|
|
2720
|
+
@if (variant() === 'error' && showRetry()) {
|
|
2721
|
+
<button kendoButton type="button" class="mm-empty-state__retry" (click)="retry.emit()">{{ retryLabel() }}</button>
|
|
2722
|
+
}
|
|
2723
|
+
<ng-content />
|
|
2724
|
+
`, host: {
|
|
2725
|
+
'class': 'mm-empty-state',
|
|
2726
|
+
'[attr.data-variant]': 'variant()'
|
|
2727
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:flex;flex-direction:column;align-items:center;gap:var(--theme-space-2, 8px);padding:var(--theme-space-6, 24px) var(--theme-space-4, 16px);text-align:center;color:var(--theme-text-secondary)}.mm-empty-state__title{margin:0;color:var(--theme-text-primary);font-weight:600}:host([data-variant=\"error\"]) .mm-empty-state__title{color:var(--theme-status-error)}.mm-empty-state__text{margin:0;max-width:48ch}.mm-empty-state__retry{margin-top:var(--theme-space-1, 4px)}\n"] }]
|
|
2728
|
+
}], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: true }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showRetry: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRetry", required: false }] }], retryLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "retryLabel", required: false }] }], retry: [{ type: i0.Output, args: ["retry"] }] } });
|
|
2729
|
+
|
|
2455
2730
|
/** Context/overflow menu class of `CommandItem.danger` items (AB#5570); styled globally in the list-view SCSS. */
|
|
2456
2731
|
const DANGER_MENU_ITEM_CLASS = 'mm-list-view-menu-item--danger';
|
|
2457
2732
|
function isOverflowRowActionData(data) {
|
|
@@ -2489,6 +2764,13 @@ class ListViewComponent extends CommandBaseService {
|
|
|
2489
2764
|
/** Indicates if the data source is currently loading data */
|
|
2490
2765
|
isLoading = signal(false, /* @ts-ignore */
|
|
2491
2766
|
...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
|
|
2767
|
+
/**
|
|
2768
|
+
* Whether the data source reported "not loading" at least once (AB#3444). {@link isLoading}
|
|
2769
|
+
* follows the data source one macrotask late (asyncScheduler), so the first render would
|
|
2770
|
+
* otherwise show the empty state while the first fetch is already in flight.
|
|
2771
|
+
*/
|
|
2772
|
+
loadSettled = signal(false, /* @ts-ignore */
|
|
2773
|
+
...(ngDevMode ? [{ debugName: "loadSettled" }] : /* istanbul ignore next */ []));
|
|
2492
2774
|
/**
|
|
2493
2775
|
* The component's own width in pixels, kept current via ResizeObserver.
|
|
2494
2776
|
* `null` until the first measurement (before that, all columns render visible
|
|
@@ -2741,6 +3023,33 @@ class ListViewComponent extends CommandBaseService {
|
|
|
2741
3023
|
* those host filters by itself.
|
|
2742
3024
|
*/
|
|
2743
3025
|
hasExternalFilters = false;
|
|
3026
|
+
/**
|
|
3027
|
+
* Empty state of the list (AB#3444): when set, a list without records shows the shared
|
|
3028
|
+
* `mm-empty-state` — one OctoBot `idle` with {@link MmListEmptyState.title} / `text` — instead
|
|
3029
|
+
* of the plain "No records available." line; while a search, row filter or host filter
|
|
3030
|
+
* ({@link hasExternalFilters}) is active it shows OctoBot `look` with the "no results" texts.
|
|
3031
|
+
* Nothing is shown while the list loads (including before the first fetch answered). The figure appears once per list, never in rows.
|
|
3032
|
+
*/
|
|
3033
|
+
emptyState = null;
|
|
3034
|
+
/**
|
|
3035
|
+
* Fully custom empty state (wins over {@link emptyState}). Context: `$implicit` / `filtered`
|
|
3036
|
+
* is `true` while a search or filter is active.
|
|
3037
|
+
*/
|
|
3038
|
+
emptyTemplate = null;
|
|
3039
|
+
/**
|
|
3040
|
+
* Whether a search, row filter or host filter narrows the rows right now (sorting does not),
|
|
3041
|
+
* i.e. an empty list means "no results" rather than "no records yet".
|
|
3042
|
+
*/
|
|
3043
|
+
get isFiltered() {
|
|
3044
|
+
if (this.hasExternalFilters || this.searchValue.trim().length > 0) {
|
|
3045
|
+
return true;
|
|
3046
|
+
}
|
|
3047
|
+
return (this.dataBindingDirective?.currentState?.filter?.filters?.length ?? 0) > 0;
|
|
3048
|
+
}
|
|
3049
|
+
get emptyContext() {
|
|
3050
|
+
const filtered = this.isFiltered;
|
|
3051
|
+
return { $implicit: filtered, filtered };
|
|
3052
|
+
}
|
|
2744
3053
|
/**
|
|
2745
3054
|
* Whether anything narrows or reorders the default view right now: a row
|
|
2746
3055
|
* filter, a column sort, free-text search, or host-side filters announced
|
|
@@ -2894,6 +3203,9 @@ class ListViewComponent extends CommandBaseService {
|
|
|
2894
3203
|
if (this.dataBindingDirective) {
|
|
2895
3204
|
this.dataBindingDirective.isLoading$.pipe(observeOn(asyncScheduler), takeUntil(this.destroy$)).subscribe(loading => {
|
|
2896
3205
|
this.isLoading.set(loading);
|
|
3206
|
+
if (!loading) {
|
|
3207
|
+
this.loadSettled.set(true);
|
|
3208
|
+
}
|
|
2897
3209
|
// Measure the fit-to-height page size only ONCE, when data first
|
|
2898
3210
|
// renders (initial default → fitted). After that, page-size changes come
|
|
2899
3211
|
// solely from the ResizeObserver (genuine viewport/density changes).
|
|
@@ -3179,6 +3491,8 @@ class ListViewComponent extends CommandBaseService {
|
|
|
3179
3491
|
case 'boolean':
|
|
3180
3492
|
case 'date':
|
|
3181
3493
|
return column.dataType;
|
|
3494
|
+
case 'booleanIcon':
|
|
3495
|
+
return 'boolean';
|
|
3182
3496
|
case 'numericRange':
|
|
3183
3497
|
case 'progressBar':
|
|
3184
3498
|
return 'numeric';
|
|
@@ -3188,6 +3502,32 @@ class ListViewComponent extends CommandBaseService {
|
|
|
3188
3502
|
return 'text';
|
|
3189
3503
|
}
|
|
3190
3504
|
}
|
|
3505
|
+
/**
|
|
3506
|
+
* State of a `booleanIcon` cell (AB#5623): `'true'` / `'false'` for booleans (also the strings
|
|
3507
|
+
* "true" / "false"), `null` for an empty or non-boolean value (empty cell).
|
|
3508
|
+
*/
|
|
3509
|
+
booleanIconState(element, column) {
|
|
3510
|
+
const value = this.getValue(element, column);
|
|
3511
|
+
if (value === true || value === 'true')
|
|
3512
|
+
return 'true';
|
|
3513
|
+
if (value === false || value === 'false')
|
|
3514
|
+
return 'false';
|
|
3515
|
+
return null;
|
|
3516
|
+
}
|
|
3517
|
+
/** Icon of a `booleanIcon` cell: the column's `booleanIcons`, else check / x; `null` = no icon. */
|
|
3518
|
+
booleanIcon(column, state) {
|
|
3519
|
+
const icons = column.booleanIcons;
|
|
3520
|
+
if (state === 'true') {
|
|
3521
|
+
return icons?.true ?? checkIcon;
|
|
3522
|
+
}
|
|
3523
|
+
return icons?.false === null ? null : icons?.false ?? xIcon;
|
|
3524
|
+
}
|
|
3525
|
+
/** Accessible name of a `booleanIcon` cell: "<column>: Yes|No" from the messages (AB#5623). */
|
|
3526
|
+
booleanIconLabel(column, state) {
|
|
3527
|
+
const value = state === 'true' ? this._messages.booleanYes : this._messages.booleanNo;
|
|
3528
|
+
const name = this.getDisplayName(column) ?? '';
|
|
3529
|
+
return name ? this._messages.booleanIconLabel.replace('{column}', name).replace('{value}', value) : value;
|
|
3530
|
+
}
|
|
3191
3531
|
/** Input attributes of a read-only boolean cell, cached per column and name (AB#5621). */
|
|
3192
3532
|
booleanCellAttributeCache = new WeakMap();
|
|
3193
3533
|
/**
|
|
@@ -3454,19 +3794,13 @@ class ListViewComponent extends CommandBaseService {
|
|
|
3454
3794
|
}
|
|
3455
3795
|
/**
|
|
3456
3796
|
* Row field naming a row for assistive technology (row menu "Actions for <name>", action
|
|
3457
|
-
* buttons "<action> <name>"). Falls back to `rtWellKnownName`, then `rtId`.
|
|
3797
|
+
* buttons "<action> <name>"). Falls back to `rtWellKnownName`, then `rtId`. A dotted path
|
|
3798
|
+
* (`contact.displayName`) reads a nested value (AB#5623).
|
|
3458
3799
|
*/
|
|
3459
3800
|
rowLabelField = 'name';
|
|
3460
3801
|
/** Human name of a row (`rowLabelField`, `rtWellKnownName`, `rtId`), or '' when unknown. */
|
|
3461
3802
|
rowLabel(dataItem) {
|
|
3462
|
-
|
|
3463
|
-
for (const key of [this.rowLabelField, 'rtWellKnownName', 'rtId']) {
|
|
3464
|
-
const value = row[key];
|
|
3465
|
-
if (value !== null && value !== undefined && String(value).trim() !== '') {
|
|
3466
|
-
return String(value);
|
|
3467
|
-
}
|
|
3468
|
-
}
|
|
3469
|
-
return '';
|
|
3803
|
+
return resolveListRowLabel(dataItem, this.rowLabelField);
|
|
3470
3804
|
}
|
|
3471
3805
|
/** Accessible name and tooltip of the row menu button. */
|
|
3472
3806
|
rowActionsLabel(dataItem) {
|
|
@@ -3678,7 +4012,7 @@ class ListViewComponent extends CommandBaseService {
|
|
|
3678
4012
|
*/
|
|
3679
4013
|
commandsIcon = slidersIcon;
|
|
3680
4014
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3681
|
-
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", 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 }], 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 ('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<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 <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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}: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)}\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: "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 });
|
|
4015
|
+
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 }], 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<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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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}: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 });
|
|
3682
4016
|
}
|
|
3683
4017
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: ListViewComponent, decorators: [{
|
|
3684
4018
|
type: Component,
|
|
@@ -3717,8 +4051,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
3717
4051
|
NumericTextBoxComponent,
|
|
3718
4052
|
NgComponentOutlet,
|
|
3719
4053
|
NgTemplateOutlet,
|
|
3720
|
-
ActionButtonComponent
|
|
3721
|
-
], 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 ('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<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 <ng-template kendoGridToolbarTemplate>\n\n @for (commandItem of leftToolbarActions; track commandItem.id) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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}: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)}\n"] }]
|
|
4054
|
+
ActionButtonComponent,
|
|
4055
|
+
NoRecordsTemplateDirective,
|
|
4056
|
+
EmptyStateComponent
|
|
4057
|
+
], 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<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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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) {\n @if (commandItem) {\n @switch (commandItem.type) {\n @case ('link') {\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (buttonClick)=\"onToolbarCommand(commandItem)\"\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) || isLoading()\"\n [textField]=\"'text'\"\n themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [buttonAttributes]=\"toolbarItemButtonAttributes(commandItem)\"\n (itemClick)=\"onToolbarDropdownItemClick($event)\">\n {{ commandItem.text }}\n </kendo-dropdownbutton>\n } @else if (commandItem.svgIcon) {\n <button kendoTooltip kendoButton themeColor=\"primary\" [svgIcon]=\"commandItem.svgIcon\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n } @else {\n <button kendoTooltip kendoButton themeColor=\"primary\"\n [fillMode]=\"$any(commandItem.fillMode ?? 'solid')\"\n [title]=\"commandItem.tooltip ?? commandItem.text\"\n [attr.aria-label]=\"toolbarItemAriaLabel(commandItem)\"\n [disabled]=\"getToolbarItemDisabled(commandItem) || isLoading()\"\n (click)=\"onToolbarCommand(commandItem)\">{{ commandItem.text }}\n </button>\n }\n }\n @case ('separator'){\n <kendo-separator></kendo-separator>\n }\n }\n }\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}: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"] }]
|
|
3722
4058
|
}], ctorParameters: () => [], propDecorators: { filtersTemplate: [{
|
|
3723
4059
|
type: ContentChild,
|
|
3724
4060
|
args: [ListViewFiltersDirective]
|
|
@@ -3792,6 +4128,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
3792
4128
|
type: Input
|
|
3793
4129
|
}], hasExternalFilters: [{
|
|
3794
4130
|
type: Input
|
|
4131
|
+
}], emptyState: [{
|
|
4132
|
+
type: Input
|
|
4133
|
+
}], emptyTemplate: [{
|
|
4134
|
+
type: Input
|
|
3795
4135
|
}], isCardMode: [{
|
|
3796
4136
|
type: HostBinding,
|
|
3797
4137
|
args: ['class.mm-list-view-cards']
|
|
@@ -7379,6 +7719,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
7379
7719
|
type: Injectable
|
|
7380
7720
|
}] });
|
|
7381
7721
|
|
|
7722
|
+
const DEFAULT_ROW_ACTIONS_MESSAGES = {
|
|
7723
|
+
actionsFor: 'Actions for {name}',
|
|
7724
|
+
actions: 'Actions',
|
|
7725
|
+
moreActionsFor: 'More actions for {name}',
|
|
7726
|
+
moreActions: 'More actions',
|
|
7727
|
+
};
|
|
7728
|
+
/** App-wide translations of `mm-row-actions`. Partial: members left out keep their English default. */
|
|
7729
|
+
const MM_ROW_ACTIONS_MESSAGES = new InjectionToken('MM_ROW_ACTIONS_MESSAGES');
|
|
7730
|
+
/**
|
|
7731
|
+
* Merges overrides over {@link DEFAULT_ROW_ACTIONS_MESSAGES}, later sources winning; members that
|
|
7732
|
+
* are missing, `undefined` or `null` keep the earlier value.
|
|
7733
|
+
*/
|
|
7734
|
+
function resolveRowActionsMessages(...overrides) {
|
|
7735
|
+
const resolved = { ...DEFAULT_ROW_ACTIONS_MESSAGES };
|
|
7736
|
+
for (const messages of overrides) {
|
|
7737
|
+
if (!messages) {
|
|
7738
|
+
continue;
|
|
7739
|
+
}
|
|
7740
|
+
for (const key of Object.keys(messages)) {
|
|
7741
|
+
const value = messages[key];
|
|
7742
|
+
if (value !== undefined && value !== null) {
|
|
7743
|
+
resolved[key] = value;
|
|
7744
|
+
}
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7747
|
+
return resolved;
|
|
7748
|
+
}
|
|
7749
|
+
|
|
7382
7750
|
/**
|
|
7383
7751
|
* The actions of one table row (AB#5570): icon buttons (16 px) with tooltip and an accessible
|
|
7384
7752
|
* name that includes the row ("Edit Mesh Adapter"), from one shared action definition.
|
|
@@ -7386,6 +7754,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
7386
7754
|
* "More actions for …" menu. Disabled actions stay focusable and announce their reason;
|
|
7387
7755
|
* in the menu the reason is shown under the item text.
|
|
7388
7756
|
*
|
|
7757
|
+
* Texts ("Actions for …", "More actions for …") come from {@link MM_ROW_ACTIONS_MESSAGES} and the
|
|
7758
|
+
* `messages` input (the input wins), English by default.
|
|
7759
|
+
*
|
|
7389
7760
|
* The component only emits — destructive handlers confirm first (danger dialog naming the target).
|
|
7390
7761
|
*
|
|
7391
7762
|
* ```html
|
|
@@ -7403,12 +7774,18 @@ class RowActionsComponent {
|
|
|
7403
7774
|
...(ngDevMode ? [{ debugName: "rowLabel" }] : /* istanbul ignore next */ []));
|
|
7404
7775
|
/** Slots incl. the overflow button. */
|
|
7405
7776
|
maxInline = input(MM_ROW_ACTIONS_MAX_INLINE, { ...(ngDevMode ? { debugName: "maxInline" } : /* istanbul ignore next */ {}), transform: numberAttribute });
|
|
7777
|
+
/** Translations for this instance; members left out come from `MM_ROW_ACTIONS_MESSAGES`, else English. */
|
|
7778
|
+
messages = input(null, /* @ts-ignore */
|
|
7779
|
+
...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
|
|
7406
7780
|
/** Fires for enabled actions only, inline or from the menu. */
|
|
7407
7781
|
triggered = output();
|
|
7408
7782
|
router = inject(Router, { optional: true });
|
|
7409
7783
|
/** Menu links resolve like the inline `routerLink`: relative to the hosting route. */
|
|
7410
7784
|
route = inject(ActivatedRoute, { optional: true });
|
|
7785
|
+
injectedMessages = inject(MM_ROW_ACTIONS_MESSAGES, { optional: true });
|
|
7411
7786
|
moreIcon = moreVerticalIcon;
|
|
7787
|
+
m = computed(() => resolveRowActionsMessages(this.injectedMessages, this.messages()), /* @ts-ignore */
|
|
7788
|
+
...(ngDevMode ? [{ debugName: "m" }] : /* istanbul ignore next */ []));
|
|
7412
7789
|
split = computed(() => splitRowActions(this.actions(), this.maxInline()), /* @ts-ignore */
|
|
7413
7790
|
...(ngDevMode ? [{ debugName: "split" }] : /* istanbul ignore next */ []));
|
|
7414
7791
|
menuItems = computed(() => this.split().menu.map((action) => ({
|
|
@@ -7421,10 +7798,14 @@ class RowActionsComponent {
|
|
|
7421
7798
|
/** No group semantics for an empty cell (all actions hidden). */
|
|
7422
7799
|
hasActions = computed(() => this.split().inline.length > 0 || this.split().menu.length > 0, /* @ts-ignore */
|
|
7423
7800
|
...(ngDevMode ? [{ debugName: "hasActions" }] : /* istanbul ignore next */ []));
|
|
7424
|
-
moreLabel = computed(() =>
|
|
7801
|
+
moreLabel = computed(() => this.format(this.m().moreActionsFor, this.m().moreActions), /* @ts-ignore */
|
|
7425
7802
|
...(ngDevMode ? [{ debugName: "moreLabel" }] : /* istanbul ignore next */ []));
|
|
7426
|
-
groupLabel = computed(() =>
|
|
7803
|
+
groupLabel = computed(() => this.format(this.m().actionsFor, this.m().actions), /* @ts-ignore */
|
|
7427
7804
|
...(ngDevMode ? [{ debugName: "groupLabel" }] : /* istanbul ignore next */ []));
|
|
7805
|
+
format(withName, withoutName) {
|
|
7806
|
+
const name = (this.rowLabel() ?? '').trim();
|
|
7807
|
+
return name ? withName.split('{name}').join(name) : withoutName;
|
|
7808
|
+
}
|
|
7428
7809
|
onMenuItem(item) {
|
|
7429
7810
|
if (!item || item.disabled) {
|
|
7430
7811
|
return;
|
|
@@ -7437,7 +7818,7 @@ class RowActionsComponent {
|
|
|
7437
7818
|
this.triggered.emit({ id: item.action.id, action: item.action });
|
|
7438
7819
|
}
|
|
7439
7820
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: RowActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7440
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: RowActionsComponent, isStandalone: true, selector: "mm-row-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: true, transformFunction: null }, rowLabel: { classPropertyName: "rowLabel", publicName: "rowLabel", isSignal: true, isRequired: true, transformFunction: null }, maxInline: { classPropertyName: "maxInline", publicName: "maxInline", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { triggered: "triggered" }, host: { properties: { "attr.role": "hasActions() ? \"group\" : null", "attr.aria-label": "hasActions() ? groupLabel() : null" }, classAttribute: "mm-row-actions" }, ngImport: i0, template: `
|
|
7821
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: RowActionsComponent, isStandalone: true, selector: "mm-row-actions", inputs: { actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: true, transformFunction: null }, rowLabel: { classPropertyName: "rowLabel", publicName: "rowLabel", isSignal: true, isRequired: true, transformFunction: null }, maxInline: { classPropertyName: "maxInline", publicName: "maxInline", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { triggered: "triggered" }, host: { properties: { "attr.role": "hasActions() ? \"group\" : null", "attr.aria-label": "hasActions() ? groupLabel() : null" }, classAttribute: "mm-row-actions" }, ngImport: i0, template: `
|
|
7441
7822
|
@for (action of split().inline; track action.id) {
|
|
7442
7823
|
<mm-action-button [action]="action" [targetLabel]="rowLabel()" context="row" display="icon"
|
|
7443
7824
|
(triggered)="triggered.emit($event)" />
|
|
@@ -7510,7 +7891,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
7510
7891
|
</kendo-dropdownbutton>
|
|
7511
7892
|
}
|
|
7512
7893
|
`, styles: [".mm-row-actions{display:inline-flex;align-items:center;gap:var(--theme-space-1, 4px)}.mm-row-actions__item{display:inline-flex;align-items:flex-start;gap:var(--theme-space-2, 8px)}.mm-row-actions__item-text{display:inline-flex;flex-direction:column}.mm-row-actions__item-reason{font-size:.85em;color:var(--theme-text-muted, #75829a);white-space:normal;max-width:280px}.mm-row-actions__item--danger{color:var(--theme-status-error, #c0385f)}.mm-row-actions__more .k-button:focus-visible{outline:none;box-shadow:var(--theme-focus-ring, 0 0 0 2px #ffffff, 0 0 0 4px #2e8473)}\n"] }]
|
|
7513
|
-
}], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: true }] }], rowLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowLabel", required: true }] }], maxInline: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxInline", required: false }] }], triggered: [{ type: i0.Output, args: ["triggered"] }] } });
|
|
7894
|
+
}], propDecorators: { actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: true }] }], rowLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowLabel", required: true }] }], maxInline: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxInline", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], triggered: [{ type: i0.Output, args: ["triggered"] }] } });
|
|
7514
7895
|
|
|
7515
7896
|
/*
|
|
7516
7897
|
* Public API Surface of shared-ui
|
|
@@ -7535,5 +7916,5 @@ function provideMmSharedUi() {
|
|
|
7535
7916
|
* Generated bundle index. Do not edit.
|
|
7536
7917
|
*/
|
|
7537
7918
|
|
|
7538
|
-
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_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_SAVE_AS_DIALOG_MESSAGES, DEFAULT_TIME_RANGE_LABELS, DangerConfirmationResult, DangerConfirmationWindowComponent, DataSourceBase, DataSourceTyped, DialogType, 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_ROW_ACTIONS_MAX_INLINE, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmListViewDataBindingDirective, NOTIFICATION_DISPLAY_OPTIONS, NotificationDisplayService, 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, isActionDisabled, isActionVisible, provideMmSharedUi, resolveListRowAction, resolveListViewMessages, sameAction, splitRowActions };
|
|
7919
|
+
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_ROW_ACTIONS_MAX_INLINE, MM_ROW_ACTIONS_MESSAGES, MessageDetailsDialogComponent, MessageDetailsDialogService, MessageListenerService, MmListViewDataBindingDirective, 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, isActionDisabled, isActionVisible, provideMmSharedUi, resolveListRowAction, resolveListRowLabel, resolveListViewMessages, resolveRowActionsMessages, sameAction, splitRowActions };
|
|
7539
7920
|
//# sourceMappingURL=meshmakers-shared-ui.mjs.map
|