diff --git a/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.html b/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.html index fac156d548f..043e5dae378 100644 --- a/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.html +++ b/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.html @@ -42,7 +42,7 @@ @@ -79,6 +79,7 @@ + @if (loadingError) { {{ loadingError }} diff --git a/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.ts b/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.ts index 5aac6ccaa45..691e523d8bb 100644 --- a/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.ts +++ b/src/app/modules/forms/ix-forms/components/ix-explorer/ix-explorer.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, input, + Component, computed, input, OnChanges, - OnInit, viewChild, + OnInit, Signal, viewChild, } from '@angular/core'; import { ControlValueAccessor, NgControl, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -16,7 +16,7 @@ import { import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { firstValueFrom, Observable, of } from 'rxjs'; -import { catchError } from 'rxjs/operators'; +import { catchError, map } from 'rxjs/operators'; import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive'; import { ExplorerNodeType } from 'app/enums/explorer-type.enum'; import { mntPath } from 'app/enums/mnt-path.enum'; @@ -63,6 +63,7 @@ import { ErrorHandlerService } from 'app/services/error-handler.service'; export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAccessor { readonly label = input(); readonly hint = input(); + readonly readonly = input(false); readonly multiple = input(false); readonly tooltip = input(); readonly required = input(false); @@ -110,13 +111,18 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces }, }; - treeOptions: ITreeOptions = { - idField: 'path', - displayField: 'name', - getChildren: (node: TreeNode) => firstValueFrom(this.loadChildren(node)), - actionMapping: this.actionMapping, - useTriState: false, - }; + treeOptions: Signal = computed(() => { + const readonly = this.readonly(); + + return { + idField: 'path', + displayField: 'name', + getChildren: (node: TreeNode) => firstValueFrom(this.loadChildren(node)), + actionMapping: readonly ? {} : this.actionMapping, + useTriState: false, + useCheckbox: this.multiple(), + }; + }); constructor( public controlDirective: NgControl, @@ -129,10 +135,6 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces } ngOnChanges(changes: IxSimpleChanges): void { - if ('multiple' in changes) { - this.treeOptions.useCheckbox = this.multiple(); - } - if ('nodeProvider' in changes || 'root' in changes) { this.setInitialNode(); this.cdr.markForCheck(); @@ -159,7 +161,7 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces } setDisabledState?(isDisabled: boolean): void { - this.isDisabled = isDisabled; + this.isDisabled = isDisabled || this.readonly(); this.cdr.markForCheck(); } @@ -267,7 +269,7 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces { path: this.root(), name: this.root(), - hasChildren: true, + hasChildren: !this.readonly(), type: ExplorerNodeType.Directory, isMountpoint: true, }, @@ -279,6 +281,9 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces } private selectTreeNodes(nodeIds: string[]): void { + if (this.readonly()) { + return; + } const treeState = { ...this.tree().treeModel.getState(), selectedLeafNodeIds: nodeIds.reduce((acc, nodeId) => ({ ...acc, [nodeId]: true }), {}), @@ -288,6 +293,9 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces } private loadChildren(node: TreeNode): Observable { + if (this.readonly()) { + return of([]); + } this.loadingError = null; this.cdr.markForCheck(); @@ -296,6 +304,10 @@ export class IxExplorerComponent implements OnInit, OnChanges, ControlValueAcces } return this.nodeProvider()(node).pipe( + map((childNodes) => childNodes.map((data) => { + data.hasChildren = !this.readonly() && data.hasChildren; + return data; + })), catchError((error: unknown) => { this.loadingError = this.errorHandler.getFirstErrorMessage(error); this.cdr.markForCheck(); diff --git a/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.html b/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.html index 0ac945a4e7f..a6f833eddcf 100644 --- a/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.html +++ b/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.html @@ -42,6 +42,7 @@ [label]="helptext.path_placeholder | translate" [tooltip]="helptext.path_tooltip | translate" [required]="true" + [readonly]="!hasRequiredRoles()" [nodeProvider]="fileNodeProvider" > } @@ -50,6 +51,7 @@ formControlName="path_source" [label]="helptext.path_placeholder | translate" [tooltip]="helptext.path_tooltip | translate" + [readonly]="!hasRequiredRoles()" [required]="true" [multiple]="true" [nodeProvider]="fileNodeProvider" diff --git a/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.ts b/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.ts index 0174315dce6..b4d23f422d1 100644 --- a/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.ts +++ b/src/app/pages/data-protection/cloudsync/cloudsync-form/cloudsync-form.component.ts @@ -212,7 +212,7 @@ export class CloudSyncFormComponent implements OnInit { bucketOptions$ = of([]); - private hasRequiredRoles = toSignal(this.authService.hasRole(this.requiredRoles)); + protected readonly hasRequiredRoles = toSignal(this.authService.hasRole(this.requiredRoles)); fileNodeProvider: TreeNodeProvider; bucketNodeProvider: TreeNodeProvider;