Merge branch 'next/major' of github.com:Start9Labs/start-os into bugfix/alpha.20

This commit is contained in:
Matt Hill
2026-03-15 16:17:02 -06:00
184 changed files with 1898 additions and 2330 deletions

View File

@@ -14,7 +14,7 @@ import { PatchMonitorService } from './services/patch-monitor.service'
selector: 'app-root',
imports: [TuiRoot, RouterOutlet, ToastContainerComponent],
template: `
<tui-root tuiTheme="dark">
<tui-root>
<router-outlet />
<toast-container />
</tui-root>

View File

@@ -10,7 +10,6 @@ import {
provideZoneChangeDetection,
} from '@angular/core'
import { UntypedFormBuilder } from '@angular/forms'
import { provideAnimations } from '@angular/platform-browser/animations'
import {
ActivationStart,
PreloadAllModules,
@@ -40,21 +39,22 @@ import {
} from '@start9labs/shared'
import { tuiObfuscateOptionsProvider } from '@taiga-ui/cdk'
import {
TUI_DATE_FORMAT,
provideTaiga,
TUI_DIALOGS_CLOSE,
TUI_MEDIA,
tuiAlertOptionsProvider,
tuiButtonOptionsProvider,
tuiDateFormatProvider,
tuiDropdownOptionsProvider,
tuiHintOptionsProvider,
tuiNotificationOptionsProvider,
tuiNumberFormatProvider,
} from '@taiga-ui/core'
import { provideEventPlugins } from '@taiga-ui/event-plugins'
import {
TUI_DATE_TIME_VALUE_TRANSFORMER,
TUI_DATE_VALUE_TRANSFORMER,
tuiInputDateOptionsProvider,
tuiInputDateTimeOptionsProvider,
} from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { filter, identity, merge, of, pairwise } from 'rxjs'
import { filter, identity, merge, pairwise } from 'rxjs'
import { FilterUpdatesPipe } from 'src/app/routes/portal/routes/updates/filter-updates.pipe'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { LiveApiService } from 'src/app/services/api/embassy-live-api.service'
@@ -63,14 +63,16 @@ import { AuthService } from 'src/app/services/auth.service'
import { CategoryService } from 'src/app/services/category.service'
import { ClientStorageService } from 'src/app/services/client-storage.service'
import { ConfigService } from 'src/app/services/config.service'
import { DateTransformerService } from 'src/app/services/date-transformer.service'
import { DatetimeTransformerService } from 'src/app/services/datetime-transformer.service'
import {
PATCH_CACHE,
PatchDbSource,
} from 'src/app/services/patch-db/patch-db-source'
import { StateService } from 'src/app/services/state.service'
import { StorageService } from 'src/app/services/storage.service'
import {
DateTransformer,
DatetimeTransformer,
} from 'src/app/utils/value-transformers'
import { environment } from 'src/environments/environment'
import { ROUTES } from './app.routes'
@@ -83,8 +85,7 @@ const {
export const APP_CONFIG: ApplicationConfig = {
providers: [
provideZoneChangeDetection(),
provideAnimations(),
provideEventPlugins(),
provideTaiga({ mode: 'dark' }),
provideHttpClient(withInterceptorsFromDi(), withFetch()),
provideRouter(
ROUTES,
@@ -107,24 +108,13 @@ export const APP_CONFIG: ApplicationConfig = {
tuiNumberFormatProvider({ decimalSeparator: '.', thousandSeparator: '' }),
tuiButtonOptionsProvider({ size: 'm' }),
tuiDropdownOptionsProvider({ appearance: 'start-os' }),
tuiAlertOptionsProvider({
tuiNotificationOptionsProvider({
autoClose: appearance => (appearance === 'negative' ? 0 : 3000),
}),
{
provide: TUI_DATE_FORMAT,
useValue: of({
mode: 'MDY',
separator: '/',
}),
},
{
provide: TUI_DATE_VALUE_TRANSFORMER,
useClass: DateTransformerService,
},
{
provide: TUI_DATE_TIME_VALUE_TRANSFORMER,
useClass: DatetimeTransformerService,
},
tuiDateFormatProvider({ mode: 'mm/dd/yyyy', separator: '/' }),
tuiInputDateOptionsProvider({ valueTransformer: DateTransformer }),
tuiInputDateTimeOptionsProvider({ valueTransformer: DatetimeTransformer }),
tuiHintOptionsProvider({ appearance: 'primary-grayscale' }),
{
provide: ApiService,
useClass: useMocks ? MockApiService : LiveApiService,

View File

@@ -7,8 +7,7 @@ import {
} from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { i18nKey, i18nPipe } from '@start9labs/shared'
import { TuiDialogContext, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { TuiDialogContext, TuiIcon, TuiTitle, TuiCell } from '@taiga-ui/core'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { map } from 'rxjs'

View File

@@ -2,7 +2,7 @@ import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { i18nPipe } from '@start9labs/shared'
import { TuiAlert, TuiLink } from '@taiga-ui/core'
import { TuiLink, TuiNotification } from '@taiga-ui/core'
import { PatchDB } from 'patch-db-client'
import { endWith, map, merge, Observable, pairwise, Subject } from 'rxjs'
import { DataModel } from 'src/app/services/patch-db/data-model'
@@ -11,9 +11,9 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
selector: 'notifications-toast',
template: `
<ng-template
[tuiAlert]="!!(visible$ | async)"
[tuiAlertOptions]="{ label: 'StartOS' }"
(tuiAlertChange)="onDismiss()"
[tuiNotification]="!!(visible$ | async)"
[tuiNotificationOptions]="{ label: 'StartOS' }"
(tuiNotificationChange)="onDismiss()"
>
{{ 'New notifications' | i18n }}
<a tuiLink routerLink="/notifications" [queryParams]="{ toast: true }">
@@ -22,7 +22,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
</ng-template>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiAlert, RouterLink, AsyncPipe, i18nPipe, TuiLink],
imports: [TuiNotification, RouterLink, AsyncPipe, i18nPipe, TuiLink],
})
export class NotificationsToastComponent {
private readonly dismiss$ = new Subject<boolean>()

View File

@@ -2,11 +2,12 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { SwUpdate } from '@angular/service-worker'
import { WA_WINDOW } from '@ng-web-apis/common'
import { i18nPipe, LoadingService } from '@start9labs/shared'
import { i18nPipe } from '@start9labs/shared'
import { Version } from '@start9labs/start-sdk'
import { TuiResponsiveDialog } from '@taiga-ui/addon-mobile'
import { TuiAutoFocus } from '@taiga-ui/cdk'
import { TuiButton } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { distinctUntilChanged, map, merge, Subject } from 'rxjs'
import { ConfigService } from 'src/app/services/config.service'
@@ -74,7 +75,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
export class RefreshAlertComponent {
private readonly win = inject(WA_WINDOW)
private readonly updates = inject(SwUpdate)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly version = Version.parse(inject(ConfigService).version)
readonly i18n = inject(i18nPipe)

View File

@@ -2,13 +2,9 @@ import { CommonModule } from '@angular/common'
import { Component, Inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { WA_WINDOW } from '@ng-web-apis/common'
import {
DialogService,
i18nKey,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { DialogService, i18nKey, i18nPipe } from '@start9labs/shared'
import { TuiButton } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ConfigService } from 'src/app/services/config.service'
@@ -29,7 +25,7 @@ export default class HomePage {
}
constructor(
private readonly loader: LoadingService,
private readonly loader: TuiNotificationMiddleService,
private readonly api: ApiService,
private readonly dialog: DialogService,
@Inject(WA_WINDOW) private readonly window: Window,

View File

@@ -1,7 +1,7 @@
import { Component, inject, DOCUMENT } from '@angular/core'
import { DocsLinkDirective, i18nPipe, RELATIVE_URL } from '@start9labs/shared'
import { TuiButton, TuiIcon, TuiSurface } from '@taiga-ui/core'
import { TuiCardLarge } from '@taiga-ui/layout'
import { TuiButton, TuiIcon } from '@taiga-ui/core'
import { TuiCardLarge, TuiSurface } from '@taiga-ui/layout'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ConfigService } from 'src/app/services/config.service'

View File

@@ -11,7 +11,7 @@
<label tuiLabel>{{ 'Password' | i18n }}</label>
<input
tuiAutoFocus
tuiTextfield
tuiInput
type="password"
[ngModelOptions]="{ standalone: true }"
[(ngModel)]="password"

View File

@@ -1,4 +1,4 @@
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
.card {
@include taiga.center-all();

View File

@@ -3,10 +3,10 @@ import { Component, DestroyRef, DOCUMENT, inject, Inject } from '@angular/core'
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'
import { FormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import { i18nKey, i18nPipe, LoadingService } from '@start9labs/shared'
import { i18nKey, i18nPipe } from '@start9labs/shared'
import { TuiAutoFocus } from '@taiga-ui/cdk'
import { TuiButton, TuiError, TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiPassword } from '@taiga-ui/kit'
import { TuiButton, TuiError, TuiIcon, TuiInput } from '@taiga-ui/core'
import { TuiNotificationMiddleService, TuiPassword } from '@taiga-ui/kit'
import { TuiCardLarge } from '@taiga-ui/layout'
import { CAWizardComponent } from 'src/app/routes/login/ca-wizard/ca-wizard.component'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@@ -23,7 +23,7 @@ import { ConfigService } from 'src/app/services/config.service'
CAWizardComponent,
TuiButton,
TuiCardLarge,
TuiTextfield,
TuiInput,
TuiIcon,
TuiPassword,
TuiAutoFocus,
@@ -39,7 +39,7 @@ export default class LoginPage {
constructor(
private readonly router: Router,
private readonly authService: AuthService,
private readonly loader: LoadingService,
private readonly loader: TuiNotificationMiddleService,
private readonly api: ApiService,
public readonly config: ConfigService,
@Inject(DOCUMENT) public readonly document: Document,

View File

@@ -14,7 +14,7 @@ import {
} from '@taiga-ui/cdk'
import { TuiButton, TuiDialogContext } from '@taiga-ui/core'
import { TuiConfirmService } from '@taiga-ui/kit'
import { POLYMORPHEUS_CONTEXT } from '@taiga-ui/polymorpheus'
import { injectContext } from '@taiga-ui/polymorpheus'
import { Operation } from 'fast-json-patch'
import { FormGroupComponent } from 'src/app/routes/portal/components/form/containers/group.component'
import { InvalidService } from 'src/app/routes/portal/components/form/containers/control.directive'
@@ -76,7 +76,7 @@ export interface FormContext<T> {
styles: `
.note {
color: var(--tui-text-secondary);
font: var(--tui-font-text-s);
font: var(--tui-typography-body-s);
margin-top: 1rem;
}
@@ -107,10 +107,9 @@ export class FormComponent<T extends Record<string, any>> implements OnInit {
private readonly confirm = inject(TuiConfirmService, { optional: true })
private readonly formService = inject(FormService)
private readonly invalidService = inject(InvalidService)
private readonly context = inject<TuiDialogContext<void, FormContext<T>>>(
POLYMORPHEUS_CONTEXT,
{ optional: true },
)
private readonly context = injectContext<
TuiDialogContext<void, FormContext<T>>
>({ optional: true })
@Input() spec = this.context?.data.spec || {}
@Input() buttons = this.context?.data.buttons || []

View File

@@ -1,4 +1,3 @@
import { AsyncPipe } from '@angular/common'
import {
ChangeDetectorRef,
Component,
@@ -11,19 +10,14 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'
import {
AbstractControl,
FormArrayName,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms'
import { DialogService, i18nKey, i18nPipe } from '@start9labs/shared'
import { IST } from '@start9labs/start-sdk'
import { TuiAnimated } from '@taiga-ui/cdk'
import {
TuiButton,
TuiError,
TuiIcon,
TuiLink,
TuiTextfield,
} from '@taiga-ui/core'
import { TuiFieldErrorPipe, TuiTooltip } from '@taiga-ui/kit'
import { TuiButton, TuiError, TuiIcon, TuiInput, TuiLink } from '@taiga-ui/core'
import { TuiTooltip } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { FormService } from 'src/app/services/form.service'
@@ -51,7 +45,13 @@ import { FormObjectComponent } from './object.component'
+ {{ 'Add' | i18n }}
</button>
</div>
<tui-error [error]="order | tuiFieldError | async" />
<!-- TODO: Remove ngModel in Taiga v5.0 -->
<tui-error
[ngModel]=""
[ngModelOptions]="{ standalone: true }"
[formArray]="array.control"
[order]="order"
/>
@for (item of array.control.controls; track item) {
<div tuiAnimated class="control">
<div>
@@ -92,7 +92,7 @@ import { FormObjectComponent } from './object.component'
}
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
display: block;
@@ -102,7 +102,7 @@ import { FormObjectComponent } from './object.component'
.label {
display: flex;
align-items: center;
font: var(--tui-font-heading-6);
font: var(--tui-typography-heading-h6);
}
.add {
@@ -173,21 +173,20 @@ import { FormObjectComponent } from './object.component'
`,
hostDirectives: [ControlDirective],
imports: [
AsyncPipe,
ReactiveFormsModule,
TuiIcon,
TuiTooltip,
TuiLink,
TuiError,
TuiFieldErrorPipe,
TuiButton,
TuiTextfield,
TuiInput,
i18nPipe,
HintPipe,
MustachePipe,
FormControlComponent,
forwardRef(() => FormObjectComponent),
TuiAnimated,
FormsModule,
],
})
export class FormArrayComponent {

View File

@@ -1,19 +1,15 @@
import { AsyncPipe } from '@angular/common'
import {
ChangeDetectionStrategy,
Component,
inject,
Input,
} from '@angular/core'
import { ReactiveFormsModule } from '@angular/forms'
import { DialogService, i18nPipe } from '@start9labs/shared'
import { IST } from '@start9labs/start-sdk'
import { tuiAsControl, TuiControl } from '@taiga-ui/cdk'
import { TuiError } from '@taiga-ui/core'
import {
TUI_FORMAT_ERROR,
TUI_VALIDATION_ERRORS,
TuiFieldErrorPipe,
} from '@taiga-ui/kit'
import { TUI_VALIDATION_ERRORS, TuiError } from '@taiga-ui/core'
import { TUI_FORMAT_ERROR } from '@taiga-ui/kit'
import { PolymorpheusOutlet } from '@taiga-ui/polymorpheus'
import { ControlSpec } from '../controls/control'
@@ -35,7 +31,7 @@ export const ERRORS = [
selector: 'form-control',
template: `
<ng-container *polymorpheusOutlet="controls[spec.type]" />
<tui-error [error]="order | tuiFieldError | async" />
<tui-error [formControl]="$any(control.control)" [order]="order" />
`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
@@ -53,7 +49,7 @@ export const ERRORS = [
},
],
hostDirectives: [ControlDirective],
imports: [AsyncPipe, PolymorpheusOutlet, TuiError, TuiFieldErrorPipe],
imports: [PolymorpheusOutlet, TuiError, ReactiveFormsModule],
})
export class FormControlComponent<
T extends ControlSpec,
@@ -91,7 +87,7 @@ export class FormControlComponent<
.openConfirm({
label: 'Warning',
data: { content: warning as any, yes: 'Confirm', no: 'Cancel' },
closeable: false,
closable: false,
dismissible: false,
})
.subscribe(confirm => {

View File

@@ -3,13 +3,14 @@ import {
ChangeDetectionStrategy,
Component,
Input,
signal,
SkipSelf,
ViewEncapsulation,
} from '@angular/core'
import { ControlContainer, ReactiveFormsModule } from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TUI_DEFAULT_ERROR_MESSAGE } from '@taiga-ui/core'
import { identity, of } from 'rxjs'
import { identity } from 'rxjs'
import { FilterHiddenPipe } from '../pipes/filter-hidden.pipe'
import { FormArrayComponent } from './array.component'
@@ -92,7 +93,7 @@ import { FormUnionComponent } from './union.component'
viewProviders: [
{
provide: TUI_DEFAULT_ERROR_MESSAGE,
useValue: of('Unknown error'),
useValue: signal('Unknown error'),
},
{
provide: ControlContainer,

View File

@@ -9,8 +9,7 @@ import {
} from '@angular/core'
import { ControlContainer } from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TuiButton, TuiIcon } from '@taiga-ui/core'
import { TuiExpand } from '@taiga-ui/experimental'
import { TuiButton, TuiIcon, TuiExpand } from '@taiga-ui/core'
import { TuiTooltip } from '@taiga-ui/kit'
import { ControlDirective } from './control.directive'
@@ -43,7 +42,7 @@ import { FormGroupComponent } from './group.component'
</tui-expand>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
display: flex;
@@ -57,7 +56,7 @@ import { FormGroupComponent } from './group.component'
display: flex;
align-items: center;
cursor: pointer;
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
font-weight: bold;
margin: 0 0 -0.75rem;
}

View File

@@ -1,3 +1,4 @@
import { TuiElasticContainer } from '@taiga-ui/layout'
import {
ChangeDetectionStrategy,
Component,
@@ -13,7 +14,6 @@ import {
} from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TuiValueChanges } from '@taiga-ui/cdk'
import { TuiElasticContainer } from '@taiga-ui/kit'
import { FormService } from 'src/app/services/form.service'
import { FormControlComponent } from './control.component'
import { FormGroupComponent } from './group.component'

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiIcon, TuiInput } from '@taiga-ui/core'
import { TuiInputColor, TuiTooltip } from '@taiga-ui/kit'
import { Control } from './control'
@@ -35,7 +35,7 @@ import { HintPipe } from '../pipes/hint.pipe'
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiInputColor,
TuiIcon,
TuiTooltip,

View File

@@ -8,7 +8,7 @@ import {
TuiMapperPipe,
TuiTime,
} from '@taiga-ui/cdk'
import { TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiIcon, TuiInput } from '@taiga-ui/core'
import {
TuiInputDate,
TuiInputDateTime,
@@ -22,21 +22,23 @@ import { HintPipe } from '../pipes/hint.pipe'
@Component({
selector: 'form-datetime',
template: `
<!--
TODO: Move @switch down to only affect <input ... /> after fix:
https://github.com/taiga-family/taiga-ui/issues/11780
-->
@switch (spec.inputmode) {
@case ('time') {
<tui-textfield (tuiActiveZoneChange)="!$event && control.onTouched()">
@if (spec.name) {
<label tuiLabel>
{{ spec.name }}
@if (spec.required) {
<span>*</span>
}
</label>
<tui-textfield (tuiActiveZoneChange)="!$event && control.onTouched()">
@if (spec.name) {
<label tuiLabel>
{{ spec.name }}
@if (spec.required) {
<span>*</span>
}
</label>
}
@if (spec | hint; as hint) {
<tui-icon [tuiTooltip]="hint" />
}
@if (spec.inputmode !== 'time') {
<tui-calendar *tuiDropdown />
}
@switch (spec.inputmode) {
@case ('time') {
<input
tuiInputTime
type="time"
@@ -47,21 +49,8 @@ import { HintPipe } from '../pipes/hint.pipe'
(ngModelChange)="value = $event?.toString() || null"
(blur)="control.onTouched()"
/>
@if (spec | hint; as hint) {
<tui-icon [tuiTooltip]="hint" />
}
</tui-textfield>
}
@case ('date') {
<tui-textfield (tuiActiveZoneChange)="!$event && control.onTouched()">
@if (spec.name) {
<label tuiLabel>
{{ spec.name }}
@if (spec.required) {
<span>*</span>
}
</label>
}
}
@case ('date') {
<input
tuiInputDate
type="date"
@@ -73,22 +62,8 @@ import { HintPipe } from '../pipes/hint.pipe'
[(ngModel)]="value"
(blur)="control.onTouched()"
/>
@if (spec | hint; as hint) {
<tui-icon [tuiTooltip]="hint" />
}
<tui-calendar *tuiTextfieldDropdown />
</tui-textfield>
}
@case ('datetime-local') {
<tui-textfield (tuiActiveZoneChange)="!$event && control.onTouched()">
@if (spec.name) {
<label tuiLabel>
{{ spec.name }}
@if (spec.required) {
<span>*</span>
}
</label>
}
}
@case ('datetime-local') {
<input
tuiInputDateTime
type="datetime-local"
@@ -100,17 +75,13 @@ import { HintPipe } from '../pipes/hint.pipe'
[(ngModel)]="value"
(blur)="control.onTouched()"
/>
@if (spec | hint; as hint) {
<tui-icon [tuiTooltip]="hint" />
}
<tui-calendar *tuiTextfieldDropdown />
</tui-textfield>
}
}
}
</tui-textfield>
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiIcon,
TuiTooltip,
TuiInputTime,

View File

@@ -30,7 +30,7 @@ import { Control } from './control'
}
</div>
@if (value) {
<tui-chip>
<span tuiChip>
{{ value.name }}
<button
tuiIconButton
@@ -42,7 +42,7 @@ import { Control } from './control'
>
{{ 'Delete' | i18n }}
</button>
</tui-chip>
</span>
} @else {
<small>{{ 'Click or drop file here' | i18n }}</small>
}
@@ -54,7 +54,7 @@ import { Control } from './control'
</label>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
.template {
@include taiga.transition(opacity);
@@ -63,7 +63,7 @@ import { Control } from './control'
display: flex;
align-items: center;
padding: 0 0.5rem;
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
&_hidden {

View File

@@ -29,12 +29,6 @@ import { Control } from './control'
}
</tui-textfield>
`,
styles: `
// TODO: Remove after Taiga UI update
:host ::ng-deep .t-input {
pointer-events: none;
}
`,
imports: [
FormsModule,
TuiTextfield,

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TuiIcon, TuiNumberFormat, TuiTextfield } from '@taiga-ui/core'
import { TuiIcon, TuiNumberFormat, TuiInput } from '@taiga-ui/core'
import { TuiInputNumber, TuiTooltip } from '@taiga-ui/kit'
import { Control } from './control'
@@ -39,7 +39,7 @@ import { HintPipe } from '../pipes/hint.pipe'
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiInputNumber,
TuiNumberFormat,
TuiIcon,

View File

@@ -1,10 +1,10 @@
import { WA_IS_MOBILE } from '@ng-web-apis/platform'
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'
import { TuiDataList, TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiDataList, TuiIcon, TuiInput } from '@taiga-ui/core'
import {
TuiChevron,
TuiFluidTypography,
@@ -50,12 +50,11 @@ import { HintPipe } from '../pipes/hint.pipe'
/>
}
@if (!mobile) {
<tui-data-list *tuiTextfieldDropdown>
<tui-data-list *tuiDropdown>
@for (item of items; track item) {
@if (inverted[item]?.startsWith('~')) {
<a
tuiOption
new
iconEnd="@tui.arrow-right"
tuiFluidTypography
[routerLink]="inverted[item]?.slice(1)"
@@ -65,7 +64,6 @@ import { HintPipe } from '../pipes/hint.pipe'
} @else {
<button
tuiOption
new
tuiFluidTypography
[style.white-space]="'nowrap'"
[value]="item"
@@ -85,7 +83,7 @@ import { HintPipe } from '../pipes/hint.pipe'
imports: [
FormsModule,
RouterLink,
TuiTextfield,
TuiInput,
TuiSelect,
TuiDataList,
TuiFluidTypography,
@@ -98,7 +96,7 @@ import { HintPipe } from '../pipes/hint.pipe'
export class FormSelectComponent extends Control<IST.ValueSpecSelect, string> {
protected readonly router = inject(Router)
protected readonly inverted = invert(this.spec.values)
protected readonly mobile = inject(TUI_IS_MOBILE)
protected readonly mobile = inject(WA_IS_MOBILE)
protected readonly items = Object.values(this.spec.values)
protected readonly disabledItemHandler = (item: string) =>
Array.isArray(this.spec.disabled) &&

View File

@@ -3,7 +3,7 @@ import { FormsModule } from '@angular/forms'
import { i18nPipe } from '@start9labs/shared'
import { IST, utils } from '@start9labs/start-sdk'
import { tuiInjectElement } from '@taiga-ui/cdk'
import { TuiButton, TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiButton, TuiIcon, TuiInput } from '@taiga-ui/core'
import { TuiTooltip } from '@taiga-ui/kit'
import { Control } from './control'
@@ -22,7 +22,7 @@ import { HintPipe } from '../pipes/hint.pipe'
</label>
}
<input
tuiTextfield
tuiInput
[attr.inputmode]="spec.inputmode"
[attr.minLength]="spec.minLength"
[attr.maxLength]="spec.maxLength"
@@ -86,7 +86,7 @@ import { HintPipe } from '../pipes/hint.pipe'
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiButton,
TuiIcon,
TuiTooltip,

View File

@@ -1,7 +1,7 @@
import { Component } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { IST } from '@start9labs/start-sdk'
import { TuiIcon, TuiTextfield } from '@taiga-ui/core'
import { TuiIcon, TuiInput } from '@taiga-ui/core'
import { TuiTextarea, TuiTooltip } from '@taiga-ui/kit'
import { Control } from './control'
@@ -37,14 +37,7 @@ import { HintPipe } from '../pipes/hint.pipe'
}
</tui-textfield>
`,
imports: [
FormsModule,
TuiTextfield,
TuiTextarea,
TuiIcon,
TuiTooltip,
HintPipe,
],
imports: [FormsModule, TuiInput, TuiTextarea, TuiIcon, TuiTooltip, HintPipe],
})
export class FormTextareaComponent extends Control<
IST.ValueSpecTextarea,

View File

@@ -2,9 +2,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { CopyService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiButton, TuiHint, TuiTitle } from '@taiga-ui/core'
import { TuiButton, TuiHint, TuiTitle, TuiCell } from '@taiga-ui/core'
import { TuiFade } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { ConfigService } from 'src/app/services/config.service'

View File

@@ -22,7 +22,7 @@ import { HeaderStatusComponent } from './status.component'
<header-menu class="item item_corner" />
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
@keyframes connecting {
25%,
@@ -122,7 +122,7 @@ import { HeaderStatusComponent } from './status.component'
display: flex;
height: 100%;
align-items: center;
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
padding: 1rem;
white-space: nowrap;
overflow: hidden;

View File

@@ -5,7 +5,6 @@ import {
DocsLinkDirective,
ErrorService,
i18nPipe,
LoadingService,
SafeLinksDirective,
} from '@start9labs/shared'
import {
@@ -15,6 +14,7 @@ import {
TuiHint,
TuiIcon,
} from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { AuthService } from 'src/app/services/auth.service'
@@ -43,71 +43,60 @@ import { ABOUT } from './about.component'
{{ status().message | i18n }}
</div>
}
<tui-data-list [style.width.rem]="13">
<tui-opt-group>
<button tuiOption iconStart="@tui.info" new (click)="about()">
{{ 'About this server' | i18n }}
</button>
</tui-opt-group>
<tui-opt-group label="" safeLinks>
<a
tuiOption
docsLink
new
iconStart="@tui.book-open-text"
path="/start-os/index.html"
>
{{ 'User manual' | i18n }}
</a>
<a
tuiOption
new
iconStart="@tui.headphones"
href="https://start9.com/contact"
>
{{ 'Contact support' | i18n }}
</a>
<a
tuiOption
new
iconStart="@tui.dollar-sign"
href="https://donate.start9.com"
>
{{ 'Donate to Start9' | i18n }}
</a>
</tui-opt-group>
<tui-opt-group label="">
<a
tuiOption
new
iconStart="@tui.settings"
routerLink="/system"
(click)="open = false"
>
{{ 'System Settings' | i18n }}
</a>
</tui-opt-group>
<tui-opt-group label="">
<button
tuiOption
new
iconStart="@tui.refresh-cw"
(click)="promptPower('restart')"
>
{{ 'Restart' | i18n }}
</button>
<button
tuiOption
new
iconStart="@tui.power"
(click)="promptPower('shutdown')"
>
{{ 'Shutdown' | i18n }}
</button>
<button tuiOption new iconStart="@tui.log-out" (click)="logout()">
{{ 'Logout' | i18n }}
</button>
</tui-opt-group>
<tui-data-list safeLinks [style.width.rem]="13">
<button tuiOption iconStart="@tui.info" (click)="about()">
{{ 'About this server' | i18n }}
</button>
<hr />
<a
tuiOption
docsLink
iconStart="@tui.book-open-text"
path="/start-os/index.html"
>
{{ 'User manual' | i18n }}
</a>
<a
tuiOption
iconStart="@tui.headphones"
href="https://start9.com/contact"
>
{{ 'Contact support' | i18n }}
</a>
<a
tuiOption
iconStart="@tui.dollar-sign"
href="https://donate.start9.com"
>
{{ 'Donate to Start9' | i18n }}
</a>
<hr />
<a
tuiOption
iconStart="@tui.settings"
routerLink="/system"
(click)="open = false"
>
{{ 'System Settings' | i18n }}
</a>
<hr />
<button
tuiOption
iconStart="@tui.refresh-cw"
(click)="promptPower('restart')"
>
{{ 'Restart' | i18n }}
</button>
<button
tuiOption
iconStart="@tui.power"
(click)="promptPower('shutdown')"
>
{{ 'Shutdown' | i18n }}
</button>
<button tuiOption iconStart="@tui.log-out" (click)="logout()">
{{ 'Logout' | i18n }}
</button>
</tui-data-list>
</ng-template>
`,
@@ -151,7 +140,7 @@ import { ABOUT } from './about.component'
export class HeaderMenuComponent {
private readonly api = inject(ApiService)
private readonly auth = inject(AuthService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly dialog = inject(DialogService)

View File

@@ -32,7 +32,7 @@ import { getMenu } from 'src/app/utils/system-utilities'
}
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
position: relative;

View File

@@ -18,7 +18,7 @@ import { STATUS } from 'src/app/services/status.service'
<span>{{ status().message | i18n }}</span>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
@include taiga.transition(all);

View File

@@ -5,21 +5,21 @@ import {
input,
signal,
} from '@angular/core'
import { WA_IS_MOBILE } from '@ng-web-apis/platform'
import {
CopyService,
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import {
TuiButton,
tuiButtonOptionsProvider,
TuiDataList,
TuiDropdown,
TuiTextfield,
TuiInput,
} from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { QRModal } from 'src/app/routes/portal/modals/qr.component'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@@ -114,11 +114,10 @@ import { DomainHealthService } from './domain-health.service'
[(tuiDropdownOpen)]="open"
>
{{ 'Actions' | i18n }}
<tui-data-list *tuiTextfieldDropdown (click)="open.set(false)">
<tui-data-list *tuiDropdown (click)="open.set(false)">
@if (address().ui) {
<a
tuiOption
new
iconStart="@tui.external-link"
target="_blank"
rel="noreferrer"
@@ -130,7 +129,6 @@ import { DomainHealthService } from './domain-health.service'
}
<button
tuiOption
new
[iconStart]="
address().enabled ? '@tui.toggle-right' : '@tui.toggle-left'
"
@@ -138,12 +136,11 @@ import { DomainHealthService } from './domain-health.service'
>
{{ (address().enabled ? 'Disable' : 'Enable') | i18n }}
</button>
<button tuiOption new iconStart="@tui.qr-code" (click)="showQR()">
<button tuiOption iconStart="@tui.qr-code" (click)="showQR()">
{{ 'Show QR' | i18n }}
</button>
<button
tuiOption
new
iconStart="@tui.copy"
(click)="copyService.copy(address().url)"
>
@@ -152,7 +149,6 @@ import { DomainHealthService } from './domain-health.service'
@if (address().hostnameInfo.metadata.kind === 'public-domain') {
<button
tuiOption
new
iconStart="@tui.settings"
(click)="showDnsValidation()"
>
@@ -162,7 +158,6 @@ import { DomainHealthService } from './domain-health.service'
@if (address().hostnameInfo.metadata.kind === 'private-domain') {
<button
tuiOption
new
iconStart="@tui.settings"
(click)="showPrivateDnsValidation()"
>
@@ -175,7 +170,6 @@ import { DomainHealthService } from './domain-health.service'
) {
<button
tuiOption
new
iconStart="@tui.settings"
(click)="showPortForwardValidation()"
>
@@ -183,12 +177,7 @@ import { DomainHealthService } from './domain-health.service'
</button>
}
@if (address().deletable) {
<button
tuiOption
new
iconStart="@tui.trash"
(click)="deleteDomain()"
>
<button tuiOption iconStart="@tui.trash" (click)="deleteDomain()">
{{ 'Delete' | i18n }}
</button>
}
@@ -224,15 +213,15 @@ import { DomainHealthService } from './domain-health.service'
}
}
`,
imports: [TuiButton, TuiDropdown, TuiDataList, i18nPipe, TuiTextfield],
imports: [TuiButton, TuiDropdown, TuiDataList, i18nPipe, TuiInput],
providers: [tuiButtonOptionsProvider({ appearance: 'icon' })],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AddressActionsComponent {
private readonly isMobile = inject(TUI_IS_MOBILE)
private readonly isMobile = inject(WA_IS_MOBILE)
private readonly dialog = inject(DialogService)
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly domainHealth = inject(DomainHealthService)
readonly copyService = inject(CopyService)
@@ -247,8 +236,8 @@ export class AddressActionsComponent {
showQR() {
this.dialog
.openComponent(new PolymorpheusComponent(QRModal), {
size: 'auto',
closeable: this.isMobile,
size: 's',
closable: this.isMobile,
data: this.address().url,
})
.subscribe()

View File

@@ -5,14 +5,10 @@ import {
input,
signal,
} from '@angular/core'
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
import { ErrorService, i18nPipe } from '@start9labs/shared'
import { ISB, utils } from '@start9labs/start-sdk'
import {
TuiButton,
TuiDataList,
TuiDropdown,
TuiTextfield,
} from '@taiga-ui/core'
import { TuiButton, TuiDataList, TuiDropdown, TuiInput } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom } from 'rxjs'
import {
@@ -46,11 +42,11 @@ import { InterfaceAddressItemComponent } from './item.component'
[(tuiDropdownOpen)]="addOpen"
>
{{ 'Add Domain' | i18n }}
<tui-data-list *tuiTextfieldDropdown (click)="addOpen.set(false)">
<button tuiOption new (click)="addPublicDomain()">
<tui-data-list *tuiDropdown (click)="addOpen.set(false)">
<button tuiOption (click)="addPublicDomain()">
{{ 'Public Domain' | i18n }}
</button>
<button tuiOption new (click)="addPrivateDomain()">
<button tuiOption (click)="addPrivateDomain()">
{{ 'Private Domain' | i18n }}
</button>
</tui-data-list>
@@ -97,7 +93,7 @@ import { InterfaceAddressItemComponent } from './item.component'
TuiButton,
TuiDropdown,
TuiDataList,
TuiTextfield,
TuiInput,
TableComponent,
PlaceholderComponent,
i18nPipe,
@@ -108,7 +104,7 @@ import { InterfaceAddressItemComponent } from './item.component'
export class InterfaceAddressesComponent {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly formDialog = inject(FormDialogService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)
private readonly i18n = inject(i18nPipe)

View File

@@ -189,7 +189,7 @@ export type DomainValidationData = {
td,
th {
padding: 0.5rem 0.5rem !important;
font: var(--tui-font-text-s) !important;
font: var(--tui-typography-body-s) !important;
color: var(--tui-text-primary) !important;
font-weight: normal !important;
}

View File

@@ -6,11 +6,15 @@ import {
input,
signal,
} from '@angular/core'
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
import { FormsModule } from '@angular/forms'
import { ErrorService, i18nPipe } from '@start9labs/shared'
import { TuiObfuscatePipe } from '@taiga-ui/cdk'
import { TuiButton, TuiIcon } from '@taiga-ui/core'
import { FormsModule } from '@angular/forms'
import { TuiBadge, TuiSwitch } from '@taiga-ui/kit'
import {
TuiBadge,
TuiNotificationMiddleService,
TuiSwitch,
} from '@taiga-ui/kit'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { GatewayAddress, MappedServiceInterface } from '../interface.service'
import { AddressActionsComponent } from './actions.component'
@@ -45,12 +49,13 @@ import { DomainHealthService } from './domain-health.service'
</span>
</td>
<td class="type">
<tui-badge
<span
tuiBadge
size="s"
[appearance]="typeAppearance(address.hostnameInfo.metadata.kind)"
>
{{ address.type }}
</tui-badge>
</span>
</td>
<td>
<div class="cert">
@@ -177,7 +182,7 @@ import { DomainHealthService } from './domain-health.service'
.access {
padding-right: 0;
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
tui-icon {
@@ -186,7 +191,7 @@ import { DomainHealthService } from './domain-health.service'
}
.type {
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
color: var(--tui-text-primary);
padding-inline-end: 0.5rem;
@@ -226,7 +231,7 @@ import { DomainHealthService } from './domain-health.service'
export class InterfaceAddressItemComponent {
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly domainHealth = inject(DomainHealthService)
readonly address = input.required<GatewayAddress>()

View File

@@ -1,3 +1,4 @@
import { WA_IS_MOBILE } from '@ng-web-apis/platform'
import {
ChangeDetectionStrategy,
Component,
@@ -7,13 +8,7 @@ import {
} from '@angular/core'
import { CopyService, DialogService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
import {
TuiButton,
TuiDataList,
TuiDropdown,
TuiTextfield,
} from '@taiga-ui/core'
import { TuiButton, TuiDataList, TuiDropdown, TuiInput } from '@taiga-ui/core'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
import { TableComponent } from 'src/app/routes/portal/components/table.component'
@@ -109,7 +104,7 @@ import {
>
{{ 'More' | i18n }}
<tui-data-list
*tuiTextfieldDropdown
*tuiDropdown
(click)="overflowOpen.set(null)"
>
@for (
@@ -120,7 +115,6 @@ import {
@if (pluginGroup().pluginActions[actionId]; as meta) {
<button
tuiOption
new
(click)="runRowAction(actionId, meta, address)"
>
{{ meta.name }}
@@ -142,7 +136,7 @@ import {
[(tuiDropdownOpen)]="open"
>
{{ 'Actions' | i18n }}
<tui-data-list *tuiTextfieldDropdown (click)="open.set(false)">
<tui-data-list *tuiDropdown (click)="open.set(false)">
@if (address.hostnameInfo.metadata.kind === 'plugin') {
@if (address.hostnameInfo.metadata.removeAction) {
@if (
@@ -153,7 +147,6 @@ import {
) {
<button
tuiOption
new
iconStart="@tui.trash"
(click)="
runRowAction(
@@ -170,7 +163,6 @@ import {
}
<button
tuiOption
new
iconStart="@tui.qr-code"
(click)="showQR(address.url)"
>
@@ -178,7 +170,6 @@ import {
</button>
<button
tuiOption
new
iconStart="@tui.copy"
(click)="copyService.copy(address.url)"
>
@@ -192,7 +183,6 @@ import {
@if (pluginGroup().pluginActions[actionId]; as meta) {
<button
tuiOption
new
(click)="runRowAction(actionId, meta, address)"
>
{{ meta.name }}
@@ -271,7 +261,7 @@ import {
TuiButton,
TuiDropdown,
TuiDataList,
TuiTextfield,
TuiInput,
TableComponent,
PlaceholderComponent,
i18nPipe,
@@ -279,7 +269,7 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PluginAddressesComponent {
private readonly isMobile = inject(TUI_IS_MOBILE)
private readonly isMobile = inject(WA_IS_MOBILE)
private readonly dialog = inject(DialogService)
private readonly actionService = inject(ActionService)
readonly copyService = inject(CopyService)
@@ -290,12 +280,12 @@ export class PluginAddressesComponent {
readonly packageId = input('')
readonly value = input<MappedServiceInterface | undefined>()
showQR(url: string) {
showQR(data: string) {
this.dialog
.openComponent(new PolymorpheusComponent(QRModal), {
size: 'auto',
closeable: this.isMobile,
data: url,
size: 's',
closable: this.isMobile,
data,
})
.subscribe()
}

View File

@@ -116,7 +116,7 @@ export type PortForwardValidationData = {
td,
th {
padding: 0.5rem 0.5rem !important;
font: var(--tui-font-text-s) !important;
font: var(--tui-typography-body-s) !important;
color: var(--tui-text-primary) !important;
font-weight: normal !important;
}

View File

@@ -119,7 +119,7 @@ export type PrivateDnsValidationData = {
td,
th {
padding: 0.5rem 0.5rem !important;
font: var(--tui-font-text-s) !important;
font: var(--tui-typography-body-s) !important;
color: var(--tui-text-primary) !important;
font-weight: normal !important;
}

View File

@@ -29,7 +29,7 @@ import { PluginAddressesComponent } from './addresses/plugin.component'
flex-direction: column;
gap: 1rem;
color: var(--tui-text-secondary);
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
::ng-deep [tuiSkeleton] {
width: 100%;

View File

@@ -3,9 +3,9 @@ import {
convertAnsi,
DownloadHTMLService,
ErrorService,
LoadingService,
} from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { LogsComponent } from './logs.component'
@Directive({
@@ -13,7 +13,7 @@ import { LogsComponent } from './logs.component'
})
export class LogsDownloadDirective {
private readonly component = inject(LogsComponent)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly downloadHtml = inject(DownloadHTMLService)

View File

@@ -1,5 +1,5 @@
import { Directive, inject, Output } from '@angular/core'
import { IntersectionObserveeService } from '@ng-web-apis/intersection-observer'
import { WaIntersectionObserveeService } from '@ng-web-apis/intersection-observer'
import { convertAnsi, ErrorService } from '@start9labs/shared'
import { catchError, defer, filter, from, map, of, switchMap, tap } from 'rxjs'
import { LogsComponent } from './logs.component'
@@ -8,7 +8,7 @@ import { LogsComponent } from './logs.component'
selector: '[logsFetch]',
})
export class LogsFetchDirective {
private readonly observer = inject(IntersectionObserveeService)
private readonly observer = inject(WaIntersectionObserveeService)
private readonly component = inject(LogsComponent)
private readonly errors = inject(ErrorService)

View File

@@ -19,7 +19,7 @@ import { TuiIcon } from '@taiga-ui/core'
justify-content: center;
text-align: center;
padding: 1rem;
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
color: var(--tui-text-tertiary);
tui-icon {

View File

@@ -75,7 +75,7 @@ const FILTER = ['services', 'system', 'marketplace']
</nav>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
display: none;

View File

@@ -14,14 +14,14 @@ import { tuiIsNumber } from '@taiga-ui/cdk'
selector: 'task-info',
template: `
@if (diff.length) {
<tui-notification>
<div tuiNotification>
{{ 'The following modifications were made' | i18n }}:
<ul>
@for (d of diff; track d) {
<li [innerHTML]="d"></li>
}
</ul>
</tui-notification>
</div>
}
`,
imports: [TuiNotification, i18nPipe],

View File

@@ -6,9 +6,19 @@ import {
} from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { RouterOutlet } from '@angular/router'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { TuiButton, TuiIcon, TuiLoader, TuiScrollbar } from '@taiga-ui/core'
import { TuiActionBar, TuiProgress } from '@taiga-ui/kit'
import { ErrorService } from '@start9labs/shared'
import {
TuiButton,
TuiIcon,
TuiLoader,
TuiPopup,
TuiScrollbar,
} from '@taiga-ui/core'
import {
TuiActionBar,
TuiNotificationMiddleService,
TuiProgress,
} from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { TabsComponent } from 'src/app/routes/portal/components/tabs.component'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@@ -26,7 +36,7 @@ import { HeaderComponent } from './components/header/header.component'
</main>
<app-tabs />
@if (update(); as update) {
<tui-action-bar *tuiActionBar="bar()">
<tui-action-bar *tuiPopup="bar()">
@if (update === true) {
<tui-icon icon="@tui.check" class="g-positive" />
Download complete, restart to apply changes
@@ -52,7 +62,7 @@ import { HeaderComponent } from './components/header/header.component'
}
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
height: 100%;
@@ -93,10 +103,11 @@ import { HeaderComponent } from './components/header/header.component'
TuiLoader,
TuiIcon,
TuiButton,
TuiPopup,
],
})
export class PortalComponent {
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly api = inject(ApiService)

View File

@@ -1,6 +1,5 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { TuiDialogService, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { TuiDialogService, TuiIcon, TuiTitle, TuiCell } from '@taiga-ui/core'
import { BackupsUpcomingComponent } from './components/upcoming.component'
import { HISTORY } from './modals/history.component'
import { JOBS } from './modals/jobs.component'

View File

@@ -2,16 +2,14 @@ import { Component, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import {
TuiButton,
TuiCheckbox,
TuiDialogContext,
TuiDialogOptions,
TuiGroup,
TuiLoader,
} from '@taiga-ui/core'
import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit'
import {
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
} from '@taiga-ui/polymorpheus'
import { TuiBlock } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, map } from 'rxjs'
import { DataModel } from 'src/app/services/patch-db/data-model'
@@ -74,9 +72,7 @@ interface Package {
export class BackupsBackupModal {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
readonly context =
inject<TuiDialogContext<string[], { btnText: string } | undefined>>(
POLYMORPHEUS_CONTEXT,
)
injectContext<TuiDialogContext<string[], { btnText: string } | undefined>>()
hasSelection = false

View File

@@ -1,17 +1,21 @@
import { Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { FormsModule } from '@angular/forms'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { ErrorService } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
TuiButton,
TuiDialogContext,
TuiDialogService,
TuiTextfield,
TuiInput,
} from '@taiga-ui/core'
import { TuiBadge, TuiSwitch } from '@taiga-ui/kit'
import {
TuiBadge,
TuiNotificationMiddleService,
TuiSwitch,
} from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { from, map } from 'rxjs'
import { T } from '@start9labs/start-sdk'
import { BackupJob } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ToHumanCronPipe } from '../pipes/to-human-cron.pipe'
@@ -25,7 +29,7 @@ import { TARGET, TARGET_CREATE } from './target.component'
<tui-textfield>
<label tuiLabel>Job Name</label>
<input
tuiTextfield
tuiInput
name="name"
[(ngModel)]="job.name"
placeholder="My Backup Job"
@@ -40,11 +44,12 @@ import { TARGET, TARGET_CREATE } from './target.component'
(click)="selectTarget()"
>
Target
<tui-badge
<span
tuiBadge
[appearance]="target()?.[job.targetId]?.type ? 'success' : 'warning'"
>
{{ target()?.[job.targetId]?.type || 'Select target' }}
</tui-badge>
</span>
</button>
<button
tuiButton
@@ -55,14 +60,17 @@ import { TARGET, TARGET_CREATE } from './target.component'
(click)="selectPackages()"
>
Packages
<tui-badge [appearance]="job.packageIds.length ? 'success' : 'warning'">
<span
tuiBadge
[appearance]="job.packageIds.length ? 'success' : 'warning'"
>
{{ job.packageIds.length + ' selected' }}
</tui-badge>
</span>
</button>
<tui-textfield>
<label tuiLabel>Schedule</label>
<input
tuiTextfield
tuiInput
name="cron"
[(ngModel)]="job.cron"
placeholder="* * * * *"
@@ -109,7 +117,7 @@ import { TARGET, TARGET_CREATE } from './target.component'
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiSwitch,
TuiButton,
TuiBadge,
@@ -119,7 +127,7 @@ import { TARGET, TARGET_CREATE } from './target.component'
export class BackupsEditModal {
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly dialogs = inject(TuiDialogService)
private readonly context =
injectContext<TuiDialogContext<BackupJob, BackupJobBuilder>>()

View File

@@ -1,5 +1,3 @@
import { toSignal } from '@angular/core/rxjs-interop'
import { TuiCheckbox, TuiSkeleton } from '@taiga-ui/kit'
import { CommonModule } from '@angular/common'
import {
ChangeDetectionStrategy,
@@ -7,10 +5,18 @@ import {
inject,
signal,
} from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { FormsModule } from '@angular/forms'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { TUI_TRUE_HANDLER, TUI_FALSE_HANDLER } from '@taiga-ui/cdk'
import { TuiDialogService, TuiIcon, TuiLink, TuiButton } from '@taiga-ui/core'
import { ErrorService } from '@start9labs/shared'
import { TUI_FALSE_HANDLER, TUI_TRUE_HANDLER } from '@taiga-ui/cdk'
import {
TuiButton,
TuiCheckbox,
TuiDialogService,
TuiIcon,
TuiLink,
} from '@taiga-ui/core'
import { TuiNotificationMiddleService, TuiSkeleton } from '@taiga-ui/kit'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { from } from 'rxjs'
import { REPORT } from 'src/app/components/backup-report.component'
@@ -101,7 +107,7 @@ import { HasErrorPipe } from '../pipes/has-error.pipe'
</table>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
tui-icon {
font-size: 1rem;
@@ -170,7 +176,7 @@ export class BackupsHistoryModal {
private readonly api = inject(ApiService)
private readonly dialogs = inject(TuiDialogService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
readonly targets = toSignal(from(this.api.getBackupTargets({})))
readonly runs = signal<BackupRun[] | null>(null)

View File

@@ -1,16 +1,22 @@
import { Component, inject, OnInit } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { ErrorService } from '@start9labs/shared'
import {
TuiButton,
TuiDialogOptions,
TuiDialogService,
TuiIcon,
TuiButton,
TuiNotification,
TuiLink,
TuiNotification,
} from '@taiga-ui/core'
import { TuiConfirmData, TUI_CONFIRM, TuiSkeleton } from '@taiga-ui/kit'
import {
TUI_CONFIRM,
TuiConfirmData,
TuiNotificationMiddleService,
TuiSkeleton,
} from '@taiga-ui/kit'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { DocsLinkDirective } from 'projects/shared/src/public-api'
import { BehaviorSubject, filter, from } from 'rxjs'
import { BackupJob } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@@ -18,18 +24,17 @@ import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe'
import { ToHumanCronPipe } from '../pipes/to-human-cron.pipe'
import { BackupJobBuilder } from '../utils/job-builder'
import { EDIT } from './edit.component'
import { DocsLinkDirective } from 'projects/shared/src/public-api'
@Component({
template: `
<tui-notification>
<div tuiNotification>
Scheduling automatic backups is an excellent way to ensure your StartOS
data is safely backed up. StartOS will issue a notification whenever one
of your scheduled backups succeeds or fails.
<a tuiLink docsLink path="/start-os/backup-create.html">
View instructions
</a>
</tui-notification>
</div>
<h3 class="g-title">
Saved Jobs
<button tuiButton size="s" iconStart="@tui.plus" (click)="create()">
@@ -147,7 +152,7 @@ import { DocsLinkDirective } from 'projects/shared/src/public-api'
})
export class BackupsJobsModal implements OnInit {
private readonly dialogs = inject(TuiDialogService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)

View File

@@ -1,14 +1,19 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { ErrorService } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiMapperPipe } from '@taiga-ui/cdk'
import { TuiButton, TuiDialogContext, TuiGroup } from '@taiga-ui/core'
import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit'
import {
TuiButton,
TuiCheckbox,
TuiDialogContext,
TuiGroup,
} from '@taiga-ui/core'
import { TuiBlock, TuiNotificationMiddleService } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { take } from 'rxjs'
import { T } from '@start9labs/start-sdk'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { ToOptionsPipe } from '../pipes/to-options.pipe'
@@ -68,7 +73,7 @@ import { RecoverOption } from '../types/recover-option'
})
export class BackupsRecoverModal {
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly context =
injectContext<TuiDialogContext<void, RecoverData>>()

View File

@@ -15,8 +15,8 @@ import {
TuiIcon,
TuiLoader,
TuiTitle,
TuiCell,
} from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { ApiService } from 'src/app/services/api/embassy-api.service'

View File

@@ -1,14 +1,12 @@
import { Component, inject, OnInit, signal } from '@angular/core'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { TuiButton, TuiLink, TuiNotification } from '@taiga-ui/core'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { ErrorService } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
BackupTargetType,
RR,
UnknownDisk,
} from 'src/app/services/api/api.types'
import { TuiButton, TuiLink, TuiNotification } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { DocsLinkDirective } from 'projects/shared/src/public-api'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { RR, UnknownDisk } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
@@ -22,11 +20,10 @@ import {
googleDriveSpec,
remoteBackupTargetSpec,
} from '../types/target'
import { DocsLinkDirective } from 'projects/shared/src/public-api'
@Component({
template: `
<tui-notification>
<div tuiNotification>
Backup targets are physical or virtual locations for storing encrypted
backups. They can be physical drives plugged into your server, shared
folders on your Local Area Network (LAN), or third party clouds such as
@@ -34,7 +31,7 @@ import { DocsLinkDirective } from 'projects/shared/src/public-api'
<a tuiLink docsLink path="/start-os/backup-create.html">
View instructions
</a>
</tui-notification>
</div>
<h3 class="g-title">
Unknown Physical Drives
<button
@@ -77,7 +74,7 @@ export class BackupsTargetsModal implements OnInit {
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly formDialog = inject(FormDialogService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
targets = signal<RR.GetBackupTargetsRes | null>(null)

View File

@@ -1,17 +1,17 @@
import { inject, Injectable } from '@angular/core'
import { LoadingService } from '@start9labs/shared'
import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
import { from, switchMap } from 'rxjs'
import { T } from '@start9labs/start-sdk'
import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { from, switchMap } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { TARGET, TARGET_CREATE } from '../modals/target.component'
import { BACKUP, BACKUP_OPTIONS } from '../modals/backup.component'
import { TARGET, TARGET_CREATE } from '../modals/target.component'
@Injectable({
providedIn: 'root',
})
export class BackupsCreateService {
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly dialogs = inject(TuiDialogService)
private readonly api = inject(ApiService)

View File

@@ -1,12 +1,10 @@
import { inject, Injectable } from '@angular/core'
import { Router } from '@angular/router'
import { verify } from '@start9labs/argon2'
import {
ErrorService,
LoadingService,
StartOSDiskInfo,
} from '@start9labs/shared'
import { ErrorService, StartOSDiskInfo } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import {
catchError,
EMPTY,
@@ -22,7 +20,6 @@ import {
PROMPT,
PromptOptions,
} from 'src/app/routes/portal/modals/prompt.component'
import { T } from '@start9labs/start-sdk'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { RECOVER } from '../modals/recover.component'
import { SERVERS } from '../modals/servers.component'
@@ -37,7 +34,7 @@ export class BackupsRestoreService {
private readonly dialogs = inject(TuiDialogService)
private readonly router = inject(Router)
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
readonly handle = () => {
this.dialogs

View File

@@ -1,15 +1,14 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { RouterLink } from '@angular/router'
import { i18nPipe } from '@start9labs/shared'
import { TuiAppearance, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCardMedium } from '@taiga-ui/layout'
import { TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TitleDirective } from 'src/app/services/title.service'
@Component({
template: `
<ng-container *title>{{ 'Logs' | i18n }}</ng-container>
@for (log of logs; track $index) {
<a tuiCardMedium tuiAppearance="neutral" [routerLink]="log.link">
<a [routerLink]="log.link">
<tui-icon [icon]="log.icon" />
<span tuiTitle>
{{ log.title | i18n }}
@@ -32,7 +31,13 @@ import { TitleDirective } from 'src/app/services/title.service'
padding: 1rem;
}
[tuiCardMedium] {
a {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 0.75rem;
border-radius: var(--tui-radius-l);
background: var(--tui-background-neutral-1);
height: 14rem;
width: 14rem;
cursor: pointer;
@@ -61,15 +66,7 @@ import { TitleDirective } from 'src/app/services/title.service'
}
`,
],
imports: [
RouterLink,
TitleDirective,
TuiTitle,
TuiCardMedium,
TuiIcon,
TuiAppearance,
i18nPipe,
],
imports: [RouterLink, TitleDirective, TuiTitle, TuiIcon, i18nPipe],
})
export default class SystemLogsComponent {
readonly logs = [

View File

@@ -15,10 +15,10 @@ import {
ExverComparesPipe,
i18nPipe,
i18nService,
LoadingService,
sameUrl,
} from '@start9labs/shared'
import { TuiButton } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, switchMap } from 'rxjs'
import { ToManifestPipe } from 'src/app/routes/portal/pipes/to-manifest'
@@ -118,7 +118,7 @@ export class MarketplaceControlsComponent {
private readonly alerts = inject(MarketplaceAlertsService)
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly exver = inject(Exver)
private readonly router = inject(Router)
private readonly marketplace = inject(MarketplaceService)

View File

@@ -5,7 +5,8 @@ import { TuiNotification } from '@taiga-ui/core'
@Component({
selector: 'marketplace-notification',
template: `
<tui-notification
<div
tuiNotification
[appearance]="status || 'warning'"
icon=""
class="notification-wrapper"
@@ -42,7 +43,7 @@ import { TuiNotification } from '@taiga-ui/core'
}}
}
}
</tui-notification>
</div>
`,
styles: `
.notification-wrapper {

View File

@@ -9,11 +9,10 @@ import { toSignal } from '@angular/core/rxjs-interop'
import { ActivatedRoute, Router } from '@angular/router'
import { ItemComponent, MarketplacePkg } from '@start9labs/marketplace'
import { TuiAutoFocus } from '@taiga-ui/cdk'
import { TuiButton, TuiDropdownService, TuiPopup } from '@taiga-ui/core'
import { TuiButton, TuiPopup } from '@taiga-ui/core'
import { TuiDrawer } from '@taiga-ui/kit'
import { debounceTime } from 'rxjs'
import { MarketplacePreviewComponent } from '../modals/preview.component'
import { MarketplaceSidebarService } from '../services/sidebar.service'
@Component({
selector: 'marketplace-tile',
@@ -70,12 +69,6 @@ import { MarketplaceSidebarService } from '../services/sidebar.service'
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: TuiDropdownService,
useExisting: MarketplaceSidebarService,
},
],
imports: [
ItemComponent,
TuiAutoFocus,

View File

@@ -7,13 +7,18 @@ import {
ErrorService,
i18nKey,
i18nPipe,
LoadingService,
sameUrl,
toUrl,
} from '@start9labs/shared'
import { IST, utils } from '@start9labs/start-sdk'
import { TuiButton, TuiDialogContext, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import {
TuiButton,
TuiCell,
TuiDialogContext,
TuiIcon,
TuiTitle,
} from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { combineLatest, filter, firstValueFrom, map, Subscription } from 'rxjs'
@@ -82,7 +87,7 @@ import { StorageService } from 'src/app/services/storage.service'
})
export class MarketplaceRegistryModal {
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly formDialog = inject(FormDialogService)
private readonly dialog = inject(DialogService)

View File

@@ -1,5 +0,0 @@
import { TuiPortalService } from '@taiga-ui/cdk'
import { Injectable } from '@angular/core'
@Injectable({ providedIn: `root` })
export class MarketplaceSidebarService extends TuiPortalService {}

View File

@@ -27,7 +27,7 @@ const LABELS: Record<string, i18nKey> = {
<metrics-data [labels]="labels" [value]="value()" />
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
.cpu {
position: relative;
@@ -53,7 +53,7 @@ const LABELS: Record<string, i18nKey> = {
bottom: 10%;
width: 100%;
text-align: center;
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
}
.arrow {

View File

@@ -4,8 +4,7 @@ import {
computed,
input,
} from '@angular/core'
import { TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { TuiTitle, TuiCell } from '@taiga-ui/core'
import { T } from '@start9labs/start-sdk'
import { ValuePipe } from './value.pipe'
import { i18nKey, i18nPipe } from '@start9labs/shared'
@@ -35,7 +34,7 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'
&:after {
content: attr(data-unit);
font: var(--tui-font-text-ui-xs);
font: var(--tui-typography-ui-2xs);
color: var(--tui-text-secondary);
}
}

View File

@@ -51,7 +51,7 @@ import { ChangeDetectionStrategy, Component, input } from '@angular/core'
<b>{{ value() ? value() + ' C°' : 'N/A' }}</b>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
height: 100%;

View File

@@ -8,8 +8,8 @@ import {
TuiLink,
TuiNotification,
TuiTitle,
TuiCell,
} from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { TimeService } from 'src/app/services/time.service'
@Component({
@@ -32,9 +32,9 @@ import { TimeService } from 'src/app/services/time.service'
}
</div>
@if (!time.synced) {
<tui-notification size="s" appearance="warning">
<div tuiNotification size="s" appearance="warning">
<ng-container *ngTemplateOutlet="hint" />
</tui-notification>
</div>
}
} @else {
{{ 'Loading' | i18n }}...
@@ -51,7 +51,6 @@ import { TimeService } from 'src/app/services/time.service'
appearance=""
path="/start-os/faq.html"
fragment="#clock-sync-failure"
[pseudo]="true"
[textContent]="'the docs' | i18n"
></a>
</div>

View File

@@ -41,11 +41,11 @@ import { TimeService } from 'src/app/services/time.service'
b {
display: block;
font: var(--tui-font-heading-5);
font: var(--tui-typography-heading-h5);
}
:host-context(tui-root._mobile) {
font: var(--tui-font-text-ui-xs);
font: var(--tui-typography-ui-2xs);
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -123,7 +123,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
td:first-child {
padding: 0;
font: var(--tui-font-text-s);
font: var(--tui-typography-body-s);
color: var(--tui-text-secondary);
margin-block-end: -0.25rem;
}

View File

@@ -8,16 +8,12 @@ import {
} from '@angular/core'
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'
import { ActivatedRoute, Router } from '@angular/router'
import {
ErrorService,
i18nPipe,
isEmptyObject,
LoadingService,
} from '@start9labs/shared'
import { ErrorService, i18nPipe, isEmptyObject } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiButton } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { distinctUntilChanged, skip } from 'rxjs/operators'
import { T } from '@start9labs/start-sdk'
import { ServerNotification } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { BadgeService } from 'src/app/services/badge.service'
@@ -58,7 +54,7 @@ import { NotificationsTableComponent } from './table.component'
export default class NotificationsComponent implements OnInit {
private readonly router = inject(Router)
private readonly route = inject(ActivatedRoute)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
readonly service = inject(NotificationService)
readonly api = inject(ApiService)

View File

@@ -1,4 +1,5 @@
import { TuiCheckbox, TuiSkeleton } from '@taiga-ui/kit'
import { TuiCheckbox } from '@taiga-ui/core'
import { TuiSkeleton } from '@taiga-ui/kit'
import {
ChangeDetectionStrategy,
Component,
@@ -97,9 +98,9 @@ import { PlaceholderComponent } from '../../components/placeholder.component'
PlaceholderComponent,
],
})
export class NotificationsTableComponent<T extends ServerNotification<number>>
implements OnChanges
{
export class NotificationsTableComponent<
T extends ServerNotification<number>,
> implements OnChanges {
readonly notifications = input<readonly T[] | null>(null)
readonly selected = signal<readonly T[]>([])

View File

@@ -47,7 +47,7 @@ import { InterfaceService } from '../../../components/interfaces/interface.servi
appearance="primary-grayscale"
iconStart="@tui.external-link"
tuiChevron
tuiDropdownOpen
tuiDropdownAuto
tuiDropdownLimitWidth="fixed"
[tuiDropdown]="content"
>
@@ -58,7 +58,6 @@ import { InterfaceService } from '../../../components/interfaces/interface.servi
@for (i of interfaces(); track $index) {
<a
tuiOption
new
target="_blank"
rel="noreferrer"
iconEnd="@tui.external-link"

View File

@@ -2,9 +2,8 @@ import { KeyValuePipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, input } from '@angular/core'
import { RouterLink } from '@angular/router'
import { i18nKey, i18nPipe } from '@start9labs/shared'
import { TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiIcon, TuiTitle, TuiCell } from '@taiga-ui/core'
import { TuiAvatar } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
import { PkgDependencyErrors } from 'src/app/services/dep-error.service'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@@ -24,7 +23,7 @@ import { ToManifestPipe } from '../../../pipes/to-manifest'
[queryParams]="services[d.key] ? {} : { search: d.key }"
[class.error]="getError(d.key)"
>
<tui-avatar appearance="action-grayscale">
<span tuiAvatar appearance="action-grayscale">
<img
alt=""
[src]="
@@ -33,7 +32,7 @@ import { ToManifestPipe } from '../../../pipes/to-manifest'
'assets/img/service-icons/fallback.png'
"
/>
</tui-avatar>
</span>
<span tuiTitle>
{{
services[d.key]

View File

@@ -74,7 +74,7 @@ import { getManifest } from 'src/app/utils/get-package-data'
h4 {
display: flex;
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
color: var(--tui-text-secondary);
text-transform: uppercase;

View File

@@ -9,7 +9,7 @@ import { i18nPipe } from '@start9labs/shared'
selector: 'service-health-checks',
template: `
<header>{{ 'Health Checks' | i18n }}</header>
<table tuiTable class="g-table">
<table tuiTable class="g-table-service">
<thead>
<tr>
<th tuiTh>{{ 'Name' | i18n }}</th>
@@ -19,14 +19,17 @@ import { i18nPipe } from '@start9labs/shared'
<tbody>
@for (check of checks(); track $index) {
<tr [healthCheck]="check"></tr>
} @empty {
<tr>
<td colspan="2">
<app-placeholder icon="@tui.heart-pulse">
{{ 'No health checks' | i18n }}
</app-placeholder>
</td>
</tr>
}
</tbody>
</table>
@if (!checks().length) {
<app-placeholder icon="@tui.heart-pulse">
{{ 'No health checks' | i18n }}
</app-placeholder>
}
`,
styles: `
:host {

View File

@@ -8,9 +8,9 @@ import { TuiBadge } from '@taiga-ui/kit'
template: `
<td><ng-content /></td>
<td>
<tui-badge size="m" [appearance]="appearance">
<span tuiBadge size="m" [appearance]="appearance">
{{ info().type }}
</tui-badge>
</span>
</td>
<td class="g-secondary" [style.grid-area]="'2 / 1 / 2 / 3'">
{{ info().description }}

View File

@@ -16,7 +16,7 @@ import { PlaceholderComponent } from '../../../components/placeholder.component'
selector: 'service-interfaces',
template: `
<header>{{ 'Service Interfaces' | i18n }}</header>
<table tuiTable class="g-table">
<table tuiTable class="g-table-service">
<thead>
<tr>
<th tuiTh>{{ 'Name' | i18n }}</th>
@@ -39,9 +39,13 @@ import { PlaceholderComponent } from '../../../components/placeholder.component'
</a>
</tr>
} @empty {
<app-placeholder icon="@tui.monitor-x">
{{ 'No service interfaces' | i18n }}
</app-placeholder>
<tr>
<td colspan="4">
<app-placeholder icon="@tui.monitor-x">
{{ 'No service interfaces' | i18n }}
</app-placeholder>
</td>
</tr>
}
</tbody>
</table>

View File

@@ -4,10 +4,10 @@ import {
inject,
Input,
} from '@angular/core'
import { ErrorService, i18nPipe, LoadingService } from '@start9labs/shared'
import { ErrorService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiButton } from '@taiga-ui/core'
import { TuiProgress } from '@taiga-ui/kit'
import { TuiNotificationMiddleService, TuiProgress } from '@taiga-ui/kit'
import { InstallingProgressPipe } from 'src/app/routes/portal/routes/services/pipes/install-progress.pipe'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@@ -84,7 +84,7 @@ export class ServiceInstallProgressComponent {
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
isIndeterminate(progress: T.Progress): boolean {
return (
@@ -94,7 +94,7 @@ export class ServiceInstallProgressComponent {
}
async cancel() {
const loader = this.loader.open().subscribe()
const loader = this.loader.open('').subscribe()
try {
await this.api.cancelInstallPackage({ id: getManifest(this.pkg).id })

View File

@@ -41,7 +41,7 @@ import {
}
h3 {
font: var(--tui-font-heading-4);
font: var(--tui-typography-heading-h4);
font-weight: normal;
margin: 0;
text-align: center;
@@ -58,7 +58,7 @@ import {
small {
display: block;
font: var(--tui-font-text-l);
font: var(--tui-typography-body-l);
color: var(--tui-text-secondary);
text-align: center;
}

View File

@@ -5,15 +5,10 @@ import {
inject,
input,
} from '@angular/core'
import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { DialogService, ErrorService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { TuiButton } from '@taiga-ui/core'
import { TuiAvatar, TuiFade } from '@taiga-ui/kit'
import { TuiAvatar, TuiFade, TuiNotificationMiddleService } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { ServiceTasksComponent } from 'src/app/routes/portal/routes/services/components/tasks.component'
import { ActionService } from 'src/app/services/action.service'
@@ -30,9 +25,9 @@ import { getManifest } from 'src/app/utils/get-package-data'
selector: 'tr[task]',
template: `
<td tuiFade class="row">
<tui-avatar appearance="action-grayscale" size="xs">
<i tuiAvatar appearance="action-grayscale" size="xs">
<img [src]="pkg()?.icon || fallback()?.icon" alt="" />
</tui-avatar>
</i>
<span>{{ title() || fallback()?.title }}</span>
</td>
<td [style.grid-row]="2">
@@ -131,7 +126,7 @@ export class ServiceTaskComponent {
private readonly dialog = inject(DialogService)
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly tasks = inject(ServiceTasksComponent)
private readonly i18n = inject(i18nPipe)
@@ -174,7 +169,7 @@ export class ServiceTaskComponent {
.openConfirm(DISMISS)
.pipe(filter(Boolean))
.subscribe(async () => {
const loader = this.loader.open().subscribe()
const loader = this.loader.open('').subscribe()
try {
await this.api.clearTask({ packageId, replayId, force: false })
} catch (e: any) {

View File

@@ -14,7 +14,7 @@ import { i18nPipe } from '@start9labs/shared'
selector: 'service-tasks',
template: `
<header>{{ 'Tasks' | i18n }}</header>
<table tuiTable class="g-table">
<table tuiTable class="g-table-service">
<thead>
<tr>
<th tuiTh>{{ 'Service' | i18n }}</th>
@@ -27,14 +27,17 @@ import { i18nPipe } from '@start9labs/shared'
<tbody>
@for (item of tasks(); track $index) {
<tr [task]="item.task" [services]="services()"></tr>
} @empty {
<tr>
<td colspan="5">
<app-placeholder icon="@tui.list-checks">
{{ 'All tasks complete' | i18n }}
</app-placeholder>
</td>
</tr>
}
</tbody>
</table>
@if (!tasks().length) {
<app-placeholder icon="@tui.list-checks">
{{ 'All tasks complete' | i18n }}
</app-placeholder>
}
`,
styles: `
:host {

View File

@@ -36,7 +36,7 @@ import { distinctUntilChanged } from 'rxjs/operators'
}
h3 {
font: var(--tui-font-heading-4);
font: var(--tui-typography-heading-h4);
font-weight: normal;
margin: 0;
text-align: center;
@@ -54,7 +54,7 @@ import { distinctUntilChanged } from 'rxjs/operators'
text-align: center;
text-transform: uppercase;
color: var(--tui-text-secondary);
font: var(--tui-font-text-ui-xs);
font: var(--tui-typography-ui-2xs);
font-size: min(4cqw, 0.75rem);
}

View File

@@ -35,7 +35,7 @@ import { StatusComponent } from './status.component'
</td>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
:host {
@include taiga.transition(background);
@@ -116,12 +116,12 @@ import { StatusComponent } from './status.component'
.title {
grid-area: 2 / 2;
font: var(--tui-font-heading-6);
font: var(--tui-typography-heading-h6);
}
.version {
grid-area: 1 / 2;
font: var(--tui-font-text-s);
font: var(--tui-typography-body-s);
}
.uptime {

View File

@@ -10,9 +10,9 @@ import { PackageActionData } from './action-input.component'
<img [src]="pkgInfo.icon" alt="" />
<h4>{{ pkgInfo.title }}</h4>
</div>
<tui-notification appearance="warning">
<div tuiNotification appearance="warning">
<div [innerHTML]="warning"></div>
</tui-notification>
</div>
<footer class="g-buttons">
<button tuiButton appearance="flat" (click)="context.completeWith(false)">
{{ 'Cancel' | i18n }}

View File

@@ -50,15 +50,15 @@ export type PackageActionData = {
<h4>{{ pkgInfo.title }}</h4>
</div>
@if (error()) {
<tui-notification appearance="negative">
<div tuiNotification appearance="negative">
<div [innerHTML]="error()"></div>
</tui-notification>
</div>
}
@if (res(); as res) {
@if (warning) {
<tui-notification appearance="warning">
<div tuiNotification appearance="warning">
<div [innerHTML]="warning"></div>
</tui-notification>
</div>
}
<app-form

View File

@@ -12,12 +12,14 @@ import { GroupResult } from './types'
<app-action-success-member [member]="member" />
}
@if (member.type === 'group') {
<tui-accordion-item>
<div tuiFade>{{ member.name }}</div>
<ng-template tuiAccordionItemContent>
<tui-accordion>
<button tuiAccordion>
<span tuiFade>{{ member.name }}</span>
</button>
<tui-expand>
<app-action-success-group [group]="member" />
</ng-template>
</tui-accordion-item>
</tui-expand>
</tui-accordion>
}
</p>
}

View File

@@ -12,9 +12,9 @@ import { DialogService, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
TuiButton,
TuiTextfield,
TuiTextfieldDirective,
TuiInputDirective,
TuiTitle,
TuiInput,
} from '@taiga-ui/core'
import { QrCodeComponent } from 'ng-qrcode'
@@ -24,7 +24,7 @@ import { QrCodeComponent } from 'ng-qrcode'
<tui-textfield>
<label tuiLabel>{{ member.name }}</label>
<input
tuiTextfield
tuiInput
[readOnly]="true"
[ngModel]="member.value"
[type]="member.masked && masked ? 'password' : 'text'"
@@ -98,7 +98,7 @@ import { QrCodeComponent } from 'ng-qrcode'
`,
changeDetection: ChangeDetectionStrategy.OnPush,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
.reveal {
@include taiga.center-all();
@@ -111,7 +111,7 @@ import { QrCodeComponent } from 'ng-qrcode'
`,
imports: [
FormsModule,
TuiTextfield,
TuiInput,
TuiButton,
QrCodeComponent,
TuiTitle,
@@ -119,7 +119,7 @@ import { QrCodeComponent } from 'ng-qrcode'
],
})
export class ActionSuccessMemberComponent {
@ViewChild(TuiTextfieldDirective, { read: ElementRef })
@ViewChild(TuiInputDirective, { read: ElementRef })
private readonly input!: ElementRef<HTMLInputElement>
private readonly dialog = inject(DialogService)

View File

@@ -7,7 +7,7 @@ import {
} from '@angular/core'
import { FormsModule } from '@angular/forms'
import { CopyService, i18nPipe } from '@start9labs/shared'
import { TuiButton, TuiTextfield } from '@taiga-ui/core'
import { TuiButton, TuiInput } from '@taiga-ui/core'
import { QrCodeComponent } from 'ng-qrcode'
import { SingleResult } from './types'
@@ -19,7 +19,7 @@ import { SingleResult } from './types'
}
<tui-textfield>
<input
tuiTextfield
tuiInput
[readOnly]="true"
[ngModel]="single.value"
[type]="single.masked && masked ? 'password' : 'text'"
@@ -74,7 +74,7 @@ import { SingleResult } from './types'
`,
changeDetection: ChangeDetectionStrategy.OnPush,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
.reveal {
@include taiga.center-all();
@@ -88,7 +88,7 @@ import { SingleResult } from './types'
imports: [
CommonModule,
FormsModule,
TuiTextfield,
TuiInput,
TuiButton,
QrCodeComponent,
i18nPipe,

View File

@@ -1,6 +1,6 @@
import { Component, inject } from '@angular/core'
import { Component } from '@angular/core'
import { TuiDialogContext } from '@taiga-ui/core'
import { POLYMORPHEUS_CONTEXT } from '@taiga-ui/polymorpheus'
import { injectContext } from '@taiga-ui/polymorpheus'
import { ActionSuccessGroupComponent } from './action-success-group.component'
import { ActionSuccessSingleComponent } from './action-success-single.component'
import { ActionResponseWithResult } from './types'
@@ -21,9 +21,7 @@ import { ActionResponseWithResult } from './types'
})
export class ActionSuccessPage {
readonly data =
inject<TuiDialogContext<void, ActionResponseWithResult>>(
POLYMORPHEUS_CONTEXT,
).data
injectContext<TuiDialogContext<void, ActionResponseWithResult>>().data
readonly single = this.data.result.type === 'single' ? this.data.result : null
readonly group = this.data.result.type === 'group' ? this.data.result : null

View File

@@ -1,3 +1,4 @@
import { TuiCell } from '@taiga-ui/core'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import {
@@ -8,7 +9,6 @@ import {
i18nPipe,
MARKDOWN,
} from '@start9labs/shared'
import { TuiCell } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { defer, map } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'

View File

@@ -6,31 +6,27 @@ import {
inject,
} from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import {
ErrorService,
getPkgId,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { ErrorService, getPkgId, i18nPipe } from '@start9labs/shared'
import { ISB, T } from '@start9labs/start-sdk'
import { TuiCell } from '@taiga-ui/layout'
import { TuiCell } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, map } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { ActionService } from 'src/app/services/action.service'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { StandardActionsService } from 'src/app/services/standard-actions.service'
import { getManifest } from 'src/app/utils/get-package-data'
import { ServiceActionComponent } from '../components/action.component'
import {
ALLOWED_STATUSES,
BaseStatus,
getInstalledBaseStatus,
INACTIVE_STATUSES,
} from 'src/app/services/pkg-status-rendering.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { StandardActionsService } from 'src/app/services/standard-actions.service'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
import { getManifest } from 'src/app/utils/get-package-data'
import { ServiceActionComponent } from '../components/action.component'
@Component({
template: `
@@ -92,7 +88,7 @@ export default class ServiceActionsRoute {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly formDialog = inject(FormDialogService)
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
ungrouped: 'General' | 'Other' = 'General'

View File

@@ -40,9 +40,9 @@ import { getInstalledBaseStatus } from 'src/app/services/pkg-status-rendering.se
<hgroup tuiTitle>
<h3>
{{ value.name }}
<tui-badge size="l" [appearance]="getAppearance(value.type)">
<span tuiBadge size="l" [appearance]="getAppearance(value.type)">
{{ value.type }}
</tui-badge>
</span>
</h3>
<p tuiSubtitle>{{ value.description }}</p>
</hgroup>

View File

@@ -7,9 +7,14 @@ import {
import { toSignal } from '@angular/core/rxjs-interop'
import { ActivatedRoute, Router, RouterModule } from '@angular/router'
import { i18nKey, i18nPipe } from '@start9labs/shared'
import { TuiAppearance, TuiButton, TuiIcon, TuiTitle } from '@taiga-ui/core'
import {
TuiAppearance,
TuiButton,
TuiIcon,
TuiTitle,
TuiCell,
} from '@taiga-ui/core'
import { TuiAvatar, TuiFade } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { distinctUntilChanged, filter, map, switchMap, tap } from 'rxjs'
import { DataModel } from 'src/app/services/patch-db/data-model'
@@ -28,16 +33,16 @@ import { getManifest } from 'src/app/utils/get-package-data'
<a routerLink=".." tuiIconButton iconStart="@tui.arrow-left">
{{ 'Back' | i18n }}
</a>
<tui-avatar size="xs" [style.margin-inline-end.rem]="0.75">
<span tuiAvatar size="xs" [style.margin-inline-end.rem]="0.75">
<img alt="" [src]="service()?.icon" />
</tui-avatar>
</span>
<span tuiFade>{{ manifest()?.title }}</span>
</div>
<aside class="g-aside">
<header tuiCell routerLink="./">
<tui-avatar appearance="action-grayscale">
<span tuiAvatar appearance="action-grayscale">
<img alt="" [src]="service()?.icon" />
</tui-avatar>
</span>
<span tuiTitle>
<strong tuiFade>{{ manifest()?.title }}</strong>
<span tuiSubtitle>{{ manifest()?.version }}</span>

View File

@@ -89,7 +89,7 @@ import { ServiceUptimeComponent } from '../components/uptime.component'
}
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
@keyframes bounce {
to {

View File

@@ -46,13 +46,13 @@ import { MarketplacePkgSideload, validateS9pk } from './sideload.utils'
<ng-template>
@if (error(); as err) {
<div>
<tui-avatar appearance="secondary" src="@tui.circle-x" />
<span tuiAvatar="@tui.circle-x" appearance="secondary"></span>
<p class="g-negative">{{ err | i18n }}</p>
<button tuiButton>{{ 'Try again' | i18n }}</button>
</div>
} @else {
<div>
<tui-avatar appearance="secondary" src="@tui.upload" />
<span tuiAvatar="@tui.upload" appearance="secondary"></span>
<p>{{ 'Upload .s9pk package file' | i18n }}</p>
<button tuiButton>{{ 'Select' | i18n }}</button>
</div>

View File

@@ -1,17 +1,13 @@
import { inject, Injectable } from '@angular/core'
import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { toSignal } from '@angular/core/rxjs-interop'
import { DialogService, ErrorService, i18nPipe } from '@start9labs/shared'
import { ISB, utils } from '@start9labs/start-sdk'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import { filter, map } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import { PatchDB } from 'patch-db-client'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { knownAuthorities, toAuthorityName } from 'src/app/utils/acme'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
@@ -27,7 +23,7 @@ export type RemoteAuthority = Authority & { url: string }
@Injectable()
export class AuthorityService {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)
private readonly formDialog = inject(FormDialogService)

View File

@@ -5,12 +5,7 @@ import {
input,
} from '@angular/core'
import { i18nPipe } from '@start9labs/shared'
import {
TuiButton,
TuiDataList,
TuiDropdown,
TuiTextfield,
} from '@taiga-ui/core'
import { TuiButton, TuiDataList, TuiDropdown, TuiInput } from '@taiga-ui/core'
import { Authority, AuthorityService } from './authority.service'
@Component({
@@ -31,41 +26,33 @@ import { Authority, AuthorityService } from './authority.service'
[(tuiDropdownOpen)]="open"
>
{{ 'More' | i18n }}
<tui-data-list *tuiTextfieldDropdown>
<tui-data-list *tuiDropdown>
@if (authority.url) {
<tui-opt-group>
<button
tuiOption
new
iconStart="@tui.pencil"
(click)="service.edit($any(authority))"
>
{{ 'Edit' | i18n }}
</button>
</tui-opt-group>
<tui-opt-group>
<button
tuiOption
new
iconStart="@tui.trash"
class="g-negative"
(click)="service.remove($any(authority))"
>
{{ 'Delete' | i18n }}
</button>
</tui-opt-group>
<button
tuiOption
iconStart="@tui.pencil"
(click)="service.edit($any(authority))"
>
{{ 'Edit' | i18n }}
</button>
<hr />
<button
tuiOption
iconStart="@tui.trash"
class="g-negative"
(click)="service.remove($any(authority))"
>
{{ 'Delete' | i18n }}
</button>
} @else {
<tui-opt-group>
<a
tuiOption
new
download
iconStart="@tui.download"
href="/static/local-root-ca.crt"
>
{{ 'Download' | i18n }}
</a>
</tui-opt-group>
<a
tuiOption
download
iconStart="@tui.download"
href="/static/local-root-ca.crt"
>
{{ 'Download' | i18n }}
</a>
}
</tui-data-list>
</button>
@@ -88,7 +75,7 @@ import { Authority, AuthorityService } from './authority.service'
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiButton, i18nPipe, TuiDropdown, TuiDataList, TuiTextfield],
imports: [TuiButton, i18nPipe, TuiDropdown, TuiDataList, TuiInput],
})
export class AuthorityItemComponent {
protected readonly service = inject(AuthorityService)

View File

@@ -1,14 +1,15 @@
import { Component, inject } from '@angular/core'
import { Component, inject, OnInit } from '@angular/core'
import { FormsModule } from '@angular/forms'
import { verify } from '@start9labs/argon2'
import { DialogService, ErrorService, i18nPipe } from '@start9labs/shared'
import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { TuiButton, TuiGroup, TuiLoader, TuiTitle } from '@taiga-ui/core'
import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit'
TuiButton,
TuiCheckbox,
TuiGroup,
TuiLoader,
TuiTitle,
} from '@taiga-ui/core'
import { TuiBlock, TuiNotificationMiddleService } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, map } from 'rxjs'
@@ -86,9 +87,9 @@ interface Package {
i18nPipe,
],
})
export class BackupsBackupComponent {
export class BackupsBackupComponent implements OnInit {
private readonly dialog = inject(DialogService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)

View File

@@ -85,7 +85,8 @@ import { BACKUP_RESTORE } from './restore.component'
</header>
@if (type === 'create' && !(os.backingUp$ | async) && server(); as s) {
<tui-notification
<div
tuiNotification
[appearance]="s.lastBackup | tuiMapper: toAppearance"
icon=""
>
@@ -95,7 +96,7 @@ import { BACKUP_RESTORE } from './restore.component'
{{ s.lastBackup ? (s.lastBackup | date: 'medium') : 'never' }}
</div>
</div>
</tui-notification>
</div>
}
@if (type === 'create' && (os.backingUp$ | async)) {

View File

@@ -5,15 +5,10 @@ import {
output,
} from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { DialogService, ErrorService, i18nPipe } from '@start9labs/shared'
import { ISB, T } from '@start9labs/start-sdk'
import { TuiButton, TuiIcon } from '@taiga-ui/core'
import { TuiTooltip } from '@taiga-ui/kit'
import { TuiNotificationMiddleService, TuiTooltip } from '@taiga-ui/kit'
import { filter } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
@@ -97,7 +92,7 @@ const ERROR =
</table>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
tr {
@include taiga.transition(background);
@@ -160,7 +155,7 @@ const ERROR =
.name {
color: var(--tui-text-primary);
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
grid-column: 1;
max-width: 12rem;
@@ -183,7 +178,7 @@ export class BackupNetworkComponent {
private readonly dialog = inject(DialogService)
private readonly formDialog = inject(FormDialogService)
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly type = inject(ActivatedRoute).snapshot.data['type']
private readonly i18n = inject(i18nPipe)

View File

@@ -61,7 +61,7 @@ import { BackupStatusComponent } from './status.component'
</table>
`,
styles: `
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
@use '@taiga-ui/styles/utils' as taiga;
tr {
@include taiga.transition(background);
@@ -98,7 +98,7 @@ import { BackupStatusComponent } from './status.component'
.name {
color: var(--tui-text-primary);
font: var(--tui-font-text-m);
font: var(--tui-typography-body-m);
font-weight: bold;
grid-column: 1;
max-width: 12rem;

View File

@@ -3,9 +3,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { i18nPipe } from '@start9labs/shared'
import { TuiMapperPipe } from '@taiga-ui/cdk'
import { TuiIcon, TuiLoader, TuiTitle } from '@taiga-ui/core'
import { TuiIcon, TuiLoader, TuiTitle, TuiCell } from '@taiga-ui/core'
import { TuiAvatar } from '@taiga-ui/kit'
import { TuiCell } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { take } from 'rxjs'
import { ToManifestPipe } from 'src/app/routes/portal/pipes/to-manifest'
@@ -18,9 +17,9 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
@for (pkg of pkgs() | keyvalue; track $index) {
@if (backupProgress()?.[pkg.key]; as progress) {
<div tuiCell>
<tui-avatar appearance="action-grayscale">
<span tuiAvatar appearance="action-grayscale">
<img alt="" [src]="pkg.value.icon" />
</tui-avatar>
</span>
<span tuiTitle>
{{ (pkg.value | toManifest).title }}
<span tuiSubtitle>

View File

@@ -3,16 +3,17 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { FormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import {
ErrorService,
i18nKey,
i18nPipe,
LoadingService,
} from '@start9labs/shared'
import { ErrorService, i18nKey, i18nPipe } from '@start9labs/shared'
import { Version } from '@start9labs/start-sdk'
import { TuiMapperPipe } from '@taiga-ui/cdk'
import { TuiButton, TuiDialogContext, TuiGroup, TuiTitle } from '@taiga-ui/core'
import { TuiBlock, TuiCheckbox } from '@taiga-ui/kit'
import {
TuiButton,
TuiCheckbox,
TuiDialogContext,
TuiGroup,
TuiTitle,
} from '@taiga-ui/core'
import { TuiBlock, TuiNotificationMiddleService } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client'
import { map, take } from 'rxjs'
@@ -85,7 +86,7 @@ import { RecoverData, RecoverOption } from './backup.types'
export class BackupsRecoverComponent {
private readonly config = inject(ConfigService)
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly errorService = inject(ErrorService)
private readonly router = inject(Router)
private readonly context =

View File

@@ -4,11 +4,10 @@ import {
DialogService,
ErrorService,
i18nPipe,
LoadingService,
StartOSDiskInfo,
} from '@start9labs/shared'
import { TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { TuiCell, TuiTitle } from '@taiga-ui/core'
import { TuiNotificationMiddleService } from '@taiga-ui/kit'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { verifyPassword } from 'src/app/utils/verify-password'
@@ -45,7 +44,7 @@ import { RECOVER } from './recover.component'
})
export class BackupRestoreComponent {
private readonly dialog = inject(DialogService)
private readonly loader = inject(LoadingService)
private readonly loader = inject(TuiNotificationMiddleService)
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly context = injectContext<BackupContext>()

Some files were not shown because too many files have changed in this diff Show More