@truenas/ui-components 0.8.15 → 0.8.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Overlay, OverlayModule, OverlayPositionBuilder, createGlobalPositionStrategy, createNoopScrollStrategy, createOverlayRef } from "@angular/cdk/overlay";
|
|
2
2
|
import { ComponentPortal, DomPortal, PortalModule, TemplatePortal } from "@angular/cdk/portal";
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
|
-
import { ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Directive, ElementRef, EnvironmentInjector, HostListener, Injectable, InjectionToken, Injector, LOCALE_ID, NgZone, PLATFORM_ID, Pipe, Renderer2, TemplateRef, ViewContainerRef, ViewEncapsulation, afterEveryRender, afterNextRender, booleanAttribute, computed, contentChild, contentChildren, createComponent, effect, forwardRef, inject, input, isDevMode, isSignal, linkedSignal, model, output, signal, untracked, viewChild, viewChildren } from "@angular/core";
|
|
4
|
+
import { ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, Directive, ElementRef, EnvironmentInjector, HostListener, Injectable, InjectionToken, Injector, LOCALE_ID, NgZone, PLATFORM_ID, Pipe, Renderer2, TemplateRef, ViewContainerRef, ViewEncapsulation, afterEveryRender, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, contentChildren, createComponent, effect, forwardRef, inject, input, isDevMode, isSignal, linkedSignal, model, output, signal, untracked, viewChild, viewChildren } from "@angular/core";
|
|
5
5
|
import * as i1 from "@angular/forms";
|
|
6
6
|
import { FormsModule, NG_VALUE_ACCESSOR, NgControl, Validators } from "@angular/forms";
|
|
7
7
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
|
@@ -26717,6 +26717,39 @@ var TnStepperHarness = class TnStepperHarness extends ComponentHarness {
|
|
|
26717
26717
|
return await (await this.locatorFor(".tn-stepper")()).hasClass("tn-stepper--vertical") ? "vertical" : "horizontal";
|
|
26718
26718
|
}
|
|
26719
26719
|
};
|
|
26720
|
+
const TN_FILE_PICKER_DEFAULT_LABELS = {
|
|
26721
|
+
placeholder: "Select file or folder",
|
|
26722
|
+
openPicker: "Open file picker",
|
|
26723
|
+
breadcrumb: "File path",
|
|
26724
|
+
navigateTo: (path) => `Navigate to ${path}`,
|
|
26725
|
+
loading: "Loading...",
|
|
26726
|
+
noItems: "No items found",
|
|
26727
|
+
selectColumn: "Select",
|
|
26728
|
+
selectItem: (name) => `Select ${name}`,
|
|
26729
|
+
openItem: (name) => `Open ${name}`,
|
|
26730
|
+
nameColumn: "Name",
|
|
26731
|
+
sizeColumn: "Size",
|
|
26732
|
+
modifiedColumn: "Modified",
|
|
26733
|
+
itemsSelected: (count) => `${count} item${count !== 1 ? "s" : ""} selected`,
|
|
26734
|
+
currentDirectorySelected: "Current directory selected",
|
|
26735
|
+
noItemsSelected: "No items selected",
|
|
26736
|
+
clearSelection: "Clear Selection",
|
|
26737
|
+
select: "Select",
|
|
26738
|
+
inlineCreateName: (actionLabel) => `${actionLabel} name`,
|
|
26739
|
+
inlineCreateFailed: "Creation failed",
|
|
26740
|
+
today: (time) => `Today ${time}`,
|
|
26741
|
+
yesterday: (time) => `Yesterday ${time}`,
|
|
26742
|
+
pathOutsideRoot: (rootPath) => `Path is outside of ${rootPath}`,
|
|
26743
|
+
invalidPath: (path) => `Invalid path: ${path}`,
|
|
26744
|
+
pathValidationFailed: "Path validation failed",
|
|
26745
|
+
loadFailed: "Failed to load directory",
|
|
26746
|
+
createFailed: "Failed to create item",
|
|
26747
|
+
createdOutsideRoot: (rootPath) => `Created item is outside of ${rootPath}`
|
|
26748
|
+
};
|
|
26749
|
+
const TN_FILE_PICKER_LABELS = new InjectionToken("TN_FILE_PICKER_LABELS", {
|
|
26750
|
+
providedIn: "root",
|
|
26751
|
+
factory: () => TN_FILE_PICKER_DEFAULT_LABELS
|
|
26752
|
+
});
|
|
26720
26753
|
function getSelectableTypes(mode) {
|
|
26721
26754
|
if (Array.isArray(mode)) return mode;
|
|
26722
26755
|
return mode === "any" ? null : [mode];
|
|
@@ -26829,28 +26862,26 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26829
26862
|
errorMessage = input(null, ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
26830
26863
|
fileExtensions = input(void 0, ...ngDevMode ? [{ debugName: "fileExtensions" }] : /* istanbul ignore next */ []);
|
|
26831
26864
|
testIdBase = input(void 0, ...ngDevMode ? [{ debugName: "testIdBase" }] : /* istanbul ignore next */ []);
|
|
26865
|
+
labels = injectTnLabels(TN_FILE_PICKER_LABELS);
|
|
26832
26866
|
iconRegistry = inject(TnIconRegistryService);
|
|
26833
26867
|
elementRef = inject(ElementRef);
|
|
26834
26868
|
constructor() {
|
|
26835
26869
|
registerTruenasIcons(this.iconRegistry);
|
|
26870
|
+
afterRenderEffect(() => {
|
|
26871
|
+
if (!this.creationFocusRequested()) return;
|
|
26872
|
+
const creation = this.inlineCreation();
|
|
26873
|
+
if (!creation) {
|
|
26874
|
+
this.creationFocusRequested.set(false);
|
|
26875
|
+
return;
|
|
26876
|
+
}
|
|
26877
|
+
if (creation.loading) return;
|
|
26878
|
+
const nameInput = this.elementRef.nativeElement.querySelector(".inline-create-input");
|
|
26879
|
+
if (!nameInput || nameInput.disabled) return;
|
|
26880
|
+
nameInput.focus();
|
|
26881
|
+
this.creationFocusRequested.set(false);
|
|
26882
|
+
});
|
|
26836
26883
|
}
|
|
26837
|
-
|
|
26838
|
-
ngAfterViewChecked() {
|
|
26839
|
-
if (!this.pendingCreationFocus) return;
|
|
26840
|
-
const creation = this.inlineCreation();
|
|
26841
|
-
if (!creation) {
|
|
26842
|
-
this.pendingCreationFocus = false;
|
|
26843
|
-
return;
|
|
26844
|
-
}
|
|
26845
|
-
if (creation.loading) return;
|
|
26846
|
-
const nameInput = this.elementRef.nativeElement.querySelector(".inline-create-input");
|
|
26847
|
-
if (!nameInput) return;
|
|
26848
|
-
if (document.activeElement === nameInput) {
|
|
26849
|
-
this.pendingCreationFocus = false;
|
|
26850
|
-
return;
|
|
26851
|
-
}
|
|
26852
|
-
setTimeout(() => nameInput.focus());
|
|
26853
|
-
}
|
|
26884
|
+
creationFocusRequested = signal(false, ...ngDevMode ? [{ debugName: "creationFocusRequested" }] : /* istanbul ignore next */ []);
|
|
26854
26885
|
itemClick = output();
|
|
26855
26886
|
itemDoubleClick = output();
|
|
26856
26887
|
pathNavigate = output();
|
|
@@ -26866,6 +26897,7 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26866
26897
|
"size",
|
|
26867
26898
|
"modified"
|
|
26868
26899
|
];
|
|
26900
|
+
emptyIcon = tnIconMarker("folder-open", "mdi");
|
|
26869
26901
|
allowCurrentDirectorySelection = computed(() => allowsCurrentDirectorySelection(this.mode()), ...ngDevMode ? [{ debugName: "allowCurrentDirectorySelection" }] : /* istanbul ignore next */ []);
|
|
26870
26902
|
baseSegments = computed(() => {
|
|
26871
26903
|
const base = this.testIdBase();
|
|
@@ -26943,7 +26975,7 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26943
26975
|
name: "",
|
|
26944
26976
|
loading: false
|
|
26945
26977
|
});
|
|
26946
|
-
this.
|
|
26978
|
+
this.creationFocusRequested.set(true);
|
|
26947
26979
|
return;
|
|
26948
26980
|
}
|
|
26949
26981
|
this.createAction.emit({
|
|
@@ -26974,13 +27006,13 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26974
27006
|
this.created.emit(createdPath);
|
|
26975
27007
|
} catch (err) {
|
|
26976
27008
|
if (this.inlineCreation() !== pending) return;
|
|
26977
|
-
const message = err instanceof Error ? err.message :
|
|
27009
|
+
const message = err instanceof Error ? err.message : this.labels().inlineCreateFailed;
|
|
26978
27010
|
this.inlineCreation.set({
|
|
26979
27011
|
...pending,
|
|
26980
27012
|
loading: false,
|
|
26981
27013
|
error: message
|
|
26982
27014
|
});
|
|
26983
|
-
this.
|
|
27015
|
+
this.creationFocusRequested.set(true);
|
|
26984
27016
|
}
|
|
26985
27017
|
}
|
|
26986
27018
|
onInlineCreationKeyDown(event) {
|
|
@@ -27070,10 +27102,10 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
27070
27102
|
minute: "2-digit",
|
|
27071
27103
|
hour12: true
|
|
27072
27104
|
});
|
|
27073
|
-
if (itemDate.getTime() === today.getTime()) return
|
|
27105
|
+
if (itemDate.getTime() === today.getTime()) return this.labels().today(timePart);
|
|
27074
27106
|
const yesterday = new Date(today);
|
|
27075
27107
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
27076
|
-
if (itemDate.getTime() === yesterday.getTime()) return
|
|
27108
|
+
if (itemDate.getTime() === yesterday.getTime()) return this.labels().yesterday(timePart);
|
|
27077
27109
|
if (date.getFullYear() === now.getFullYear()) return `${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")} ${timePart}`;
|
|
27078
27110
|
return `${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")}/${date.getFullYear()} ${timePart}`;
|
|
27079
27111
|
}
|
|
@@ -27183,8 +27215,8 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
27183
27215
|
},
|
|
27184
27216
|
host: { classAttribute: "tn-file-picker-popup" },
|
|
27185
27217
|
ngImport: i0,
|
|
27186
|
-
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"
|
|
27187
|
-
styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.tn-file-picker-error{display:flex;align-items:center;gap:6px;margin:8px var(--tn-content-padding, 24px) 0;padding:6px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-error .error-icon{flex-shrink:0}.tn-file-picker-error .error-text{flex:1}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);border:1px solid transparent;font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.
|
|
27218
|
+
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" [attr.aria-label]=\"labels().breadcrumb\">\n @for (segment of currentPath() | tnTruncatePath : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? labels().navigateTo(segment.path) : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\n</div>\n\n<!-- Failed listing or creation, reported by the owning picker -->\n@if (errorMessage(); as message) {\n <div\n class=\"tn-file-picker-error\"\n role=\"alert\"\n tnTestIdType=\"text\"\n [tnTestId]=\"errorTestId()\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ message }}</span>\n </div>\n}\n\n<!-- Loading indicator -->\n@if (loading()) {\n <div class=\"tn-file-picker-loading\">\n <tn-icon name=\"loading\" library=\"mdi\" />\n <span>{{ labels().loading }}</span>\n </div>\n}\n\n<!-- File table -->\n@if (!loading()) {\n <div class=\"tn-file-picker-content\">\n\n <tn-table\n [emptyMessage]=\"labels().noItems\"\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n [emptyIcon]=\"emptyIcon\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <!-- `hideLabel` rather than an empty `tnHeaderCellDef`: a <th> with no\n text fails axe `empty-table-header`, which is what the Storybook a11y\n run reported on Components/File Picker > Multi Select Workflow\n (#337). The empty template that used to sit here OVERRODE the header,\n so the column was unnamed for anyone reading the header row too —\n `hideLabel` renders the label into a `.cdk-visually-hidden` span\n instead, which is the same route tn-table's own row-actions column\n takes (#246). There is no select-all control, so the name describes\n what the column holds. -->\n <ng-container tnColumnDef=\"select\" width=\"20px\" [label]=\"labels().selectColumn\" [hideLabel]=\"true\">\n <ng-template let-item tnCellDef>\n @if (!item.inlineCreate) {\n <tn-checkbox\n [hideLabel]=\"true\"\n [label]=\"labels().selectItem(item.name)\"\n [testId]=\"itemTestId(item)\"\n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\" />\n }\n </ng-template>\n </ng-container>\n }\n\n <!-- Name column -->\n <ng-container tnColumnDef=\"name\">\n <ng-template tnHeaderCellDef>{{ labels().nameColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n\n <!-- Inline creation row for create actions with a `create` callback -->\n @if (item.inlineCreate) {\n @if (inlineCreation(); as creation) {\n <div class=\"inline-create-cell\">\n <div class=\"inline-create-row\" [class.has-error]=\"!!creation.error\">\n <tn-icon class=\"file-icon\" [name]=\"creation.action.icon || 'mdi-folder'\" />\n <input\n type=\"text\"\n class=\"inline-create-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n tnTestIdType=\"input\"\n [tnTestId]=\"inlineCreateTestId()\"\n [attr.aria-label]=\"labels().inlineCreateName(creation.action.label)\"\n [attr.aria-invalid]=\"creation.error ? true : null\"\n [attr.aria-describedby]=\"creation.error ? inlineErrorId : null\"\n [class.error]=\"!!creation.error\"\n [disabled]=\"creation.loading\"\n [value]=\"creation.name\"\n (input)=\"onInlineCreationInput($event)\"\n (keydown)=\"onInlineCreationKeyDown($event)\"\n (blur)=\"onInlineCreationBlur()\">\n @if (creation.loading) {\n <tn-icon name=\"mdi-loading\" class=\"creation-loading-icon\" aria-hidden=\"true\" />\n }\n </div>\n @if (creation.error) {\n <div class=\"inline-create-error\" role=\"alert\" [id]=\"inlineErrorId\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ creation.error }}</span>\n </div>\n }\n </div>\n }\n } @else {\n <div\n class=\"file-name-cell\"\n tnTestIdType=\"option\"\n [tnTestId]=\"itemTestId(item)\"\n [class.selected]=\"isSelected(item)\"\n [class.disabled]=\"!!item.dimmed\"\n [class.zfs-object]=\"isZfsObject(item)\">\n <tn-icon\n [name]=\"getItemIcon(item)\"\n [class]=\"'file-icon file-icon-' + item.type\" />\n <span class=\"file-name\">{{ item.name }}</span>\n\n <!-- ZFS badge -->\n @if (isZfsObject(item)) {\n <span\n [class]=\"'zfs-badge zfs-badge-' + item.type\">\n {{ getZfsBadge(item) }}\n </span>\n }\n\n <!-- Permission indicator -->\n @if (item.permissions === 'none') {\n <tn-icon\n name=\"lock\"\n library=\"mdi\"\n class=\"permission-icon\" />\n }\n\n <!-- Navigation affordance: single click opens the directory -->\n @if (isNavigatable(item)) {\n <button\n type=\"button\"\n class=\"navigate-button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"navigateTestId(item)\"\n [attr.aria-label]=\"labels().openItem(item.name)\"\n [attr.title]=\"labels().openItem(item.name)\"\n (click)=\"onNavigateClick($event, item)\"\n (dblclick)=\"$event.stopPropagation()\">\n <tn-icon name=\"mdi-chevron-right\" size=\"sm\" />\n </button>\n }\n </div>\n }\n </ng-template>\n </ng-container>\n\n <!-- Size column -->\n <ng-container tnColumnDef=\"size\">\n <ng-template tnHeaderCellDef>{{ labels().sizeColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.size !== undefined) {\n <span>{{ item.size | tnFileSize }}</span>\n }\n @if (item.size === undefined && item.type === 'folder') {\n <span class=\"folder-indicator\">--</span>\n }\n </ng-template>\n </ng-container>\n\n <!-- Modified column -->\n <ng-container tnColumnDef=\"modified\">\n <ng-template tnHeaderCellDef>{{ labels().modifiedColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.modified) {\n <span>{{ formatDate(item.modified) }}</span>\n }\n </ng-template>\n </ng-container>\n\n\n </tn-table>\n\n </div>\n}\n\n<!-- Footer -->\n@if (!loading()) {\n <div class=\"tn-file-picker-footer\">\n <div class=\"footer-selection\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ labels().itemsSelected(selectedItems().length) }}\n </span>\n <tn-button\n variant=\"outline\"\n [label]=\"labels().clearSelection\"\n [testId]=\"clearSelectionTestId()\"\n (onClick)=\"onClearSelection()\" />\n } @else if (allowCurrentDirectorySelection()) {\n <span class=\"selection-count current-directory-selection\">\n {{ labels().currentDirectorySelected }}\n </span>\n } @else {\n <span class=\"selection-count\">\n {{ labels().noItemsSelected }}\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n @for (action of createActions(); track action.id) {\n <tn-button\n variant=\"outline\"\n [label]=\"action.label\"\n [testId]=\"createActionTestId(action)\"\n [disabled]=\"!!inlineCreation()\"\n (onClick)=\"onCreateAction(action)\" />\n }\n <!-- Disabled while the inline creation row is open: its blur auto-submit\n would race the selection submit -->\n <tn-button\n [label]=\"labels().select\"\n [testId]=\"selectTestId()\"\n [disabled]=\"(selectedItems().length === 0 && !allowCurrentDirectorySelection()) || !!inlineCreation()\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}",
|
|
27219
|
+
styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.tn-file-picker-error{display:flex;align-items:center;gap:6px;margin:8px var(--tn-content-padding, 24px) 0;padding:6px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-error .error-icon{flex-shrink:0}.tn-file-picker-error .error-text{flex:1}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);border:1px solid transparent;font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.tn-file-picker-footer{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px var(--tn-content-padding, 24px);border-top:1px solid var(--tn-lines);background:var(--tn-bg2);border-bottom-left-radius:8px;border-bottom-right-radius:8px}.tn-file-picker-footer .footer-selection{display:flex;align-items:center;gap:12px}.selection-count{font-size:1rem;color:var(--tn-fg2);font-weight:500}.footer-actions{display:flex;gap:8px}@media(prefers-reduced-motion:reduce){.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){:host{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge,.zfs-badge.zfs-badge-dataset,.zfs-badge.zfs-badge-zvol,.zfs-badge.zfs-badge-mountpoint{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"],
|
|
27188
27220
|
dependencies: [
|
|
27189
27221
|
{
|
|
27190
27222
|
kind: "component",
|
|
@@ -27371,8 +27403,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
27371
27403
|
],
|
|
27372
27404
|
changeDetection: ChangeDetectionStrategy.Eager,
|
|
27373
27405
|
host: { "class": "tn-file-picker-popup" },
|
|
27374
|
-
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"
|
|
27375
|
-
styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.tn-file-picker-error{display:flex;align-items:center;gap:6px;margin:8px var(--tn-content-padding, 24px) 0;padding:6px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-error .error-icon{flex-shrink:0}.tn-file-picker-error .error-text{flex:1}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);border:1px solid transparent;font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.
|
|
27406
|
+
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" [attr.aria-label]=\"labels().breadcrumb\">\n @for (segment of currentPath() | tnTruncatePath : rootPath(); track $index; let last = $last) {\n <button\n class=\"breadcrumb-segment\"\n tnTestIdType=\"button\"\n [tnTestId]=\"breadcrumbTestId(segment.name)\"\n [class.current]=\"last\"\n [class.nameless]=\"!segment.name\"\n [disabled]=\"last\"\n [attr.aria-label]=\"segment.name === '…' || !segment.name ? labels().navigateTo(segment.path) : null\"\n (click)=\"navigateToPath(segment.path)\">\n {{ segment.name }}\n </button>\n }\n </nav>\n</div>\n\n<!-- Failed listing or creation, reported by the owning picker -->\n@if (errorMessage(); as message) {\n <div\n class=\"tn-file-picker-error\"\n role=\"alert\"\n tnTestIdType=\"text\"\n [tnTestId]=\"errorTestId()\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ message }}</span>\n </div>\n}\n\n<!-- Loading indicator -->\n@if (loading()) {\n <div class=\"tn-file-picker-loading\">\n <tn-icon name=\"loading\" library=\"mdi\" />\n <span>{{ labels().loading }}</span>\n </div>\n}\n\n<!-- File table -->\n@if (!loading()) {\n <div class=\"tn-file-picker-content\">\n\n <tn-table\n [emptyMessage]=\"labels().noItems\"\n [dataSource]=\"filteredFileItems()\"\n [displayedColumns]=\"multiSelect() ? displayedColumns : displayedColumns.slice(1)\"\n [clickable]=\"true\"\n [activeWhen]=\"isRowSelected\"\n [emptyIcon]=\"emptyIcon\"\n (rowClick)=\"onItemClick($event)\"\n (rowDoubleClick)=\"onItemDoubleClick($event)\">\n\n <!-- Selection column: explicit width so the auto table layout doesn't\n hand the near-empty column a share of the spare width -->\n @if (multiSelect()) {\n <!-- `hideLabel` rather than an empty `tnHeaderCellDef`: a <th> with no\n text fails axe `empty-table-header`, which is what the Storybook a11y\n run reported on Components/File Picker > Multi Select Workflow\n (#337). The empty template that used to sit here OVERRODE the header,\n so the column was unnamed for anyone reading the header row too —\n `hideLabel` renders the label into a `.cdk-visually-hidden` span\n instead, which is the same route tn-table's own row-actions column\n takes (#246). There is no select-all control, so the name describes\n what the column holds. -->\n <ng-container tnColumnDef=\"select\" width=\"20px\" [label]=\"labels().selectColumn\" [hideLabel]=\"true\">\n <ng-template let-item tnCellDef>\n @if (!item.inlineCreate) {\n <tn-checkbox\n [hideLabel]=\"true\"\n [label]=\"labels().selectItem(item.name)\"\n [testId]=\"itemTestId(item)\"\n [checked]=\"isSelected(item)\"\n [disabled]=\"!!item.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onItemClick(item)\" />\n }\n </ng-template>\n </ng-container>\n }\n\n <!-- Name column -->\n <ng-container tnColumnDef=\"name\">\n <ng-template tnHeaderCellDef>{{ labels().nameColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n\n <!-- Inline creation row for create actions with a `create` callback -->\n @if (item.inlineCreate) {\n @if (inlineCreation(); as creation) {\n <div class=\"inline-create-cell\">\n <div class=\"inline-create-row\" [class.has-error]=\"!!creation.error\">\n <tn-icon class=\"file-icon\" [name]=\"creation.action.icon || 'mdi-folder'\" />\n <input\n type=\"text\"\n class=\"inline-create-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n tnTestIdType=\"input\"\n [tnTestId]=\"inlineCreateTestId()\"\n [attr.aria-label]=\"labels().inlineCreateName(creation.action.label)\"\n [attr.aria-invalid]=\"creation.error ? true : null\"\n [attr.aria-describedby]=\"creation.error ? inlineErrorId : null\"\n [class.error]=\"!!creation.error\"\n [disabled]=\"creation.loading\"\n [value]=\"creation.name\"\n (input)=\"onInlineCreationInput($event)\"\n (keydown)=\"onInlineCreationKeyDown($event)\"\n (blur)=\"onInlineCreationBlur()\">\n @if (creation.loading) {\n <tn-icon name=\"mdi-loading\" class=\"creation-loading-icon\" aria-hidden=\"true\" />\n }\n </div>\n @if (creation.error) {\n <div class=\"inline-create-error\" role=\"alert\" [id]=\"inlineErrorId\">\n <tn-icon name=\"mdi-alert-circle\" class=\"error-icon\" aria-hidden=\"true\" />\n <span class=\"error-text\">{{ creation.error }}</span>\n </div>\n }\n </div>\n }\n } @else {\n <div\n class=\"file-name-cell\"\n tnTestIdType=\"option\"\n [tnTestId]=\"itemTestId(item)\"\n [class.selected]=\"isSelected(item)\"\n [class.disabled]=\"!!item.dimmed\"\n [class.zfs-object]=\"isZfsObject(item)\">\n <tn-icon\n [name]=\"getItemIcon(item)\"\n [class]=\"'file-icon file-icon-' + item.type\" />\n <span class=\"file-name\">{{ item.name }}</span>\n\n <!-- ZFS badge -->\n @if (isZfsObject(item)) {\n <span\n [class]=\"'zfs-badge zfs-badge-' + item.type\">\n {{ getZfsBadge(item) }}\n </span>\n }\n\n <!-- Permission indicator -->\n @if (item.permissions === 'none') {\n <tn-icon\n name=\"lock\"\n library=\"mdi\"\n class=\"permission-icon\" />\n }\n\n <!-- Navigation affordance: single click opens the directory -->\n @if (isNavigatable(item)) {\n <button\n type=\"button\"\n class=\"navigate-button\"\n tnTestIdType=\"button\"\n [tnTestId]=\"navigateTestId(item)\"\n [attr.aria-label]=\"labels().openItem(item.name)\"\n [attr.title]=\"labels().openItem(item.name)\"\n (click)=\"onNavigateClick($event, item)\"\n (dblclick)=\"$event.stopPropagation()\">\n <tn-icon name=\"mdi-chevron-right\" size=\"sm\" />\n </button>\n }\n </div>\n }\n </ng-template>\n </ng-container>\n\n <!-- Size column -->\n <ng-container tnColumnDef=\"size\">\n <ng-template tnHeaderCellDef>{{ labels().sizeColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.size !== undefined) {\n <span>{{ item.size | tnFileSize }}</span>\n }\n @if (item.size === undefined && item.type === 'folder') {\n <span class=\"folder-indicator\">--</span>\n }\n </ng-template>\n </ng-container>\n\n <!-- Modified column -->\n <ng-container tnColumnDef=\"modified\">\n <ng-template tnHeaderCellDef>{{ labels().modifiedColumn }}</ng-template>\n <ng-template let-item tnCellDef>\n @if (item.modified) {\n <span>{{ formatDate(item.modified) }}</span>\n }\n </ng-template>\n </ng-container>\n\n\n </tn-table>\n\n </div>\n}\n\n<!-- Footer -->\n@if (!loading()) {\n <div class=\"tn-file-picker-footer\">\n <div class=\"footer-selection\">\n @if (selectedItems().length > 0) {\n <span class=\"selection-count\">\n {{ labels().itemsSelected(selectedItems().length) }}\n </span>\n <tn-button\n variant=\"outline\"\n [label]=\"labels().clearSelection\"\n [testId]=\"clearSelectionTestId()\"\n (onClick)=\"onClearSelection()\" />\n } @else if (allowCurrentDirectorySelection()) {\n <span class=\"selection-count current-directory-selection\">\n {{ labels().currentDirectorySelected }}\n </span>\n } @else {\n <span class=\"selection-count\">\n {{ labels().noItemsSelected }}\n </span>\n }\n </div>\n <div class=\"footer-actions\">\n @for (action of createActions(); track action.id) {\n <tn-button\n variant=\"outline\"\n [label]=\"action.label\"\n [testId]=\"createActionTestId(action)\"\n [disabled]=\"!!inlineCreation()\"\n (onClick)=\"onCreateAction(action)\" />\n }\n <!-- Disabled while the inline creation row is open: its blur auto-submit\n would race the selection submit -->\n <tn-button\n [label]=\"labels().select\"\n [testId]=\"selectTestId()\"\n [disabled]=\"(selectedItems().length === 0 && !allowCurrentDirectorySelection()) || !!inlineCreation()\"\n (onClick)=\"onSubmit()\" />\n </div>\n </div>\n}",
|
|
27407
|
+
styles: [":host{display:block;background:var(--tn-bg1, white);color:var(--tn-fg1, #333);padding:0;box-shadow:0 4px 16px #0000001f,0 1px 4px #00000014;border-radius:8px;border:1px solid var(--tn-lines, #e0e0e0);width:520px;max-width:calc(100vw - 32px);min-height:min(500px,100vh - 16px);max-height:min(600px,100vh - 16px);font-family:var(--tn-font-family-body);display:flex;flex-direction:column;overflow:hidden}.tn-file-picker-header{display:flex;align-items:center;justify-content:space-between;padding:var(--tn-content-padding, 24px);padding-bottom:16px;border-bottom:1px solid var(--tn-lines)}.tn-file-picker-breadcrumb{display:flex;align-items:center;flex:1;min-width:0}.tn-file-picker-breadcrumb .breadcrumb-segment{background:transparent;border:none;color:var(--tn-primary-text, var(--tn-primary, #0074a7));cursor:pointer;padding:4px 2px;border-radius:4px;font-size:1rem;white-space:nowrap;transition:background-color .15s ease-in-out}.tn-file-picker-breadcrumb .breadcrumb-segment:hover:not(:disabled){background:var(--tn-bg2)}.tn-file-picker-breadcrumb .breadcrumb-segment:disabled,.tn-file-picker-breadcrumb .breadcrumb-segment.current{color:var(--tn-fg1);cursor:default;font-weight:500}.tn-file-picker-breadcrumb .breadcrumb-segment:not(:last-child):after{content:\"/\";margin-left:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment:first-child:before{content:\"/\";margin-right:2px;color:var(--tn-alt-fg1)}.tn-file-picker-breadcrumb .breadcrumb-segment.nameless:not(:last-child):after{content:none}.tn-file-picker-loading{display:flex;align-items:center;justify-content:center;gap:8px;padding:40px;color:var(--tn-fg2)}.tn-file-picker-loading tn-icon{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.tn-file-picker-content{flex:1;min-height:0;overflow-y:auto}.inline-create-cell{display:flex;flex-direction:column;gap:4px;flex:1;min-width:0}.inline-create-row{display:flex;align-items:center;gap:8px}.inline-create-row .inline-create-input{flex:1;padding:4px 8px;border:2px solid var(--tn-primary);border-radius:3px;background:var(--tn-bg1);color:var(--tn-fg1);font-size:inherit;font-family:inherit;outline:none;min-width:0}.inline-create-row .inline-create-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-row .inline-create-input:disabled{opacity:.6;cursor:not-allowed;background:var(--tn-bg2)}.inline-create-row .creation-loading-icon{animation:spin 1s linear infinite;color:var(--tn-primary);flex-shrink:0}.tn-file-picker-error{display:flex;align-items:center;gap:6px;margin:8px var(--tn-content-padding, 24px) 0;padding:6px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-error .error-icon{flex-shrink:0}.tn-file-picker-error .error-text{flex:1}.inline-create-error{display:flex;align-items:center;gap:6px;margin-top:4px;padding:4px 8px;background:color-mix(in srgb,var(--tn-error, var(--tn-red, #bd2626)) 10%,transparent);border-left:3px solid var(--tn-error, var(--tn-red, #bd2626));border-radius:3px;font-size:1rem;color:var(--tn-error, var(--tn-red, #bd2626))}.inline-create-error .error-icon{flex-shrink:0}.inline-create-error .error-text{flex:1}.file-list-viewport{width:100%;height:100%}.file-list-viewport .cdk-virtual-scroll-content-wrapper{width:100%}tn-table{width:100%}tn-table th,tn-table .tn-table__header-cell{font-weight:600;padding:12px 16px;border-bottom:2px solid var(--tn-lines)}tn-table td,tn-table .tn-table__cell{padding:8px 16px;border-bottom:1px solid var(--tn-lines)}.file-name-cell{display:flex;align-items:center;gap:8px;cursor:pointer}.file-name-cell.disabled{opacity:.5;color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-name{color:var(--tn-fg2, #757575)}.file-name-cell.disabled .file-icon{opacity:.6}.file-name-cell.disabled:has(.file-icon-folder),.file-name-cell.disabled:has(.file-icon-dataset),.file-name-cell.disabled:has(.file-icon-mountpoint){cursor:pointer}.file-name-cell.disabled:not(:has(.file-icon-folder)):not(:has(.file-icon-dataset)):not(:has(.file-icon-mountpoint)){cursor:not-allowed}.file-icon{display:flex;align-items:center;justify-content:center;font-size:var(--tn-icon-md, 20px);flex-shrink:0;line-height:1}.file-icon.file-icon-folder{color:var(--tn-primary)}.file-icon.file-icon-dataset{color:var(--tn-blue, #007db3)}.file-icon.file-icon-zvol{color:var(--tn-green, #71BF44)}.file-icon.file-icon-mountpoint{color:var(--tn-orange, #E68D37)}.file-name{flex:1;font-weight:500;line-height:1.4}.zfs-badge{display:inline-flex;align-items:center;background:var(--tn-alt-bg2);color:var(--tn-alt-fg2);border:1px solid transparent;font-size:.625rem;font-weight:600;padding:2px 6px;border-radius:12px;text-transform:uppercase;letter-spacing:.5px;line-height:1}.zfs-badge.zfs-badge-dataset{border-color:var(--tn-blue)}.zfs-badge.zfs-badge-zvol{border-color:var(--tn-green)}.zfs-badge.zfs-badge-mountpoint{border-color:var(--tn-orange)}.permission-icon{display:flex;align-items:center;justify-content:center;color:var(--tn-red);font-size:var(--tn-icon-sm, 16px);line-height:1}.navigate-button{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:2px;background:none;border:none;border-radius:4px;color:var(--tn-fg2);cursor:pointer}.navigate-button:hover,.navigate-button:focus-visible{background:var(--tn-bg3);color:var(--tn-primary)}.file-type{font-size:1rem;padding:2px 8px;border-radius:12px}.file-type.type-folder{background:var(--tn-alt-bg1);color:var(--tn-alt-fg2)}.file-type.type-file{background:var(--tn-bg2);color:var(--tn-fg2)}.file-type.type-dataset{background:#007db31a;color:var(--tn-blue)}.file-type.type-zvol{background:#71bf441a;color:var(--tn-green)}.file-type.type-mountpoint{background:#e68d371a;color:var(--tn-orange)}.folder-indicator{color:var(--tn-alt-fg1);font-style:italic}.tn-file-picker-footer{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px var(--tn-content-padding, 24px);border-top:1px solid var(--tn-lines);background:var(--tn-bg2);border-bottom-left-radius:8px;border-bottom-right-radius:8px}.tn-file-picker-footer .footer-selection{display:flex;align-items:center;gap:12px}.selection-count{font-size:1rem;color:var(--tn-fg2);font-weight:500}.footer-actions{display:flex;gap:8px}@media(prefers-reduced-motion:reduce){.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){:host{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge,.zfs-badge.zfs-badge-dataset,.zfs-badge.zfs-badge-zvol,.zfs-badge.zfs-badge-mountpoint{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"]
|
|
27376
27408
|
}]
|
|
27377
27409
|
}],
|
|
27378
27410
|
ctorParameters: () => [],
|
|
@@ -27511,7 +27543,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27511
27543
|
allowFreeText = input(false, ...ngDevMode ? [{ debugName: "allowFreeText" }] : /* istanbul ignore next */ []);
|
|
27512
27544
|
ariaLabel = input(void 0, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
27513
27545
|
openOnClick = input(false, ...ngDevMode ? [{ debugName: "openOnClick" }] : /* istanbul ignore next */ []);
|
|
27514
|
-
placeholder = input(
|
|
27546
|
+
placeholder = input(TN_FILE_PICKER_DEFAULT_LABELS.placeholder, ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
|
|
27515
27547
|
disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
|
|
27516
27548
|
readonly = input(false, ...ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []);
|
|
27517
27549
|
testId = input(void 0, ...ngDevMode ? [{ debugName: "testId" }] : /* istanbul ignore next */ []);
|
|
@@ -27542,6 +27574,11 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27542
27574
|
formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
|
|
27543
27575
|
fieldAria = injectTnFormFieldAria(this.ariaLabel);
|
|
27544
27576
|
listedItems = /* @__PURE__ */ new Map();
|
|
27577
|
+
labels = injectTnLabels(TN_FILE_PICKER_LABELS);
|
|
27578
|
+
resolvedPlaceholder = computed(() => {
|
|
27579
|
+
const placeholder = this.placeholder();
|
|
27580
|
+
return placeholder === TN_FILE_PICKER_DEFAULT_LABELS.placeholder ? this.labels().placeholder : placeholder;
|
|
27581
|
+
}, ...ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []);
|
|
27545
27582
|
isDisabled = computed(() => this.disabled() || this.formDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
|
|
27546
27583
|
effectiveCallbacks = computed(() => this.callbacks() ?? this.source()?.callbacks, ...ngDevMode ? [{ debugName: "effectiveCallbacks" }] : /* istanbul ignore next */ []);
|
|
27547
27584
|
effectiveStartPath = computed(() => this.startPath() ?? this.source()?.startPath ?? "/mnt", ...ngDevMode ? [{ debugName: "effectiveStartPath" }] : /* istanbul ignore next */ []);
|
|
@@ -27610,16 +27647,16 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27610
27647
|
return;
|
|
27611
27648
|
}
|
|
27612
27649
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27613
|
-
this.emitError("validation",
|
|
27650
|
+
this.emitError("validation", this.labels().pathOutsideRoot(this.effectiveRootPath()), path);
|
|
27614
27651
|
this.onTouched();
|
|
27615
27652
|
return;
|
|
27616
27653
|
}
|
|
27617
27654
|
const cb = this.effectiveCallbacks();
|
|
27618
27655
|
if (cb?.validatePath) cb.validatePath(path).then((isValid) => {
|
|
27619
27656
|
if (isValid) this.updateSelection(path);
|
|
27620
|
-
else this.emitError("validation",
|
|
27657
|
+
else this.emitError("validation", this.labels().invalidPath(path), path);
|
|
27621
27658
|
}).catch((err) => {
|
|
27622
|
-
this.emitError("validation", err.message ||
|
|
27659
|
+
this.emitError("validation", err.message || this.labels().pathValidationFailed, path);
|
|
27623
27660
|
});
|
|
27624
27661
|
else this.updateSelection(path);
|
|
27625
27662
|
}
|
|
@@ -27719,14 +27756,14 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27719
27756
|
try {
|
|
27720
27757
|
createdPath = await action.run(event.parentPath);
|
|
27721
27758
|
} catch (err) {
|
|
27722
|
-
this.emitError("creation", err instanceof Error ? err.message :
|
|
27759
|
+
this.emitError("creation", err instanceof Error ? err.message : this.labels().createFailed, event.parentPath);
|
|
27723
27760
|
return;
|
|
27724
27761
|
}
|
|
27725
27762
|
if (createdPath) await this.selectCreatedPath(createdPath);
|
|
27726
27763
|
}
|
|
27727
27764
|
async selectCreatedPath(path) {
|
|
27728
27765
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27729
|
-
this.emitError("creation",
|
|
27766
|
+
this.emitError("creation", this.labels().createdOutsideRoot(this.effectiveRootPath()), path);
|
|
27730
27767
|
return;
|
|
27731
27768
|
}
|
|
27732
27769
|
await this.selectPath(path);
|
|
@@ -27736,7 +27773,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27736
27773
|
}
|
|
27737
27774
|
async selectPath(path) {
|
|
27738
27775
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27739
|
-
this.emitError("validation",
|
|
27776
|
+
this.emitError("validation", this.labels().pathOutsideRoot(this.effectiveRootPath()), path);
|
|
27740
27777
|
return;
|
|
27741
27778
|
}
|
|
27742
27779
|
const parent = path.substring(0, path.lastIndexOf("/"));
|
|
@@ -27780,7 +27817,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27780
27817
|
this.clearStalePendingSelection(directoryChanged);
|
|
27781
27818
|
this.pathChange.emit(path);
|
|
27782
27819
|
} catch (err) {
|
|
27783
|
-
this.emitError("navigation", err instanceof Error ? err.message :
|
|
27820
|
+
this.emitError("navigation", err instanceof Error ? err.message : this.labels().loadFailed, path);
|
|
27784
27821
|
} finally {
|
|
27785
27822
|
this.loading.set(false);
|
|
27786
27823
|
}
|
|
@@ -28081,7 +28118,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
28081
28118
|
isSignal: true
|
|
28082
28119
|
}],
|
|
28083
28120
|
ngImport: i0,
|
|
28084
|
-
template: "<div class=\"tn-file-picker-container\" tnTestIdType=\"file-picker\" [tnTestId]=\"resolvedTestId()\">\n <div #wrapper ixInput class=\"tn-file-picker-wrapper\" style=\"padding-right: 40px;\">\n <input\n type=\"text\"\n class=\"tn-file-picker-input\"\n tnTestIdType=\"input\"\n [tnTestId]=\"resolvedTestId()\"\n [class.error]=\"hasError()\"\n [value]=\"selectedPath()\"\n [placeholder]=\"
|
|
28121
|
+
template: "<div class=\"tn-file-picker-container\" tnTestIdType=\"file-picker\" [tnTestId]=\"resolvedTestId()\">\n <div #wrapper ixInput class=\"tn-file-picker-wrapper\" style=\"padding-right: 40px;\">\n <input\n type=\"text\"\n class=\"tn-file-picker-input\"\n tnTestIdType=\"input\"\n [tnTestId]=\"resolvedTestId()\"\n [class.error]=\"hasError()\"\n [value]=\"selectedPath()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [readonly]=\"!allowManualInput() || readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"fieldAria.labelledby()\"\n [attr.aria-describedby]=\"fieldAria.describedby()\"\n [attr.aria-invalid]=\"fieldAria.invalid()\"\n [attr.aria-required]=\"fieldAria.required()\"\n [disabled]=\"isDisabled()\"\n (click)=\"onInputClick()\"\n (change)=\"onPathCommit($event)\">\n\n <button\n type=\"button\"\n class=\"tn-file-picker-toggle\"\n tnTestIdType=\"button\"\n [attr.aria-label]=\"labels().openPicker\"\n [tnTestId]=\"toggleTestId()\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"openFilePicker()\">\n <tn-icon name=\"folder\" library=\"mdi\" />\n </button>\n </div>\n \n <ng-template #filePickerTemplate>\n <tn-file-picker-popup\n class=\"tn-file-picker-popup\"\n tnTestIdType=\"file-picker-popup\"\n [tnTestId]=\"resolvedTestId()\"\n [testIdBase]=\"resolvedTestId()\"\n [mode]=\"mode()\"\n [multiSelect]=\"multiSelect()\"\n [createActions]=\"availableCreateActions()\"\n [currentPath]=\"currentPath()\"\n [rootPath]=\"effectiveRootPath()\"\n [fileItems]=\"fileItems()\"\n [selectedItems]=\"selectedItems()\"\n [loading]=\"loading()\"\n [errorMessage]=\"popupError()\"\n [fileExtensions]=\"fileExtensions()\"\n (itemClick)=\"onItemClick($event)\"\n (itemDoubleClick)=\"onItemDoubleClick($event)\"\n (pathNavigate)=\"navigateToPath($event)\"\n (createAction)=\"runCreateAction($event)\"\n (created)=\"onCreated($event)\"\n (clearSelection)=\"onClearSelection()\"\n (submit)=\"onSubmit()\"\n (cancel)=\"onCancel()\"\n (close)=\"close()\" />\n </ng-template>\n</div>",
|
|
28085
28122
|
styles: [":host{display:block;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-file-picker-container{position:relative;display:flex;align-items:center;width:100%}.tn-file-picker-wrapper{display:flex;align-items:center;width:100%;position:relative}.tn-file-picker-input{display:block;width:100%;min-height:2.5rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5;color:var(--tn-fg1, #212529);background-color:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;outline:none;box-sizing:border-box;font-family:inherit}.tn-file-picker-input::placeholder{color:var(--tn-alt-fg1, #999);opacity:1}.tn-file-picker-input:focus{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px #007bff40}.tn-file-picker-input:disabled{background-color:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-file-picker-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-input.error:focus{border-color:var(--tn-error, var(--tn-red, #bd2626));box-shadow:0 0 0 2px #dc354540}.tn-file-picker-toggle{position:absolute;right:8px;z-index:2;pointer-events:auto;background:transparent;border:none;cursor:pointer;padding:4px;color:var(--tn-fg1);border-radius:4px}.tn-file-picker-toggle:hover{background:var(--tn-bg2, #f0f0f0)}.tn-file-picker-toggle:focus{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-file-picker-toggle:disabled{cursor:not-allowed;opacity:.5}.tn-file-picker-toggle tn-icon{font-size:var(--tn-icon-md, 20px)}:host:focus-within .tn-file-picker-input{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px #007bff40}:host.error .tn-file-picker-input{border-color:var(--tn-error, var(--tn-red, #bd2626))}:host.error .tn-file-picker-input:focus{border-color:var(--tn-error, var(--tn-red, #bd2626));box-shadow:0 0 0 2px #dc354540}@media(prefers-reduced-motion:reduce){.tn-file-picker-input,.tn-file-picker-toggle,.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){.tn-file-picker-input{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host ::ng-deep .tn-file-picker-overlay .tn-file-picker-dialog{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"],
|
|
28086
28123
|
dependencies: [
|
|
28087
28124
|
{
|
|
@@ -28181,7 +28218,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28181
28218
|
"[class.error]": "hasError()",
|
|
28182
28219
|
"(keydown)": "onHostKeydown($event)"
|
|
28183
28220
|
},
|
|
28184
|
-
template: "<div class=\"tn-file-picker-container\" tnTestIdType=\"file-picker\" [tnTestId]=\"resolvedTestId()\">\n <div #wrapper ixInput class=\"tn-file-picker-wrapper\" style=\"padding-right: 40px;\">\n <input\n type=\"text\"\n class=\"tn-file-picker-input\"\n tnTestIdType=\"input\"\n [tnTestId]=\"resolvedTestId()\"\n [class.error]=\"hasError()\"\n [value]=\"selectedPath()\"\n [placeholder]=\"
|
|
28221
|
+
template: "<div class=\"tn-file-picker-container\" tnTestIdType=\"file-picker\" [tnTestId]=\"resolvedTestId()\">\n <div #wrapper ixInput class=\"tn-file-picker-wrapper\" style=\"padding-right: 40px;\">\n <input\n type=\"text\"\n class=\"tn-file-picker-input\"\n tnTestIdType=\"input\"\n [tnTestId]=\"resolvedTestId()\"\n [class.error]=\"hasError()\"\n [value]=\"selectedPath()\"\n [placeholder]=\"resolvedPlaceholder()\"\n [readonly]=\"!allowManualInput() || readonly()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-labelledby]=\"fieldAria.labelledby()\"\n [attr.aria-describedby]=\"fieldAria.describedby()\"\n [attr.aria-invalid]=\"fieldAria.invalid()\"\n [attr.aria-required]=\"fieldAria.required()\"\n [disabled]=\"isDisabled()\"\n (click)=\"onInputClick()\"\n (change)=\"onPathCommit($event)\">\n\n <button\n type=\"button\"\n class=\"tn-file-picker-toggle\"\n tnTestIdType=\"button\"\n [attr.aria-label]=\"labels().openPicker\"\n [tnTestId]=\"toggleTestId()\"\n [disabled]=\"isDisabled() || readonly()\"\n (click)=\"openFilePicker()\">\n <tn-icon name=\"folder\" library=\"mdi\" />\n </button>\n </div>\n \n <ng-template #filePickerTemplate>\n <tn-file-picker-popup\n class=\"tn-file-picker-popup\"\n tnTestIdType=\"file-picker-popup\"\n [tnTestId]=\"resolvedTestId()\"\n [testIdBase]=\"resolvedTestId()\"\n [mode]=\"mode()\"\n [multiSelect]=\"multiSelect()\"\n [createActions]=\"availableCreateActions()\"\n [currentPath]=\"currentPath()\"\n [rootPath]=\"effectiveRootPath()\"\n [fileItems]=\"fileItems()\"\n [selectedItems]=\"selectedItems()\"\n [loading]=\"loading()\"\n [errorMessage]=\"popupError()\"\n [fileExtensions]=\"fileExtensions()\"\n (itemClick)=\"onItemClick($event)\"\n (itemDoubleClick)=\"onItemDoubleClick($event)\"\n (pathNavigate)=\"navigateToPath($event)\"\n (createAction)=\"runCreateAction($event)\"\n (created)=\"onCreated($event)\"\n (clearSelection)=\"onClearSelection()\"\n (submit)=\"onSubmit()\"\n (cancel)=\"onCancel()\"\n (close)=\"close()\" />\n </ng-template>\n</div>",
|
|
28185
28222
|
styles: [":host{display:block;width:100%;font-family:var(--tn-font-family-body, \"Inter\"),sans-serif}.tn-file-picker-container{position:relative;display:flex;align-items:center;width:100%}.tn-file-picker-wrapper{display:flex;align-items:center;width:100%;position:relative}.tn-file-picker-input{display:block;width:100%;min-height:2.5rem;padding:.5rem .75rem;font-size:1rem;line-height:1.5;color:var(--tn-fg1, #212529);background-color:var(--tn-bg1, #ffffff);border:1px solid var(--tn-lines, #d1d5db);border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;outline:none;box-sizing:border-box;font-family:inherit}.tn-file-picker-input::placeholder{color:var(--tn-alt-fg1, #999);opacity:1}.tn-file-picker-input:focus{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px #007bff40}.tn-file-picker-input:disabled{background-color:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-fg2, #6c757d);cursor:not-allowed;opacity:.6}.tn-file-picker-input.error{border-color:var(--tn-error, var(--tn-red, #bd2626))}.tn-file-picker-input.error:focus{border-color:var(--tn-error, var(--tn-red, #bd2626));box-shadow:0 0 0 2px #dc354540}.tn-file-picker-toggle{position:absolute;right:8px;z-index:2;pointer-events:auto;background:transparent;border:none;cursor:pointer;padding:4px;color:var(--tn-fg1);border-radius:4px}.tn-file-picker-toggle:hover{background:var(--tn-bg2, #f0f0f0)}.tn-file-picker-toggle:focus{outline:2px solid var(--tn-primary);outline-offset:2px}.tn-file-picker-toggle:disabled{cursor:not-allowed;opacity:.5}.tn-file-picker-toggle tn-icon{font-size:var(--tn-icon-md, 20px)}:host:focus-within .tn-file-picker-input{border-color:var(--tn-primary, #007bff);box-shadow:0 0 0 2px #007bff40}:host.error .tn-file-picker-input{border-color:var(--tn-error, var(--tn-red, #bd2626))}:host.error .tn-file-picker-input:focus{border-color:var(--tn-error, var(--tn-red, #bd2626));box-shadow:0 0 0 2px #dc354540}@media(prefers-reduced-motion:reduce){.tn-file-picker-input,.tn-file-picker-toggle,.file-item,.breadcrumb-segment{transition:none}.tn-file-picker-loading tn-icon{animation:none}}@media(prefers-contrast:high){.tn-file-picker-input{border-width:2px}.file-item:hover,.file-item.selected{border:2px solid var(--tn-fg1)}.zfs-badge{border:1px solid var(--tn-fg1)}}@media(max-width:768px){:host ::ng-deep .tn-file-picker-overlay .tn-file-picker-dialog{min-width:300px;max-width:calc(100vw - 32px);max-height:calc(100vh - 64px)}.tn-file-picker-header{flex-direction:column;gap:12px;align-items:stretch}.tn-file-picker-breadcrumb{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}.tn-file-picker-breadcrumb::-webkit-scrollbar{display:none}.file-item{padding:12px;min-height:56px}.file-info{font-size:1rem}}\n"]
|
|
28186
28223
|
}]
|
|
28187
28224
|
}],
|
|
@@ -28352,6 +28389,20 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28352
28389
|
}]
|
|
28353
28390
|
}
|
|
28354
28391
|
});
|
|
28392
|
+
var FilePickerNameCellHarness = class extends ComponentHarness {
|
|
28393
|
+
static hostSelector = "tn-file-picker-popup .file-name-cell";
|
|
28394
|
+
name = this.locatorFor(".file-name");
|
|
28395
|
+
navigateButton = this.locatorForOptional(".navigate-button");
|
|
28396
|
+
async getName() {
|
|
28397
|
+
return (await (await this.name()).text()).trim();
|
|
28398
|
+
}
|
|
28399
|
+
async clickNavigate() {
|
|
28400
|
+
const button = await this.navigateButton();
|
|
28401
|
+
if (!button) return false;
|
|
28402
|
+
await button.click();
|
|
28403
|
+
return true;
|
|
28404
|
+
}
|
|
28405
|
+
};
|
|
28355
28406
|
var TnFilePickerHarness = class TnFilePickerHarness extends ComponentHarness {
|
|
28356
28407
|
static hostSelector = "tn-file-picker";
|
|
28357
28408
|
_container = this.locatorFor(".tn-file-picker-container");
|
|
@@ -28409,21 +28460,18 @@ var TnFilePickerHarness = class TnFilePickerHarness extends ComponentHarness {
|
|
|
28409
28460
|
throw new Error(`No item named "${name}" found in the file picker popup.`);
|
|
28410
28461
|
}
|
|
28411
28462
|
async navigateToItem(name) {
|
|
28412
|
-
const
|
|
28413
|
-
|
|
28414
|
-
|
|
28463
|
+
const cells = await this.documentRootLocatorFactory().locatorForAll(FilePickerNameCellHarness)();
|
|
28464
|
+
for (const cell of cells) if (await cell.getName() === name && await cell.clickNavigate()) return;
|
|
28465
|
+
throw new Error(`No navigatable item named "${name}" found in the file picker popup.`);
|
|
28415
28466
|
}
|
|
28416
28467
|
async clickSelect() {
|
|
28417
28468
|
return (await this.documentRootLocatorFactory().locatorFor(TnButtonHarness.with({
|
|
28418
|
-
|
|
28419
|
-
ancestor: ".tn-file-picker-footer"
|
|
28469
|
+
selector: ":last-child",
|
|
28470
|
+
ancestor: ".tn-file-picker-footer .footer-actions"
|
|
28420
28471
|
}))()).click();
|
|
28421
28472
|
}
|
|
28422
28473
|
async clickClearSelection() {
|
|
28423
|
-
const button = await this.documentRootLocatorFactory().locatorForOptional(TnButtonHarness.with({
|
|
28424
|
-
label: "Clear Selection",
|
|
28425
|
-
ancestor: ".tn-file-picker-footer"
|
|
28426
|
-
}))();
|
|
28474
|
+
const button = await this.documentRootLocatorFactory().locatorForOptional(TnButtonHarness.with({ ancestor: ".tn-file-picker-footer .footer-selection" }))();
|
|
28427
28475
|
if (!button) throw new Error("No Clear Selection button found — nothing is selected in the file picker popup.");
|
|
28428
28476
|
return button.click();
|
|
28429
28477
|
}
|
|
@@ -29025,6 +29073,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29025
29073
|
}],
|
|
29026
29074
|
ctorParameters: () => []
|
|
29027
29075
|
});
|
|
29028
|
-
export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, FlatTreeControl, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, THEME_MAP, THEME_STORAGE_KEY, TN_AUTOCOMPLETE_DEFAULT_LABELS, TN_AUTOCOMPLETE_LABELS, TN_BRANDED_SPINNER_DEFAULT_LABEL, TN_CALENDAR_INTL, TN_CALENDAR_INTL_DEFAULTS, TN_CHIP_INPUT_DEFAULT_LABELS, TN_CHIP_INPUT_LABELS, TN_DEFAULT_FALLBACK_LABELS, TN_DIALOG_CHROME_LABELS, TN_DIALOG_DEFAULT_CHROME_LABELS, TN_DIALOG_SHELL_DEFAULT_LABEL, TN_DRAWER_CONTENT_LABEL, TN_DRAWER_DEFAULT_LABEL, TN_FALLBACK_LABELS, TN_FORM_FIELD_CONTEXT, TN_FORM_FIELD_DISMISSIBLE_ERRORS, TN_FORM_FIELD_ERRORS, TN_FORM_LIST_CONTEXT, TN_PARTICLE_PROGRESS_BAR_DEFAULT_LABEL, TN_PROGRESS_BAR_DEFAULT_LABEL, TN_RADIO_GROUP, TN_SELECT_DEFAULT_LABELS, TN_SELECT_LABELS, TN_SIDE_PANEL_CONTENT_LABEL, TN_SIDE_PANEL_DEFAULT_LABEL, TN_SIDE_PANEL_OVERFLOW_TOLERANCE_PX, TN_SPINNER_DEFAULT_LABEL, TN_STEPPER_STATUS_COMPLETED, TN_STEPPER_STATUS_ERROR, TN_TABLE_DEFAULT_LABELS, TN_TABLE_LABELS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TABLE_SCROLL_REGION_LABEL, TN_TAB_PANEL_CONTENT_LABEL, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TN_TOAST_ANNOUNCE_DELAY_MS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerActionHarness, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarCellHarness, TnCalendarComponent, TnCalendarHarness, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxGroupComponent, TnCheckboxGroupHarness, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerHarness, TnFilePickerPopupComponent, TnFormErrorsComponent, TnFormErrorsHarness, TnFormFieldComponent, TnFormFieldHarness, TnFormListComponent, TnFormListHarness, TnFormListItemComponent, TnFormListItemHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeDataSource, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioGroupComponent, TnRadioGroupHarness, TnRadioHarness, TnRowActionsDefDirective, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSidePanelTitleDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnStepperHarness, TnStepperNextDirective, TnStepperPreviousDirective, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTableTesting, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTooltipHarness, TnTooltipTesting, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeHarness, TnTreeNodeComponent, TnTreeNodeHarness, TnTreeNodeOutletDirective, TnTreeVirtualScrollNodeOutletDirective, TnTreeVirtualScrollViewComponent, TnTreeVirtualScrollViewHarness, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, allowsCurrentDirectorySelection, canonicalizeSize, composeTestId, controlTestId, createFlatTreeControl, createLucideLibrary, createNestedTreeControl, createShortcut, createTnOptionsDataSource, defaultSpriteBasePath, defaultSpriteConfigPath, defaultTreeItemSize, formatSize, formatSizeExact, formatSizeForEditing, getSelectableTypes, injectTnCalendarIntl, injectTnFallbackName, injectTnFormFieldAria, injectTnLabels, isPathWithinRoot, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, normalizeRootPath, optionTestId, parseLabelMarkup, parseSize, parseSizeParts, registerLucideIcons, resolveErrorMessage, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
29076
|
+
export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, FlatTreeControl, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, THEME_MAP, THEME_STORAGE_KEY, TN_AUTOCOMPLETE_DEFAULT_LABELS, TN_AUTOCOMPLETE_LABELS, TN_BRANDED_SPINNER_DEFAULT_LABEL, TN_CALENDAR_INTL, TN_CALENDAR_INTL_DEFAULTS, TN_CHIP_INPUT_DEFAULT_LABELS, TN_CHIP_INPUT_LABELS, TN_DEFAULT_FALLBACK_LABELS, TN_DIALOG_CHROME_LABELS, TN_DIALOG_DEFAULT_CHROME_LABELS, TN_DIALOG_SHELL_DEFAULT_LABEL, TN_DRAWER_CONTENT_LABEL, TN_DRAWER_DEFAULT_LABEL, TN_FALLBACK_LABELS, TN_FILE_PICKER_DEFAULT_LABELS, TN_FILE_PICKER_LABELS, TN_FORM_FIELD_CONTEXT, TN_FORM_FIELD_DISMISSIBLE_ERRORS, TN_FORM_FIELD_ERRORS, TN_FORM_LIST_CONTEXT, TN_PARTICLE_PROGRESS_BAR_DEFAULT_LABEL, TN_PROGRESS_BAR_DEFAULT_LABEL, TN_RADIO_GROUP, TN_SELECT_DEFAULT_LABELS, TN_SELECT_LABELS, TN_SIDE_PANEL_CONTENT_LABEL, TN_SIDE_PANEL_DEFAULT_LABEL, TN_SIDE_PANEL_OVERFLOW_TOLERANCE_PX, TN_SPINNER_DEFAULT_LABEL, TN_STEPPER_STATUS_COMPLETED, TN_STEPPER_STATUS_ERROR, TN_TABLE_DEFAULT_LABELS, TN_TABLE_LABELS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TABLE_SCROLL_REGION_LABEL, TN_TAB_PANEL_CONTENT_LABEL, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TN_TOAST_ANNOUNCE_DELAY_MS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerActionHarness, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarCellHarness, TnCalendarComponent, TnCalendarHarness, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxGroupComponent, TnCheckboxGroupHarness, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerHarness, TnFilePickerPopupComponent, TnFormErrorsComponent, TnFormErrorsHarness, TnFormFieldComponent, TnFormFieldHarness, TnFormListComponent, TnFormListHarness, TnFormListItemComponent, TnFormListItemHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeDataSource, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioGroupComponent, TnRadioGroupHarness, TnRadioHarness, TnRowActionsDefDirective, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSidePanelTitleDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnStepperHarness, TnStepperNextDirective, TnStepperPreviousDirective, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTableTesting, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTooltipHarness, TnTooltipTesting, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeHarness, TnTreeNodeComponent, TnTreeNodeHarness, TnTreeNodeOutletDirective, TnTreeVirtualScrollNodeOutletDirective, TnTreeVirtualScrollViewComponent, TnTreeVirtualScrollViewHarness, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, allowsCurrentDirectorySelection, canonicalizeSize, composeTestId, controlTestId, createFlatTreeControl, createLucideLibrary, createNestedTreeControl, createShortcut, createTnOptionsDataSource, defaultSpriteBasePath, defaultSpriteConfigPath, defaultTreeItemSize, formatSize, formatSizeExact, formatSizeForEditing, getSelectableTypes, injectTnCalendarIntl, injectTnFallbackName, injectTnFormFieldAria, injectTnLabels, isPathWithinRoot, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, normalizeRootPath, optionTestId, parseLabelMarkup, parseSize, parseSizeParts, registerLucideIcons, resolveErrorMessage, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
|
|
29029
29077
|
|
|
29030
29078
|
//# sourceMappingURL=truenas-ui-components.mjs.map
|