diff --git a/web/projects/shared/src/i18n/dictionaries/de.ts b/web/projects/shared/src/i18n/dictionaries/de.ts index 00615c96b..3439cb7c4 100644 --- a/web/projects/shared/src/i18n/dictionaries/de.ts +++ b/web/projects/shared/src/i18n/dictionaries/de.ts @@ -520,4 +520,5 @@ export default { 518: 'Verwerfen', 519: 'Um Clearnet-Domains zu veröffentlichen, musst du oben auf „Öffentlich machen“ klicken.', 520: 'Update verfügbar', + 521: 'Um das Problem zu beheben, siehe', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/en.ts b/web/projects/shared/src/i18n/dictionaries/en.ts index 489f60198..d097f4694 100644 --- a/web/projects/shared/src/i18n/dictionaries/en.ts +++ b/web/projects/shared/src/i18n/dictionaries/en.ts @@ -519,4 +519,5 @@ export const ENGLISH = { 'Dismiss': 518, // as in, dismiss or delete a task 'To publish clearnet domains, you must click "Make Public", above.': 519, 'Update available': 520, + 'To resolve the issue, refer to': 521, } as const diff --git a/web/projects/shared/src/i18n/dictionaries/es.ts b/web/projects/shared/src/i18n/dictionaries/es.ts index 6be84075f..bcac39cf0 100644 --- a/web/projects/shared/src/i18n/dictionaries/es.ts +++ b/web/projects/shared/src/i18n/dictionaries/es.ts @@ -520,4 +520,5 @@ export default { 518: 'Descartar', 519: 'Para publicar dominios en clearnet, debes hacer clic en "Hacer público" arriba.', 520: 'Actualización disponible', + 521: 'Para resolver el problema, consulta', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/fr.ts b/web/projects/shared/src/i18n/dictionaries/fr.ts index df8db1d33..c3af56e08 100644 --- a/web/projects/shared/src/i18n/dictionaries/fr.ts +++ b/web/projects/shared/src/i18n/dictionaries/fr.ts @@ -520,4 +520,5 @@ export default { 518: 'Ignorer', 519: 'Pour publier des domaines clearnet, vous devez cliquer sur « Rendre public » ci-dessus.', 520: 'Mise à jour disponible', + 521: 'Pour résoudre le problème, consultez', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/pl.ts b/web/projects/shared/src/i18n/dictionaries/pl.ts index f0f40e452..2d81b99d9 100644 --- a/web/projects/shared/src/i18n/dictionaries/pl.ts +++ b/web/projects/shared/src/i18n/dictionaries/pl.ts @@ -520,4 +520,5 @@ export default { 518: 'Odrzuć', 519: 'Aby opublikować domeny w clearnet, kliknij „Upublicznij” powyżej.', 520: 'Aktualizacja dostępna', + 521: 'Aby rozwiązać problem, zapoznaj się z', } satisfies i18n diff --git a/web/projects/shared/src/util/format-progress.ts b/web/projects/shared/src/util/format-progress.ts index 5857e815f..6b974516e 100644 --- a/web/projects/shared/src/util/format-progress.ts +++ b/web/projects/shared/src/util/format-progress.ts @@ -20,7 +20,7 @@ export function formatProgress({ phases, overall }: T.FullProgress): { } } => p.progress !== true && p.progress !== null, ) - .map(p => `${p.name}: (${getPhaseBytes(p.progress)})`) + .map(p => `${p.name}${getPhaseBytes(p.progress)}`) .join(', '), } } @@ -42,6 +42,6 @@ function getPhaseBytes( done: number total: number | null }, -): string { - return !progress ? 'unknown' : `${progress.done}/${progress.total}` +) { + return progress ? `: ${progress.done}/${progress.total}` : '' } diff --git a/web/projects/ui/src/app/components/backup-report.component.ts b/web/projects/ui/src/app/components/backup-report.component.ts index f8e91b715..86cbc443c 100644 --- a/web/projects/ui/src/app/components/backup-report.component.ts +++ b/web/projects/ui/src/app/components/backup-report.component.ts @@ -5,11 +5,16 @@ import { computed, inject, } from '@angular/core' +import { toSignal } from '@angular/core/rxjs-interop' import { i18nKey, i18nPipe } from '@start9labs/shared' import { TuiDialogContext, TuiIcon, TuiTitle } from '@taiga-ui/core' import { TuiCell } from '@taiga-ui/layout' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' +import { PatchDB } from 'patch-db-client' +import { scan } from 'rxjs' import { BackupReport } from 'src/app/services/api/api.types' +import { getManifest } from '../utils/get-package-data' +import { T } from '@start9labs/start-sdk' @Component({ template: ` @@ -25,23 +30,25 @@ import { BackupReport } from 'src/app/services/api/api.types' - @for (pkg of data.content.packages | keyvalue; track $index) { -
-
- {{ pkg.key }} -
- {{ - pkg.value.error - ? ('Failed' | i18n) + ': ' + pkg.value.error - : ('Succeeded' | i18n) - }} + @if (pkgTitles(); as titles) { + @for (pkg of data.content.packages | keyvalue; track $index) { +
+
+ {{ titles[pkg.key] || pkg.key }} +
+ {{ + pkg.value.error + ? ('Failed' | i18n) + ': ' + pkg.value.error + : ('Succeeded' | i18n) + }} +
+
- -
+ } } `, changeDetection: ChangeDetectionStrategy.OnPush, @@ -49,12 +56,25 @@ import { BackupReport } from 'src/app/services/api/api.types' }) export class BackupsReportModal { private readonly i18n = inject(i18nPipe) + private readonly patch = inject(PatchDB) readonly data = injectContext< TuiDialogContext >().data + readonly pkgTitles = toSignal( + this.patch.watch$('packageData').pipe( + scan>((acc, pkg) => { + const { id, title } = getManifest(pkg) + return { + ...acc, + [id]: title, + } + }, {}), + ), + ) + readonly system = computed( (): { result: i18nKey; icon: string; color: string } => { if (!this.data.content.server.attempted) { diff --git a/web/projects/ui/src/app/routes/portal/routes/metrics/time.component.ts b/web/projects/ui/src/app/routes/portal/routes/metrics/time.component.ts index aa9ac2c2c..00d97e853 100644 --- a/web/projects/ui/src/app/routes/portal/routes/metrics/time.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/metrics/time.component.ts @@ -43,7 +43,7 @@ import { TimeService } from 'src/app/services/time.service'
{{ 'Clock sync failure' | i18n }}
- To resolve it, refer to + {{ 'To resolve the issue, refer to' | i18n }} {{ d.value.title || d.key }} @if (getError(d.key); as error) { - {{ error | i18n }} + + {{ error | i18n }} + @if (getHealthCheckName(d.key); as healthCheckName) { + : {{ getHealthCheckName }} + } + } @else { {{ 'Satisfied' | i18n }} } @@ -100,4 +105,11 @@ export class ServiceDependenciesComponent { return 'Unknown error' } } + + getHealthCheckName(id: string) { + const depError = this.errors[id] + return depError?.type === 'healthChecksFailed' + ? depError.check.name + : undefined + } } diff --git a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts index 3e35b6b4b..f6fbf26b3 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts @@ -50,7 +50,12 @@ export class StatusComponent { get healthy(): boolean { const { primary, health } = this.getStatus(this.pkg) - return !this.hasDepErrors && primary !== 'error' && health !== 'failure' + return ( + !this.hasDepErrors && + primary !== 'actionRequired' && + primary !== 'error' && + health !== 'failure' + ) } get loading(): boolean { diff --git a/web/projects/ui/src/app/routes/portal/routes/services/routes/outlet.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/routes/outlet.component.ts index 11dfaca7f..c36dfc14b 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/routes/outlet.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/routes/outlet.component.ts @@ -43,7 +43,9 @@ const INACTIVE: PrimaryStatus[] = [ {{ manifest()?.title }} - {{ manifest()?.version }} + + {{ manifest()?.version }} +