Skip to content

Commit

Permalink
NAS-130468: Changing catalog trains should trigger resync (#10415)
Browse files Browse the repository at this point in the history
  • Loading branch information
undsoft authored Aug 9, 2024
1 parent 55be791 commit d3d818c
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export class IxSlideInComponent implements OnInit, OnDestroy {
private slideInService: IxSlideInService,
private renderer: Renderer2,
private cdr: ChangeDetectorRef,
private defaultInjector: Injector,
) {
this.element = this.el.nativeElement as HTMLElement;
}
Expand Down Expand Up @@ -81,7 +82,7 @@ export class IxSlideInComponent implements OnInit, OnDestroy {

openSlideIn<T, D>(
componentType: Type<T>,
params?: { wide?: boolean; data?: D },
params?: { wide?: boolean; data?: D; injector?: Injector },
): IxSlideInRef<T, D> {
if (this.isSlideInOpen) {
console.error('SlideIn is already open');
Expand All @@ -100,19 +101,25 @@ export class IxSlideInComponent implements OnInit, OnDestroy {

this.cdr.markForCheck();

return this.createSlideInRef<T, D>(componentType, params?.data);
return this.createSlideInRef<T, D>(
componentType,
params?.data,
params?.injector || this.defaultInjector,
);
}

private createSlideInRef<T, D>(
componentType: Type<T>,
data?: D,
parentInjector?: Injector,
): IxSlideInRef<T, D> {
const slideInRef = new IxSlideInRef<T, D>();
const injector = Injector.create({
providers: [
{ provide: SLIDE_IN_DATA, useValue: data },
{ provide: IxSlideInRef, useValue: slideInRef },
],
parent: parentInjector,
});
slideInRef.componentRef = this.slideInBody.createComponent<T>(componentType, { injector });
slideInRef.id = UUID.UUID();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
<ix-modal-header
[title]="'Edit Catalog' | translate"
[loading]="isFormLoading"
[loading]="isFormLoading()"
></ix-modal-header>

<mat-card>
<mat-card-content>
<form class="ix-form-container" [formGroup]="form" (submit)="onSubmit()">
<ix-fieldset>
<ix-input
formControlName="label"
[label]="'Catalog Name' | translate"
[required]="true"
[tooltip]="tooltips.label | translate"
></ix-input>

<ix-chips
formControlName="preferred_trains"
[required]="true"
[label]="'Preferred Trains' | translate"
[tooltip]="tooltips.preferred_trains | translate"
></ix-chips>
Expand All @@ -27,11 +21,11 @@
type="submit"
color="primary"
ixTest="save"
[disabled]="form.invalid || isFormLoading"
[disabled]="form.invalid || isFormLoading()"
>
{{ 'Save' | translate }}
</button>
</ix-form-actions>
</form>
</mat-card-content>
</mat-card>
</mat-card>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { IxFormsModule } from 'app/modules/forms/ix-forms/ix-forms.module';
import { FormErrorHandlerService } from 'app/modules/forms/ix-forms/services/form-error-handler.service';
import { IxFormHarness } from 'app/modules/forms/ix-forms/testing/ix-form.harness';
import { CatalogSettingsComponent } from 'app/pages/apps/components/catalog-settings/catalog-settings.component';
import { AppsStore } from 'app/pages/apps/store/apps-store.service';
import { WebSocketService } from 'app/services/ws.service';

describe('CatalogEditFormComponent', () => {
Expand All @@ -30,6 +31,7 @@ describe('CatalogEditFormComponent', () => {
preferred_trains: ['test'],
} as Catalog),
]),
mockProvider(AppsStore),
mockProvider(IxSlideInRef),
mockProvider(FormErrorHandlerService),
mockAuth(),
Expand All @@ -41,17 +43,16 @@ describe('CatalogEditFormComponent', () => {
loader = TestbedHarnessEnvironment.loader(spectator.fixture);
});

it('shows catalog name and preferred trains when catalog is open for editing', async () => {
it('shows preferred trains when catalog is open for editing', async () => {
const form = await loader.getHarness(IxFormHarness);
const values = await form.getValues();

expect(values).toEqual({
'Catalog Name': 'TrueNAS',
'Preferred Trains': ['test'],
});
});

it('saves catalog updates when form is saved', async () => {
it('saves catalog updates and reloads catalog apps when form is saved', async () => {
const form = await loader.getHarness(IxFormHarness);
await form.fillForm({
'Preferred Trains': ['stable', 'incubator'],
Expand All @@ -63,5 +64,6 @@ describe('CatalogEditFormComponent', () => {
expect(spectator.inject(WebSocketService).call).toHaveBeenCalledWith('catalog.update', [
{ preferred_trains: ['stable', 'incubator'] },
]);
expect(spectator.inject(AppsStore).loadCatalog).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit,
ChangeDetectionStrategy, Component, OnInit, signal,
} from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { switchMap } from 'rxjs';
import { helptextApps } from 'app/helptext/apps/apps';
import { Catalog, CatalogUpdate } from 'app/interfaces/catalog.interface';
import { IxSlideInRef } from 'app/modules/forms/ix-forms/components/ix-slide-in/ix-slide-in-ref';
import { FormErrorHandlerService } from 'app/modules/forms/ix-forms/services/form-error-handler.service';
import { AppsStore } from 'app/pages/apps/store/apps-store.service';
import { WebSocketService } from 'app/services/ws.service';

@UntilDestroy()
Expand All @@ -16,28 +18,25 @@ import { WebSocketService } from 'app/services/ws.service';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CatalogSettingsComponent implements OnInit {
isFormLoading = false;
protected isFormLoading = signal(false);

form = this.fb.group({
label: ['', Validators.required],
protected form = this.fb.group({
preferred_trains: [[] as string[], Validators.required],
});

readonly tooltips = {
label: helptextApps.catalogForm.name.tooltip,
preferred_trains: helptextApps.catalogForm.preferredTrains.tooltip,
};

constructor(
private ws: WebSocketService,
private slideInRef: IxSlideInRef<CatalogSettingsComponent>,
private errorHandler: FormErrorHandlerService,
private cdr: ChangeDetectorRef,
private fb: FormBuilder,
private appsStore: AppsStore,
) {}

ngOnInit(): void {
this.form.controls.label.disable();
this.setupForm();
}

Expand All @@ -47,7 +46,6 @@ export class CatalogSettingsComponent implements OnInit {
).subscribe({
next: (config: Catalog) => {
this.form.patchValue({
label: config.label,
preferred_trains: config.preferred_trains,
});
},
Expand All @@ -57,19 +55,20 @@ export class CatalogSettingsComponent implements OnInit {
onSubmit(): void {
const { preferred_trains: preferredTrains } = this.form.value;

this.isFormLoading = true;
this.isFormLoading.set(true);
this.ws.call('catalog.update', [{ preferred_trains: preferredTrains } as CatalogUpdate])
.pipe(untilDestroyed(this))
.pipe(
switchMap(() => this.appsStore.loadCatalog()),
untilDestroyed(this),
)
.subscribe({
next: () => {
this.isFormLoading = false;
this.cdr.markForCheck();
this.isFormLoading.set(false);
this.slideInRef.close(true);
},
error: (error: unknown) => {
this.isFormLoading = false;
this.isFormLoading.set(false);
this.errorHandler.handleWsFormError(error, this.form);
this.cdr.markForCheck();
},
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
ChangeDetectionStrategy, Component, ViewContainerRef,
ChangeDetectionStrategy, Component, Injector, ViewContainerRef,
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
Expand Down Expand Up @@ -32,6 +32,7 @@ export class AppSettingsButtonComponent {
private snackbar: SnackbarService,
protected dockerStore: DockerStore,
private viewContainerRef: ViewContainerRef,
private injector: Injector,
) { }

onChoosePool(): void {
Expand All @@ -54,6 +55,6 @@ export class AppSettingsButtonComponent {
}

manageCatalog(): void {
this.ixSlideInService.open(CatalogSettingsComponent);
this.ixSlideInService.open(CatalogSettingsComponent, { injector: this.injector });
}
}
8 changes: 7 additions & 1 deletion src/app/pages/apps/store/apps-store.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export class AppsStore extends ComponentStore<AppsState> {

readonly initialize = this.effect((triggers$: Observable<void>) => {
return triggers$.pipe(
switchMap(() => this.loadCatalog()),
);
});

loadCatalog(): Observable<unknown> {
return of(null).pipe(
tap(() => {
this.patchState({
...initialState,
Expand All @@ -93,7 +99,7 @@ export class AppsStore extends ComponentStore<AppsState> {
return EMPTY;
}),
);
});
}

private loadLatestApps(): Observable<unknown> {
return this.appsService.getLatestApps().pipe(
Expand Down
7 changes: 5 additions & 2 deletions src/app/services/ix-slide-in.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Location } from '@angular/common';
import { Injectable, Type } from '@angular/core';
import { Injectable, Injector, Type } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import {
Expand Down Expand Up @@ -40,7 +40,10 @@ export class IxSlideInService {
this.slideInComponent = slideComponent;
}

open<T, D>(component: Type<T>, params?: { wide?: boolean; data?: D }): IxSlideInRef<T, D> {
open<T, D>(
component: Type<T>,
params?: { wide?: boolean; data?: D; injector?: Injector },
): IxSlideInRef<T, D> {
this.slideInRefMap.forEach((ref) => ref.close());

const slideInRef = this.slideInComponent.openSlideIn<T, D>(component, params);
Expand Down

0 comments on commit d3d818c

Please sign in to comment.