From 2e5cd4b8ca88bfbf1f8314ef883fa2578117bb51 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Tue, 20 Jan 2026 17:08:40 -0700 Subject: [PATCH] ability to shutdown after install --- .../setup-wizard/src/app/pages/drives.page.ts | 46 ++++++++++++++++--- .../src/app/pages/success.page.ts | 2 +- .../src/app/services/api.service.ts | 1 + .../src/app/services/live-api.service.ts | 7 +++ .../src/app/services/mock-api.service.ts | 18 +++++--- .../shared/src/i18n/dictionaries/de.ts | 5 +- .../shared/src/i18n/dictionaries/en.ts | 7 ++- .../shared/src/i18n/dictionaries/es.ts | 5 +- .../shared/src/i18n/dictionaries/fr.ts | 5 +- .../shared/src/i18n/dictionaries/pl.ts | 5 +- 10 files changed, 81 insertions(+), 20 deletions(-) diff --git a/web/projects/setup-wizard/src/app/pages/drives.page.ts b/web/projects/setup-wizard/src/app/pages/drives.page.ts index 11e9c2553..f3c7ded42 100644 --- a/web/projects/setup-wizard/src/app/pages/drives.page.ts +++ b/web/projects/setup-wizard/src/app/pages/drives.page.ts @@ -336,12 +336,46 @@ export default class DrivesPage { this.stateService.dataDriveGuid = result.guid this.stateService.attach = result.attach - if (result.attach) { - this.stateService.setupType = 'attach' - await this.router.navigate(['/password']) - } else { - await this.router.navigate(['/home']) - } + loader.unsubscribe() + + // Show success dialog + this.dialogs + .openConfirm({ + label: 'Installation Complete!', + size: 's', + data: { + content: 'StartOS has been installed successfully.', + yes: 'Continue to Setup', + no: 'Shutdown', + }, + }) + .subscribe(continueSetup => { + if (continueSetup) { + this.navigateToNextStep(result.attach) + } else { + this.shutdownServer() + } + }) + } catch (e: any) { + loader.unsubscribe() + this.errorService.handleError(e) + } + } + + private async navigateToNextStep(attach: boolean) { + if (attach) { + this.stateService.setupType = 'attach' + await this.router.navigate(['/password']) + } else { + await this.router.navigate(['/home']) + } + } + + private async shutdownServer() { + const loader = this.loader.open('Beginning shutdown').subscribe() + + try { + await this.api.shutdown() } catch (e: any) { this.errorService.handleError(e) } finally { diff --git a/web/projects/setup-wizard/src/app/pages/success.page.ts b/web/projects/setup-wizard/src/app/pages/success.page.ts index ab60d41e8..e83e756b6 100644 --- a/web/projects/setup-wizard/src/app/pages/success.page.ts +++ b/web/projects/setup-wizard/src/app/pages/success.page.ts @@ -73,7 +73,7 @@ import { SetupCompleteRes } from '../types' >
- {{ 'Remove USB Media' | i18n }} + {{ 'USB Removed' | i18n }}
{{ 'Remove the USB installation media from your server' | i18n diff --git a/web/projects/setup-wizard/src/app/services/api.service.ts b/web/projects/setup-wizard/src/app/services/api.service.ts index 82ff96857..b11aa86a5 100644 --- a/web/projects/setup-wizard/src/app/services/api.service.ts +++ b/web/projects/setup-wizard/src/app/services/api.service.ts @@ -46,6 +46,7 @@ export abstract class ApiService { // Completion abstract complete(): Promise // setup.complete abstract exit(): Promise // setup.exit + abstract shutdown(): Promise // setup.shutdown // Logs & Progress abstract initFollowLogs(): Promise // setup.logs.follow diff --git a/web/projects/setup-wizard/src/app/services/live-api.service.ts b/web/projects/setup-wizard/src/app/services/live-api.service.ts index 1308433ec..42c306d50 100644 --- a/web/projects/setup-wizard/src/app/services/live-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/live-api.service.ts @@ -149,6 +149,13 @@ export class LiveApiService extends ApiService { }) } + async shutdown() { + await this.rpcRequest({ + method: 'setup.shutdown', + params: {}, + }) + } + async restart() { await this.rpcRequest({ method: 'setup.restart', diff --git a/web/projects/setup-wizard/src/app/services/mock-api.service.ts b/web/projects/setup-wizard/src/app/services/mock-api.service.ts index 47720229d..b94f9fda3 100644 --- a/web/projects/setup-wizard/src/app/services/mock-api.service.ts +++ b/web/projects/setup-wizard/src/app/services/mock-api.service.ts @@ -70,13 +70,13 @@ export class MockApiService extends ApiService { this.statusIndex++ if (this.statusIndex === 1) { - // return { status: 'needs-install', keyboard: null } - return { - status: 'incomplete', - attach: false, - guid: 'mock-data-guid', - keyboard: null, - } + return { status: 'needs-install', keyboard: null } + // return { + // status: 'incomplete', + // attach: false, + // guid: 'mock-data-guid', + // keyboard: null, + // } } if (this.statusIndex > 3) { @@ -187,6 +187,10 @@ export class MockApiService extends ApiService { await pauseFor(500) } + async shutdown(): Promise { + await pauseFor(500) + } + async restart(): Promise { await pauseFor(500) } diff --git a/web/projects/shared/src/i18n/dictionaries/de.ts b/web/projects/shared/src/i18n/dictionaries/de.ts index 370338362..e229d9f24 100644 --- a/web/projects/shared/src/i18n/dictionaries/de.ts +++ b/web/projects/shared/src/i18n/dictionaries/de.ts @@ -644,7 +644,7 @@ export default { 675: 'http://start.local war nur für die Einrichtung gedacht. Es funktioniert nicht mehr.', 676: 'Adressinformationen herunterladen', 677: 'Enthält die permanente lokale Adresse Ihres Servers und die Root-CA', - 678: 'USB-Medium entfernen', + 678: 'USB entfernt', 679: 'Entfernen Sie das USB-Installationsmedium aus Ihrem Server', 680: 'Server neu starten', 681: 'Warten, bis der Server wieder online ist', @@ -677,4 +677,7 @@ export default { 711: 'Die Liste ist leer', 712: 'Jetzt neu starten', 713: 'Später', + 714: 'Installation abgeschlossen!', + 715: 'StartOS wurde erfolgreich installiert.', + 716: 'Weiter zur Einrichtung', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/en.ts b/web/projects/shared/src/i18n/dictionaries/en.ts index 5822feb65..1b1160f31 100644 --- a/web/projects/shared/src/i18n/dictionaries/en.ts +++ b/web/projects/shared/src/i18n/dictionaries/en.ts @@ -644,7 +644,7 @@ export const ENGLISH = { 'http://start.local was for setup only. It will no longer work.': 675, 'Download Address Info': 676, "Contains your server's permanent local address and Root CA": 677, - 'Remove USB Media': 678, + 'USB Removed': 678, 'Remove the USB installation media from your server': 679, 'Restart Server': 680, 'Waiting for server to come back online': 681, @@ -677,4 +677,7 @@ export const ENGLISH = { 'The list is empty': 711, 'Restart now': 712, 'Later': 713, // as in, (do it) later -} as const + 'Installation Complete!': 714, + 'StartOS has been installed successfully.': 715, + 'Continue to Setup': 716, +} as Record diff --git a/web/projects/shared/src/i18n/dictionaries/es.ts b/web/projects/shared/src/i18n/dictionaries/es.ts index f5bca9c40..3233d1496 100644 --- a/web/projects/shared/src/i18n/dictionaries/es.ts +++ b/web/projects/shared/src/i18n/dictionaries/es.ts @@ -644,7 +644,7 @@ export default { 675: 'http://start.local era solo para la configuración. Ya no funcionará.', 676: 'Descargar información de direcciones', 677: 'Contiene la dirección local permanente de su servidor y la CA raíz', - 678: 'Retirar medio USB', + 678: 'USB retirado', 679: 'Retire el medio de instalación USB de su servidor', 680: 'Reiniciar servidor', 681: 'Esperando a que el servidor vuelva a estar en línea', @@ -677,4 +677,7 @@ export default { 711: 'La lista está vacía', 712: 'Reiniciar ahora', 713: 'Más tarde', + 714: '¡Instalación completada!', + 715: 'StartOS se ha instalado correctamente.', + 716: 'Continuar con la configuración', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/fr.ts b/web/projects/shared/src/i18n/dictionaries/fr.ts index d5df17f61..fc86d901c 100644 --- a/web/projects/shared/src/i18n/dictionaries/fr.ts +++ b/web/projects/shared/src/i18n/dictionaries/fr.ts @@ -644,7 +644,7 @@ export default { 675: 'http://start.local était réservé à la configuration. Il ne fonctionnera plus.', 676: 'Télécharger les informations d’adresse', 677: 'Contient l’adresse locale permanente de votre serveur et la CA racine', - 678: 'Retirer le support USB', + 678: 'USB retiré', 679: 'Retirez le support d’installation USB de votre serveur', 680: 'Redémarrer le serveur', 681: 'En attente du retour en ligne du serveur', @@ -677,4 +677,7 @@ export default { 711: 'La liste est vide', 712: 'Redémarrer maintenant', 713: 'Plus tard', + 714: 'Installation terminée !', + 715: 'StartOS a été installé avec succès.', + 716: 'Continuer vers la configuration', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/pl.ts b/web/projects/shared/src/i18n/dictionaries/pl.ts index 63b9ef1e7..5f9432121 100644 --- a/web/projects/shared/src/i18n/dictionaries/pl.ts +++ b/web/projects/shared/src/i18n/dictionaries/pl.ts @@ -644,7 +644,7 @@ export default { 675: 'http://start.local służył tylko do konfiguracji. Nie będzie już działać.', 676: 'Pobierz informacje adresowe', 677: 'Zawiera stały lokalny adres serwera oraz główny urząd certyfikacji (Root CA)', - 678: 'Usuń nośnik USB', + 678: 'USB usunięty', 679: 'Usuń instalacyjny nośnik USB z serwera', 680: 'Uruchom ponownie serwer', 681: 'Oczekiwanie na ponowne połączenie serwera', @@ -677,4 +677,7 @@ export default { 711: 'Lista jest pusta', 712: 'Uruchom ponownie teraz', 713: 'Później', + 714: 'Instalacja zakończona', + 715: 'StartOS został pomyślnie zainstalowany.', + 716: 'Przejdź do konfiguracji', } satisfies i18n