feat: add "Add new gateway" option (#3098)

* feat: add "Add new gateway" option

* Update web/projects/ui/src/app/routes/portal/components/form/controls/select.component.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add translation

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
Alex Inkin
2026-01-18 08:37:30 +04:00
committed by GitHub
parent 0d4ddc3451
commit 65fc3e5c52
8 changed files with 52 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
import { inject, provideAppInitializer } from '@angular/core'
import { UntypedFormBuilder } from '@angular/forms'
import { provideAnimations } from '@angular/platform-browser/animations'
import { Router } from '@angular/router'
import { ActivationStart, Router } from '@angular/router'
import { WA_LOCATION } from '@ng-web-apis/common'
import initArgon from '@start9labs/argon2'
import {
@@ -33,7 +33,7 @@ import {
TUI_DATE_VALUE_TRANSFORMER,
} from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { filter, identity, of, pairwise } from 'rxjs'
import { filter, identity, merge, of, pairwise } from 'rxjs'
import { ConfigService } from 'src/app/services/config.service'
import {
PATCH_CACHE,
@@ -116,11 +116,15 @@ export const APP_PROVIDERS = [
{
provide: TUI_DIALOGS_CLOSE,
useFactory: () =>
inject(StateService).pipe(
pairwise(),
filter(
([prev, curr]) =>
prev === 'running' && (curr === 'error' || curr === 'initializing'),
merge(
inject(Router).events.pipe(filter(e => e instanceof ActivationStart)),
inject(StateService).pipe(
pairwise(),
filter(
([prev, curr]) =>
prev === 'running' &&
(curr === 'error' || curr === 'initializing'),
),
),
),
},

View File

@@ -1,5 +1,6 @@
import { Component, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { Router, RouterLink } from '@angular/router'
import { invert } from '@start9labs/shared'
import { IST } from '@start9labs/start-sdk'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
@@ -36,6 +37,7 @@ import { HintPipe } from '../pipes/hint.pipe'
[placeholder]="spec.name"
[items]="items"
[(ngModel)]="selected"
(ngModelChange)="onChange($event)"
></select>
} @else {
<input
@@ -50,15 +52,27 @@ import { HintPipe } from '../pipes/hint.pipe'
@if (!mobile) {
<tui-data-list *tuiTextfieldDropdown>
@for (item of items; track item) {
<button
tuiOption
new
tuiFluidTypography
[style.white-space]="'nowrap'"
[value]="item"
>
{{ item }}
</button>
@if (inverted[item]?.startsWith('~')) {
<a
tuiOption
new
iconEnd="@tui.arrow-right"
tuiFluidTypography
[routerLink]="inverted[item]?.slice(1)"
>
{{ item }}
</a>
} @else {
<button
tuiOption
new
tuiFluidTypography
[style.white-space]="'nowrap'"
[value]="item"
>
{{ item }}
</button>
}
}
</tui-data-list>
}
@@ -70,6 +84,7 @@ import { HintPipe } from '../pipes/hint.pipe'
providers: [tuiFluidTypographyOptionsProvider({ max: 1 })],
imports: [
FormsModule,
RouterLink,
TuiTextfield,
TuiSelect,
TuiDataList,
@@ -81,8 +96,8 @@ import { HintPipe } from '../pipes/hint.pipe'
],
})
export class FormSelectComponent extends Control<IST.ValueSpecSelect, string> {
private readonly inverted = invert(this.spec.values)
protected readonly router = inject(Router)
protected readonly inverted = invert(this.spec.values)
protected readonly mobile = inject(TUI_IS_MOBILE)
protected readonly items = Object.values(this.spec.values)
protected readonly disabledItemHandler = (item: string) =>
@@ -101,4 +116,12 @@ export class FormSelectComponent extends Control<IST.ValueSpecSelect, string> {
set selected(value: string | null) {
this.value = (value && this.inverted[value]) || null
}
protected onChange(value: string) {
const mapped = this.inverted[value]
if (typeof mapped === 'string' && mapped.startsWith('~')) {
this.router.navigate([mapped.slice(1)])
}
}
}

View File

@@ -247,10 +247,10 @@ export class PublicDomainService {
),
values: gateways.reduce<Record<string, string>>(
(obj, gateway) => ({
...obj,
[gateway.id]: gateway.name || gateway.ipInfo.name,
...obj,
}),
{},
{ '~/system/gateways': this.i18n.transform('New gateway') },
),
default: '',
disabled: gateways