mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Multiple (#3111)
* fix alerts i18n, fix status display, better, remove usb media, hide shutdown for install complete * trigger chnage detection for localize pipe and round out implementing localize pipe for consistency even though not needed
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
{{ pkg.title }}
|
{{ pkg.title }}
|
||||||
</span>
|
</span>
|
||||||
<span class="detail-description">
|
<span class="detail-description">
|
||||||
{{ pkg.description.short }}
|
{{ pkg.description.short | localize }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { CommonModule } from '@angular/common'
|
import { CommonModule } from '@angular/common'
|
||||||
import { NgModule } from '@angular/core'
|
import { NgModule } from '@angular/core'
|
||||||
import { RouterModule } from '@angular/router'
|
import { RouterModule } from '@angular/router'
|
||||||
import { SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
import { LocalizePipe, SharedPipesModule, TickerComponent } from '@start9labs/shared'
|
||||||
import { ItemComponent } from './item.component'
|
import { ItemComponent } from './item.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [ItemComponent],
|
declarations: [ItemComponent],
|
||||||
exports: [ItemComponent],
|
exports: [ItemComponent],
|
||||||
imports: [CommonModule, RouterModule, SharedPipesModule, TickerComponent],
|
imports: [CommonModule, RouterModule, SharedPipesModule, TickerComponent, LocalizePipe],
|
||||||
})
|
})
|
||||||
export class ItemModule {}
|
export class ItemModule {}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
output,
|
output,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { MarketplacePkgBase } from '../../types'
|
import { MarketplacePkgBase } from '../../types'
|
||||||
import { CopyService, i18nPipe } from '@start9labs/shared'
|
import { CopyService, i18nPipe, LocalizePipe } from '@start9labs/shared'
|
||||||
import { DatePipe } from '@angular/common'
|
import { DatePipe } from '@angular/common'
|
||||||
import { MarketplaceItemComponent } from './item.component'
|
import { MarketplaceItemComponent } from './item.component'
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ import { MarketplaceItemComponent } from './item.component'
|
|||||||
<div class="background-border box-shadow-lg shadow-color-light">
|
<div class="background-border box-shadow-lg shadow-color-light">
|
||||||
<div class="box-container">
|
<div class="box-container">
|
||||||
<h2 class="additional-detail-title">{{ 'Description' | i18n }}</h2>
|
<h2 class="additional-detail-title">{{ 'Description' | i18n }}</h2>
|
||||||
<p [innerHTML]="pkg().description.long"></p>
|
<p [innerHTML]="pkg().description.long | localize"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -129,7 +129,7 @@ import { MarketplaceItemComponent } from './item.component'
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
imports: [MarketplaceItemComponent, DatePipe, i18nPipe],
|
imports: [MarketplaceItemComponent, DatePipe, i18nPipe, LocalizePipe],
|
||||||
})
|
})
|
||||||
export class MarketplaceAboutComponent {
|
export class MarketplaceAboutComponent {
|
||||||
readonly copyService = inject(CopyService)
|
readonly copyService = inject(CopyService)
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
import { Component } from '@angular/core'
|
||||||
|
import { i18nPipe } from '@start9labs/shared'
|
||||||
|
import { TuiButton, TuiDialogContext } from '@taiga-ui/core'
|
||||||
|
import { injectContext } from '@taiga-ui/polymorpheus'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
standalone: true,
|
||||||
|
imports: [TuiButton, i18nPipe],
|
||||||
|
template: `
|
||||||
|
<div class="animation-container">
|
||||||
|
<div class="port">
|
||||||
|
<div class="port-inner"></div>
|
||||||
|
</div>
|
||||||
|
<div class="usb-stick">
|
||||||
|
<div class="usb-connector"></div>
|
||||||
|
<div class="usb-body"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
{{
|
||||||
|
'Remove USB stick or other installation media from your server' | i18n
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<footer>
|
||||||
|
<button tuiButton (click)="context.completeWith(true)">
|
||||||
|
{{ 'Done' | i18n }}
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
`,
|
||||||
|
styles: `
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animation-container {
|
||||||
|
position: relative;
|
||||||
|
width: 160px;
|
||||||
|
height: 69px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.port {
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 28px;
|
||||||
|
height: 18px;
|
||||||
|
background: var(--tui-background-neutral-1);
|
||||||
|
border: 2px solid var(--tui-border-normal);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.port-inner {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
right: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
background: var(--tui-background-neutral-2);
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usb-stick {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
animation: slide-out 2s ease-in-out 0.5s infinite;
|
||||||
|
left: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usb-connector {
|
||||||
|
width: 20px;
|
||||||
|
height: 12px;
|
||||||
|
background: var(--tui-text-secondary);
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.usb-body {
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
background: var(--tui-status-info);
|
||||||
|
border-radius: 2px 4px 4px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-out {
|
||||||
|
0% {
|
||||||
|
left: 32px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
5% {
|
||||||
|
left: 32px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
left: 130px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: 130px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class RemoveMediaDialog {
|
||||||
|
protected readonly context = injectContext<TuiDialogContext<boolean>>()
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
import { ChangeDetectorRef, Component, inject } from '@angular/core'
|
import {
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
HostListener,
|
||||||
|
inject,
|
||||||
|
} from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { FormsModule } from '@angular/forms'
|
import { FormsModule } from '@angular/forms'
|
||||||
import {
|
import {
|
||||||
@@ -21,13 +26,14 @@ import {
|
|||||||
import { TuiDataListWrapper, TuiSelect, TuiTooltip } from '@taiga-ui/kit'
|
import { TuiDataListWrapper, TuiSelect, TuiTooltip } from '@taiga-ui/kit'
|
||||||
import { TuiCardLarge, TuiHeader } from '@taiga-ui/layout'
|
import { TuiCardLarge, TuiHeader } from '@taiga-ui/layout'
|
||||||
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||||
import { filter } from 'rxjs'
|
import { filter, Subscription } from 'rxjs'
|
||||||
import { ApiService } from '../services/api.service'
|
import { ApiService } from '../services/api.service'
|
||||||
import { StateService } from '../services/state.service'
|
import { StateService } from '../services/state.service'
|
||||||
import { PreserveOverwriteDialog } from '../components/preserve-overwrite.dialog'
|
import { PreserveOverwriteDialog } from '../components/preserve-overwrite.dialog'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
|
@if (!shuttingDown) {
|
||||||
<section tuiCardLarge="compact">
|
<section tuiCardLarge="compact">
|
||||||
<header tuiHeader>
|
<header tuiHeader>
|
||||||
<h2 tuiTitle>{{ 'Select Drives' | i18n }}</h2>
|
<h2 tuiTitle>{{ 'Select Drives' | i18n }}</h2>
|
||||||
@@ -132,6 +138,7 @@ import { PreserveOverwriteDialog } from '../components/preserve-overwrite.dialog
|
|||||||
}
|
}
|
||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
styles: `
|
styles: `
|
||||||
.no-drives {
|
.no-drives {
|
||||||
@@ -176,6 +183,14 @@ export default class DrivesPage {
|
|||||||
|
|
||||||
protected readonly mobile = inject(TUI_IS_MOBILE)
|
protected readonly mobile = inject(TUI_IS_MOBILE)
|
||||||
|
|
||||||
|
@HostListener('document:keydown', ['$event'])
|
||||||
|
onKeydown(event: KeyboardEvent) {
|
||||||
|
if (event.ctrlKey && event.shiftKey && event.key === 'X') {
|
||||||
|
event.preventDefault()
|
||||||
|
this.shutdownServer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly osDriveTooltip = this.i18n.transform(
|
readonly osDriveTooltip = this.i18n.transform(
|
||||||
'The drive where the StartOS operating system will be installed.',
|
'The drive where the StartOS operating system will be installed.',
|
||||||
)
|
)
|
||||||
@@ -185,6 +200,8 @@ export default class DrivesPage {
|
|||||||
|
|
||||||
drives: DiskInfo[] = []
|
drives: DiskInfo[] = []
|
||||||
loading = true
|
loading = true
|
||||||
|
shuttingDown = false
|
||||||
|
private dialogSub?: Subscription
|
||||||
selectedOsDrive: DiskInfo | null = null
|
selectedOsDrive: DiskInfo | null = null
|
||||||
selectedDataDrive: DiskInfo | null = null
|
selectedDataDrive: DiskInfo | null = null
|
||||||
preserveData: boolean | null = null
|
preserveData: boolean | null = null
|
||||||
@@ -339,22 +356,18 @@ export default class DrivesPage {
|
|||||||
loader.unsubscribe()
|
loader.unsubscribe()
|
||||||
|
|
||||||
// Show success dialog
|
// Show success dialog
|
||||||
this.dialogs
|
this.dialogSub = this.dialogs
|
||||||
.openConfirm({
|
.openAlert('StartOS has been installed successfully.', {
|
||||||
label: 'Installation Complete!',
|
label: 'Installation Complete!',
|
||||||
size: 's',
|
size: 's',
|
||||||
data: {
|
dismissible: false,
|
||||||
content: 'StartOS has been installed successfully.',
|
closeable: true,
|
||||||
yes: 'Continue to Setup',
|
data: { button: this.i18n.transform('Continue to Setup') },
|
||||||
no: 'Shutdown',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
.subscribe(continueSetup => {
|
.subscribe({
|
||||||
if (continueSetup) {
|
complete: () => {
|
||||||
this.navigateToNextStep(result.attach)
|
this.navigateToNextStep(result.attach)
|
||||||
} else {
|
},
|
||||||
this.shutdownServer()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
loader.unsubscribe()
|
loader.unsubscribe()
|
||||||
@@ -372,10 +385,12 @@ export default class DrivesPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async shutdownServer() {
|
private async shutdownServer() {
|
||||||
|
this.dialogSub?.unsubscribe()
|
||||||
const loader = this.loader.open('Beginning shutdown').subscribe()
|
const loader = this.loader.open('Beginning shutdown').subscribe()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.api.shutdown()
|
await this.api.shutdown()
|
||||||
|
this.shuttingDown = true
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.errorService.handleError(e)
|
this.errorService.handleError(e)
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
DOCUMENT,
|
DOCUMENT,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { DownloadHTMLService, ErrorService, i18nPipe } from '@start9labs/shared'
|
import {
|
||||||
|
DialogService,
|
||||||
|
DownloadHTMLService,
|
||||||
|
ErrorService,
|
||||||
|
i18nPipe,
|
||||||
|
} from '@start9labs/shared'
|
||||||
import { TuiIcon, TuiLoader, TuiTitle } from '@taiga-ui/core'
|
import { TuiIcon, TuiLoader, TuiTitle } from '@taiga-ui/core'
|
||||||
import { TuiAvatar } from '@taiga-ui/kit'
|
import { TuiAvatar } from '@taiga-ui/kit'
|
||||||
import { TuiCardLarge, TuiCell, TuiHeader } from '@taiga-ui/layout'
|
import { TuiCardLarge, TuiCell, TuiHeader } from '@taiga-ui/layout'
|
||||||
@@ -14,7 +19,9 @@ import { ApiService } from '../services/api.service'
|
|||||||
import { StateService } from '../services/state.service'
|
import { StateService } from '../services/state.service'
|
||||||
import { DocumentationComponent } from '../components/documentation.component'
|
import { DocumentationComponent } from '../components/documentation.component'
|
||||||
import { MatrixComponent } from '../components/matrix.component'
|
import { MatrixComponent } from '../components/matrix.component'
|
||||||
|
import { RemoveMediaDialog } from '../components/remove-media.dialog'
|
||||||
import { SetupCompleteRes } from '../types'
|
import { SetupCompleteRes } from '../types'
|
||||||
|
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
@@ -29,12 +36,8 @@ import { SetupCompleteRes } from '../types'
|
|||||||
@if (!stateService.kiosk) {
|
@if (!stateService.kiosk) {
|
||||||
<span tuiSubtitle>
|
<span tuiSubtitle>
|
||||||
{{
|
{{
|
||||||
stateService.setupType === 'restore'
|
'http://start.local was for setup only. It will no longer work.'
|
||||||
? ('You can unplug your backup drive' | i18n)
|
| i18n
|
||||||
: stateService.setupType === 'transfer'
|
|
||||||
? ('You can unplug your transfer drive' | i18n)
|
|
||||||
: ('http://start.local was for setup only. It will no longer work.'
|
|
||||||
| i18n)
|
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -69,14 +72,15 @@ import { SetupCompleteRes } from '../types'
|
|||||||
tuiCell="l"
|
tuiCell="l"
|
||||||
[class.disabled]="!stateService.kiosk && !downloaded"
|
[class.disabled]="!stateService.kiosk && !downloaded"
|
||||||
[disabled]="(!stateService.kiosk && !downloaded) || usbRemoved"
|
[disabled]="(!stateService.kiosk && !downloaded) || usbRemoved"
|
||||||
(click)="usbRemoved = true"
|
(click)="removeMedia()"
|
||||||
>
|
>
|
||||||
<tui-avatar appearance="secondary" src="@tui.usb" />
|
<tui-avatar appearance="secondary" src="@tui.usb" />
|
||||||
<div tuiTitle>
|
<div tuiTitle>
|
||||||
{{ 'USB Removed' | i18n }}
|
{{ 'Remove Installation Media' | i18n }}
|
||||||
<div tuiSubtitle>
|
<div tuiSubtitle>
|
||||||
{{
|
{{
|
||||||
'Remove the USB installation media from your server' | i18n
|
'Remove USB stick or other installation media from your server'
|
||||||
|
| i18n
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -184,6 +188,7 @@ export default class SuccessPage implements AfterViewInit {
|
|||||||
private readonly errorService = inject(ErrorService)
|
private readonly errorService = inject(ErrorService)
|
||||||
private readonly api = inject(ApiService)
|
private readonly api = inject(ApiService)
|
||||||
private readonly downloadHtml = inject(DownloadHTMLService)
|
private readonly downloadHtml = inject(DownloadHTMLService)
|
||||||
|
private readonly dialogs = inject(DialogService)
|
||||||
private readonly i18n = inject(i18nPipe)
|
private readonly i18n = inject(i18nPipe)
|
||||||
|
|
||||||
readonly stateService = inject(StateService)
|
readonly stateService = inject(StateService)
|
||||||
@@ -225,6 +230,21 @@ export default class SuccessPage implements AfterViewInit {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeMedia() {
|
||||||
|
this.dialogs
|
||||||
|
.openComponent<boolean>(
|
||||||
|
new PolymorpheusComponent(RemoveMediaDialog),
|
||||||
|
{
|
||||||
|
size: 's',
|
||||||
|
dismissible: false,
|
||||||
|
closeable: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
this.usbRemoved = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
exitKiosk() {
|
exitKiosk() {
|
||||||
this.api.exit()
|
this.api.exit()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export default {
|
|||||||
102: 'Verlassen',
|
102: 'Verlassen',
|
||||||
103: 'Sind Sie sicher?',
|
103: 'Sind Sie sicher?',
|
||||||
104: 'Neues Netzwerk-Gateway',
|
104: 'Neues Netzwerk-Gateway',
|
||||||
|
107: 'Onion-Domains',
|
||||||
108: 'Öffentlich',
|
108: 'Öffentlich',
|
||||||
109: 'privat',
|
109: 'privat',
|
||||||
111: 'Keine Onion-Domains',
|
111: 'Keine Onion-Domains',
|
||||||
@@ -639,13 +640,11 @@ export default {
|
|||||||
667: 'Einrichtung wird gestartet',
|
667: 'Einrichtung wird gestartet',
|
||||||
670: 'Warten Sie 1–2 Minuten und aktualisieren Sie die Seite',
|
670: 'Warten Sie 1–2 Minuten und aktualisieren Sie die Seite',
|
||||||
672: 'Einrichtung abgeschlossen!',
|
672: 'Einrichtung abgeschlossen!',
|
||||||
673: 'Sie können Ihr Backup-Laufwerk entfernen',
|
|
||||||
674: 'Sie können Ihr Übertragungs-Laufwerk entfernen',
|
|
||||||
675: 'http://start.local war nur für die Einrichtung gedacht. Es funktioniert nicht mehr.',
|
675: 'http://start.local war nur für die Einrichtung gedacht. Es funktioniert nicht mehr.',
|
||||||
676: 'Adressinformationen herunterladen',
|
676: 'Adressinformationen herunterladen',
|
||||||
677: 'Enthält die permanente lokale Adresse Ihres Servers und die Root-CA',
|
677: 'Enthält die permanente lokale Adresse Ihres Servers und die Root-CA',
|
||||||
678: 'USB entfernt',
|
678: 'Installationsmedium entfernen',
|
||||||
679: 'Entfernen Sie das USB-Installationsmedium aus Ihrem Server',
|
679: 'Entfernen Sie den USB-Stick oder andere Installationsmedien von Ihrem Server',
|
||||||
680: 'Server neu starten',
|
680: 'Server neu starten',
|
||||||
681: 'Warten, bis der Server wieder online ist',
|
681: 'Warten, bis der Server wieder online ist',
|
||||||
682: 'Server ist wieder online',
|
682: 'Server ist wieder online',
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export const ENGLISH: Record<string, number> = {
|
|||||||
'Leave': 102,
|
'Leave': 102,
|
||||||
'Are you sure?': 103,
|
'Are you sure?': 103,
|
||||||
'New gateway': 104, // as in, a network gateway
|
'New gateway': 104, // as in, a network gateway
|
||||||
|
'Tor Domains': 107,
|
||||||
'public': 108,
|
'public': 108,
|
||||||
'private': 109,
|
'private': 109,
|
||||||
'No Tor domains': 111,
|
'No Tor domains': 111,
|
||||||
@@ -639,13 +640,11 @@ export const ENGLISH: Record<string, number> = {
|
|||||||
'Starting setup': 667,
|
'Starting setup': 667,
|
||||||
'Wait 1-2 minutes and refresh the page': 670,
|
'Wait 1-2 minutes and refresh the page': 670,
|
||||||
'Setup Complete!': 672,
|
'Setup Complete!': 672,
|
||||||
'You can unplug your backup drive': 673,
|
|
||||||
'You can unplug your transfer drive': 674,
|
|
||||||
'http://start.local was for setup only. It will no longer work.': 675,
|
'http://start.local was for setup only. It will no longer work.': 675,
|
||||||
'Download Address Info': 676,
|
'Download Address Info': 676,
|
||||||
"Contains your server's permanent local address and Root CA": 677,
|
"Contains your server's permanent local address and Root CA": 677,
|
||||||
'USB Removed': 678,
|
'Remove Installation Media': 678,
|
||||||
'Remove the USB installation media from your server': 679,
|
'Remove USB stick or other installation media from your server': 679,
|
||||||
'Restart Server': 680,
|
'Restart Server': 680,
|
||||||
'Waiting for server to come back online': 681,
|
'Waiting for server to come back online': 681,
|
||||||
'Server is back online': 682,
|
'Server is back online': 682,
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export default {
|
|||||||
102: 'Salir',
|
102: 'Salir',
|
||||||
103: '¿Estás seguro?',
|
103: '¿Estás seguro?',
|
||||||
104: 'Nueva puerta de enlace de red',
|
104: 'Nueva puerta de enlace de red',
|
||||||
|
107: 'dominios onion',
|
||||||
108: 'público',
|
108: 'público',
|
||||||
109: 'privado',
|
109: 'privado',
|
||||||
111: 'Sin dominios onion',
|
111: 'Sin dominios onion',
|
||||||
@@ -639,13 +640,11 @@ export default {
|
|||||||
667: 'Iniciando configuración',
|
667: 'Iniciando configuración',
|
||||||
670: 'Espere 1–2 minutos y actualice la página',
|
670: 'Espere 1–2 minutos y actualice la página',
|
||||||
672: '¡Configuración completa!',
|
672: '¡Configuración completa!',
|
||||||
673: 'Puede desconectar su unidad de copia de seguridad',
|
|
||||||
674: 'Puede desconectar su unidad de transferencia',
|
|
||||||
675: 'http://start.local era solo para la configuración. Ya no funcionará.',
|
675: 'http://start.local era solo para la configuración. Ya no funcionará.',
|
||||||
676: 'Descargar información de direcciones',
|
676: 'Descargar información de direcciones',
|
||||||
677: 'Contiene la dirección local permanente de su servidor y la CA raíz',
|
677: 'Contiene la dirección local permanente de su servidor y la CA raíz',
|
||||||
678: 'USB retirado',
|
678: 'Retirar medio de instalación',
|
||||||
679: 'Retire el medio de instalación USB de su servidor',
|
679: 'Retire la memoria USB u otro medio de instalación de su servidor',
|
||||||
680: 'Reiniciar servidor',
|
680: 'Reiniciar servidor',
|
||||||
681: 'Esperando a que el servidor vuelva a estar en línea',
|
681: 'Esperando a que el servidor vuelva a estar en línea',
|
||||||
682: 'El servidor ha vuelto a estar en línea',
|
682: 'El servidor ha vuelto a estar en línea',
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export default {
|
|||||||
102: 'Quitter',
|
102: 'Quitter',
|
||||||
103: 'Êtes-vous sûr ?',
|
103: 'Êtes-vous sûr ?',
|
||||||
104: 'Nouvelle passerelle réseau',
|
104: 'Nouvelle passerelle réseau',
|
||||||
|
107: 'domaine onion',
|
||||||
108: 'public',
|
108: 'public',
|
||||||
109: 'privé',
|
109: 'privé',
|
||||||
111: 'Aucune domaine onion',
|
111: 'Aucune domaine onion',
|
||||||
@@ -639,13 +640,11 @@ export default {
|
|||||||
667: 'Démarrage de la configuration',
|
667: 'Démarrage de la configuration',
|
||||||
670: 'Attendez 1 à 2 minutes puis actualisez la page',
|
670: 'Attendez 1 à 2 minutes puis actualisez la page',
|
||||||
672: 'Configuration terminée !',
|
672: 'Configuration terminée !',
|
||||||
673: 'Vous pouvez débrancher votre disque de sauvegarde',
|
|
||||||
674: 'Vous pouvez débrancher votre disque de transfert',
|
|
||||||
675: 'http://start.local était réservé à la configuration. Il ne fonctionnera plus.',
|
675: 'http://start.local était réservé à la configuration. Il ne fonctionnera plus.',
|
||||||
676: 'Télécharger les informations d’adresse',
|
676: 'Télécharger les informations d’adresse',
|
||||||
677: 'Contient l’adresse locale permanente de votre serveur et la CA racine',
|
677: 'Contient l\u2019adresse locale permanente de votre serveur et la CA racine',
|
||||||
678: 'USB retiré',
|
678: 'Retirer le support d\u2019installation',
|
||||||
679: 'Retirez le support d’installation USB de votre serveur',
|
679: 'Retirez la clé USB ou tout autre support d\u2019installation de votre serveur',
|
||||||
680: 'Redémarrer le serveur',
|
680: 'Redémarrer le serveur',
|
||||||
681: 'En attente du retour en ligne du serveur',
|
681: 'En attente du retour en ligne du serveur',
|
||||||
682: 'Le serveur est de nouveau en ligne',
|
682: 'Le serveur est de nouveau en ligne',
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export default {
|
|||||||
102: 'Opuść',
|
102: 'Opuść',
|
||||||
103: 'Czy jesteś pewien?',
|
103: 'Czy jesteś pewien?',
|
||||||
104: 'Nowa brama sieciowa',
|
104: 'Nowa brama sieciowa',
|
||||||
|
107: 'domeny onion',
|
||||||
108: 'publiczny',
|
108: 'publiczny',
|
||||||
109: 'prywatny',
|
109: 'prywatny',
|
||||||
111: 'Brak domeny onion',
|
111: 'Brak domeny onion',
|
||||||
@@ -639,13 +640,11 @@ export default {
|
|||||||
667: 'Rozpoczynanie konfiguracji',
|
667: 'Rozpoczynanie konfiguracji',
|
||||||
670: 'Poczekaj 1–2 minuty i odśwież stronę',
|
670: 'Poczekaj 1–2 minuty i odśwież stronę',
|
||||||
672: 'Konfiguracja zakończona!',
|
672: 'Konfiguracja zakończona!',
|
||||||
673: 'Możesz odłączyć dysk kopii zapasowej',
|
|
||||||
674: 'Możesz odłączyć dysk transferowy',
|
|
||||||
675: 'http://start.local służył tylko do konfiguracji. Nie będzie już działać.',
|
675: 'http://start.local służył tylko do konfiguracji. Nie będzie już działać.',
|
||||||
676: 'Pobierz informacje adresowe',
|
676: 'Pobierz informacje adresowe',
|
||||||
677: 'Zawiera stały lokalny adres serwera oraz główny urząd certyfikacji (Root CA)',
|
677: 'Zawiera stały lokalny adres serwera oraz główny urząd certyfikacji (Root CA)',
|
||||||
678: 'USB usunięty',
|
678: 'Usuń nośnik instalacyjny',
|
||||||
679: 'Usuń instalacyjny nośnik USB z serwera',
|
679: 'Usuń pamięć USB lub inny nośnik instalacyjny z serwera',
|
||||||
680: 'Uruchom ponownie serwer',
|
680: 'Uruchom ponownie serwer',
|
||||||
681: 'Oczekiwanie na ponowne połączenie serwera',
|
681: 'Oczekiwanie na ponowne połączenie serwera',
|
||||||
682: 'Serwer jest ponownie online',
|
682: 'Serwer jest ponownie online',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { inject, Injectable, Pipe, PipeTransform } from '@angular/core'
|
import { inject, Injectable, Pipe, PipeTransform } from '@angular/core'
|
||||||
import { i18nService } from './i18n.service'
|
import { i18nService } from './i18n.service'
|
||||||
|
import { I18N } from './i18n.providers'
|
||||||
import { T } from '@start9labs/start-sdk'
|
import { T } from '@start9labs/start-sdk'
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
@@ -9,8 +10,10 @@ import { T } from '@start9labs/start-sdk'
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class LocalizePipe implements PipeTransform {
|
export class LocalizePipe implements PipeTransform {
|
||||||
private readonly i18nService = inject(i18nService)
|
private readonly i18nService = inject(i18nService)
|
||||||
|
private readonly i18n = inject(I18N)
|
||||||
|
|
||||||
transform(string: T.LocaleString): string {
|
transform(string: T.LocaleString): string {
|
||||||
|
this.i18n() // read signal to trigger change detection on language switch
|
||||||
return this.i18nService.localize(string)
|
return this.i18nService.localize(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ type OnionForm = {
|
|||||||
selector: 'section[torDomains]',
|
selector: 'section[torDomains]',
|
||||||
template: `
|
template: `
|
||||||
<header>
|
<header>
|
||||||
Tor Domains
|
{{ 'Tor Domains' | i18n }}
|
||||||
<a
|
<a
|
||||||
tuiIconButton
|
tuiIconButton
|
||||||
docsLink
|
docsLink
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
ErrorService,
|
ErrorService,
|
||||||
i18nKey,
|
i18nKey,
|
||||||
i18nPipe,
|
i18nPipe,
|
||||||
|
i18nService,
|
||||||
LoadingService,
|
LoadingService,
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
import { T } from '@start9labs/start-sdk'
|
import { T } from '@start9labs/start-sdk'
|
||||||
@@ -24,6 +25,7 @@ export class ControlsService {
|
|||||||
private readonly api = inject(ApiService)
|
private readonly api = inject(ApiService)
|
||||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||||
private readonly i18n = inject(i18nPipe)
|
private readonly i18n = inject(i18nPipe)
|
||||||
|
private readonly i18nService = inject(i18nService)
|
||||||
|
|
||||||
async start({ title, alerts, id }: T.Manifest, unmet: boolean) {
|
async start({ title, alerts, id }: T.Manifest, unmet: boolean) {
|
||||||
const deps =
|
const deps =
|
||||||
@@ -31,7 +33,7 @@ export class ControlsService {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
(unmet && !(await this.alert(deps))) ||
|
(unmet && !(await this.alert(deps))) ||
|
||||||
(alerts.start && !(await this.alert(alerts.start as i18nKey)))
|
(alerts.start && !(await this.alert(alerts.start)))
|
||||||
) {
|
) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -49,7 +51,7 @@ export class ControlsService {
|
|||||||
|
|
||||||
async stop({ id, title, alerts }: T.Manifest) {
|
async stop({ id, title, alerts }: T.Manifest) {
|
||||||
const depMessage = `${this.i18n.transform('Services that depend on')} ${title} ${this.i18n.transform('will no longer work properly and may crash.')}`
|
const depMessage = `${this.i18n.transform('Services that depend on')} ${title} ${this.i18n.transform('will no longer work properly and may crash.')}`
|
||||||
let content = alerts.stop || ''
|
let content = alerts.stop ? this.i18nService.localize(alerts.stop) : ''
|
||||||
|
|
||||||
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
||||||
content = content ? `${content}.\n\n${depMessage}` : depMessage
|
content = content ? `${content}.\n\n${depMessage}` : depMessage
|
||||||
@@ -113,14 +115,14 @@ export class ControlsService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private alert(content: i18nKey): Promise<boolean> {
|
private alert(content: T.LocaleString): Promise<boolean> {
|
||||||
return firstValueFrom(
|
return firstValueFrom(
|
||||||
this.dialog
|
this.dialog
|
||||||
.openConfirm({
|
.openConfirm({
|
||||||
label: 'Warning',
|
label: 'Warning',
|
||||||
size: 's',
|
size: 's',
|
||||||
data: {
|
data: {
|
||||||
content,
|
content: this.i18nService.localize(content),
|
||||||
yes: 'Continue',
|
yes: 'Continue',
|
||||||
no: 'Cancel',
|
no: 'Cancel',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function getInstalledBaseStatus(statusInfo: T.StatusInfo): BaseStatus {
|
|||||||
(!statusInfo.started ||
|
(!statusInfo.started ||
|
||||||
Object.values(statusInfo.health)
|
Object.values(statusInfo.health)
|
||||||
.filter(h => !!h)
|
.filter(h => !!h)
|
||||||
.some(h => h.result === 'starting'))
|
.some(h => h.result === 'starting' || h.result === 'waiting'))
|
||||||
) {
|
) {
|
||||||
return 'starting'
|
return 'starting'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
ErrorService,
|
ErrorService,
|
||||||
i18nKey,
|
i18nKey,
|
||||||
i18nPipe,
|
i18nPipe,
|
||||||
|
i18nService,
|
||||||
LoadingService,
|
LoadingService,
|
||||||
} from '@start9labs/shared'
|
} from '@start9labs/shared'
|
||||||
import { T } from '@start9labs/start-sdk'
|
import { T } from '@start9labs/start-sdk'
|
||||||
@@ -27,6 +28,7 @@ export class StandardActionsService {
|
|||||||
private readonly loader = inject(LoadingService)
|
private readonly loader = inject(LoadingService)
|
||||||
private readonly router = inject(Router)
|
private readonly router = inject(Router)
|
||||||
private readonly i18n = inject(i18nPipe)
|
private readonly i18n = inject(i18nPipe)
|
||||||
|
private readonly i18nService = inject(i18nService)
|
||||||
|
|
||||||
async rebuild(id: string) {
|
async rebuild(id: string) {
|
||||||
const loader = this.loader.open('Rebuilding container').subscribe()
|
const loader = this.loader.open('Rebuilding container').subscribe()
|
||||||
@@ -50,11 +52,12 @@ export class StandardActionsService {
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let content = soft
|
let content = soft
|
||||||
? ''
|
? ''
|
||||||
: alerts.uninstall ||
|
: alerts.uninstall
|
||||||
`${this.i18n.transform('Uninstalling')} ${title} ${this.i18n.transform('will permanently delete its data.')}`
|
? this.i18nService.localize(alerts.uninstall)
|
||||||
|
: `${this.i18n.transform('Uninstalling')} ${title} ${this.i18n.transform('will permanently delete its data.')}`
|
||||||
|
|
||||||
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
||||||
content = `${content}${content ? ' ' : ''}${this.i18n.transform('Services that depend on')} ${title} ${this.i18n.transform('will no longer work properly and may crash.')}`
|
content = `${content ? `${content} ` : ''}${this.i18n.transform('Services that depend on')} ${title} ${this.i18n.transform('will no longer work properly and may crash.')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content) {
|
if (!content) {
|
||||||
|
|||||||
Reference in New Issue
Block a user