Skip to content

Commit

Permalink
NAS-131403 / 25.04 / Use app.redeploy endpoint for restart apps (#1…
Browse files Browse the repository at this point in the history
…0760)

* NAS-131403: Use `app.redeploy` endpoint for restart apps

* NAS-131403: Add restart action to installed apps

* NAS-131403: Update tests

* NAS-131403: Use app.redeploy endpoint for restart apps

* NAS-131403: Preserve space for row actions
  • Loading branch information
denysbutenko authored Oct 7, 2024
1 parent 06665ce commit 0af0925
Show file tree
Hide file tree
Showing 99 changed files with 243 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/app/interfaces/api/api-job-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface ApiJobDirectory {
'app.update': { params: [string, AppUpdate]; response: App };
'app.start': { params: AppStartQueryParams; response: void };
'app.stop': { params: AppStartQueryParams; response: void };
'app.redeploy': { params: AppStartQueryParams; response: void };
'app.delete': { params: AppDeleteParams; response: boolean };
'app.upgrade': { params: AppUpgradeParams; response: App };
'app.rollback': { params: AppRollbackParams; response: App };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@
<ix-icon name="mdi-play"></ix-icon>
</button>
} @else {
<button
mat-icon-button
matTooltipPosition="above"
[ixTest]="[app().name, 'restart']"
[attr.aria-label]="'Restart App' | translate"
[matTooltip]="'Restart App' | translate"
(click)="restart()"
>
<ix-icon name="mdi-restart"></ix-icon>
</button>

<button
mat-icon-button
matTooltipPosition="above"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,10 @@ describe('AppRowComponent', () => {

const stopIcon = await loader.getHarness(IxIconHarness.with({ name: 'mdi-stop' }));
const startIcon = await loader.getHarnessOrNull(IxIconHarness.with({ name: 'mdi-play' }));
const restartIcon = await loader.getHarnessOrNull(IxIconHarness.with({ name: 'mdi-restart' }));

expect(stopIcon).toExist();
expect(restartIcon).toExist();
expect(startIcon).not.toExist();
});

Expand All @@ -114,7 +116,9 @@ describe('AppRowComponent', () => {

const stopIcon = await loader.getHarnessOrNull(IxIconHarness.with({ name: 'mdi-stop' }));
const startIcon = await loader.getHarness(IxIconHarness.with({ name: 'mdi-play' }));
const restartIcon = await loader.getHarnessOrNull(IxIconHarness.with({ name: 'mdi-restart' }));

expect(restartIcon).not.toExist();
expect(stopIcon).not.toExist();
expect(startIcon).toExist();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class AppRowComponent {

readonly startApp = output();
readonly stopApp = output();
readonly restartApp = output();
readonly clickStatus = output();
readonly selectionChange = output();

Expand Down Expand Up @@ -60,6 +61,10 @@ export class AppRowComponent {
this.stopApp.emit();
}

restart(): void {
this.restartApp.emit();
}

statusPressed(): void {
this.clickStatus.emit();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ <h2>{{ 'Applications' | translate }}</h2>
[job]="appJobs.get(app.name)"
(startApp)="start(app.name)"
(stopApp)="stop(app.name)"
(restartApp)="restart(app.name)"
(clickStatus)="openStatusDialog(app.name)"
(selectionChange)="selection.toggle(app.id)"
(click)="viewDetails(app)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@

ix-app-row,
.app-header-row {
grid-template-columns: 45px minmax(160px, auto) minmax(100px, 120px) 50px 55px 85px 85px 85px 40px;
grid-template-columns: 45px minmax(160px, auto) minmax(100px, 120px) 50px 55px 85px 85px 85px 88px;

@media (max-width: $breakpoint-tablet) {
grid-template-columns: 45px auto 0 0 0 0 0 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ describe('InstalledAppsComponent', () => {
events: of(),
}),
mockProvider(ApplicationsService, {
restartApplication: jest.fn(() => of()),
startApplication: jest.fn(() => of()),
stopApplication: jest.fn(() => of()),
getInstalledAppsStatusUpdates: jest.fn(() => of({
Expand Down Expand Up @@ -150,6 +151,11 @@ describe('InstalledAppsComponent', () => {
expect(spectator.inject(ApplicationsService).stopApplication).toHaveBeenCalledWith('test-app');
});

it('restarts application', () => {
spectator.query(AppRowComponent).restartApp.emit();
expect(spectator.inject(ApplicationsService).restartApplication).toHaveBeenCalledWith('test-app');
});

it('removes selected applications', async () => {
spectator.component.selection.select(app.name);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ export class InstalledAppsComponent implements OnInit, AfterViewInit {

start(name: string): void {
this.appService.startApplication(name)
.pipe(this.errorHandler.catchError(), untilDestroyed(this))
.pipe(
tapOnce(() => this.loader.open(this.translate.instant('Starting "{app}"', { app: name }))),
this.errorHandler.catchError(),
untilDestroyed(this),
)
.subscribe((job: Job<void, AppStartQueryParams>) => {
this.appJobs.set(name, job);
this.sortChanged(this.sortingInfo);
Expand All @@ -336,6 +340,23 @@ export class InstalledAppsComponent implements OnInit, AfterViewInit {
});
}

restart(name: string): void {
this.appService.restartApplication(name)
.pipe(
tapOnce(() => this.loader.open(this.translate.instant('Restarting "{app}"', { app: name }))),
this.errorHandler.catchError(),
untilDestroyed(this),
)
.subscribe((job: Job<void, AppStartQueryParams>) => {
if (job.state !== JobState.Running) {
this.loader.close();
}
this.appJobs.set(name, job);
this.sortChanged(this.sortingInfo);
this.cdr.markForCheck();
});
}

openStatusDialog(name: string): void {
if (!this.appJobs.has(name)) {
return;
Expand Down
20 changes: 2 additions & 18 deletions src/app/pages/apps/services/applications.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import {
EMPTY,
Observable, OperatorFunction, filter, map, pipe,
shareReplay,
switchMap,
} from 'rxjs';
import { customApp } from 'app/constants/catalog.constants';
import { AppExtraCategory } from 'app/enums/app-extra-category.enum';
import { AppState } from 'app/enums/app-state.enum';
import { JobState } from 'app/enums/job-state.enum';
import { ApiEvent } from 'app/interfaces/api-message.interface';
import {
App, AppStartQueryParams, AppUpgradeParams,
Expand Down Expand Up @@ -107,20 +103,8 @@ export class ApplicationsService {
return this.ws.job('app.stop', [name]);
}

restartApplication(app: App): Observable<Job<void>> {
switch (app.state) {
case AppState.Running:
return this.stopApplication(app.name).pipe(
filter((job) => job.state === JobState.Success),
switchMap(() => this.startApplication(app.name)),
);
case AppState.Crashed:
case AppState.Stopped:
return this.startApplication(app.name);
case AppState.Deploying:
default:
return EMPTY;
}
restartApplication(name: string): Observable<Job<void>> {
return this.ws.job('app.redeploy', [name]);
}

convertDateToRelativeDate(date: Date): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('AppControlsComponent', () => {
await restartButton.click();

expect(snackbarSpy).toHaveBeenCalledWith('App is restarting');
expect(restartSpy).toHaveBeenCalledWith(app);
expect(restartSpy).toHaveBeenCalledWith(app.name);
});

it('checks redirect to installed apps page', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {
Component, ChangeDetectionStrategy, input,
signal,
computed,
} from '@angular/core';
import { Router } from '@angular/router';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { AppState } from 'app/enums/app-state.enum';
import { tapOnce } from 'app/helpers/operators/tap-once.operator';
import { LoadingState } from 'app/helpers/operators/to-loading-state.helper';
import { App } from 'app/interfaces/app.interface';
import { mapLoadedValue } from 'app/modules/loader/directives/with-loading-state/map-loaded-value.utils';
import { SnackbarService } from 'app/modules/snackbar/services/snackbar.service';
import { ApplicationsService } from 'app/pages/apps/services/applications.service';
import { RedirectService } from 'app/services/redirect.service';
Expand All @@ -21,7 +24,9 @@ import { RedirectService } from 'app/services/redirect.service';
export class AppControlsComponent {
app = input.required<LoadingState<App>>();

protected isRestarting = signal<boolean>(false);
protected isRestarting = computed(() => {
return mapLoadedValue(this.app(), (app) => app.state === AppState.Deploying);
});

constructor(
private translate: TranslateService,
Expand All @@ -32,15 +37,13 @@ export class AppControlsComponent {
) {}

onRestartApp(app: App): void {
this.isRestarting.set(true);
this.snackbar.success(this.translate.instant('App is restarting'));
this.appService.restartApplication(app)
.pipe(untilDestroyed(this))
this.appService.restartApplication(app.name)
.pipe(
tapOnce(() => this.snackbar.success(this.translate.instant('App is restarting'))),
untilDestroyed(this),
)
.subscribe({
complete: () => {
this.isRestarting.set(false);
this.snackbar.success(this.translate.instant('App is restarted'));
},
complete: () => this.snackbar.success(this.translate.instant('App is restarted')),
});
}

Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/af.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/ast.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/az.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/be.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/bn.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/br.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/bs.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
2 changes: 2 additions & 0 deletions src/assets/i18n/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -3381,6 +3381,7 @@
"Restart is required after changing this setting.": "",
"Restart of a remote system is required for new FIPS setting to take effect. Would you like to restart standby now?": "",
"Restart the system?": "",
"Restarting \"{app}\"": "",
"Restarting Standby": "",
"Restore": "",
"Restore Cloud Sync Task": "",
Expand Down Expand Up @@ -4057,6 +4058,7 @@
"Start {service} Service": "",
"Started": "",
"Starting": "",
"Starting \"{app}\"": "",
"Starting task": "",
"State": "",
"Static IP addresses which SMB listens on for connections. Leaving all unselected defaults to listening on all active interfaces.": "",
Expand Down
Loading

0 comments on commit 0af0925

Please sign in to comment.