Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/projects/shared/src/i18n/dictionaries/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export default {
584: 'Verbindungen können manchmal langsam oder unzuverlässig sein',
585: 'Öffentlich, wenn Sie die Adresse öffentlich teilen, andernfalls privat',
586: 'Erfordert ein Tor-fähiges Gerät oder einen Browser',
587: 'In den meisten Fällen nicht empfohlen. Nur erforderlich für Apps, die HTTPS erzwingen',
587: 'Sollte nur für Apps benötigt werden, die SSL erzwingen',
588: 'Ideal für anonyme, zensurresistente Bereitstellung und Fernzugriff',
589: 'Ideal für lokalen Zugriff',
590: 'Erfordert die Verbindung mit demselben lokalen Netzwerk (LAN) wie Ihr Server, entweder physisch oder über VPN',
Expand Down
2 changes: 1 addition & 1 deletion web/projects/shared/src/i18n/dictionaries/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ export const ENGLISH = {
'Connections can be slow or unreliable at times': 584,
'Public if you share the address publicly, otherwise private': 585,
'Requires using a Tor-enabled device or browser': 586,
'Not recommended in most cases. Only needed for apps that enforce HTTPS': 587,
'Should only needed for apps that enforce SSL': 587,
'Ideal for anonymous, censorship-resistant hosting and remote access': 588,
'Ideal for local access': 589,
'Requires being connected to the same Local Area Network (LAN) as your server, either physically or via VPN': 590,
Expand Down
2 changes: 1 addition & 1 deletion web/projects/shared/src/i18n/dictionaries/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export default {
584: 'Las conexiones pueden ser lentas o poco confiables a veces',
585: 'Público si compartes la dirección públicamente, de lo contrario privado',
586: 'Requiere un dispositivo o navegador habilitado para Tor',
587: 'No recomendado en la mayoría de los casos. Solo necesario para aplicaciones que imponen HTTPS',
587: 'Solo debería ser necesario para aplicaciones que imponen SSL',
588: 'Ideal para alojamiento y acceso remoto anónimo y resistente a la censura',
589: 'Ideal para acceso local',
590: 'Requiere estar conectado a la misma red de área local (LAN) que tu servidor, ya sea físicamente o mediante VPN',
Expand Down
2 changes: 1 addition & 1 deletion web/projects/shared/src/i18n/dictionaries/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export default {
584: 'Les connexions peuvent parfois être lentes ou peu fiables',
585: 'Public si vous partagez l’adresse publiquement, sinon privé',
586: 'Nécessite un appareil ou un navigateur compatible Tor',
587: 'Non recommandé dans la plupart des cas. Nécessaire uniquement pour les applications qui imposent HTTPS',
587: 'Ne devrait être nécessaire que pour les applications qui imposent SSL',
588: 'Idéal pour l’hébergement et l’accès à distance anonymes et résistants à la censure',
589: 'Idéal pour un accès local',
590: 'Nécessite d’être connecté au même réseau local (LAN) que votre serveur, soit physiquement, soit via VPN',
Expand Down
2 changes: 1 addition & 1 deletion web/projects/shared/src/i18n/dictionaries/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export default {
584: 'Połączenia mogą być czasami wolne lub niestabilne',
585: 'Publiczne, jeśli udostępniasz adres publicznie, w przeciwnym razie prywatne',
586: 'Wymaga urządzenia lub przeglądarki obsługującej Tor',
587: 'Niezalecane w większości przypadków. Wymagane tylko dla aplikacji wymuszających HTTPS',
587: 'Powinno być wymagane tylko dla aplikacji wymuszających SSL',
588: 'Idealne do anonimowego, odpornego na cenzurę hostingu i zdalnego dostępu',
589: 'Idealne do dostępu lokalnego',
590: 'Wymaga połączenia z tą samą siecią lokalną (LAN) co serwer, fizycznie lub przez VPN',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,19 @@ import { AsyncPipe } from '@angular/common'
import {
ChangeDetectionStrategy,
Component,
DestroyRef,
inject,
Input,
TemplateRef,
ViewChild,
} from '@angular/core'
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'
import { i18nPipe } from '@start9labs/shared'
import { DialogService, i18nPipe } from '@start9labs/shared'
import { IST } from '@start9labs/start-sdk'
import { tuiAsControl, TuiControl } from '@taiga-ui/cdk'
import {
TuiAlertService,
TuiButton,
TuiDialogContext,
TuiError,
} from '@taiga-ui/core'
import { TuiError } from '@taiga-ui/core'
import {
TUI_FORMAT_ERROR,
TUI_VALIDATION_ERRORS,
TuiFieldErrorPipe,
} from '@taiga-ui/kit'
import { PolymorpheusOutlet } from '@taiga-ui/polymorpheus'
import { filter } from 'rxjs'

import { ControlSpec } from '../controls/control'
import { CONTROLS } from '../controls/controls'
Expand All @@ -46,35 +36,6 @@ export const ERRORS = [
template: `
<ng-container *polymorpheusOutlet="controls[spec.type]" />
<tui-error [error]="order | tuiFieldError | async" />
@if (spec.warning || immutable) {
<ng-template #warning let-completeWith="completeWith">
{{ spec.warning }}
@if (immutable) {
<p>{{ 'This value cannot be changed once set' | i18n }}!</p>
}
<div [style.margin-top.rem]="0.5">
<button
tuiButton
type="button"
appearance="secondary-grayscale"
size="s"
[style.margin-inline-end.rem]="0.5"
(click)="completeWith(false)"
>
{{ 'Continue' | i18n }}
</button>
<button
tuiButton
type="button"
appearance="flat-grayscale"
size="s"
(click)="completeWith(true)"
>
{{ 'Cancel' | i18n }}
</button>
</div>
</ng-template>
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
Expand All @@ -92,52 +53,43 @@ export const ERRORS = [
},
],
hostDirectives: [ControlDirective],
imports: [
AsyncPipe,
i18nPipe,
PolymorpheusOutlet,
TuiError,
TuiFieldErrorPipe,
TuiButton,
],
imports: [AsyncPipe, PolymorpheusOutlet, TuiError, TuiFieldErrorPipe],
})
export class FormControlComponent<
T extends ControlSpec,
V,
> extends TuiControl<V | null> {
private readonly destroyRef = inject(DestroyRef)
private readonly alerts = inject(TuiAlertService)
private readonly dialogs = inject(DialogService)
private readonly i18n = inject(i18nPipe)

protected readonly controls = CONTROLS

@Input({ required: true })
spec!: T

@ViewChild('warning')
warning?: TemplateRef<TuiDialogContext<boolean>>

warned = false
readonly order = ERRORS

get immutable(): boolean {
return 'immutable' in this.spec && this.spec.immutable
}

onInput(value: V | null) {
const previous = this.value()
const immutable =
'immutable' in this.spec && this.spec.immutable
? `<p>${this.i18n.transform('This value cannot be changed once set')}</p>`
: ''
const warning = this.spec.warning + immutable

if (!this.warned && this.warning) {
this.alerts
.open<boolean>(this.warning, {
label: this.i18n.transform('Warning'),
appearance: 'warning',
if (!this.warned && warning) {
this.dialogs
.openConfirm({
label: 'Warning',
data: { content: warning as any, yes: 'Confirm', no: 'Cancel' },
closeable: false,
autoClose: 0,
dismissible: false,
})
.pipe(filter(Boolean), takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.onChange(previous)
.subscribe(confirm => {
if (!confirm) {
this.onChange(previous)
}
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import { HintPipe } from '../pipes/hint.pipe'
}
<input
tuiInputNumber
[postfix]="spec.units ? ' ' + spec.units : ''"
[postfix]="postfix"
[min]="spec.min"
[max]="spec.max"
[step]="spec.step || 0"
[invalid]="control.invalid()"
[disabled]="!!spec.disabled"
[readOnly]="readOnly"
[placeholder]="spec.placeholder || ''"
[placeholder]="placeholder"
[(ngModel)]="value"
(blur)="control.onTouched()"
/>
Expand All @@ -51,4 +51,16 @@ export class FormNumberComponent extends Control<IST.ValueSpecNumber, number> {
get precision(): number {
return this.spec.integer ? 0 : Infinity
}

get postfix(): string {
return this.spec.units && (this.value !== null || !this.spec.placeholder)
? ` ${this.spec.units}`
: ''
}

get placeholder(): string {
const units = this.spec.units ? ` (${this.spec.units})` : ''

return this.spec.placeholder ? this.spec.placeholder + units : ''
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ import { FormsModule } from '@angular/forms'
import { invert } from '@start9labs/shared'
import { IST } from '@start9labs/start-sdk'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import { TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiDataListWrapper, TuiSelect, TuiTooltip } from '@taiga-ui/kit'
import { TuiDataList, TuiIcon, TuiTextfield } from '@taiga-ui/core'
import {
TuiDataListWrapper,
TuiFluidTypography,
tuiFluidTypographyOptionsProvider,
TuiSelect,
TuiTooltip,
} from '@taiga-ui/kit'

import { Control } from './control'
import { HintPipe } from '../pipes/hint.pipe'
Expand Down Expand Up @@ -41,18 +47,32 @@ import { HintPipe } from '../pipes/hint.pipe'
/>
}
@if (!mobile) {
<tui-data-list-wrapper *tuiTextfieldDropdown new [items]="items" />
<tui-data-list *tuiTextfieldDropdown>
@for (item of items; track $index) {
<button
tuiOption
new
tuiFluidTypography
[style.white-space]="'nowrap'"
[value]="item"
>
{{ item }}
</button>
}
</tui-data-list>
}
@if (spec | hint; as hint) {
<tui-icon [tuiTooltip]="hint" />
}
</tui-textfield>
`,
providers: [tuiFluidTypographyOptionsProvider({ max: 1 })],
imports: [
FormsModule,
TuiTextfield,
TuiSelect,
TuiDataListWrapper,
TuiDataList,
TuiFluidTypography,
TuiIcon,
TuiTooltip,
HintPipe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { getMenu } from 'src/app/utils/system-utilities'
class="link"
routerLinkActive="link_active"
tuiHintDirection="bottom"
[tuiHintShowDelay]="250"
[tuiHintShowDelay]="128"
[routerLink]="['/', item.routerLink]"
[class.link_system]="item.routerLink === 'system'"
[tuiHint]="rla.isActive ? '' : (item.name | i18n)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'

type AddressWithInfo = {
url: string
ssl: boolean
info: T.HostnameInfo
gateway?: GatewayPlus
showSsl: boolean
}

function cmpWithRankedPredicates<T extends AddressWithInfo>(
Expand All @@ -30,10 +30,7 @@ function filterTor(a: AddressWithInfo): a is TorAddress {
return a.info.kind === 'onion'
}
function cmpTor(a: TorAddress, b: TorAddress): -1 | 0 | 1 {
for (let [x, y, sign] of [[a, b, 1] as const, [b, a, -1] as const]) {
if (y.url.startsWith('http:') && x.url.startsWith('https:')) return sign
}
return 0
return cmpWithRankedPredicates(a, b, [x => !x.showSsl])
}

type LanAddress = AddressWithInfo & { info: { kind: 'ip'; public: false } }
Expand Down Expand Up @@ -146,10 +143,15 @@ export class InterfaceService {
: undefined
const res = []
if (url) {
res.push({ url, ssl: false, info, gateway })
res.push({ url, info, gateway, showSsl: false })
}
if (sslUrl) {
res.push({ url: sslUrl, ssl: true, info, gateway })
res.push({
url: sslUrl,
info,
gateway,
showSsl: !!url,
})
}
return res
},
Expand Down Expand Up @@ -326,7 +328,7 @@ export class InterfaceService {
}

private toDisplayAddress(
{ info, ssl, url, gateway }: AddressWithInfo,
{ info, url, gateway, showSsl }: AddressWithInfo,
publicDomains: Record<string, T.PublicDomainConfig>,
): DisplayAddress {
let access: DisplayAddress['access']
Expand All @@ -351,15 +353,8 @@ export class InterfaceService {
this.i18n.transform('Requires using a Tor-enabled device or browser'),
]
// Tor (SSL)
if (ssl) {
type = `${type} (SSL)`
bullets = [
this.i18n.transform(
'Not recommended in most cases. Only needed for apps that enforce HTTPS',
),
rootCaRequired,
...bullets,
]
if (showSsl) {
bullets = [rootCaRequired, ...bullets]
// Tor (NON-SSL)
} else {
bullets.unshift(
Expand Down Expand Up @@ -500,6 +495,14 @@ export class InterfaceService {
}
}

if (showSsl) {
type = `${type} (SSL)`

bullets.unshift(
this.i18n.transform('Should only needed for apps that enforce SSL'),
)
}

return {
url,
access,
Expand Down
Loading