fix ssh, undeprecate wifi (#3121)

This commit is contained in:
Matt Hill
2026-02-12 08:10:01 -07:00
committed by GitHub
parent b6262c8e13
commit 0260c1532d
11 changed files with 151 additions and 95 deletions

View File

@@ -28,7 +28,7 @@ import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
<a routerLink=".." tuiIconButton iconStart="@tui.arrow-left">
{{ 'Back' | i18n }}
</a>
{{ 'Email' | i18n }}
{{ 'SMTP' | i18n }}
</ng-container>
@if (form$ | async; as form) {
<form [formGroup]="form">

View File

@@ -160,7 +160,11 @@ export default class SystemSSHComponent {
const loader = this.loader.open('Deleting').subscribe()
try {
await this.api.deleteSshKey({ fingerprint: '' })
await Promise.all(
fingerprints.map(fingerprint =>
this.api.deleteSshKey({ fingerprint }),
),
)
this.local$.next(
all.filter(s => !fingerprints.includes(s.fingerprint)),
)

View File

@@ -5,8 +5,23 @@ import {
inject,
Input,
} from '@angular/core'
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
import { TuiButton, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { NgTemplateOutlet } from '@angular/common'
import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { filter } from 'rxjs'
import { IST } from '@start9labs/start-sdk'
import {
TuiButton,
TuiDataList,
TuiDropdown,
TuiIcon,
TuiTextfield,
TuiTitle,
} from '@taiga-ui/core'
import { TuiBadge, TuiFade } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import {
@@ -22,50 +37,78 @@ import { wifiSpec } from './wifi.const'
@Component({
selector: '[wifi]',
template: `
@for (network of wifi; track $index) {
@if (network.ssid) {
<ng-template #row let-network>
@if (getSignal(network.strength); as signal) {
<tui-icon
background="@tui.wifi"
[icon]="signal.icon"
[style.background]="'var(--tui-background-neutral-2)'"
[style.color]="signal.color"
/>
} @else {
<tui-icon icon="@tui.wifi-off" />
}
<tui-icon
[icon]="network.security.length ? '@tui.lock' : '@tui.lock-open'"
/>
<div tuiTitle>
<strong tuiFade>
{{ network.ssid }}
</strong>
</div>
@if (network.connected) {
<tui-badge appearance="positive">
{{ 'Connected' | i18n }}
</tui-badge>
}
@if (network.connected === false) {
<button
tuiCell
[disabled]="network.connected"
(click)="prompt(network)"
tuiIconButton
tuiDropdown
size="s"
appearance="flat-grayscale"
iconStart="@tui.ellipsis-vertical"
[(tuiDropdownOpen)]="open"
>
<div tuiTitle>
<strong tuiFade>
{{ network.ssid }}
@if (network.connected) {
<tui-badge appearance="positive">
{{ 'Connected' | i18n }}
</tui-badge>
}
</strong>
</div>
@if (network.connected !== undefined) {
{{ 'More' | i18n }}
<tui-data-list *tuiTextfieldDropdown>
<button
tuiIconButton
size="s"
appearance="icon"
iconStart="@tui.trash-2"
(click.stop)="forget(network)"
tuiOption
new
iconStart="@tui.wifi"
(click)="prompt(network)"
>
{{ 'Connect' | i18n }}
</button>
<button
tuiOption
new
iconStart="@tui.trash"
class="g-negative"
(click)="forget(network)"
>
{{ 'Forget' | i18n }}
</button>
} @else {
<tui-icon
[icon]="network.security.length ? '@tui.lock' : '@tui.lock-open'"
/>
}
@if (getSignal(network.strength); as signal) {
<tui-icon
background="@tui.wifi"
[icon]="signal.icon"
[style.background]="'var(--tui-background-neutral-2)'"
[style.color]="signal.color"
/>
} @else {
<tui-icon icon="@tui.wifi-off" />
}
</tui-data-list>
</button>
}
</ng-template>
@for (network of wifi; track $index) {
@if (network.ssid) {
@if (network.connected === undefined) {
<button tuiCell (click)="prompt(network)">
<ng-container
*ngTemplateOutlet="row; context: { $implicit: network }"
/>
</button>
} @else {
<div tuiCell>
<ng-container
*ngTemplateOutlet="row; context: { $implicit: network }"
/>
</div>
}
}
}
`,
styles: `
@@ -75,8 +118,6 @@ import { wifiSpec } from './wifi.const'
}
[tuiCell] {
padding-inline: 1rem !important;
&:disabled > * {
opacity: 1;
}
@@ -88,11 +129,24 @@ import { wifiSpec } from './wifi.const'
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiCell, TuiTitle, TuiBadge, TuiButton, TuiIcon, TuiFade, i18nPipe],
imports: [
NgTemplateOutlet,
TuiCell,
TuiTitle,
TuiBadge,
TuiButton,
TuiIcon,
TuiFade,
TuiDropdown,
TuiDataList,
TuiTextfield,
i18nPipe,
],
})
export class WifiTableComponent {
private readonly loader = inject(LoadingService)
private readonly errorService = inject(ErrorService)
private readonly dialogs = inject(DialogService)
private readonly api = inject(ApiService)
private readonly formDialog = inject(FormDialogService)
private readonly component = inject(SystemWifiComponent)
@@ -102,6 +156,8 @@ export class WifiTableComponent {
@Input()
wifi: readonly Wifi[] = []
open = false
getSignal(signal: number) {
if (signal < 5) {
return null
@@ -141,17 +197,30 @@ export class WifiTableComponent {
async prompt(network: Wifi): Promise<void> {
if (!network.security.length) {
await this.component.saveAndConnect(network.ssid)
this.dialogs
.openConfirm({
label: `${this.i18n.transform('Connect to')} ${network.ssid}?`,
size: 's',
})
.pipe(filter(Boolean))
.subscribe(() => this.component.saveAndConnect(network.ssid))
} else {
const ssid = wifiSpec.spec['ssid'] as IST.ValueSpecText
const spec: IST.InputSpec = {
...wifiSpec.spec,
ssid: { ...ssid, disabled: 'ssid', default: network.ssid },
}
this.formDialog.open<FormContext<WiFiForm>>(FormComponent, {
label: 'Password needed',
data: {
spec: wifiSpec.spec,
spec,
value: { ssid: network.ssid, password: '' },
buttons: [
{
text: this.i18n.transform('Connect')!,
handler: async ({ ssid, password }) =>
this.component.saveAndConnect(ssid, password),
handler: async ({ password }) =>
this.component.saveAndConnect(network.ssid, password),
},
],
},

View File

@@ -8,6 +8,7 @@ import { toSignal } from '@angular/core/rxjs-interop'
import { FormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import {
DocsLinkDirective,
ErrorService,
i18nKey,
i18nPipe,
@@ -19,11 +20,9 @@ import {
TuiAppearance,
TuiButton,
TuiLoader,
TuiNotification,
TuiTitle,
} from '@taiga-ui/core'
import { TuiSwitch } from '@taiga-ui/kit'
import { TuiCardLarge, TuiHeader } from '@taiga-ui/layout'
import { TuiCardLarge } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { catchError, defer, map, merge, Observable, of, Subject } from 'rxjs'
import {
@@ -47,23 +46,20 @@ import { wifiSpec } from './wifi.const'
</a>
WiFi
</ng-container>
<header tuiHeader>
<tui-notification appearance="negative">
<div tuiTitle>
{{ 'Deprecated' | i18n }}
<div tuiSubtitle>
{{
'WiFi support will be removed in StartOS v0.4.1. If you do not have access to Ethernet, you can use a WiFi extender to connect to the local network, then connect your server to the extender via Ethernet. Please contact Start9 support with any questions or concerns.'
| i18n
}}
</div>
</div>
</tui-notification>
</header>
@if (status()?.interface) {
<section class="g-card">
<header>
Wi-Fi
<a
tuiIconButton
size="xs"
docsLink
path="/user-manual/wifi.html"
appearance="icon"
iconStart="@tui.external-link"
>
{{ 'Documentation' | i18n }}
</a>
<input
type="checkbox"
tuiSwitch
@@ -92,8 +88,8 @@ import { wifiSpec } from './wifi.const'
></div>
}
<p>
<button tuiButton (click)="other(data)">
{{ 'Add' | i18n }}
<button tuiButton (click)="other(data)" appearance="flat">
+ {{ 'Connect to hidden network' | i18n }}
</button>
</p>
} @else {
@@ -128,10 +124,8 @@ import { wifiSpec } from './wifi.const'
TitleDirective,
RouterLink,
PlaceholderComponent,
TuiHeader,
TuiTitle,
TuiNotification,
i18nPipe,
DocsLinkDirective,
],
})
export default class SystemWifiComponent {

View File

@@ -1,4 +1,3 @@
import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { RouterModule } from '@angular/router'
@@ -6,12 +5,9 @@ import { i18nPipe } from '@start9labs/shared'
import { TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiBadgeNotification } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { BadgeService } from 'src/app/services/badge.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { TitleDirective } from 'src/app/services/title.service'
import { SYSTEM_MENU } from './system.const'
import { map } from 'rxjs'
@Component({
template: `
@@ -26,9 +22,6 @@ import { map } from 'rxjs'
tuiCell="s"
routerLinkActive="active"
[routerLink]="page.link"
[style.display]="
!(wifiEnabled$ | async) && page.item === 'WiFi' ? 'none' : null
"
>
<tui-icon [icon]="page.icon" />
<span tuiTitle>
@@ -116,13 +109,9 @@ import { map } from 'rxjs'
TitleDirective,
TuiBadgeNotification,
i18nPipe,
AsyncPipe,
],
})
export class SystemComponent {
readonly menu = SYSTEM_MENU
readonly badge = toSignal(inject(BadgeService).getCount('system'))
readonly wifiEnabled$ = inject<PatchDB<DataModel>>(PatchDB)
.watch$('serverInfo', 'network', 'wifi')
.pipe(map(wifi => !!wifi.interface && wifi.enabled))
}

View File

@@ -28,7 +28,7 @@ export const SYSTEM_MENU = [
},
{
icon: '@tui.mail',
item: 'Email',
item: 'SMTP',
link: 'email',
},
{