This commit is contained in:
Matt Hill
2025-08-07 09:03:54 -06:00
parent 8796e41ea0
commit 2762076683
13 changed files with 91 additions and 95 deletions

View File

@@ -36,7 +36,7 @@ import { ClearnetDomain } from './interface.utils'
} @empty {
<tr>
<td colspan="4">
<app-placeholder icon="@tui.app-window">
<app-placeholder icon="@tui.globe">
{{ 'No clearnet domains' | i18n }}
</app-placeholder>
</td>

View File

@@ -19,7 +19,6 @@ import {
import { TuiBadge } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { InterfaceComponent } from './interface.component'
import { ClearnetDomain } from './interface.utils'

View File

@@ -1,11 +1,16 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, input } from '@angular/core'
import {
ChangeDetectionStrategy,
Component,
computed,
input,
} from '@angular/core'
import { TuiTitle } from '@taiga-ui/core'
import { TuiSwitch } from '@taiga-ui/kit'
import { FormsModule } from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import { TuiCell } from '@taiga-ui/layout'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
import { InterfaceGateway } from './interface.utils'
@Component({
selector: 'section[gateways]',
@@ -21,28 +26,18 @@ import { PlaceholderComponent } from 'src/app/routes/portal/components/placehold
[showIcons]="false"
[ngModel]="gateway.enabled"
(ngModelChange)="onToggle(gateway)"
[disabled]="osUi() && !gateway.public"
/>
</label>
} @empty {
<app-placeholder icon="@tui.door-closed-locked">
No gateways
</app-placeholder>
}
`,
host: { class: 'g-card' },
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
CommonModule,
FormsModule,
TuiSwitch,
i18nPipe,
TuiCell,
TuiTitle,
PlaceholderComponent,
],
imports: [CommonModule, FormsModule, TuiSwitch, i18nPipe, TuiCell, TuiTitle],
})
export class InterfaceGatewaysComponent {
readonly gateways = input.required<any>()
readonly gateways = input.required<InterfaceGateway[]>()
readonly osUi = input.required<boolean>()
async onToggle(event: any) {}
async onToggle(gateway: InterfaceGateway) {}
}

View File

@@ -11,7 +11,7 @@ import { InterfaceAddressesComponent } from './addresses/addresses.component'
template: `
<!-- @TODO Alex / Matt translation in all nested components -->
<div [style.display]="'grid'">
<section [gateways]="value().gateways"></section>
<section [gateways]="value().gateways" [osUi]="osUi()"></section>
<section [torDomains]="value().torDomains"></section>
<section [clearnetDomains]="value().clearnetDomains"></section>
</div>
@@ -48,4 +48,5 @@ export class InterfaceComponent {
readonly packageId = input('')
readonly value = input.required<MappedServiceInterface>()
readonly isRunning = input.required<boolean>()
readonly osUi = input(false)
}

View File

@@ -40,13 +40,13 @@ export function getAddresses(
{
type: 'Local',
description: '',
gateway: 'Wire Conenction 1',
gateway: 'Wired Connection 1',
url: 'https://test.local:1234',
},
{
type: 'IPv4 (LAN)',
description: '',
gateway: 'Wire Connction 1',
gateway: 'Wired Connection 1',
url: 'https://192.168.1.10.local:1234',
},
]
@@ -54,7 +54,7 @@ export function getAddresses(
{
type: 'IPv4 (WAN)',
description: '',
gateway: 'Wire Conenction 1',
gateway: 'Wired Connection 1',
url: 'https://72.72.72.72',
},
]
@@ -112,11 +112,7 @@ export function getAddresses(
}
export type MappedServiceInterface = T.ServiceInterface & {
gateways: {
id: string
name: string
enabled: boolean
}[]
gateways: InterfaceGateway[]
torDomains: string[]
clearnetDomains: ClearnetDomain[]
addresses: {
@@ -125,6 +121,13 @@ export type MappedServiceInterface = T.ServiceInterface & {
}
}
export type InterfaceGateway = {
id: string
name: string
enabled: boolean
public: boolean
}
export type ClearnetDomain = {
fqdn: string
authority: string | null

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { DocsLinkDirective, i18nPipe } from '@start9labs/shared'
import { TuiButton, TuiLink } from '@taiga-ui/core'
import { TuiButton } from '@taiga-ui/core'
import { TitleDirective } from 'src/app/services/title.service'
import { AuthorityService } from './authority.service'
import { AuthoritiesTableComponent } from './table.component'
@@ -18,13 +18,15 @@ import { AuthoritiesTableComponent } from './table.component'
<header>
{{ 'Certificate Authorities' | i18n }}
<a
tuiLink
tuiIconButton
size="xs"
docsLink
path="/user-manual/authorities.html"
appearance="action-grayscale"
iconEnd="@tui.external-link"
[pseudo]="true"
></a>
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
@if (authorityService.authorities(); as authorities) {
<button
tuiButton
@@ -43,7 +45,6 @@ import { AuthoritiesTableComponent } from './table.component'
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
TuiButton,
TuiLink,
RouterLink,
TitleDirective,
i18nPipe,

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { DocsLinkDirective, i18nPipe } from '@start9labs/shared'
import { TuiButton, TuiLink } from '@taiga-ui/core'
import { TuiButton } from '@taiga-ui/core'
import { TitleDirective } from 'src/app/services/title.service'
import { DomainService } from './domain.service'
import { DomainsTableComponent } from './table.component'
@@ -19,13 +19,15 @@ import { DomainsTableComponent } from './table.component'
<header>
{{ 'Domains' | i18n }}
<a
tuiLink
tuiIconButton
size="xs"
docsLink
path="/user-manual/domains.html"
appearance="action-grayscale"
iconEnd="@tui.external-link"
[pseudo]="true"
></a>
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
@if (domainService.data(); as value) {
<button
tuiButton
@@ -44,7 +46,6 @@ import { DomainsTableComponent } from './table.component'
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
TuiButton,
TuiLink,
RouterLink,
TitleDirective,
i18nPipe,

View File

@@ -11,7 +11,7 @@ import {
LoadingService,
} from '@start9labs/shared'
import { inputSpec, IST } from '@start9labs/start-sdk'
import { TuiButton, TuiLink, TuiTitle } from '@taiga-ui/core'
import { TuiButton, TuiTitle } from '@taiga-ui/core'
import { TuiHeader } from '@taiga-ui/layout'
import { TuiInputModule } from '@taiga-ui/legacy'
import { PatchDB } from 'patch-db-client'
@@ -38,13 +38,15 @@ import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
<b>
{{ 'SMTP Credentials' | i18n }}
<a
tuiLink
tuiIconButton
size="xs"
docsLink
path="/user-manual/smtp.html"
appearance="action-grayscale"
iconEnd="@tui.external-link"
[pseudo]="true"
></a>
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
</b>
</h3>
</header>
@@ -124,7 +126,6 @@ import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
TuiInputModule,
TuiHeader,
TuiTitle,
TuiLink,
RouterLink,
TitleDirective,
i18nPipe,

View File

@@ -7,7 +7,7 @@ import {
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { TuiButton, TuiLink } from '@taiga-ui/core'
import { TuiButton } from '@taiga-ui/core'
import { PatchDB } from 'patch-db-client'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { DataModel } from 'src/app/services/patch-db/data-model'
@@ -33,13 +33,15 @@ import { GatewayPlus } from './item.component'
<header>
{{ 'Gateways' | i18n }}
<a
tuiLink
tuiIconButton
size="xs"
docsLink
path="/user-manual/gateways.html"
appearance="action-grayscale"
iconEnd="@tui.external-link"
[pseudo]="true"
></a>
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
<button
tuiButton
size="xs"
@@ -58,7 +60,6 @@ import { GatewayPlus } from './item.component'
CommonModule,
RouterLink,
TuiButton,
TuiLink,
GatewaysTableComponent,
TitleDirective,
i18nPipe,

View File

@@ -31,22 +31,22 @@ export type GatewayPlus = T.NetworkInterfaceInfo & {
}
@Component({
selector: 'tr[proxy]',
selector: 'tr[gateway]',
template: `
@if (proxy(); as proxy) {
<td [style.grid-column]="'span 2'">{{ proxy.ipInfo.name }}</td>
<td class="type">{{ proxy.ipInfo.deviceType || '-' }}</td>
@if (gateway(); as gateway) {
<td [style.grid-column]="'span 2'">{{ gateway.ipInfo.name }}</td>
<td class="type">{{ gateway.ipInfo.deviceType || '-' }}</td>
<td [style.order]="-2">
{{ proxy.public ? ('Public' | i18n) : ('Private' | i18n) }}
{{ gateway.public ? ('Public' | i18n) : ('Private' | i18n) }}
</td>
<td class="lan">{{ proxy.ipv4.join(', ') }}</td>
<td class="lan">{{ gateway.ipv4.join(', ') }}</td>
<td
class="wan"
[style.color]="
proxy.ipInfo.wanIp ? 'var(--tui-text-warning)' : undefined
gateway.ipInfo.wanIp ? 'var(--tui-text-warning)' : undefined
"
>
{{ proxy.ipInfo.wanIp || ('Error' | i18n) }}
{{ gateway.ipInfo.wanIp || ('Error' | i18n) }}
</td>
<td>
<button
@@ -65,7 +65,7 @@ export type GatewayPlus = T.NetworkInterfaceInfo & {
{{ 'Rename' | i18n }}
</button>
</tui-opt-group>
@if (proxy.ipInfo.deviceType === 'wireguard') {
@if (gateway.ipInfo.deviceType === 'wireguard') {
<tui-opt-group>
<button
tuiOption
@@ -137,7 +137,7 @@ export class GatewaysItemComponent {
private readonly api = inject(ApiService)
private readonly formDialog = inject(FormDialogService)
readonly proxy = input.required<GatewayPlus>()
readonly gateway = input.required<GatewayPlus>()
open = false
@@ -149,7 +149,7 @@ export class GatewaysItemComponent {
const loader = this.loader.open('Deleting').subscribe()
try {
await this.api.removeTunnel({ id: this.proxy().id })
await this.api.removeTunnel({ id: this.gateway().id })
} catch (e: any) {
this.errorService.handleError(e)
} finally {
@@ -159,7 +159,7 @@ export class GatewaysItemComponent {
}
async rename() {
const { ipInfo, id } = this.proxy()
const { ipInfo, id } = this.gateway()
const renameSpec = ISB.InputSpec.of({
label: ISB.Value.text({
name: 'Label',

View File

@@ -1,7 +1,6 @@
import { ChangeDetectionStrategy, Component, input } from '@angular/core'
import { i18nPipe } from '@start9labs/shared'
import { TuiSkeleton } from '@taiga-ui/kit'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
import { TableComponent } from 'src/app/routes/portal/components/table.component'
import { GatewaysItemComponent, GatewayPlus } from './item.component'
@@ -18,32 +17,19 @@ import { GatewaysItemComponent, GatewayPlus } from './item.component'
null,
]"
>
@for (proxy of gateways(); track $index) {
<tr [proxy]="proxy"></tr>
@for (gateway of gateways(); track $index) {
<tr [gateway]="gateway"></tr>
} @empty {
<tr>
<td colspan="5">
@if (gateways()) {
<app-placeholder icon="@tui.door-closed-locked">
<!-- @TODO translation -->
No gateways
</app-placeholder>
} @else {
<div [tuiSkeleton]="true">{{ 'Loading' | i18n }}</div>
}
<div [tuiSkeleton]="true">{{ 'Loading' | i18n }}</div>
</td>
</tr>
}
</table>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
TuiSkeleton,
i18nPipe,
TableComponent,
GatewaysItemComponent,
PlaceholderComponent,
],
imports: [TuiSkeleton, i18nPipe, TableComponent, GatewaysItemComponent],
})
export class GatewaysTableComponent<T extends GatewayPlus> {
readonly gateways = input<readonly T[] | null>(null)

View File

@@ -14,7 +14,7 @@ import {
LoadingService,
} from '@start9labs/shared'
import { ISB } from '@start9labs/start-sdk'
import { TuiButton, TuiLink } from '@taiga-ui/core'
import { TuiButton } from '@taiga-ui/core'
import { filter, from, merge, Subject } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { SSHKey } from 'src/app/services/api/api.types'
@@ -37,13 +37,15 @@ import { SSHTableComponent } from './table.component'
<header>
{{ 'SSH Keys' | i18n }}
<a
tuiLink
tuiIconButton
size="xs"
docsLink
path="/user-manual/ssh.html"
appearance="action-grayscale"
iconEnd="@tui.external-link"
[pseudo]="true"
></a>
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
<button
tuiButton
size="xs"
@@ -82,7 +84,6 @@ import { SSHTableComponent } from './table.component'
SSHTableComponent,
RouterLink,
TitleDirective,
TuiLink,
i18nPipe,
DocsLinkDirective,
],

View File

@@ -35,7 +35,7 @@ import { TitleDirective } from 'src/app/services/title.service'
</hgroup>
</header>
@if (ui(); as ui) {
<service-interface [value]="ui" [isRunning]="true" />
<service-interface [value]="ui" [isRunning]="true" [osUi]="true" />
}
`,
host: { class: 'g-subpage' },
@@ -80,7 +80,14 @@ export default class StartOsUiComponent {
return {
...this.iface,
addresses: getAddresses(this.iface, host, this.config),
gateways: [],
gateways: [
{
id: 'eth0',
name: 'Wired Connection 1',
public: false,
enabled: true,
},
],
torDomains: [],
clearnetDomains: [],
}