diff --git a/src/app/directives/disable-focusable-elements/disable-focusable-elements.directive.ts b/src/app/directives/disable-focusable-elements/disable-focusable-elements.directive.ts index f9615283d30..cbbbbd35dd2 100644 --- a/src/app/directives/disable-focusable-elements/disable-focusable-elements.directive.ts +++ b/src/app/directives/disable-focusable-elements/disable-focusable-elements.directive.ts @@ -1,5 +1,5 @@ import { - Directive, Input, Renderer2, ElementRef, OnChanges, + Directive, Renderer2, ElementRef, OnChanges, input, } from '@angular/core'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { take, timer } from 'rxjs'; @@ -11,7 +11,7 @@ import { IxSimpleChanges } from 'app/interfaces/simple-changes.interface'; standalone: true, }) export class DisableFocusableElementsDirective implements OnChanges { - @Input() disableFocusableElements: boolean; + readonly disableFocusableElements = input.required(); constructor( private elementRef: ElementRef, @@ -26,7 +26,7 @@ export class DisableFocusableElementsDirective implements OnChanges { private updateFocusableElements(): void { timer(0).pipe(take(1), untilDestroyed(this)).subscribe(() => { - const tabIndex = this.disableFocusableElements ? -1 : 0; + const tabIndex = this.disableFocusableElements() ? -1 : 0; this.updateTabIndex(tabIndex); }); } diff --git a/src/app/modules/forms/search-input/components/advanced-search/advanced-search.component.ts b/src/app/modules/forms/search-input/components/advanced-search/advanced-search.component.ts index c333f18ca98..4c651bcac6c 100644 --- a/src/app/modules/forms/search-input/components/advanced-search/advanced-search.component.ts +++ b/src/app/modules/forms/search-input/components/advanced-search/advanced-search.component.ts @@ -3,8 +3,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - ElementRef, - Input, + ElementRef, input, OnInit, output, ViewChild, } from '@angular/core'; @@ -49,9 +48,9 @@ const setDiagnostics = StateEffect.define(); ], }) export class AdvancedSearchComponent implements OnInit { - @Input() query: QueryFilters = []; - @Input() properties: SearchProperty[] = []; - @Input() placeholder: string; + readonly query = input>([]); + readonly properties = input[]>([]); + readonly placeholder = input(''); readonly paramsChange = output>(); readonly switchToBasic = output(); @@ -79,12 +78,12 @@ export class AdvancedSearchComponent implements OnInit { ngOnInit(): void { this.initEditor(); - this.advancedSearchAutocomplete.setProperties(this.properties); + this.advancedSearchAutocomplete.setProperties(this.properties()); this.advancedSearchAutocomplete.setEditorView(this.editorView); - if (this.query) { + if (this.query()) { this.replaceEditorContents( - this.queryParser.formatFiltersToQuery(this.query, this.properties), + this.queryParser.formatFiltersToQuery(this.query(), this.properties()), ); } } @@ -141,7 +140,7 @@ export class AdvancedSearchComponent implements OnInit { customKeyMap, EditorView.lineWrapping, closeBrackets(), - placeholder(this.placeholder), + placeholder(this.placeholder()), ], }), parent: this.inputArea.nativeElement, @@ -195,7 +194,7 @@ export class AdvancedSearchComponent implements OnInit { }); this.errorMessages = null; - const filters = this.queryToApi.buildFilters(parsedQuery, this.properties); + const filters = this.queryToApi.buildFilters(parsedQuery, this.properties()); this.paramsChange.emit(filters); } diff --git a/src/app/modules/global-search/components/global-search-results/global-search-results.component.html b/src/app/modules/global-search/components/global-search-results/global-search-results.component.html index 508a792d25e..7459c816b5e 100644 --- a/src/app/modules/global-search/components/global-search-results/global-search-results.component.html +++ b/src/app/modules/global-search/components/global-search-results/global-search-results.component.html @@ -1,4 +1,4 @@ -@if (!isLoading || results?.length) { +@if (!isLoading() || results()?.length) { @for (section of availableSections; track trackBySection($index, section)) {

@@ -12,13 +12,13 @@

class="search-result" role="link" [attr.tabindex]="result.section === GlobalSearchSection.RecentSearches ? i + 1 : 0" - [class.highlighted-result]="isSearchInputFocused && isSameHierarchyResult(firstAvailableSearchResult, result)" + [class.highlighted-result]="isSearchInputFocused() && isSameHierarchyResult(firstAvailableSearchResult, result)" [ixTest]="['search-result', result.hierarchy.join('-')]" [attr.aria-label]="'UI Search Result: {result}' | translate: { result: result.hierarchy.join(' ') }" (click)="selectElement(result)" (keydown.enter)="selectElement(result)" > -

+

@if (result.section === GlobalSearchSection.RecentSearches) { ([]); readonly recentSearchRemoved = output(); @@ -57,10 +57,10 @@ export class GlobalSearchResultsComponent implements OnChanges { showAll = { ...this.initialShowAll }; get availableSections(): Option[] { - const uniqueSectionValues = new Set(this.results.map((result) => result.section)); + const uniqueSectionValues = new Set(this.results().map((result) => result.section)); if ( - this.searchTerm + this.searchTerm() && !uniqueSectionValues.has(GlobalSearchSection.Ui) && !uniqueSectionValues.has(GlobalSearchSection.RecentSearches) ) { @@ -113,7 +113,7 @@ export class GlobalSearchResultsComponent implements OnChanges { } getLimitedSectionResults(section: GlobalSearchSection): UiSearchableElement[] { - const sectionResults = this.results.filter((element) => element.section === section); + const sectionResults = this.results().filter((element) => element.section === section); if (this.showAll[section] || sectionResults.length <= this.initialResultsLimit) { return sectionResults; @@ -123,7 +123,7 @@ export class GlobalSearchResultsComponent implements OnChanges { } getElementsBySection(section: GlobalSearchSection): UiSearchableElement[] { - return this.results.filter((element) => element?.section === section); + return this.results().filter((element) => element?.section === section); } isSameHierarchyResult(a: UiSearchableElement, b: UiSearchableElement): boolean { diff --git a/src/app/modules/loader/components/fake-progress-bar/fake-progress-bar.component.html b/src/app/modules/loader/components/fake-progress-bar/fake-progress-bar.component.html index 3179fbd6204..3c35038798b 100644 --- a/src/app/modules/loader/components/fake-progress-bar/fake-progress-bar.component.html +++ b/src/app/modules/loader/components/fake-progress-bar/fake-progress-bar.component.html @@ -1,4 +1,4 @@ -@if (isAnimating || !hideOnComplete) { +@if (isAnimating || !hideOnComplete()) { (); /** * Pretend time for the whole progress bar. * Will never reach it, getting slower and slower. */ - @Input() duration = 1000; + readonly duration = input(1000); /** * Automatically fades out progress bar when loading becomes false. */ - @Input() hideOnComplete = true; + readonly hideOnComplete = input(true); progress: number; isAnimating = false; @@ -62,7 +61,7 @@ export class FakeProgressBarComponent implements OnChanges, OnDestroy { return; } - if (this.loading) { + if (this.loading()) { this.start(); } else { this.stop.next(); @@ -101,7 +100,7 @@ export class FakeProgressBarComponent implements OnChanges, OnDestroy { } const timeElapsed = this.redrawTime * sequence; - const scale = this.duration; + const scale = this.duration(); return 100 * timeElapsed / (timeElapsed + scale); } diff --git a/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.html b/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.html index 8e02724878e..bba42e38fb6 100644 --- a/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.html +++ b/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.html @@ -12,8 +12,8 @@

-
{{ crontab }}
-
{{ crontab | crontabExplanation }}
+
{{ crontab() }}
+
{{ crontab() | crontabExplanation }}
@@ -22,7 +22,7 @@

- {{ 'System Time Zone:' | translate }} {{ timezone }} + {{ 'System Time Zone:' | translate }} {{ timezone() }}
@if (cronPreview && !isPastMonth) { diff --git a/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.ts b/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.ts index 2544530f9ec..32b9ff5026a 100644 --- a/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.ts +++ b/src/app/modules/scheduler/components/scheduler-modal/scheduler-preview-column/scheduler-preview-column.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, - Input, + input, OnChanges, OnInit, ViewChild, @@ -41,11 +41,11 @@ import { TestDirective } from 'app/modules/test-id/test.directive'; ], }) export class SchedulerPreviewColumnComponent implements OnChanges, OnInit { - @Input() crontab: string; - @Input() timezone: string; + readonly crontab = input.required(); + readonly timezone = input.required(); - @Input() startTime: string; - @Input() endTime: string; + readonly startTime = input(); + readonly endTime = input(); /** * 1 for 1st day of the month, etc. @@ -58,7 +58,7 @@ export class SchedulerPreviewColumnComponent implements OnChanges, OnInit { get startDate(): Date { if (!this.calendar.activeDate || differenceInCalendarMonths(this.calendar.activeDate, new Date()) < 1) { - return utcToZonedTime(new Date(), this.timezone); + return utcToZonedTime(new Date(), this.timezone()); } return startOfMonth(this.calendar.activeDate); @@ -101,9 +101,9 @@ export class SchedulerPreviewColumnComponent implements OnChanges, OnInit { try { this.cronPreview = new CronSchedulePreview({ - crontab: this.crontab, - startTime: this.startTime, - endTime: this.endTime, + crontab: this.crontab(), + startTime: this.startTime(), + endTime: this.endTime(), }); this.highlightedCalendarDays = this.cronPreview.getNextDaysInMonthWithRuns(this.startDate); diff --git a/src/app/modules/terminal/components/terminal/terminal.component.ts b/src/app/modules/terminal/components/terminal/terminal.component.ts index 5ca7189a2a7..c25b9132354 100644 --- a/src/app/modules/terminal/components/terminal/terminal.component.ts +++ b/src/app/modules/terminal/components/terminal/terminal.component.ts @@ -1,7 +1,7 @@ import { NgStyle } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, HostListener, Input, OnDestroy, OnInit, ViewChild, + Component, ElementRef, HostListener, input, OnDestroy, OnInit, ViewChild, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; @@ -45,7 +45,8 @@ import { waitForPreferences } from 'app/store/preferences/preferences.selectors' ], }) export class TerminalComponent implements OnInit, OnDestroy { - @Input() conf: TerminalConfiguration; + readonly conf = input.required(); + @ViewChild('terminal', { static: true }) container: ElementRef; waitParentChanges = 300; @@ -86,16 +87,16 @@ export class TerminalComponent implements OnInit, OnDestroy { ) {} ngOnInit(): void { - if (this.conf.preInit) { - this.conf.preInit().pipe(untilDestroyed(this)).subscribe(() => { + if (this.conf().preInit) { + this.conf().preInit().pipe(untilDestroyed(this)).subscribe(() => { this.initShell(); }); } else { this.initShell(); } - if (this.conf.reconnectShell$) { - this.conf.reconnectShell$.pipe(untilDestroyed(this)).subscribe(() => { + if (this.conf().reconnectShell$) { + this.conf().reconnectShell$.pipe(untilDestroyed(this)).subscribe(() => { this.reconnect(); }); } @@ -196,7 +197,7 @@ export class TerminalComponent implements OnInit, OnDestroy { } initializeWebShell(): void { - this.shellService.connect(this.token, this.conf.connectionData); + this.shellService.connect(this.token, this.conf().connectionData); this.shellService.shellConnected$.pipe(untilDestroyed(this)).subscribe((event: ShellConnectedEvent) => { this.shellConnected = event.connected; @@ -212,7 +213,7 @@ export class TerminalComponent implements OnInit, OnDestroy { } reconnect(): void { - this.shellService.connect(this.token, this.conf.connectionData); + this.shellService.connect(this.token, this.conf().connectionData); } onFontSizeChanged(newSize: number): void { diff --git a/src/app/pages/data-protection/replication/replication-form/sections/general-section/general-section.component.ts b/src/app/pages/data-protection/replication/replication-form/sections/general-section/general-section.component.ts index d20df626a40..0fa2426e16c 100644 --- a/src/app/pages/data-protection/replication/replication-form/sections/general-section/general-section.component.ts +++ b/src/app/pages/data-protection/replication/replication-form/sections/general-section/general-section.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, OnChanges, + ChangeDetectionStrategy, Component, input, OnChanges, } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; @@ -30,7 +30,7 @@ import { IxSelectComponent } from 'app/modules/forms/ix-forms/components/ix-sele ], }) export class GeneralSectionComponent implements OnChanges { - @Input() replication: ReplicationTask; + readonly replication = input(); form = this.formBuilder.group({ name: ['', Validators.required], @@ -71,10 +71,10 @@ export class GeneralSectionComponent implements OnChanges { } ngOnChanges(): void { - if (this.replication) { + if (this.replication()) { this.form.patchValue({ - ...this.replication, - logging_level: this.replication.logging_level || LoggingLevel.Default, + ...this.replication(), + logging_level: this.replication().logging_level || LoggingLevel.Default, }); } } diff --git a/src/app/pages/data-protection/replication/replication-form/sections/schedule-section/schedule-section.component.ts b/src/app/pages/data-protection/replication/replication-form/sections/schedule-section/schedule-section.component.ts index 3ab7af98709..6e8667914da 100644 --- a/src/app/pages/data-protection/replication/replication-form/sections/schedule-section/schedule-section.component.ts +++ b/src/app/pages/data-protection/replication/replication-form/sections/schedule-section/schedule-section.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, OnChanges, + ChangeDetectionStrategy, Component, input, OnChanges, } from '@angular/core'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule } from '@ngx-translate/core'; @@ -30,7 +30,7 @@ import { TaskService } from 'app/services/task.service'; ], }) export class ScheduleSectionComponent implements OnChanges { - @Input() replication: ReplicationTask; + readonly replication = input(); form = this.formBuilder.group({ auto: [true], @@ -52,8 +52,8 @@ export class ScheduleSectionComponent implements OnChanges { ) {} ngOnChanges(): void { - if (this.replication) { - this.setFormValues(this.replication); + if (this.replication()) { + this.setFormValues(this.replication()); } } diff --git a/src/app/pages/data-protection/replication/replication-wizard/steps/replication-when/replication-when.component.ts b/src/app/pages/data-protection/replication/replication-wizard/steps/replication-when/replication-when.component.ts index 1afda98d7fb..f3fa3433c3a 100644 --- a/src/app/pages/data-protection/replication/replication-wizard/steps/replication-when/replication-when.component.ts +++ b/src/app/pages/data-protection/replication/replication-wizard/steps/replication-when/replication-when.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, output, + ChangeDetectionStrategy, Component, input, OnChanges, OnInit, output, } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -48,7 +48,8 @@ import { TestDirective } from 'app/modules/test-id/test.directive'; ], }) export class ReplicationWhenComponent implements OnInit, OnChanges, SummaryProvider { - @Input() isCustomRetentionVisible = true; + readonly isCustomRetentionVisible = input(true); + readonly save = output(); form = this.formBuilder.group({ @@ -82,7 +83,7 @@ export class ReplicationWhenComponent implements OnInit, OnChanges, SummaryProvi ]); get retentionPolicyOptions$(): Observable { - return this.isCustomRetentionVisible + return this.isCustomRetentionVisible() ? of([ ...this.defaultRetentionPolicyOptions, { label: this.translate.instant('Custom'), value: RetentionPolicy.Custom }, diff --git a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.html b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.html index 820e898ae2f..fa98d645979 100644 --- a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.html +++ b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.html @@ -1,5 +1,5 @@ - {{ state.state | translate }} + {{ state().state | translate }} diff --git a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.ts b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.ts index ed92b35f9b7..1aed514e363 100644 --- a/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.ts +++ b/src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, - Component, HostBinding, Input, + Component, HostBinding, input, } from '@angular/core'; import { MatTooltip } from '@angular/material/tooltip'; import { TranslateService, TranslateModule } from '@ngx-translate/core'; @@ -26,19 +26,19 @@ export interface VmwareState { imports: [MatTooltip, TranslateModule], }) export class VmwareStatusCellComponent { - @Input() state: VmwareState; + readonly state = input.required(); get tooltip(): string { - if (this.state.state === VmwareSnapshotStatus.Error) { - return this.state.error ? this.translate.instant(this.state.error) : this.translate.instant('Error'); + if (this.state().state === VmwareSnapshotStatus.Error) { + return this.state().error ? this.translate.instant(this.state().error) : this.translate.instant('Error'); } - return this.state.state === VmwareSnapshotStatus.Pending + return this.state().state === VmwareSnapshotStatus.Pending ? this.translate.instant('Pending') : this.translate.instant('Success'); } @HostBinding('class') get hostClasses(): string[] { - return ['status', this.state?.state.toLowerCase()]; + return ['status', this.state()?.state.toLowerCase()]; } constructor(private translate: TranslateService) { } diff --git a/src/app/pages/datasets/components/dataset-form/dataset-form.component.html b/src/app/pages/datasets/components/dataset-form/dataset-form.component.html index 92963a76380..edfbcf8c699 100644 --- a/src/app/pages/datasets/components/dataset-form/dataset-form.component.html +++ b/src/app/pages/datasets/components/dataset-form/dataset-form.component.html @@ -14,7 +14,6 @@ > @if (isAdvancedMode && isNew) { } diff --git a/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.html b/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.html index f657f340013..3e45f96155f 100644 --- a/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.html +++ b/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.html @@ -2,7 +2,7 @@ [title]="'Name and Options' | translate" [formGroup]="form" > - @if (parent && !existing) { + @if (parent() && !existing()) { - @if (!existing) { + @if (!existing()) { -@if (!existing) { +@if (!existing()) {
@if (form.value.share_type) { diff --git a/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.ts b/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.ts index 1c9f402cff2..157cf187cf1 100644 --- a/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.ts +++ b/src/app/pages/datasets/components/dataset-form/sections/name-and-options-section/name-and-options-section.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, output, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnChanges, OnInit, output, } from '@angular/core'; import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; @@ -43,8 +43,8 @@ import { SmbValidationService } from 'app/pages/sharing/smb/smb-form/smb-validat ], }) export class NameAndOptionsSectionComponent implements OnInit, OnChanges { - @Input() existing: Dataset; - @Input() parent: Dataset; + readonly existing = input(); + readonly parent = input(); readonly formValidityChange = output(); @@ -85,8 +85,8 @@ export class NameAndOptionsSectionComponent implements OnInit, OnChanges { ) {} ngOnChanges(): void { - if (this.parent) { - this.form.controls.parent.setValue(this.parent.name); + if (this.parent()) { + this.form.controls.parent.setValue(this.parent().name); this.addNameValidators(); } @@ -107,29 +107,29 @@ export class NameAndOptionsSectionComponent implements OnInit, OnChanges { getPayload(): Partial | Partial { const payload = this.form.value; - if (this.existing) { + if (this.existing()) { delete payload.share_type; return payload; } return { ...payload, - name: payload.name && this.form.controls.name.valid ? `${this.parent.name}/${payload.name}` : null, + name: payload.name && this.form.controls.name.valid ? `${this.parent().name}/${payload.name}` : null, }; } private setFormValues(): void { - if (!this.existing) { + if (!this.existing()) { return; } this.form.patchValue({ - name: this.existing.name, + name: this.existing().name, }); } private setNameDisabledStatus(): void { - if (this.existing) { + if (this.existing()) { this.form.controls.name.disable(); } else { this.form.controls.name.enable(); @@ -137,8 +137,8 @@ export class NameAndOptionsSectionComponent implements OnInit, OnChanges { } private addNameValidators(): void { - const isNameCaseSensitive = this.parent.casesensitivity.value === DatasetCaseSensitivity.Sensitive; - const namesInUse = this.parent.children.map((child) => { + const isNameCaseSensitive = this.parent().casesensitivity.value === DatasetCaseSensitivity.Sensitive; + const namesInUse = this.parent().children.map((child) => { const childName = /[^/]*$/.exec(child.name)[0]; if (isNameCaseSensitive) { return childName.toLowerCase(); @@ -148,7 +148,7 @@ export class NameAndOptionsSectionComponent implements OnInit, OnChanges { }); this.form.controls.name.addValidators([ - datasetNameTooLong(this.parent.name), + datasetNameTooLong(this.parent().name), forbiddenValues(namesInUse, isNameCaseSensitive), ]); } diff --git a/src/app/pages/datasets/components/dataset-form/sections/quotas-section/quotas-section.component.ts b/src/app/pages/datasets/components/dataset-form/sections/quotas-section/quotas-section.component.ts index 428e88068b8..332a6159259 100644 --- a/src/app/pages/datasets/components/dataset-form/sections/quotas-section/quotas-section.component.ts +++ b/src/app/pages/datasets/components/dataset-form/sections/quotas-section/quotas-section.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, OnInit, output, + ChangeDetectionStrategy, Component, OnInit, output, } from '@angular/core'; import { AbstractControl, FormBuilder, ReactiveFormsModule, Validators, @@ -9,7 +9,7 @@ import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { pickBy } from 'lodash-es'; import { GiB } from 'app/constants/bytes.constant'; import { helptextDatasetForm } from 'app/helptext/storage/volumes/datasets/dataset-form'; -import { Dataset, DatasetCreate } from 'app/interfaces/dataset.interface'; +import { DatasetCreate } from 'app/interfaces/dataset.interface'; import { IxCheckboxComponent } from 'app/modules/forms/ix-forms/components/ix-checkbox/ix-checkbox.component'; import { IxFieldsetComponent } from 'app/modules/forms/ix-forms/components/ix-fieldset/ix-fieldset.component'; import { IxInputComponent } from 'app/modules/forms/ix-forms/components/ix-input/ix-input.component'; @@ -35,8 +35,6 @@ const critical = 95; ], }) export class QuotasSectionComponent implements OnInit { - @Input() parent: Dataset; - readonly formValidityChange = output(); readonly form = this.formBuilder.group({ diff --git a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.html b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.html index 98600629f27..6a8d3aa1654 100644 --- a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.html +++ b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.html @@ -17,7 +17,7 @@

{{ 'ZFS Encryption' | translate }}

mat-button color="primary" ixTest="unlock" - [routerLink]="['/datasets', dataset.id, 'unlock']" + [routerLink]="['/datasets', dataset().id, 'unlock']" > {{ 'Unlock' | translate }} @@ -28,7 +28,7 @@

{{ 'ZFS Encryption' | translate }}

{{ 'Current State' | translate }}:
{{ currentStateLabel }}
- @if (dataset.encrypted) { + @if (dataset().encrypted) {
{{ 'Encryption Root' | translate }}:
@if (isEncryptionRoot) { @@ -36,11 +36,11 @@

{{ 'ZFS Encryption' | translate }}

{{ 'Yes' | translate }}
} @else { -
/{{ dataset.encryption_root }}
+
/{{ dataset().encryption_root }}
{{ 'Go To Encryption Root' | translate }} @@ -54,11 +54,11 @@

{{ 'ZFS Encryption' | translate }}

{{ 'Algorithm' | translate }}:
-
{{ dataset.encryption_algorithm?.value }}
+
{{ dataset().encryption_algorithm?.value }}
} - @if (dataset.encrypted && isEncryptionRoot && !this.dataset.locked) { + @if (dataset().encrypted && isEncryptionRoot && !dataset().locked) { @if (canExportKey && isRoot) { diff --git a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.spec.ts b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.spec.ts index 0434bb3c92b..53584b844b3 100644 --- a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.spec.ts +++ b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.spec.ts @@ -2,6 +2,7 @@ import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatButtonHarness } from '@angular/material/button/testing'; import { MatDialog } from '@angular/material/dialog'; +import { InferInputSignals } from '@ngneat/spectator'; import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest'; import { of } from 'rxjs'; import { mockAuth } from 'app/core/testing/utils/mock-auth.utils'; @@ -63,7 +64,7 @@ describe('ZfsEncryptionCardComponent', () => { locked: true, } as DatasetDetails; - function setupTest(props: Partial = {}): void { + function setupTest(props: InferInputSignals = {}): void { spectator = createComponent({ props }); loader = TestbedHarnessEnvironment.loader(spectator.fixture); } diff --git a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.ts b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.ts index 51576abd12e..ce9adc6a77c 100644 --- a/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.ts +++ b/src/app/pages/datasets/modules/encryption/components/zfs-encryption-card/zfs-encryption-card.component.ts @@ -1,4 +1,6 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { + ChangeDetectionStrategy, Component, input, +} from '@angular/core'; import { MatAnchor, MatButton } from '@angular/material/button'; import { MatCard, MatCardActions, MatCardContent, MatCardHeader, MatCardTitle, @@ -54,8 +56,8 @@ import { isEncryptionRoot, isPasswordEncrypted, isRootDataset } from 'app/pages/ ], }) export class ZfsEncryptionCardComponent { - @Input() dataset: DatasetDetails; - @Input() parentDataset: DatasetDetails | undefined; + readonly dataset = input.required(); + readonly parentDataset = input(undefined); constructor( private matDialog: MatDialog, @@ -64,19 +66,19 @@ export class ZfsEncryptionCardComponent { ) { } get hasPassphrase(): boolean { - return isPasswordEncrypted(this.dataset); + return isPasswordEncrypted(this.dataset()); } get isEncryptionRoot(): boolean { - return isEncryptionRoot(this.dataset); + return isEncryptionRoot(this.dataset()); } get currentStateLabel(): string { - if (!this.dataset.encrypted) { + if (!this.dataset().encrypted) { return this.translate.instant('Unencrypted'); } - if (this.dataset.locked) { + if (this.dataset().locked) { if (!this.isEncryptionRoot) { return this.translate.instant('Locked by ancestor'); } @@ -88,22 +90,22 @@ export class ZfsEncryptionCardComponent { } get canExportKey(): boolean { - return !this.hasPassphrase && this.dataset.key_loaded; + return !this.hasPassphrase && this.dataset().key_loaded; } get canEdit(): boolean { - return this.dataset.encrypted && !this.dataset.locked; + return this.dataset().encrypted && !this.dataset().locked; } get canUnlock(): boolean { - return this.isEncryptionRoot && this.dataset.locked && !this.parentDataset?.locked; + return this.isEncryptionRoot && this.dataset().locked && !this.parentDataset()?.locked; } onEditPressed(): void { const dialog = this.matDialog.open(EncryptionOptionsDialogComponent, { data: { - dataset: this.dataset, - parent: this.parentDataset, + dataset: this.dataset(), + parent: this.parentDataset(), } as EncryptionOptionsDialogData, }); dialog @@ -114,7 +116,7 @@ export class ZfsEncryptionCardComponent { onLock(): void { this.matDialog.open(LockDatasetDialogComponent, { - data: this.dataset, + data: this.dataset(), }) .afterClosed() .pipe(filter(Boolean), untilDestroyed(this)) @@ -123,18 +125,18 @@ export class ZfsEncryptionCardComponent { onExportKey(): void { this.matDialog.open(ExportDatasetKeyDialogComponent, { - data: this.dataset, + data: this.dataset(), }); } onExportAllKeys(): void { this.matDialog.open(ExportAllKeysDialogComponent, { - data: this.dataset, + data: this.dataset(), }); } get isRoot(): boolean { - return isRootDataset(this.dataset); + return isRootDataset(this.dataset()); } protected readonly Role = Role; diff --git a/src/app/pages/datasets/modules/permissions/components/acl-editor-list/acl-editor-list.component.html b/src/app/pages/datasets/modules/permissions/components/acl-editor-list/acl-editor-list.component.html index 416826e4e6a..e571ca99a22 100644 --- a/src/app/pages/datasets/modules/permissions/components/acl-editor-list/acl-editor-list.component.html +++ b/src/app/pages/datasets/modules/permissions/components/acl-editor-list/acl-editor-list.component.html @@ -2,7 +2,7 @@ {{ 'Access Control List' | translate }}

- @if (!acl.acl.length) { + @if (!acl().acl.length) {
{{ 'The list is empty.' | translate }}
@@ -10,8 +10,8 @@ @for (ace of aces; track ace; let i = $index) {
@if (permissionItems[i]) { @@ -20,7 +20,7 @@ [item]="permissionItems[i]" > } - @if (acesWithError.includes(i)) { + @if (acesWithError().includes(i)) { (); + readonly selectedAceIndex = input.required(); + readonly acesWithError = input.required(); + readonly owner = input.required(); + readonly ownerGroup = input.required(); permissionItems: PermissionItem[] = []; aces: (NfsAclItem | PosixAclItem)[] = []; @@ -46,28 +46,28 @@ export class AclEditorListComponent implements OnChanges { } ngOnChanges(): void { - this.aces = this.acl.acl; - if (this.acl.acltype === AclType.Nfs4) { - this.permissionItems = this.acl.acl.map((ace) => { + this.aces = this.acl().acl; + if (this.acl().acltype === AclType.Nfs4) { + this.permissionItems = this.acl().acl.map((ace) => { if (ace.tag === NfsAclTag.Owner) { - return nfsAceToPermissionItem(this.translate, { ...ace, who: this.owner }); + return nfsAceToPermissionItem(this.translate, { ...ace, who: this.owner() }); } if (ace.tag === NfsAclTag.Group) { - return nfsAceToPermissionItem(this.translate, { ...ace, who: this.ownerGroup }); + return nfsAceToPermissionItem(this.translate, { ...ace, who: this.ownerGroup() }); } - return nfsAceToPermissionItem(this.translate, ace); + return nfsAceToPermissionItem(this.translate, ace as NfsAclItem); }); } else { - this.permissionItems = this.acl.acl.map((ace) => { + this.permissionItems = this.acl().acl.map((ace) => { if (ace.tag === PosixAclTag.UserObject) { - return posixAceToPermissionItem(this.translate, { ...ace, who: this.owner }); + return posixAceToPermissionItem(this.translate, { ...ace, who: this.owner() }); } if (ace.tag === PosixAclTag.GroupObject) { - return posixAceToPermissionItem(this.translate, { ...ace, who: this.ownerGroup }); + return posixAceToPermissionItem(this.translate, { ...ace, who: this.ownerGroup() }); } - return posixAceToPermissionItem(this.translate, ace); + return posixAceToPermissionItem(this.translate, ace as PosixAclItem); }); } } @@ -76,14 +76,14 @@ export class AclEditorListComponent implements OnChanges { * POSIX acl must have at least one of each: USER_OBJ, GROUP_OBJ and OTHER. */ canBeRemoved(aceToRemove: NfsAclItem | PosixAclItem): boolean { - if (this.acl.acltype === AclType.Nfs4) { + if (this.acl().acltype === AclType.Nfs4) { return true; } let hasAnotherUserObj = false; let hasAnotherGroupObj = false; let hasAnotherOtherAce = false; - this.acl.acl.forEach((ace) => { + this.acl().acl.forEach((ace) => { if (ace === aceToRemove) { return; } diff --git a/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.html b/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.html index 4d5503b60df..f0aefada986 100644 --- a/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.html +++ b/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.html @@ -77,8 +77,8 @@ @@ -86,8 +86,8 @@ @@ -99,9 +99,9 @@ diff --git a/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.ts b/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.ts index 25cedd21011..73825b5c31d 100644 --- a/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.ts +++ b/src/app/pages/datasets/modules/snapshots/snapshot-details-row/snapshot-details-row.component.ts @@ -1,5 +1,5 @@ import { - Component, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnInit, OnDestroy, + Component, ChangeDetectionStrategy, ChangeDetectorRef, OnInit, OnDestroy, input, } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -51,7 +51,7 @@ import { ApiService } from 'app/services/websocket/api.service'; ], }) export class SnapshotDetailsRowComponent implements OnInit, OnDestroy { - @Input() snapshot: ZfsSnapshotUi; + readonly snapshot = input.required(); isLoading = true; snapshotInfo: ZfsSnapshotUi; @@ -89,7 +89,7 @@ export class SnapshotDetailsRowComponent implements OnInit, OnDestroy { this.api.call( 'zfs.snapshot.query', [ - [['id', '=', this.snapshot.name]], { + [['id', '=', this.snapshot().name]], { extra: { retention: true, holds: true, @@ -98,7 +98,7 @@ export class SnapshotDetailsRowComponent implements OnInit, OnDestroy { ], ) .pipe( - map((snapshots) => ({ ...snapshots[0], selected: this.snapshot.selected })), + map((snapshots) => ({ ...snapshots[0], selected: this.snapshot().selected })), untilDestroyed(this), ) .subscribe({ diff --git a/src/app/pages/directory-service/components/idmap-list/idmap-list.component.html b/src/app/pages/directory-service/components/idmap-list/idmap-list.component.html index 34e44c7ad5c..9118dad0075 100644 --- a/src/app/pages/directory-service/components/idmap-list/idmap-list.component.html +++ b/src/app/pages/directory-service/components/idmap-list/idmap-list.component.html @@ -1,4 +1,4 @@ -@if (!inCard) { +@if (!inCard()) {
diff --git a/src/app/pages/storage/components/dashboard-pool/dashboard-pool.component.ts b/src/app/pages/storage/components/dashboard-pool/dashboard-pool.component.ts index d91bff5ad2d..df790f0575b 100644 --- a/src/app/pages/storage/components/dashboard-pool/dashboard-pool.component.ts +++ b/src/app/pages/storage/components/dashboard-pool/dashboard-pool.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, + ChangeDetectionStrategy, Component, input, OnChanges, } from '@angular/core'; import { MatButton } from '@angular/material/button'; @@ -59,10 +59,10 @@ import { ZfsHealthCardComponent } from './zfs-health-card/zfs-health-card.compon ], }) export class DashboardPoolComponent implements OnChanges { - @Input() pool: Pool; - @Input() rootDataset: Dataset; - @Input() isLoading: boolean; - @Input() disks: StorageDashboardDisk[]; + readonly pool = input(); + readonly rootDataset = input(); + readonly isLoading = input(); + readonly disks = input(); readonly requiredRoles = [Role.FullAdmin]; protected readonly searchableElements = dashboardPoolElements; @@ -80,7 +80,7 @@ export class DashboardPoolComponent implements OnChanges { ) {} ngOnChanges(changes: IxSimpleChanges): void { - if (changes.isLoading || !this.isLoading) { + if (changes.isLoading || !this.isLoading()) { setTimeout(() => this.handlePendingGlobalSearchElement(), searchDelayConst * 2); } } @@ -88,7 +88,7 @@ export class DashboardPoolComponent implements OnChanges { onExport(): void { this.matDialog .open(ExportDisconnectModalComponent, { - data: this.pool, + data: this.pool(), }) .afterClosed() .pipe(untilDestroyed(this)) @@ -109,12 +109,12 @@ export class DashboardPoolComponent implements OnChanges { .pipe( filter(Boolean), switchMap(() => { - return this.api.job('pool.expand', [this.pool.id]).pipe(this.loader.withLoader()); + return this.api.job('pool.expand', [this.pool().id]).pipe(this.loader.withLoader()); }), filter((job) => job.state === JobState.Success), tap(() => { this.snackbar.success( - this.translate.instant('Successfully expanded pool {name}.', { name: this.pool.name }), + this.translate.instant('Successfully expanded pool {name}.', { name: this.pool().name }), ); this.store.loadDashboard(); }), @@ -127,15 +127,15 @@ export class DashboardPoolComponent implements OnChanges { onUpgrade(): void { this.dialogService.confirm({ title: this.translate.instant('Upgrade Pool'), - message: this.translate.instant(helptextVolumes.upgradePoolDialog_warning) + this.pool.name, + message: this.translate.instant(helptextVolumes.upgradePoolDialog_warning) + this.pool().name, }).pipe( filter(Boolean), switchMap(() => { - return this.api.call('pool.upgrade', [this.pool.id]).pipe(this.loader.withLoader()); + return this.api.call('pool.upgrade', [this.pool().id]).pipe(this.loader.withLoader()); }), tap(() => { this.snackbar.success( - this.translate.instant('Pool {name} successfully upgraded.', { name: this.pool.name }), + this.translate.instant('Pool {name} successfully upgraded.', { name: this.pool().name }), ); this.store.loadDashboard(); }), diff --git a/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.html b/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.html index 1c260cd7645..b17b17d254e 100644 --- a/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.html +++ b/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.html @@ -55,7 +55,7 @@

{{ 'Pool Status' | translate }}:
-
{{ pool.status | mapValue: poolStatusLabels | translate }}
+
{{ pool().status | mapValue: poolStatusLabels | translate }}
@@ -76,7 +76,7 @@

{{ 'Auto TRIM' | translate }}:
- {{ pool.autotrim.value === 'on' ? ('On' | translate) : ('Off' | translate) }} + {{ pool().autotrim.value === 'on' ? ('On' | translate) : ('Off' | translate) }}
{{ 'Edit Auto TRIM' | translate }} diff --git a/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.ts b/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.ts index 820b065401d..729ebf87233 100644 --- a/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.ts +++ b/src/app/pages/storage/components/dashboard-pool/zfs-health-card/zfs-health-card.component.ts @@ -1,6 +1,6 @@ import { DecimalPipe, PercentPipe } from '@angular/common'; import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnChanges, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { @@ -69,7 +69,7 @@ import { ApiService } from 'app/services/websocket/api.service'; ], }) export class ZfsHealthCardComponent implements OnChanges { - @Input() pool: Pool; + readonly pool = input.required(); protected readonly searchableElements = zfsHealthCardElements; @@ -153,33 +153,33 @@ export class ZfsHealthCardComponent implements OnChanges { } get iconType(): PoolCardIconType { - if (!this.pool.healthy) { + if (!this.pool().healthy) { return PoolCardIconType.Error; } - if (this.pool.status === PoolStatus.Degraded) { + if (this.pool().status === PoolStatus.Degraded) { return PoolCardIconType.Warn; } - if (this.pool.status === PoolStatus.Faulted) { + if (this.pool().status === PoolStatus.Faulted) { return PoolCardIconType.Faulted; } return PoolCardIconType.Safe; } get iconTooltip(): string { - if (!this.pool.healthy) { + if (!this.pool().healthy) { return this.translate.instant('Pool is not healthy'); } - if (this.pool.status === PoolStatus.Degraded) { - return this.translate.instant('Pool status is {status}', { status: this.pool.status }); + if (this.pool().status === PoolStatus.Degraded) { + return this.translate.instant('Pool status is {status}', { status: this.pool().status }); } - if (this.pool.status === PoolStatus.Faulted) { - return this.translate.instant('Pool status is {status}', { status: this.pool.status }); + if (this.pool().status === PoolStatus.Faulted) { + return this.translate.instant('Pool status is {status}', { status: this.pool().status }); } return this.translate.instant('Everything is fine'); } ngOnChanges(): void { - this.scan = this.pool.scan; + this.scan = this.pool().scan; this.subscribeToScan(); this.calculateTotalZfsErrors(); @@ -187,7 +187,7 @@ export class ZfsHealthCardComponent implements OnChanges { } onStartScrub(): void { - const message = this.translate.instant('Start scrub on pool {poolName}?', { poolName: this.pool.name }); + const message = this.translate.instant('Start scrub on pool {poolName}?', { poolName: this.pool().name }); this.dialogService.confirm({ message, title: this.translate.instant('Scrub Pool'), @@ -195,7 +195,7 @@ export class ZfsHealthCardComponent implements OnChanges { }) .pipe( filter(Boolean), - switchMap(() => this.api.startJob('pool.scrub', [this.pool.id, PoolScrubAction.Start])), + switchMap(() => this.api.startJob('pool.scrub', [this.pool().id, PoolScrubAction.Start])), this.errorHandler.catchError(), untilDestroyed(this), ) @@ -203,34 +203,34 @@ export class ZfsHealthCardComponent implements OnChanges { } onStopScrub(): void { - const message = this.translate.instant('Stop the scrub on {poolName}?', { poolName: this.pool.name }); + const message = this.translate.instant('Stop the scrub on {poolName}?', { poolName: this.pool().name }); this.dialogService.confirm({ message, title: this.translate.instant('Scrub Pool'), buttonText: this.translate.instant('Stop Scrub'), }).pipe( filter(Boolean), - switchMap(() => this.api.startJob('pool.scrub', [this.pool.id, PoolScrubAction.Stop])), + switchMap(() => this.api.startJob('pool.scrub', [this.pool().id, PoolScrubAction.Stop])), this.errorHandler.catchError(), untilDestroyed(this), ).subscribe(); } onPauseScrub(): void { - this.api.startJob('pool.scrub', [this.pool.id, PoolScrubAction.Pause]) + this.api.startJob('pool.scrub', [this.pool().id, PoolScrubAction.Pause]) .pipe(untilDestroyed(this)) .subscribe(); } onResumeScrub(): void { - this.api.startJob('pool.scrub', [this.pool.id, PoolScrubAction.Start]) + this.api.startJob('pool.scrub', [this.pool().id, PoolScrubAction.Start]) .pipe(untilDestroyed(this)) .subscribe(); } onEditAutotrim(): void { this.matDialog - .open(AutotrimDialogComponent, { data: this.pool }) + .open(AutotrimDialogComponent, { data: this.pool() }) .afterClosed() .pipe(filter(Boolean), untilDestroyed(this)) .subscribe(() => this.store.loadDashboard()); @@ -243,7 +243,7 @@ export class ZfsHealthCardComponent implements OnChanges { this.poolScanSubscription = this.api.subscribe('zfs.pool.scan') .pipe( map((apiEvent) => apiEvent.fields), - filter((scan) => scan.name === this.pool.name), + filter((scan) => scan.name === this.pool().name), this.errorHandler.catchError(), untilDestroyed(this), ) @@ -254,17 +254,17 @@ export class ZfsHealthCardComponent implements OnChanges { } private loadScrubTaskStatus(): void { - this.hasScrubTask$ = this.api.call('pool.scrub.query', [[['pool_name', '=', this.pool.name]]]).pipe( + this.hasScrubTask$ = this.api.call('pool.scrub.query', [[['pool_name', '=', this.pool().name]]]).pipe( map((scrubTasks) => scrubTasks.length > 0), toLoadingState(), ); } private calculateTotalZfsErrors(): void { - if (!this.pool.topology) { + if (!this.pool().topology) { return; } - this.totalZfsErrors = Object.values(this.pool.topology).reduce((totalErrors: number, vdevs: TopologyItem[]) => { + this.totalZfsErrors = Object.values(this.pool().topology).reduce((totalErrors: number, vdevs: TopologyItem[]) => { return totalErrors + vdevs.reduce((vdevCategoryErrors, vdev) => { return vdevCategoryErrors + (vdev.stats?.read_errors || 0) diff --git a/src/app/pages/storage/components/unused-resources/unused-resources.component.html b/src/app/pages/storage/components/unused-resources/unused-resources.component.html index cdd27096011..e9b364e76d8 100644 --- a/src/app/pages/storage/components/unused-resources/unused-resources.component.html +++ b/src/app/pages/storage/components/unused-resources/unused-resources.component.html @@ -3,7 +3,7 @@ @@ -12,7 +12,7 @@ diff --git a/src/app/pages/storage/components/unused-resources/unused-resources.component.ts b/src/app/pages/storage/components/unused-resources/unused-resources.component.ts index 00b7e3e189f..9eb43c052c6 100644 --- a/src/app/pages/storage/components/unused-resources/unused-resources.component.ts +++ b/src/app/pages/storage/components/unused-resources/unused-resources.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnInit, } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; @@ -24,7 +24,8 @@ import { UnusedDiskCardComponent } from './unused-disk-card/unused-disk-card.com imports: [UnusedDiskCardComponent, TranslateModule], }) export class UnusedResourcesComponent implements OnInit { - @Input() pools: Pool[]; + readonly pools = input.required(); + noPoolsDisks: DetailsDisk[] = []; exportedPoolsDisks: DetailsDisk[] = []; diskQuerySubscription: Subscription; @@ -76,7 +77,7 @@ export class UnusedResourcesComponent implements OnInit { private addUnusedDisksToStorage(disks: DetailsDisk[]): void { this.matDialog.open(ManageUnusedDiskDialogComponent, { data: { - pools: this.pools, + pools: this.pools(), unusedDisks: [...disks], }, width: '600px', diff --git a/src/app/pages/storage/modules/devices/components/hardware-disk-encryption/hardware-disk-encryption.component.ts b/src/app/pages/storage/modules/devices/components/hardware-disk-encryption/hardware-disk-encryption.component.ts index 5cc13d842f9..e1adaf4f7b2 100644 --- a/src/app/pages/storage/modules/devices/components/hardware-disk-encryption/hardware-disk-encryption.component.ts +++ b/src/app/pages/storage/modules/devices/components/hardware-disk-encryption/hardware-disk-encryption.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnChanges, } from '@angular/core'; import { MatCard, MatCardHeader, MatCardTitle, MatCardContent, @@ -41,7 +41,7 @@ import { ApiService } from 'app/services/websocket/api.service'; ], }) export class HardwareDiskEncryptionComponent implements OnChanges { - @Input() topologyDisk: TopologyDisk; + readonly topologyDisk = input.required(); hasGlobalEncryption$ = this.api.call('system.advanced.sed_global_password_is_set').pipe(toLoadingState()); hasDiskEncryption$: Observable>; @@ -60,7 +60,7 @@ export class HardwareDiskEncryptionComponent implements OnChanges { onManageSedPassword(): void { const dialog = this.matDialog.open(ManageDiskSedDialogComponent, { - data: this.topologyDisk.disk, + data: this.topologyDisk().disk, }); dialog .afterClosed() @@ -76,7 +76,7 @@ export class HardwareDiskEncryptionComponent implements OnChanges { } private loadDiskEncryption(): void { - this.hasDiskEncryption$ = this.api.call('disk.query', [[['devname', '=', this.topologyDisk.disk]], { extra: { passwords: true } }]) + this.hasDiskEncryption$ = this.api.call('disk.query', [[['devname', '=', this.topologyDisk().disk]], { extra: { passwords: true } }]) .pipe( map((disks) => disks[0].passwd !== ''), toLoadingState(), diff --git a/src/app/pages/storage/modules/pool-manager/components/manual-disk-selection/components/manual-selection-disks/manual-selection-disks.component.ts b/src/app/pages/storage/modules/pool-manager/components/manual-disk-selection/components/manual-selection-disks/manual-selection-disks.component.ts index c60cecb0e80..8c53383b133 100644 --- a/src/app/pages/storage/modules/pool-manager/components/manual-disk-selection/components/manual-selection-disks/manual-selection-disks.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/manual-disk-selection/components/manual-selection-disks/manual-selection-disks.component.ts @@ -1,7 +1,7 @@ import { NestedTreeControl } from '@angular/cdk/tree'; import { NgClass, AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, Component, Input, OnInit, + ChangeDetectionStrategy, Component, input, OnInit, } from '@angular/core'; import { RouterLinkActive } from '@angular/router'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; @@ -75,7 +75,7 @@ const noEnclosureId = 'no-enclosure'; ], }) export class ManualSelectionDisksComponent implements OnInit { - @Input() enclosures: Enclosure[] = []; + readonly enclosures = input.required(); dataSource: NestedTreeDataSource; treeControl = new NestedTreeControl((node) => node.children, { @@ -116,7 +116,7 @@ export class ManualSelectionDisksComponent implements OnInit { .pipe(untilDestroyed(this)) .subscribe(([disks, filterValues]) => { const filteredDisks = this.filterDisks(disks, filterValues); - const disksInEnclosures = this.mapDisksToEnclosures(filteredDisks, this.enclosures); + const disksInEnclosures = this.mapDisksToEnclosures(filteredDisks, this.enclosures()); // Don't show enclosure header if there is only one enclosure const nodes = disksInEnclosures.length === 1 diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.html index 7f4e0745d4a..981081d8479 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.html @@ -2,16 +2,16 @@

{{ 'Automated Disk Selection' | translate }}

{{ 'Automated Disk Selection' | translate }}

@if (!isNumberOfVdevsLimitedToOne) { {{ 'Advanced Options' | translate }}

mat-button type="button" class="manual-disk-selection" - [ixTest]="['manual', type]" - [disabled]="!layout" - (click)="store.openManualSelectionDialog(type)" + [ixTest]="['manual', type()]" + [disabled]="!layout()" + (click)="store.openManualSelectionDialog(type())" > {{ 'Manual Disk Selection' | translate }} diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.ts index cae3053a8ea..11aeb012008 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/automated-disk-selection/normal-selection/normal-selection.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, + ChangeDetectionStrategy, Component, input, OnChanges, OnInit, } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -42,10 +42,10 @@ import { minDisksPerLayout } from 'app/pages/storage/modules/pool-manager/utils/ ], }) export class NormalSelectionComponent implements OnInit, OnChanges { - @Input() type: VdevType; - @Input() layout: CreateVdevLayout; - @Input() isStepActive: boolean; - @Input() inventory: DetailsDisk[]; + readonly type = input.required(); + readonly layout = input.required(); + readonly isStepActive = input(); + readonly inventory = input.required(); form = this.formBuilder.group({ width: [{ value: null as number, disabled: true }, Validators.required], @@ -75,7 +75,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { } get isNumberOfVdevsLimitedToOne(): boolean { - return this.type === VdevType.Spare || this.type === VdevType.Cache || this.type === VdevType.Log; + return this.type() === VdevType.Spare || this.type() === VdevType.Cache || this.type() === VdevType.Log; } protected onDisksSelected(disks: DetailsDisk[]): void { @@ -87,7 +87,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { private listenForResetEvents(): void { merge( this.store.startOver$, - this.store.resetStep$.pipe(filter((vdevType) => vdevType === this.type)), + this.store.resetStep$.pipe(filter((vdevType) => vdevType === this.type())), ) .pipe(untilDestroyed(this)) .subscribe(() => { @@ -119,7 +119,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { this.form.valueChanges.pipe(untilDestroyed(this)).subscribe(() => { const values = this.form.value; - this.store.setAutomaticTopologyCategory(this.type, { + this.store.setAutomaticTopologyCategory(this.type(), { width: values.width, vdevsNumber: this.isNumberOfVdevsLimitedToOne ? 1 : values.vdevsNumber, }); @@ -131,7 +131,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { if (!availableDisks) { return; } - const minRequired = minDisksPerLayout[this.layout]; + const minRequired = minDisksPerLayout[this.layout()]; let nextOptions: Option[] = []; if (availableDisks && minRequired && availableDisks >= minRequired) { @@ -142,7 +142,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { unsetControlIfNoMatchingOption(this.form.controls.width, nextOptions); - if (nextOptions.length === 1 && this.isStepActive) { + if (nextOptions.length === 1 && this.isStepActive()) { setValueIfNotSame(this.form.controls.width, Number(nextOptions[0].value)); } @@ -167,7 +167,7 @@ export class NormalSelectionComponent implements OnInit, OnChanges { unsetControlIfNoMatchingOption(this.form.controls.vdevsNumber, nextOptions); - if (nextOptions.length === 1 && this.isStepActive) { + if (nextOptions.length === 1 && this.isStepActive()) { setValueIfNotSame(this.form.controls.vdevsNumber, Number(nextOptions[0].value)); } } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.html index 8be84d6ddf6..d21df332c5b 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.html @@ -7,8 +7,8 @@

{{ 'Manually Configured VDEVs' | translate }}

mat-button type="button" class="manual-disk-selection" - [ixTest]="['manual', type]" - (click)="poolManagerStore.openManualSelectionDialog(type)" + [ixTest]="['manual', type()]" + (click)="poolManagerStore.openManualSelectionDialog(type())" > {{ 'Edit Manual Disk Selection' | translate }} @@ -18,7 +18,7 @@

{{ 'Manually Configured VDEVs' | translate }}

{{ 'Description' | translate }}

  • - {{ 'VDEVs' | translate }}: {{ vdevs.length }} + {{ 'VDEVs' | translate }}: {{ vdevs().length }}
  • {{ 'No warnings' | translate }} diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.ts index 516cb4bb779..1832d3db5cf 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/custom-layout-applied/custom-layout-applied.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, Component, Input, + ChangeDetectionStrategy, Component, input, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; @@ -24,8 +24,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class CustomLayoutAppliedComponent { - @Input() type: VdevType; - @Input() vdevs: DetailsDisk[][]; + readonly type = input.required(); + readonly vdevs = input.required(); readonly manualDiskSelectionMessage = helptextManager.manual_disk_selection_message; @@ -33,13 +33,13 @@ export class CustomLayoutAppliedComponent { protected poolManagerStore: PoolManagerStore, ) { this.poolManagerStore.resetStep$.pipe(untilDestroyed(this)).subscribe((vdevType: VdevType) => { - if (vdevType === this.type) { + if (vdevType === this.type()) { this.resetLayout(); } }); } resetLayout(): void { - this.poolManagerStore.resetTopologyCategory(this.type); + this.poolManagerStore.resetTopologyCategory(this.type()); } } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.html index bf6d1f76b44..c2e419ac633 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.html @@ -1,19 +1,19 @@
    - {{ description }} + {{ description() }}
    @if (!topologyCategory.hasCustomDiskSelection) { } @else { } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.ts index 3d96866a09e..cece882d9ec 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/components/layout-step/layout-step.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnInit, } from '@angular/core'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { CreateVdevLayout, VdevType } from 'app/enums/v-dev-type.enum'; @@ -21,19 +21,19 @@ import { CustomLayoutAppliedComponent } from './custom-layout-applied/custom-lay imports: [AutomatedDiskSelectionComponent, CustomLayoutAppliedComponent], }) export class LayoutStepComponent implements OnInit { - @Input() isStepActive: boolean; - @Input() type: VdevType; - @Input() description: string; + readonly isStepActive = input(); + readonly type = input.required(); + readonly description = input(); - @Input() canChangeLayout = false; - @Input() limitLayouts: CreateVdevLayout[]; + readonly canChangeLayout = input(false); + readonly limitLayouts = input(); - @Input() inventory: DetailsDisk[]; + readonly inventory = input(); protected topologyCategory: PoolManagerTopologyCategory; get isVdevsLimitedToOne(): boolean { - return this.type === VdevType.Spare || this.type === VdevType.Cache || this.type === VdevType.Log; + return this.type() === VdevType.Spare || this.type() === VdevType.Cache || this.type() === VdevType.Log; } constructor( @@ -47,7 +47,7 @@ export class LayoutStepComponent implements OnInit { private connectToStore(): void { this.store.state$.pipe(untilDestroyed(this)).subscribe(({ topology }) => { - this.topologyCategory = topology[this.type]; + this.topologyCategory = topology[this.type()]; this.cdr.markForCheck(); }); } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/pool-manager-wizard.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/pool-manager-wizard.component.html index 1751b5018e8..387e7e6c32b 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/pool-manager-wizard.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/pool-manager-wizard.component.html @@ -25,7 +25,6 @@ @@ -50,6 +49,7 @@ } @@ -218,7 +218,6 @@ {{ 'Review' | translate }} diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.html index 5fd7de13c08..c3bcde31a5f 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.html @@ -3,17 +3,17 @@ formControlName="name" [label]="'Name' | translate" [required]="true" - [readonly]="isAddingVdevs" + [readonly]="isAddingVdevs()" > - @if (!isAddingVdevs) { + @if (!isAddingVdevs()) { } - @if (form.controls.encryption.value && !isAddingVdevs) { + @if (form.controls.encryption.value && !isAddingVdevs()) { { }); beforeEach(() => { - spectator = createComponent({ - props: { - isStepActive: true, - }, - }); + spectator = createComponent(); loader = TestbedHarnessEnvironment.loader(spectator.fixture); }); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.ts index f0433ade955..3a0e1281629 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/1-general-wizard-step/general-wizard-step.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnChanges, OnInit, } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -48,9 +48,8 @@ const defaultEncryptionStandard = 'AES-256-GCM'; ], }) export class GeneralWizardStepComponent implements OnInit, OnChanges { - @Input() isAddingVdevs = false; - @Input() pool: Pool; - @Input() isStepActive: boolean; + readonly isAddingVdevs = input(false); + readonly pool = input(undefined); form = this.formBuilder.group({ name: ['', Validators.required], @@ -80,10 +79,10 @@ export class GeneralWizardStepComponent implements OnInit, OnChanges { ) { } ngOnChanges(): void { - if (this.isAddingVdevs) { + if (this.isAddingVdevs()) { this.form.controls.encryption.disable(); this.form.controls.encryptionStandard.disable(); - this.form.controls.name.setValue(this.pool?.name || ''); + this.form.controls.name.setValue(this.pool()?.name || ''); this.form.controls.name.removeAsyncValidators(this.oldNameForbiddenValidator); this.form.controls.name.updateValueAndValidity(); } else { diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.html index da710ec044d..2c5f3dff924 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.html @@ -20,9 +20,9 @@ } -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.ts index 0dd2dcc878a..edd3badc87e 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/2-enclosure-wizard-step/enclosure-wizard-step.component.ts @@ -1,5 +1,5 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnChanges, OnInit, } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; @@ -44,8 +44,8 @@ export enum DispersalStrategy { ], }) export class EnclosureWizardStepComponent implements OnInit, OnChanges { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); form = this.formBuilder.group({ dispersalStrategy: [DispersalStrategy.None], diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.html index 4d3fdb96489..bd07e64894e 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.html @@ -4,12 +4,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="canChangeLayout" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.ts index 7304198e01f..e8528917efb 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/3-data-wizard-step/data-wizard-step.component.ts @@ -2,8 +2,7 @@ import { AsyncPipe } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, - Input, + Component, input, OnInit, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; @@ -40,8 +39,8 @@ import { parseDraidVdevName } from 'app/pages/storage/modules/pool-manager/utils ], }) export class DataWizardStepComponent implements OnInit { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input.required(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.html index 2971efc3b67..64a7c801fa5 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.html @@ -4,12 +4,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="canChangeLayout" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.ts index 712b1a24b8d..52faff8808b 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/4-log-wizard-step/log-wizard-step.component.ts @@ -1,6 +1,6 @@ import { AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, output, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnInit, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; @@ -33,8 +33,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class LogWizardStepComponent implements OnInit { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.html index 1b14f00f317..034c11d144f 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.html @@ -4,12 +4,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="false" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.ts index 292dbc42c89..b48492e089c 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/5-spare-wizard-step/spare-wizard-step.component.ts @@ -1,6 +1,6 @@ import { AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, Component, Input, output, + ChangeDetectionStrategy, Component, input, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; @@ -29,8 +29,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class SpareWizardStepComponent { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.html index 75bd0a4c28c..f9ebf89eb21 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.html @@ -5,12 +5,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="false" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.ts index 05492e6e621..6380a35c2d3 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/6-cache-wizard-step/cache-wizard-step.component.ts @@ -1,6 +1,6 @@ import { AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, Component, Input, output, + ChangeDetectionStrategy, Component, input, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; @@ -29,8 +29,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class CacheWizardStepComponent { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.html index 14e6f8bb527..c26e1e7fb7b 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.html @@ -4,12 +4,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="canChangeLayout" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.ts index 2ab4b4c734d..0ba3e189522 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/7-metadata-wizard-step/metadata-wizard-step.component.ts @@ -1,6 +1,6 @@ import { AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, output, + ChangeDetectionStrategy, ChangeDetectorRef, Component, input, OnInit, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; @@ -33,8 +33,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class MetadataWizardStepComponent implements OnInit { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.html index 92ba8cf7125..6facde2cc87 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.html @@ -4,12 +4,12 @@ [inventory]="inventory$ | async" [canChangeLayout]="canChangeLayout" [limitLayouts]="allowedLayouts" - [isStepActive]="isStepActive" + [isStepActive]="isStepActive()" > -@if (stepWarning) { +@if (stepWarning()) {

    - {{ stepWarning }} + {{ stepWarning() }}

    } diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.ts index c88755e5e06..464304defe2 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/8-dedup-wizard-step/dedup-wizard-step.component.ts @@ -1,6 +1,6 @@ import { AsyncPipe } from '@angular/common'; import { - ChangeDetectionStrategy, Component, Input, output, + ChangeDetectionStrategy, Component, input, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper'; @@ -31,8 +31,8 @@ import { PoolManagerStore } from 'app/pages/storage/modules/pool-manager/store/p ], }) export class DedupWizardStepComponent { - @Input() isStepActive: boolean; - @Input() stepWarning: string | null; + readonly isStepActive = input(); + readonly stepWarning = input(); readonly goToLastStep = output(); diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.html b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.html index 733da604483..41626b69bfa 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.html +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.html @@ -114,6 +114,6 @@

    {{ 'Warnings' | translate }}

    [disabled]="isCreateDisabled" (click)="createPool.emit()" > - {{ isAddingVdevs ? ('Update Pool' | translate) : ('Create Pool' | translate) }} + {{ isAddingVdevs() ? ('Update Pool' | translate) : ('Create Pool' | translate) }}
diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.spec.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.spec.ts index 27becc1b8c1..202472dfbb6 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.spec.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.spec.ts @@ -94,11 +94,7 @@ describe('ReviewWizardStepComponent', () => { describe('buttons', () => { beforeEach(() => { - spectator = createComponent({ - props: { - isStepActive: true, - }, - }); + spectator = createComponent(); loader = TestbedHarnessEnvironment.loader(spectator.fixture); }); @@ -126,11 +122,7 @@ describe('ReviewWizardStepComponent', () => { describe('summary', () => { beforeEach(() => { - spectator = createComponent({ - props: { - isStepActive: true, - }, - }); + spectator = createComponent(); loader = TestbedHarnessEnvironment.loader(spectator.fixture); }); @@ -196,9 +188,6 @@ describe('ReviewWizardStepComponent', () => { describe('validation', () => { beforeEach(() => { spectator = createComponent({ - props: { - isStepActive: true, - }, providers: [ mockProvider(PoolManagerStore, { state$, diff --git a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.ts b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.ts index 0252637ce85..ac022a297f9 100644 --- a/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.ts +++ b/src/app/pages/storage/modules/pool-manager/components/pool-manager-wizard/steps/9-review-wizard-step/review-wizard-step.component.ts @@ -1,7 +1,7 @@ import { AsyncPipe } from '@angular/common'; import { ChangeDetectionStrategy, - ChangeDetectorRef, Component, Input, OnInit, output, + ChangeDetectorRef, Component, input, OnInit, output, } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; @@ -51,8 +51,7 @@ import { ], }) export class ReviewWizardStepComponent implements OnInit { - @Input() isStepActive: boolean; - @Input() isAddingVdevs: boolean; + readonly isAddingVdevs = input(); readonly createPool = output(); diff --git a/tsconfig.strictNullChecks.json b/tsconfig.strictNullChecks.json index 53e4dfeadd2..9443d08bc1e 100644 --- a/tsconfig.strictNullChecks.json +++ b/tsconfig.strictNullChecks.json @@ -265,7 +265,6 @@ "./src/app/interfaces/alert.interface.ts", "./src/app/interfaces/api-date.interface.ts", "./src/app/interfaces/api-key.interface.ts", - "./src/app/interfaces/api-message.interface.ts", "./src/app/interfaces/app-details-route-params.interface.ts", "./src/app/interfaces/apps-filters-values.interface.ts", "./src/app/interfaces/audit/audit.interface.ts", @@ -389,7 +388,6 @@ "./src/app/interfaces/validated-file.interface.ts", "./src/app/interfaces/virtual-machine.interface.ts", "./src/app/interfaces/vm-device.interface.ts", - "./src/app/interfaces/vmware.interface.ts", "./src/app/interfaces/volume-data.interface.ts", "./src/app/interfaces/volumes-list-pool.interface.ts", "./src/app/interfaces/api-error.interface.ts", @@ -564,7 +562,6 @@ "./src/app/pages/data-protection/cloudsync/cloudsync-provider-description/cloudsync-provider-description.ts", "./src/app/pages/data-protection/cloudsync/transfer-mode-explanation/transfer-mode-explanation.component.ts", "./src/app/pages/data-protection/replication/replication-wizard/replication-wizard-data.interface.ts", - "./src/app/pages/data-protection/vmware-snapshot/vmware-snapshot-list/vmware-status-cell/vmware-status-cell.component.ts", "./src/app/pages/datasets/components/dataset-form/utils/name-length-validation.spec.ts", "./src/app/pages/datasets/components/dataset-form/utils/name-length-validation.ts", "./src/app/pages/datasets/components/dataset-form/utils/special-small-block-size-options.constant.ts",