Skip to content

Commit

Permalink
NAS-130988 / 25.04 / Migrate more components to signal inputs (#10680)
Browse files Browse the repository at this point in the history
* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs

* NAS-130988: Migrate more components to signal inputs
  • Loading branch information
denysbutenko authored Sep 19, 2024
1 parent 119af35 commit 5f70210
Show file tree
Hide file tree
Showing 139 changed files with 817 additions and 427 deletions.
9 changes: 9 additions & 0 deletions src/app/enums/iscsi.enum.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { marker as T } from '@biesbjerg/ngx-translate-extract-marker';

export enum IscsiAuthMethod {
None = 'NONE',
Chap = 'CHAP',
Expand Down Expand Up @@ -30,3 +32,10 @@ export enum IscsiExtentUsefor {
Legacyos = 'legacyos',
Modernos = 'modernos',
}

export const iscsiExtentUseforMap = new Map([
[IscsiExtentUsefor.Vmware, T('VMware: Extent block size 512b, TPC enabled, no Xen compat mode, SSD speed')],
[IscsiExtentUsefor.Xen, T('Xen: Extent block size 512b, TPC enabled, Xen compat mode enabled, SSD speed')],
[IscsiExtentUsefor.Legacyos, T('Legacy OS: Extent block size 512b, TPC enabled, no Xen compat mode, SSD speed')],
[IscsiExtentUsefor.Modernos, T('Modern OS: Extent block size 4k, TPC enabled, no Xen compat mode, SSD speed')],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ <h3>{{ 'Application Info' | translate }}</h3>

<div class="app-list-item">
<span class="label">{{ 'Version' | translate }}:</span>
@if (isLoading$() | async) {
@if (isLoading()) {
<ngx-skeleton-loader></ngx-skeleton-loader>
} @else {
{{ app()?.latest_app_version | orNotAvailable }}
}
</div>
<div class="app-list-item sources">
<span class="label">{{ 'Source' | translate }}:</span>
@if (isLoading$() | async) {
@if (isLoading()) {
<ngx-skeleton-loader></ngx-skeleton-loader>
} @else {
<div>
Expand All @@ -33,7 +33,7 @@ <h3>{{ 'Application Info' | translate }}</h3>
</div>
<div class="app-list-item">
<span class="label">{{ 'Last App Update' }}:</span>
@if (isLoading$() | async) {
@if (isLoading()) {
<ngx-skeleton-loader></ngx-skeleton-loader>
} @else {
@if (app()?.last_update) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Spectator } from '@ngneat/spectator';
import { createComponentFactory } from '@ngneat/spectator/jest';
import { BehaviorSubject } from 'rxjs';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { AvailableApp } from 'app/interfaces/available-app.interface';
import { CleanLinkPipe } from 'app/modules/pipes/clean-link/clean-link.pipe';
import { OrNotAvailablePipe } from 'app/modules/pipes/or-not-available/or-not-available.pipe';
Expand All @@ -9,8 +9,6 @@ import { AppAvailableInfoCardComponent } from 'app/pages/apps/components/app-det
describe('AppAvailableInfoCardComponent', () => {
let spectator: Spectator<AppAvailableInfoCardComponent>;

const isLoading$ = new BehaviorSubject(false);

const fakeApp = {
catalog: 'OFFICIAL',
train: 'charts',
Expand All @@ -35,14 +33,15 @@ describe('AppAvailableInfoCardComponent', () => {
imports: [
CleanLinkPipe,
OrNotAvailablePipe,
NgxSkeletonLoaderModule,
],
});

beforeEach(() => {
spectator = createComponent({
props: {
isLoading$,
app: fakeApp,
isLoading: false,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
} from '@angular/core';
import { UntilDestroy } from '@ngneat/until-destroy';
import { formatRelative } from 'date-fns';
import { Observable } from 'rxjs';
import { AvailableApp } from 'app/interfaces/available-app.interface';

@UntilDestroy()
Expand All @@ -15,9 +14,8 @@ import { AvailableApp } from 'app/interfaces/available-app.interface';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppAvailableInfoCardComponent {
readonly isLoading$ = input.required<Observable<boolean>>();
readonly isLoading = input<boolean>(true);
readonly app = input<AvailableApp>();

readonly relativeDate = computed(() => {
return formatRelative(new Date(this.app().last_update.$date), new Date());
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
<ix-page-header
[pageTitle]="pageTitle"
[loading]="isLoading$ | async"
[pageTitle]="pageTitle()"
[loading]="isLoading()"
></ix-page-header>

<div class="flex-container">
<div class="app-wrapper">
<section>
<ix-app-details-header
[app]="app"
[isLoading$]="isLoading$"
[app]="app()"
[isLoading]="isLoading()"
></ix-app-details-header>
</section>

@if ((isLoading$ | async) || app?.screenshots?.length) {
@if (isLoading() || app()?.screenshots?.length) {
<section>
<h2>{{ 'Screenshots' | translate }}</h2>
<div>
@if (isLoading$ | async) {
@if (isLoading()) {
<div class="screenshots-loader">
<ngx-skeleton-loader class="screenshot-loader"></ngx-skeleton-loader>
<ngx-skeleton-loader class="screenshot-loader"></ngx-skeleton-loader>
<ngx-skeleton-loader class="screenshot-loader"></ngx-skeleton-loader>
</div>
} @else {
<div class="screenshots" gallerize>
@for (image of app.screenshots; track image) {
@for (image of app().screenshots; track image) {
<div class="screenshot">
<img class="screenshot-image" [src]="image" [src-fallback]="imagePlaceholder" />
</div>
Expand All @@ -39,9 +39,9 @@ <h2>{{ 'Screenshots' | translate }}</h2>
<ng-container *ngTemplateOutlet="appDetailCards"></ng-container>
</div>

@if (app) {
@if (app()) {
<section>
<ix-app-details-similar [app]="app"></ix-app-details-similar>
<ix-app-details-similar [app]="app()"></ix-app-details-similar>
</section>
}
</div>
Expand All @@ -56,25 +56,27 @@ <h2>{{ 'Screenshots' | translate }}</h2>
<section class="app-info-cards">
<ix-app-resources-card
class="app-info-card"
[isLoading]="isLoading$ | async"
[isLoading]="isLoading()"
></ix-app-resources-card>

<ix-app-available-info-card
class="app-info-card"
[app]="app"
[isLoading$]="isLoading$"
[app]="app()"
[isLoading]="isLoading()"
></ix-app-available-info-card>

<ix-app-json-details-card
class="app-info-card"
[title]="'Run As Context' | translate"
[jsonDetails]="app?.app_metadata?.run_as_context"
[isLoading$]="isLoading$"
[jsonDetails]="app()?.app_metadata?.run_as_context"
[isLoading]="isLoading()"
></ix-app-json-details-card>

<ix-app-json-details-card
class="app-info-card"
[title]="'Capabilities' | translate"
[jsonDetails]="app?.app_metadata?.capabilities"
[isLoading$]="isLoading$"
[jsonDetails]="app()?.app_metadata?.capabilities"
[isLoading]="isLoading()"
></ix-app-json-details-card>
</section>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@
}

.screenshot-loader {
flex: 1;

::ng-deep span {
height: 160px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { AuthService } from 'app/services/auth/auth.service';

const appsResponse = [{
name: 'webdav',
catalog: 'TRUENAS',
train: 'community',
description: 'webdav',
app_readme: '<h1>WebDAV</h1>\n<p> When application ...</p>',
Expand Down Expand Up @@ -93,7 +92,7 @@ describe('AppDetailViewComponent', () => {
}),
mockProvider(AppsStatsService),
],
params: { appId: 'webdav', catalog: 'TRUENAS', train: 'community' },
params: { appId: 'webdav', train: 'community' },
});

beforeEach(() => {
Expand All @@ -104,6 +103,9 @@ describe('AppDetailViewComponent', () => {
it('redirect to install app when Install button is pressed', async () => {
const saveButton = await loader.getHarness(MatButtonHarness.with({ text: 'Install' }));
await saveButton.click();
expect(spectator.inject(Router).navigate).toHaveBeenCalledWith(['/apps', 'available', 'community', 'webdav', 'install']);

expect(spectator.inject(Router).navigate).toHaveBeenCalledWith([
'/apps', 'available', 'community', 'webdav', 'install',
]);
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {
ChangeDetectionStrategy, Component, OnInit, ChangeDetectorRef,
ChangeDetectionStrategy, Component, OnInit,
signal,
computed,
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { Gallery, GalleryItem, ImageItem } from 'ng-gallery';
import {
map, filter, BehaviorSubject, tap, switchMap,
map, filter, switchMap,
tap,
} from 'rxjs';
import { appImagePlaceholder } from 'app/constants/catalog.constants';
import { AppDetailsRouteParams } from 'app/interfaces/app-details-route-params.interface';
Expand All @@ -21,23 +24,20 @@ import { AppsStore } from 'app/pages/apps/store/apps-store.service';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppDetailViewComponent implements OnInit {
app: AvailableApp;

appId: string;
train: string;

isLoading$ = new BehaviorSubject<boolean>(true);
readonly app = signal<AvailableApp>(null);
readonly appId = signal<string>('');
readonly train = signal<string>('');
readonly isLoading = signal(true);
readonly imagePlaceholder = appImagePlaceholder;
readonly items = signal<GalleryItem[]>([]);

items: GalleryItem[];

get pageTitle(): string {
return this.app?.title || this.app?.name || this.translate.instant('...');
}
pageTitle = computed<string>(() => {
const app = this.app();
return app?.title || app?.name || this.translate.instant('...');
});

constructor(
private activatedRoute: ActivatedRoute,
private cdr: ChangeDetectorRef,
private translate: TranslateService,
private applicationsStore: AppsStore,
private gallery: Gallery,
Expand All @@ -50,54 +50,53 @@ export class AppDetailViewComponent implements OnInit {
}

private listenForRouteChanges(): void {
// TODO: Update when `input()` will have support for router params
this.activatedRoute.params
.pipe(
filter((params) => {
return !!(params.appId as string) && !!(params.train as string);
}),
tap(() => {
this.isLoading$.next(true);
}),
filter(({ appId, train }: AppDetailsRouteParams) => Boolean(appId && train)),
tap(() => this.isLoading.set(true)),
untilDestroyed(this),
)
.subscribe(({ appId, train }: AppDetailsRouteParams) => {
this.appId = appId;
this.train = train;
.subscribe(({ appId, train }) => {
this.appId.set(appId);
this.train.set(train);
this.loadAppInfo();
});
}

private loadAppInfo(): void {
this.isLoading$.next(true);
this.isLoading.set(true);
this.applicationsStore.isLoading$.pipe(
filter((isLoading) => !isLoading),
switchMap(() => {
return this.applicationsStore.availableApps$.pipe(
map((apps: AvailableApp[]) => apps.find(
(app) => app.name === this.appId && this.train === app.train,
)),
map((apps: AvailableApp[]) => {
const appId = this.appId();
const train = this.train();
return apps.find((app) => app.name === appId && app.train === train);
}),
);
}),
).pipe(untilDestroyed(this)).subscribe({
next: (app) => {
this.isLoading$.next(false);
this.cdr.markForCheck();
this.isLoading.set(false);

if (app) {
this.app = app;
} else {
if (!app) {
this.router.navigate(['/apps/installed']);
} else {
this.app.set(app);
}
},
error: () => {
this.isLoading$.next(false);
this.cdr.markForCheck();
this.isLoading.set(false);
},
});
}

setLightbox(): void {
this.items = this.app?.screenshots?.map((image) => new ImageItem({ src: image, thumb: image }));
this.gallery.ref('lightbox').load(this.items);
const app = this.app();
const images = app?.screenshots?.map((image) => new ImageItem({ src: image, thumb: image }));
this.items.set(images);
this.gallery.ref('lightbox').load(this.items());
}
}
Loading

0 comments on commit 5f70210

Please sign in to comment.