@truenas/ui-components 0.8.16 → 0.8.18
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.
|
@@ -11017,6 +11017,7 @@ var TnTabComponent = class TnTabComponent {
|
|
|
11017
11017
|
isActive = signal(false, ...ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []);
|
|
11018
11018
|
tabsComponent;
|
|
11019
11019
|
elementRef = inject(ElementRef);
|
|
11020
|
+
tabButton = viewChild.required("tabButton", ...ngDevMode ? [{ debugName: "tabButton" }] : /* istanbul ignore next */ []);
|
|
11020
11021
|
hasIconContent = signal(false, ...ngDevMode ? [{ debugName: "hasIconContent" }] : /* istanbul ignore next */ []);
|
|
11021
11022
|
ngAfterContentInit() {
|
|
11022
11023
|
this.hasIconContent.set(!!this.iconContent());
|
|
@@ -11027,6 +11028,9 @@ var TnTabComponent = class TnTabComponent {
|
|
|
11027
11028
|
onKeydown(event) {
|
|
11028
11029
|
if (this.tabsComponent) this.tabsComponent.onKeydown(event, this.index());
|
|
11029
11030
|
}
|
|
11031
|
+
focus() {
|
|
11032
|
+
this.tabButton().nativeElement.focus();
|
|
11033
|
+
}
|
|
11030
11034
|
classes = computed(() => {
|
|
11031
11035
|
const classes = ["tn-tab"];
|
|
11032
11036
|
if (this.isActive()) classes.push("tn-tab--active");
|
|
@@ -11100,8 +11104,15 @@ var TnTabComponent = class TnTabComponent {
|
|
|
11100
11104
|
descendants: true,
|
|
11101
11105
|
isSignal: true
|
|
11102
11106
|
}],
|
|
11107
|
+
viewQueries: [{
|
|
11108
|
+
propertyName: "tabButton",
|
|
11109
|
+
first: true,
|
|
11110
|
+
predicate: ["tabButton"],
|
|
11111
|
+
descendants: true,
|
|
11112
|
+
isSignal: true
|
|
11113
|
+
}],
|
|
11103
11114
|
ngImport: i0,
|
|
11104
|
-
template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.id]=\"tabId()\"\n [attr.aria-controls]=\"hasPanel() ? panelId() : null\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>",
|
|
11115
|
+
template: "<button\n #tabButton\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.id]=\"tabId()\"\n [attr.aria-controls]=\"hasPanel() ? panelId() : null\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>",
|
|
11105
11116
|
styles: [".tn-tab{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));--tn-primary-text: var(--tn-fg1, #222222);display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:12px 16px;border:none;border-bottom:none;background:transparent;color:var(--tn-fg2, #666);font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;font-weight:500;line-height:1.5;cursor:pointer;white-space:nowrap;min-width:0;flex-shrink:0}.tn-tab:hover:not(.tn-tab--disabled):not(.tn-tab--active){background-color:var(--tn-alt-bg1, #f5f5f5);color:var(--tn-fg1, #333)}.tn-tab:focus-visible{outline:2px solid var(--tn-primary, #0095d5);outline-offset:-2px;border-radius:4px}.tn-tab--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-tab__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}.tn-tab__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-tab__label{display:flex;align-items:center;min-width:0;text-overflow:ellipsis;overflow:hidden}@media(prefers-contrast:high){.tn-tab{border-width:3px}.tn-tab:focus-visible{outline-width:3px}}:host-context(.tn-tabs--vertical){width:100%}:host-context(.tn-tabs--vertical) .tn-tab{width:100%}\n"],
|
|
11106
11117
|
dependencies: [
|
|
11107
11118
|
{
|
|
@@ -11160,7 +11171,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
11160
11171
|
LabelMarkupPipe
|
|
11161
11172
|
],
|
|
11162
11173
|
changeDetection: ChangeDetectionStrategy.Eager,
|
|
11163
|
-
template: "<button\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.id]=\"tabId()\"\n [attr.aria-controls]=\"hasPanel() ? panelId() : null\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>",
|
|
11174
|
+
template: "<button\n #tabButton\n role=\"tab\"\n type=\"button\"\n tnTestIdType=\"tab\"\n [ngClass]=\"classes()\"\n [tnTestId]=\"testId()\"\n [attr.id]=\"tabId()\"\n [attr.aria-controls]=\"hasPanel() ? panelId() : null\"\n [attr.aria-selected]=\"isActive()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"tabIndex()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\"\n (keydown)=\"onKeydown($event)\"\n>\n @if (hasIcon()) {\n <span class=\"tn-tab__icon\">\n @if (iconContent()) {\n <ng-container *ngTemplateOutlet=\"iconContent()\" />\n } @else if (iconTemplate()) {\n <ng-container *ngTemplateOutlet=\"iconTemplate()\" />\n } @else {\n <span [innerHTML]=\"icon()\"></span>\n }\n </span>\n }\n <span class=\"tn-tab__label\">\n <span [innerHTML]=\"label() | tnLabelMarkup\"></span>\n <ng-content />\n </span>\n</button>",
|
|
11164
11175
|
styles: [".tn-tab{--tn-error-text: var(--tn-error, var(--tn-red, #bd2626));--tn-primary-text: var(--tn-fg1, #222222);display:flex;align-items:center;justify-content:flex-start;gap:8px;padding:12px 16px;border:none;border-bottom:none;background:transparent;color:var(--tn-fg2, #666);font-family:var(--tn-font-family-body, \"Inter\", sans-serif);font-size:14px;font-weight:500;line-height:1.5;cursor:pointer;white-space:nowrap;min-width:0;flex-shrink:0}.tn-tab:hover:not(.tn-tab--disabled):not(.tn-tab--active){background-color:var(--tn-alt-bg1, #f5f5f5);color:var(--tn-fg1, #333)}.tn-tab:focus-visible{outline:2px solid var(--tn-primary, #0095d5);outline-offset:-2px;border-radius:4px}.tn-tab--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.tn-tab__icon{display:flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;flex-shrink:0}.tn-tab__label ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-tab__label{display:flex;align-items:center;min-width:0;text-overflow:ellipsis;overflow:hidden}@media(prefers-contrast:high){.tn-tab{border-width:3px}.tn-tab:focus-visible{outline-width:3px}}:host-context(.tn-tabs--vertical){width:100%}:host-context(.tn-tabs--vertical) .tn-tab{width:100%}\n"]
|
|
11165
11176
|
}]
|
|
11166
11177
|
}],
|
|
@@ -11212,6 +11223,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
11212
11223
|
iconContent: [{
|
|
11213
11224
|
type: i0.ContentChild,
|
|
11214
11225
|
args: ["iconContent", { isSignal: true }]
|
|
11226
|
+
}],
|
|
11227
|
+
tabButton: [{
|
|
11228
|
+
type: i0.ViewChild,
|
|
11229
|
+
args: ["tabButton", { isSignal: true }]
|
|
11215
11230
|
}]
|
|
11216
11231
|
}
|
|
11217
11232
|
});
|
|
@@ -11563,8 +11578,7 @@ var TnTabsComponent = class TnTabsComponent {
|
|
|
11563
11578
|
return tabs.length - 1;
|
|
11564
11579
|
}
|
|
11565
11580
|
focusTab(index) {
|
|
11566
|
-
|
|
11567
|
-
if (tab && tab.elementRef) tab.elementRef.nativeElement.focus();
|
|
11581
|
+
this.tabs()[index]?.focus();
|
|
11568
11582
|
}
|
|
11569
11583
|
classes = computed(() => {
|
|
11570
11584
|
const classes = ["tn-tabs"];
|
|
@@ -26717,6 +26731,39 @@ var TnStepperHarness = class TnStepperHarness extends ComponentHarness {
|
|
|
26717
26731
|
return await (await this.locatorFor(".tn-stepper")()).hasClass("tn-stepper--vertical") ? "vertical" : "horizontal";
|
|
26718
26732
|
}
|
|
26719
26733
|
};
|
|
26734
|
+
const TN_FILE_PICKER_DEFAULT_LABELS = {
|
|
26735
|
+
placeholder: "Select file or folder",
|
|
26736
|
+
openPicker: "Open file picker",
|
|
26737
|
+
breadcrumb: "File path",
|
|
26738
|
+
navigateTo: (path) => `Navigate to ${path}`,
|
|
26739
|
+
loading: "Loading...",
|
|
26740
|
+
noItems: "No items found",
|
|
26741
|
+
selectColumn: "Select",
|
|
26742
|
+
selectItem: (name) => `Select ${name}`,
|
|
26743
|
+
openItem: (name) => `Open ${name}`,
|
|
26744
|
+
nameColumn: "Name",
|
|
26745
|
+
sizeColumn: "Size",
|
|
26746
|
+
modifiedColumn: "Modified",
|
|
26747
|
+
itemsSelected: (count) => `${count} item${count !== 1 ? "s" : ""} selected`,
|
|
26748
|
+
currentDirectorySelected: "Current directory selected",
|
|
26749
|
+
noItemsSelected: "No items selected",
|
|
26750
|
+
clearSelection: "Clear Selection",
|
|
26751
|
+
select: "Select",
|
|
26752
|
+
inlineCreateName: (actionLabel) => `${actionLabel} name`,
|
|
26753
|
+
inlineCreateFailed: "Creation failed",
|
|
26754
|
+
today: (time) => `Today ${time}`,
|
|
26755
|
+
yesterday: (time) => `Yesterday ${time}`,
|
|
26756
|
+
pathOutsideRoot: (rootPath) => `Path is outside of ${rootPath}`,
|
|
26757
|
+
invalidPath: (path) => `Invalid path: ${path}`,
|
|
26758
|
+
pathValidationFailed: "Path validation failed",
|
|
26759
|
+
loadFailed: "Failed to load directory",
|
|
26760
|
+
createFailed: "Failed to create item",
|
|
26761
|
+
createdOutsideRoot: (rootPath) => `Created item is outside of ${rootPath}`
|
|
26762
|
+
};
|
|
26763
|
+
const TN_FILE_PICKER_LABELS = new InjectionToken("TN_FILE_PICKER_LABELS", {
|
|
26764
|
+
providedIn: "root",
|
|
26765
|
+
factory: () => TN_FILE_PICKER_DEFAULT_LABELS
|
|
26766
|
+
});
|
|
26720
26767
|
function getSelectableTypes(mode) {
|
|
26721
26768
|
if (Array.isArray(mode)) return mode;
|
|
26722
26769
|
return mode === "any" ? null : [mode];
|
|
@@ -26829,6 +26876,7 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26829
26876
|
errorMessage = input(null, ...ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []);
|
|
26830
26877
|
fileExtensions = input(void 0, ...ngDevMode ? [{ debugName: "fileExtensions" }] : /* istanbul ignore next */ []);
|
|
26831
26878
|
testIdBase = input(void 0, ...ngDevMode ? [{ debugName: "testIdBase" }] : /* istanbul ignore next */ []);
|
|
26879
|
+
labels = injectTnLabels(TN_FILE_PICKER_LABELS);
|
|
26832
26880
|
iconRegistry = inject(TnIconRegistryService);
|
|
26833
26881
|
elementRef = inject(ElementRef);
|
|
26834
26882
|
constructor() {
|
|
@@ -26972,7 +27020,7 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
26972
27020
|
this.created.emit(createdPath);
|
|
26973
27021
|
} catch (err) {
|
|
26974
27022
|
if (this.inlineCreation() !== pending) return;
|
|
26975
|
-
const message = err instanceof Error ? err.message :
|
|
27023
|
+
const message = err instanceof Error ? err.message : this.labels().inlineCreateFailed;
|
|
26976
27024
|
this.inlineCreation.set({
|
|
26977
27025
|
...pending,
|
|
26978
27026
|
loading: false,
|
|
@@ -27068,10 +27116,10 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
27068
27116
|
minute: "2-digit",
|
|
27069
27117
|
hour12: true
|
|
27070
27118
|
});
|
|
27071
|
-
if (itemDate.getTime() === today.getTime()) return
|
|
27119
|
+
if (itemDate.getTime() === today.getTime()) return this.labels().today(timePart);
|
|
27072
27120
|
const yesterday = new Date(today);
|
|
27073
27121
|
yesterday.setDate(yesterday.getDate() - 1);
|
|
27074
|
-
if (itemDate.getTime() === yesterday.getTime()) return
|
|
27122
|
+
if (itemDate.getTime() === yesterday.getTime()) return this.labels().yesterday(timePart);
|
|
27075
27123
|
if (date.getFullYear() === now.getFullYear()) return `${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")} ${timePart}`;
|
|
27076
27124
|
return `${(date.getMonth() + 1).toString().padStart(2, "0")}/${date.getDate().toString().padStart(2, "0")}/${date.getFullYear()} ${timePart}`;
|
|
27077
27125
|
}
|
|
@@ -27181,7 +27229,7 @@ var TnFilePickerPopupComponent = class TnFilePickerPopupComponent {
|
|
|
27181
27229
|
},
|
|
27182
27230
|
host: { classAttribute: "tn-file-picker-popup" },
|
|
27183
27231
|
ngImport: i0,
|
|
27184
|
-
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"
|
|
27232
|
+
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}",
|
|
27185
27233
|
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"],
|
|
27186
27234
|
dependencies: [
|
|
27187
27235
|
{
|
|
@@ -27369,7 +27417,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
27369
27417
|
],
|
|
27370
27418
|
changeDetection: ChangeDetectionStrategy.Eager,
|
|
27371
27419
|
host: { "class": "tn-file-picker-popup" },
|
|
27372
|
-
template: "<!-- Header with breadcrumb navigation -->\n<div class=\"tn-file-picker-header\">\n <nav class=\"tn-file-picker-breadcrumb\" aria-label=\"
|
|
27420
|
+
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}",
|
|
27373
27421
|
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"]
|
|
27374
27422
|
}]
|
|
27375
27423
|
}],
|
|
@@ -27509,7 +27557,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27509
27557
|
allowFreeText = input(false, ...ngDevMode ? [{ debugName: "allowFreeText" }] : /* istanbul ignore next */ []);
|
|
27510
27558
|
ariaLabel = input(void 0, ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
|
|
27511
27559
|
openOnClick = input(false, ...ngDevMode ? [{ debugName: "openOnClick" }] : /* istanbul ignore next */ []);
|
|
27512
|
-
placeholder = input(
|
|
27560
|
+
placeholder = input(TN_FILE_PICKER_DEFAULT_LABELS.placeholder, ...ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []);
|
|
27513
27561
|
disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
|
|
27514
27562
|
readonly = input(false, ...ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []);
|
|
27515
27563
|
testId = input(void 0, ...ngDevMode ? [{ debugName: "testId" }] : /* istanbul ignore next */ []);
|
|
@@ -27540,6 +27588,11 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27540
27588
|
formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
|
|
27541
27589
|
fieldAria = injectTnFormFieldAria(this.ariaLabel);
|
|
27542
27590
|
listedItems = /* @__PURE__ */ new Map();
|
|
27591
|
+
labels = injectTnLabels(TN_FILE_PICKER_LABELS);
|
|
27592
|
+
resolvedPlaceholder = computed(() => {
|
|
27593
|
+
const placeholder = this.placeholder();
|
|
27594
|
+
return placeholder === TN_FILE_PICKER_DEFAULT_LABELS.placeholder ? this.labels().placeholder : placeholder;
|
|
27595
|
+
}, ...ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []);
|
|
27543
27596
|
isDisabled = computed(() => this.disabled() || this.formDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
|
|
27544
27597
|
effectiveCallbacks = computed(() => this.callbacks() ?? this.source()?.callbacks, ...ngDevMode ? [{ debugName: "effectiveCallbacks" }] : /* istanbul ignore next */ []);
|
|
27545
27598
|
effectiveStartPath = computed(() => this.startPath() ?? this.source()?.startPath ?? "/mnt", ...ngDevMode ? [{ debugName: "effectiveStartPath" }] : /* istanbul ignore next */ []);
|
|
@@ -27608,16 +27661,16 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27608
27661
|
return;
|
|
27609
27662
|
}
|
|
27610
27663
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27611
|
-
this.emitError("validation",
|
|
27664
|
+
this.emitError("validation", this.labels().pathOutsideRoot(this.effectiveRootPath()), path);
|
|
27612
27665
|
this.onTouched();
|
|
27613
27666
|
return;
|
|
27614
27667
|
}
|
|
27615
27668
|
const cb = this.effectiveCallbacks();
|
|
27616
27669
|
if (cb?.validatePath) cb.validatePath(path).then((isValid) => {
|
|
27617
27670
|
if (isValid) this.updateSelection(path);
|
|
27618
|
-
else this.emitError("validation",
|
|
27671
|
+
else this.emitError("validation", this.labels().invalidPath(path), path);
|
|
27619
27672
|
}).catch((err) => {
|
|
27620
|
-
this.emitError("validation", err.message ||
|
|
27673
|
+
this.emitError("validation", err.message || this.labels().pathValidationFailed, path);
|
|
27621
27674
|
});
|
|
27622
27675
|
else this.updateSelection(path);
|
|
27623
27676
|
}
|
|
@@ -27717,14 +27770,14 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27717
27770
|
try {
|
|
27718
27771
|
createdPath = await action.run(event.parentPath);
|
|
27719
27772
|
} catch (err) {
|
|
27720
|
-
this.emitError("creation", err instanceof Error ? err.message :
|
|
27773
|
+
this.emitError("creation", err instanceof Error ? err.message : this.labels().createFailed, event.parentPath);
|
|
27721
27774
|
return;
|
|
27722
27775
|
}
|
|
27723
27776
|
if (createdPath) await this.selectCreatedPath(createdPath);
|
|
27724
27777
|
}
|
|
27725
27778
|
async selectCreatedPath(path) {
|
|
27726
27779
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27727
|
-
this.emitError("creation",
|
|
27780
|
+
this.emitError("creation", this.labels().createdOutsideRoot(this.effectiveRootPath()), path);
|
|
27728
27781
|
return;
|
|
27729
27782
|
}
|
|
27730
27783
|
await this.selectPath(path);
|
|
@@ -27734,7 +27787,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27734
27787
|
}
|
|
27735
27788
|
async selectPath(path) {
|
|
27736
27789
|
if (!isPathWithinRoot(path, this.effectiveRootPath())) {
|
|
27737
|
-
this.emitError("validation",
|
|
27790
|
+
this.emitError("validation", this.labels().pathOutsideRoot(this.effectiveRootPath()), path);
|
|
27738
27791
|
return;
|
|
27739
27792
|
}
|
|
27740
27793
|
const parent = path.substring(0, path.lastIndexOf("/"));
|
|
@@ -27778,7 +27831,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
27778
27831
|
this.clearStalePendingSelection(directoryChanged);
|
|
27779
27832
|
this.pathChange.emit(path);
|
|
27780
27833
|
} catch (err) {
|
|
27781
|
-
this.emitError("navigation", err instanceof Error ? err.message :
|
|
27834
|
+
this.emitError("navigation", err instanceof Error ? err.message : this.labels().loadFailed, path);
|
|
27782
27835
|
} finally {
|
|
27783
27836
|
this.loading.set(false);
|
|
27784
27837
|
}
|
|
@@ -28079,7 +28132,7 @@ var TnFilePickerComponent = class TnFilePickerComponent {
|
|
|
28079
28132
|
isSignal: true
|
|
28080
28133
|
}],
|
|
28081
28134
|
ngImport: i0,
|
|
28082
|
-
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]=\"
|
|
28135
|
+
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>",
|
|
28083
28136
|
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"],
|
|
28084
28137
|
dependencies: [
|
|
28085
28138
|
{
|
|
@@ -28179,7 +28232,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28179
28232
|
"[class.error]": "hasError()",
|
|
28180
28233
|
"(keydown)": "onHostKeydown($event)"
|
|
28181
28234
|
},
|
|
28182
|
-
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]=\"
|
|
28235
|
+
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>",
|
|
28183
28236
|
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"]
|
|
28184
28237
|
}]
|
|
28185
28238
|
}],
|
|
@@ -28350,6 +28403,20 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28350
28403
|
}]
|
|
28351
28404
|
}
|
|
28352
28405
|
});
|
|
28406
|
+
var FilePickerNameCellHarness = class extends ComponentHarness {
|
|
28407
|
+
static hostSelector = "tn-file-picker-popup .file-name-cell";
|
|
28408
|
+
name = this.locatorFor(".file-name");
|
|
28409
|
+
navigateButton = this.locatorForOptional(".navigate-button");
|
|
28410
|
+
async getName() {
|
|
28411
|
+
return (await (await this.name()).text()).trim();
|
|
28412
|
+
}
|
|
28413
|
+
async clickNavigate() {
|
|
28414
|
+
const button = await this.navigateButton();
|
|
28415
|
+
if (!button) return false;
|
|
28416
|
+
await button.click();
|
|
28417
|
+
return true;
|
|
28418
|
+
}
|
|
28419
|
+
};
|
|
28353
28420
|
var TnFilePickerHarness = class TnFilePickerHarness extends ComponentHarness {
|
|
28354
28421
|
static hostSelector = "tn-file-picker";
|
|
28355
28422
|
_container = this.locatorFor(".tn-file-picker-container");
|
|
@@ -28407,21 +28474,18 @@ var TnFilePickerHarness = class TnFilePickerHarness extends ComponentHarness {
|
|
|
28407
28474
|
throw new Error(`No item named "${name}" found in the file picker popup.`);
|
|
28408
28475
|
}
|
|
28409
28476
|
async navigateToItem(name) {
|
|
28410
|
-
const
|
|
28411
|
-
|
|
28412
|
-
|
|
28477
|
+
const cells = await this.documentRootLocatorFactory().locatorForAll(FilePickerNameCellHarness)();
|
|
28478
|
+
for (const cell of cells) if (await cell.getName() === name && await cell.clickNavigate()) return;
|
|
28479
|
+
throw new Error(`No navigatable item named "${name}" found in the file picker popup.`);
|
|
28413
28480
|
}
|
|
28414
28481
|
async clickSelect() {
|
|
28415
28482
|
return (await this.documentRootLocatorFactory().locatorFor(TnButtonHarness.with({
|
|
28416
|
-
|
|
28417
|
-
ancestor: ".tn-file-picker-footer"
|
|
28483
|
+
selector: ":last-child",
|
|
28484
|
+
ancestor: ".tn-file-picker-footer .footer-actions"
|
|
28418
28485
|
}))()).click();
|
|
28419
28486
|
}
|
|
28420
28487
|
async clickClearSelection() {
|
|
28421
|
-
const button = await this.documentRootLocatorFactory().locatorForOptional(TnButtonHarness.with({
|
|
28422
|
-
label: "Clear Selection",
|
|
28423
|
-
ancestor: ".tn-file-picker-footer"
|
|
28424
|
-
}))();
|
|
28488
|
+
const button = await this.documentRootLocatorFactory().locatorForOptional(TnButtonHarness.with({ ancestor: ".tn-file-picker-footer .footer-selection" }))();
|
|
28425
28489
|
if (!button) throw new Error("No Clear Selection button found — nothing is selected in the file picker popup.");
|
|
28426
28490
|
return button.click();
|
|
28427
28491
|
}
|
|
@@ -29023,6 +29087,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29023
29087
|
}],
|
|
29024
29088
|
ctorParameters: () => []
|
|
29025
29089
|
});
|
|
29026
|
-
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 };
|
|
29090
|
+
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 };
|
|
29027
29091
|
|
|
29028
29092
|
//# sourceMappingURL=truenas-ui-components.mjs.map
|