mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
feat: refactor logs (#2856)
* feat: refactor logs * download root ca, minor transaltions, better interfaces buttons * chore: comments --------- Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
@@ -12,7 +12,7 @@ export default {
|
||||
email: 'Email',
|
||||
backup: 'Create Backup',
|
||||
restore: 'Restore Backup',
|
||||
interfaces: 'User Interface Addresses',
|
||||
interfaces: 'StartOS UI',
|
||||
acme: 'ACME',
|
||||
wifi: 'WiFi',
|
||||
sessions: 'Active Sessions',
|
||||
@@ -22,16 +22,29 @@ export default {
|
||||
general: {
|
||||
title: 'General Settings',
|
||||
subtitle: 'Manage your overall setup and preferences',
|
||||
update: 'Software Update',
|
||||
restart: 'Restart to apply',
|
||||
check: 'Check for updates',
|
||||
tab: 'Browser Tab Title',
|
||||
language: 'Language',
|
||||
tor: 'Reset Tor',
|
||||
daemon: 'Restart the Tor daemon on your server',
|
||||
disk: 'Disk Repair',
|
||||
attempt: 'Attempt automatic repair',
|
||||
repair: 'Repair',
|
||||
repair: {
|
||||
title: 'Disk Repair',
|
||||
subtitle: 'Attempt automatic repair',
|
||||
button: 'Repair',
|
||||
},
|
||||
ca: {
|
||||
title: 'Root Certificate Authority',
|
||||
subtitle: `Download your server's Root CA`,
|
||||
button: 'Download',
|
||||
},
|
||||
tor: {
|
||||
title: 'Reset Tor',
|
||||
subtitle: 'Restart the Tor daemon on your server',
|
||||
},
|
||||
update: {
|
||||
title: 'Software Update',
|
||||
button: {
|
||||
restart: 'Restart to apply',
|
||||
check: 'Check for updates',
|
||||
},
|
||||
},
|
||||
sync: {
|
||||
title: 'Clock sync failure',
|
||||
subtitle:
|
||||
|
||||
@@ -24,16 +24,29 @@ export default {
|
||||
general: {
|
||||
title: 'Configuración General',
|
||||
subtitle: 'Gestiona tu configuración general y preferencias',
|
||||
update: 'Actualización de Software',
|
||||
restart: 'Reiniciar para aplicar',
|
||||
check: 'Buscar actualizaciones',
|
||||
tab: 'Título de la Pestaña del Navegador',
|
||||
language: 'Idioma',
|
||||
tor: 'Reiniciar Tor',
|
||||
daemon: 'Reiniciar el daemon de Tor en tu servidor',
|
||||
disk: 'Reparación de Disco',
|
||||
attempt: 'Intentar reparación automática',
|
||||
repair: 'Reparar',
|
||||
repair: {
|
||||
title: 'Reparación de Disco',
|
||||
subtitle: 'Intentar reparación automática',
|
||||
button: 'Reparar',
|
||||
},
|
||||
ca: {
|
||||
title: 'Autoridad de Certificación Raíz',
|
||||
subtitle: 'Descarga la autoridad certificadora raíz de tu servidor',
|
||||
button: 'Descarga',
|
||||
},
|
||||
tor: {
|
||||
title: 'Reiniciar Tor',
|
||||
subtitle: 'Reiniciar el daemon de Tor en tu servidor',
|
||||
},
|
||||
update: {
|
||||
title: 'Actualización de Software',
|
||||
button: {
|
||||
restart: 'Reiniciar para aplicar',
|
||||
check: 'Buscar actualizaciones',
|
||||
},
|
||||
},
|
||||
sync: {
|
||||
title: 'Fallo en la sincronización del reloj',
|
||||
subtitle:
|
||||
|
||||
@@ -61,6 +61,15 @@ type ClearnetForm = {
|
||||
Learn More
|
||||
</a>
|
||||
</ng-template>
|
||||
<button
|
||||
tuiButton
|
||||
appearance="accent"
|
||||
[iconStart]="isPublic() ? '@tui.globe-lock' : '@tui.globe'"
|
||||
[style.margin-inline-start]="'auto'"
|
||||
(click)="toggle()"
|
||||
>
|
||||
Make {{ isPublic() ? 'private' : 'public' }}
|
||||
</button>
|
||||
@if (clearnet().length) {
|
||||
<button
|
||||
tuiButton
|
||||
@@ -70,14 +79,6 @@ type ClearnetForm = {
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
<button
|
||||
tuiButton
|
||||
appearance="accent"
|
||||
[iconStart]="isPublic() ? '@tui.globe-lock' : '@tui.globe'"
|
||||
(click)="toggle()"
|
||||
>
|
||||
Make {{ isPublic() ? 'private' : 'public' }}
|
||||
</button>
|
||||
}
|
||||
</header>
|
||||
@if (clearnet().length) {
|
||||
@@ -110,8 +111,10 @@ type ClearnetForm = {
|
||||
</table>
|
||||
} @else {
|
||||
<app-placeholder icon="@tui.app-window">
|
||||
No interfaces available
|
||||
<button tuiButton iconStart="@tui.plus" (click)="add()">Add</button>
|
||||
No public addresses
|
||||
<button tuiButton iconStart="@tui.plus" (click)="add()">
|
||||
Add Domain
|
||||
</button>
|
||||
</app-placeholder>
|
||||
}
|
||||
`,
|
||||
|
||||
@@ -54,6 +54,16 @@ type OnionForm = {
|
||||
Learn More
|
||||
</a>
|
||||
</ng-template>
|
||||
@if (tor().length) {
|
||||
<button
|
||||
tuiButton
|
||||
iconStart="@tui.plus"
|
||||
[style.margin-inline-start]="'auto'"
|
||||
(click)="add()"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
}
|
||||
</header>
|
||||
@if (tor().length) {
|
||||
<table [appTable]="['Protocol', 'URL', '']">
|
||||
@@ -85,7 +95,7 @@ type OnionForm = {
|
||||
} @else {
|
||||
<app-placeholder icon="@tui.app-window">
|
||||
No Tor addresses available
|
||||
<button tuiButton iconStart="@tui.plus">Add</button>
|
||||
<button tuiButton iconStart="@tui.plus" (click)="add()">Add</button>
|
||||
</app-placeholder>
|
||||
}
|
||||
`,
|
||||
@@ -149,7 +159,7 @@ export class InterfaceTorComponent {
|
||||
|
||||
async add() {
|
||||
const options: Partial<TuiDialogOptions<FormContext<OnionForm>>> = {
|
||||
label: 'Select Domain/Subdomain',
|
||||
label: 'New Tor Address',
|
||||
data: {
|
||||
spec: await configBuilderToSpec(
|
||||
ISB.InputSpec.of({
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
.scrollbar {
|
||||
flex: 1;
|
||||
background: var(--tui-background-neutral-1);
|
||||
border-radius: var(--tui-radius-m);
|
||||
border: 1rem solid transparent;
|
||||
}
|
||||
|
||||
.loading-dots {
|
||||
@@ -27,7 +30,6 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid var(--tui-background-neutral-1);
|
||||
}
|
||||
|
||||
[data-status='reconnecting'] {
|
||||
|
||||
@@ -1,44 +1,87 @@
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { TuiSelectModule, TuiTextfieldControllerModule } from '@taiga-ui/legacy'
|
||||
import { KeyValuePipe } from '@angular/common'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core'
|
||||
import {
|
||||
TuiAppearance,
|
||||
TuiButton,
|
||||
TuiIcon,
|
||||
TuiLink,
|
||||
TuiTitle,
|
||||
} from '@taiga-ui/core'
|
||||
import { TuiCardMedium } from '@taiga-ui/layout'
|
||||
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { TitleDirective } from 'src/app/services/title.service'
|
||||
|
||||
interface Log {
|
||||
title: string
|
||||
subtitle: string
|
||||
icon: string
|
||||
follow: (params: RR.FollowServerLogsReq) => Promise<RR.FollowServerLogsRes>
|
||||
fetch: (params: RR.GetServerLogsReq) => Promise<RR.GetServerLogsRes>
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<ng-container *title>Logs</ng-container>
|
||||
<tui-select
|
||||
tuiTextfieldAppearance="secondary"
|
||||
tuiTextfieldSize="m"
|
||||
[style.max-width.rem]="26"
|
||||
[(ngModel)]="logs"
|
||||
>
|
||||
{{ subtitle }}
|
||||
<select tuiSelect [items]="items"></select>
|
||||
</tui-select>
|
||||
@switch (logs) {
|
||||
@case ('OS Logs') {
|
||||
<logs
|
||||
context="OS Logs"
|
||||
[followLogs]="followOS"
|
||||
[fetchLogs]="fetchOS"
|
||||
></logs>
|
||||
<ng-container *title>
|
||||
@if (current(); as key) {
|
||||
<button
|
||||
tuiIconButton
|
||||
iconStart="@tui.arrow-left"
|
||||
(click)="current.set(null)"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
{{ logs[key].title }}
|
||||
} @else {
|
||||
Logs
|
||||
}
|
||||
@case ('Kernel Logs') {
|
||||
<logs
|
||||
context="Kernel Logs"
|
||||
[followLogs]="followKernel"
|
||||
[fetchLogs]="fetchKernel"
|
||||
></logs>
|
||||
</ng-container>
|
||||
@if (current(); as key) {
|
||||
<header tuiTitle>
|
||||
<strong class="title">
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="secondary-grayscale"
|
||||
iconStart="@tui.x"
|
||||
size="s"
|
||||
class="close"
|
||||
(click)="current.set(null)"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
{{ logs[key].title }}
|
||||
</strong>
|
||||
<p tuiSubtitle>{{ logs[key].subtitle }}</p>
|
||||
</header>
|
||||
@for (log of logs | keyvalue; track $index) {
|
||||
@if (log.key === current()) {
|
||||
<logs
|
||||
[context]="log.value.title"
|
||||
[followLogs]="log.value.follow"
|
||||
[fetchLogs]="log.value.fetch"
|
||||
/>
|
||||
}
|
||||
}
|
||||
@case ('Tor Logs') {
|
||||
<logs
|
||||
context="Tor Logs"
|
||||
[followLogs]="followTor"
|
||||
[fetchLogs]="fetchTor"
|
||||
></logs>
|
||||
} @else {
|
||||
@for (log of logs | keyvalue; track $index) {
|
||||
<button
|
||||
tuiCardMedium
|
||||
tuiAppearance="neutral"
|
||||
(click)="current.set(log.key)"
|
||||
>
|
||||
<tui-icon [icon]="log.value.icon" />
|
||||
<span tuiTitle>
|
||||
<strong>{{ log.value.title }}</strong>
|
||||
<span tuiSubtitle>{{ log.value.subtitle }}</span>
|
||||
</span>
|
||||
<tui-icon icon="@tui.chevron-right" />
|
||||
</button>
|
||||
}
|
||||
}
|
||||
`,
|
||||
@@ -47,51 +90,114 @@ import { TitleDirective } from 'src/app/services/title.service'
|
||||
host: { class: 'g-page' },
|
||||
styles: [
|
||||
`
|
||||
tui-select {
|
||||
margin: 1rem 0;
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
header {
|
||||
width: 100%;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
logs {
|
||||
height: calc(100% - 5rem);
|
||||
height: calc(100% - 4rem);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
button::before {
|
||||
margin: 0 -0.25rem 0 -0.375rem;
|
||||
--tui-icon-size: 1.5rem;
|
||||
}
|
||||
|
||||
[tuiCardMedium] {
|
||||
height: 14rem;
|
||||
width: 14rem;
|
||||
cursor: pointer;
|
||||
box-shadow:
|
||||
inset 0 0 0 1px var(--tui-background-neutral-1),
|
||||
var(--tui-shadow-small);
|
||||
|
||||
[tuiSubtitle] {
|
||||
color: var(--tui-text-secondary);
|
||||
}
|
||||
|
||||
tui-icon:last-child {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
:host-context(tui-root._mobile) {
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
logs {
|
||||
height: calc(100% - 2rem);
|
||||
}
|
||||
|
||||
[tuiCardMedium] {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
`,
|
||||
],
|
||||
imports: [
|
||||
FormsModule,
|
||||
TuiSelectModule,
|
||||
TuiTextfieldControllerModule,
|
||||
LogsComponent,
|
||||
TitleDirective,
|
||||
KeyValuePipe,
|
||||
TuiTitle,
|
||||
TuiCardMedium,
|
||||
TuiIcon,
|
||||
TuiAppearance,
|
||||
TuiLink,
|
||||
TuiButton,
|
||||
],
|
||||
})
|
||||
export default class SystemLogsComponent {
|
||||
private readonly api = inject(ApiService)
|
||||
readonly items = ['OS Logs', 'Kernel Logs', 'Tor Logs']
|
||||
logs = 'OS Logs'
|
||||
|
||||
readonly followOS = async (params: RR.FollowServerLogsReq) =>
|
||||
this.api.followServerLogs(params)
|
||||
readonly fetchOS = async (params: RR.GetServerLogsReq) =>
|
||||
this.api.getServerLogs(params)
|
||||
|
||||
readonly followKernel = async (params: RR.FollowServerLogsReq) =>
|
||||
this.api.followKernelLogs(params)
|
||||
readonly fetchKernel = async (params: RR.GetServerLogsReq) =>
|
||||
this.api.getKernelLogs(params)
|
||||
|
||||
readonly followTor = async (params: RR.FollowServerLogsReq) =>
|
||||
this.api.followTorLogs(params)
|
||||
readonly fetchTor = async (params: RR.GetServerLogsReq) =>
|
||||
this.api.getTorLogs(params)
|
||||
|
||||
get subtitle(): string {
|
||||
switch (this.logs) {
|
||||
case 'OS Logs':
|
||||
return 'Raw, unfiltered operating system logs'
|
||||
case 'Kernel Logs':
|
||||
return 'Diagnostic log stream for device drivers and other kernel processes'
|
||||
default:
|
||||
return 'Diagnostic log stream for the Tor daemon on StartOS'
|
||||
}
|
||||
readonly current = signal<string | null>(null)
|
||||
readonly logs: Record<string, Log> = {
|
||||
os: {
|
||||
title: 'OS Logs',
|
||||
subtitle: 'Raw, unfiltered operating system logs',
|
||||
icon: '@tui.square-dashed-bottom-code',
|
||||
follow: params => this.api.followServerLogs(params),
|
||||
fetch: params => this.api.getServerLogs(params),
|
||||
},
|
||||
kernel: {
|
||||
title: 'Kernel Logs',
|
||||
subtitle: 'Diagnostics for drivers and other kernel processes',
|
||||
icon: '@tui.square-chevron-right',
|
||||
follow: params => this.api.followKernelLogs(params),
|
||||
fetch: params => this.api.getKernelLogs(params),
|
||||
},
|
||||
tor: {
|
||||
title: 'Tor Logs',
|
||||
subtitle: 'Diagnostic logs for the Tor daemon on StartOS',
|
||||
icon: '@tui.globe',
|
||||
follow: params => this.api.followTorLogs(params),
|
||||
fetch: params => this.api.getTorLogs(params),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
import { toSignal } from '@angular/core/rxjs-interop'
|
||||
import { RouterLink } from '@angular/router'
|
||||
import { getPkgId } from '@start9labs/shared'
|
||||
import { TuiButton } from '@taiga-ui/core'
|
||||
import { TuiItem } from '@taiga-ui/cdk'
|
||||
import { TuiButton, TuiLink } from '@taiga-ui/core'
|
||||
import { TuiBreadcrumbs } from '@taiga-ui/kit'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { InterfaceComponent } from 'src/app/routes/portal/components/interfaces/interface.component'
|
||||
import { getAddresses } from 'src/app/routes/portal/components/interfaces/interface.utils'
|
||||
@@ -22,6 +24,12 @@ import { TitleDirective } from 'src/app/services/title.service'
|
||||
<a routerLink="../.." tuiIconButton iconStart="@tui.arrow-left">Back</a>
|
||||
{{ interface()?.name }}
|
||||
</ng-container>
|
||||
<tui-breadcrumbs size="l" [style.margin-block-end.rem]="1">
|
||||
<a *tuiItem tuiLink appearance="action-grayscale" routerLink="../..">
|
||||
Dashboard
|
||||
</a>
|
||||
<span *tuiItem class="g-primary">{{ interface()?.name }}</span>
|
||||
</tui-breadcrumbs>
|
||||
@if (interface(); as serviceInterface) {
|
||||
<app-interface
|
||||
[packageId]="pkgId"
|
||||
@@ -29,10 +37,23 @@ import { TitleDirective } from 'src/app/services/title.service'
|
||||
/>
|
||||
}
|
||||
`,
|
||||
styles: `
|
||||
:host-context(tui-root._mobile) tui-breadcrumbs {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
host: { class: 'g-subpage' },
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [InterfaceComponent, RouterLink, TuiButton, TitleDirective],
|
||||
imports: [
|
||||
InterfaceComponent,
|
||||
RouterLink,
|
||||
TuiButton,
|
||||
TitleDirective,
|
||||
TuiBreadcrumbs,
|
||||
TuiItem,
|
||||
TuiLink,
|
||||
],
|
||||
})
|
||||
export default class ServiceInterfaceRoute {
|
||||
private readonly config = inject(ConfigService)
|
||||
|
||||
@@ -52,6 +52,9 @@ const ICONS = {
|
||||
>
|
||||
<tui-icon [icon]="icons[item]" />
|
||||
<span tuiTitle>{{ item }}</span>
|
||||
@if (item === 'dashboard') {
|
||||
<a routerLink="interface" routerLinkActive="active"></a>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
</nav>
|
||||
@@ -80,7 +83,12 @@ const ICONS = {
|
||||
margin: 0 -0.5rem;
|
||||
}
|
||||
|
||||
.active {
|
||||
a a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.active,
|
||||
a:has(.active) {
|
||||
color: var(--tui-text-primary);
|
||||
|
||||
[tuiTitle] {
|
||||
@@ -117,7 +125,8 @@ const ICONS = {
|
||||
background: var(--tui-background-neutral-1);
|
||||
box-shadow: inset 0 -1px var(--tui-background-neutral-1);
|
||||
|
||||
&.active {
|
||||
&.active,
|
||||
&:has(.active) {
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AsyncPipe } from '@angular/common'
|
||||
import { AsyncPipe, DOCUMENT } from '@angular/common'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
@@ -68,7 +68,7 @@ import { SystemWipeComponent } from './wipe.component'
|
||||
<tui-icon icon="@tui.zap" />
|
||||
<span tuiTitle>
|
||||
<strong>
|
||||
{{ 'system.general.update' | i18n }}
|
||||
{{ 'system.general.update.title' | i18n }}
|
||||
</strong>
|
||||
<span tuiSubtitle>{{ server.version }}</span>
|
||||
</span>
|
||||
@@ -79,12 +79,12 @@ import { SystemWipeComponent } from './wipe.component'
|
||||
(click)="onUpdate()"
|
||||
>
|
||||
@if (server.statusInfo.updated) {
|
||||
{{ 'system.general.restart' | i18n }}
|
||||
{{ 'system.general.update.button.restart' | i18n }}
|
||||
} @else {
|
||||
@if (eos.showUpdate$ | async) {
|
||||
{{ 'ui.update' | i18n }}
|
||||
} @else {
|
||||
{{ 'system.general.check' | i18n }}
|
||||
{{ 'system.general.update.button.check' | i18n }}
|
||||
}
|
||||
}
|
||||
</button>
|
||||
@@ -124,14 +124,28 @@ import { SystemWipeComponent } from './wipe.component'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div tuiCell tuiAppearance="outline-grayscale">
|
||||
<tui-icon icon="@tui.download" />
|
||||
<span tuiTitle>
|
||||
<strong>
|
||||
{{ 'system.general.ca.title' | i18n }}
|
||||
</strong>
|
||||
<span tuiSubtitle>
|
||||
{{ 'system.general.ca.subtitle' | i18n }}
|
||||
</span>
|
||||
</span>
|
||||
<button tuiButton (click)="downloadCA()">
|
||||
{{ 'system.general.ca.button' | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
<div tuiCell tuiAppearance="outline-grayscale">
|
||||
<tui-icon icon="@tui.circle-power" (click)="count = count + 1" />
|
||||
<span tuiTitle>
|
||||
<strong>
|
||||
{{ 'system.general.tor' | i18n }}
|
||||
{{ 'system.general.tor.title' | i18n }}
|
||||
</strong>
|
||||
<span tuiSubtitle>
|
||||
{{ 'system.general.daemon' | i18n }}
|
||||
{{ 'system.general.tor.subtitle' | i18n }}
|
||||
</span>
|
||||
</span>
|
||||
<button tuiButton appearance="glass" (click)="onReset()">
|
||||
@@ -143,18 +157,20 @@ import { SystemWipeComponent } from './wipe.component'
|
||||
<tui-icon icon="@tui.briefcase-medical" />
|
||||
<span tuiTitle>
|
||||
<strong>
|
||||
{{ 'system.general.disk' | i18n }}
|
||||
{{ 'system.general.repair.title' | i18n }}
|
||||
</strong>
|
||||
<span tuiSubtitle>
|
||||
{{ 'system.general.attempt' | i18n }}
|
||||
{{ 'system.general.repair.subtitle' | i18n }}
|
||||
</span>
|
||||
</span>
|
||||
<button tuiButton appearance="glass" (click)="onRepair()">
|
||||
{{ 'system.general.repair' | i18n }}
|
||||
{{ 'system.general.repair.button' | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
<!-- hidden element for downloading cert -->
|
||||
<a id="download-ca" href="/static/local-root-ca.crt"></a>
|
||||
`,
|
||||
styles: `
|
||||
:host {
|
||||
@@ -209,6 +225,7 @@ export default class SystemGeneralComponent {
|
||||
SystemWipeComponent,
|
||||
inject(INJECTOR),
|
||||
)
|
||||
private readonly document = inject(DOCUMENT)
|
||||
|
||||
wipe = false
|
||||
count = 0
|
||||
@@ -268,6 +285,10 @@ export default class SystemGeneralComponent {
|
||||
.subscribe(() => this.resetTor(this.wipe))
|
||||
}
|
||||
|
||||
downloadCA() {
|
||||
this.document.getElementById('download-ca')?.click()
|
||||
}
|
||||
|
||||
async onRepair() {
|
||||
this.dialogs
|
||||
.open(TUI_CONFIRM, {
|
||||
|
||||
@@ -14,9 +14,9 @@ import { TitleDirective } from 'src/app/services/title.service'
|
||||
|
||||
const iface: T.ServiceInterface = {
|
||||
id: '',
|
||||
name: 'StartOS User Interface',
|
||||
name: 'StartOS UI',
|
||||
description:
|
||||
'The primary user interface for your StartOS server, accessible from any browser.',
|
||||
'The web user interface for your StartOS server, accessible from any browser.',
|
||||
type: 'ui' as const,
|
||||
masked: false,
|
||||
addressInfo: {
|
||||
@@ -33,15 +33,12 @@ const iface: T.ServiceInterface = {
|
||||
template: `
|
||||
<ng-container *title>
|
||||
<a routerLink=".." tuiIconButton iconStart="@tui.arrow-left">Back</a>
|
||||
Web Addresses
|
||||
StartOS UI
|
||||
</ng-container>
|
||||
<header tuiHeader>
|
||||
<hgroup tuiTitle>
|
||||
<h3>User Interface Addresses</h3>
|
||||
<p tuiSubtitle>
|
||||
View and manage private and public addresses for accessing your
|
||||
StartOS UI
|
||||
</p>
|
||||
<h3>{{ iface.name }}</h3>
|
||||
<p tuiSubtitle>{{ iface.description }}</p>
|
||||
</hgroup>
|
||||
</header>
|
||||
@if (ui(); as ui) {
|
||||
@@ -61,6 +58,7 @@ const iface: T.ServiceInterface = {
|
||||
})
|
||||
export default class StartOsUiComponent {
|
||||
private readonly config = inject(ConfigService)
|
||||
iface = iface
|
||||
|
||||
readonly ui = toSignal(
|
||||
inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
@@ -366,6 +366,10 @@ button.g-action {
|
||||
color: var(--tui-status-info) !important;
|
||||
}
|
||||
|
||||
.g-primary {
|
||||
color: var(--tui-text-primary) !important;
|
||||
}
|
||||
|
||||
.g-secondary {
|
||||
color: var(--tui-text-secondary) !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user