fix: fix merge issues for setup-wizard project

This commit is contained in:
waterplea
2024-08-10 14:26:15 +04:00
parent 81932c8cff
commit 657aac0d68
27 changed files with 322 additions and 497 deletions

View File

@@ -1,6 +1,5 @@
import { TuiInputModule, TuiInputPasswordModule } from '@taiga-ui/legacy'
import { CommonModule } from '@angular/common'
import { Component, inject, Inject } from '@angular/core'
import { Component, inject } from '@angular/core'
import {
FormControl,
FormGroup,
@@ -9,24 +8,26 @@ import {
Validators,
} from '@angular/forms'
import { LoadingService, StartOSDiskInfo } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
TuiButton,
TuiDialogContext,
TuiDialogService,
TuiError,
TuiButton,
} from '@taiga-ui/core'
import { TUI_VALIDATION_ERRORS, TuiFieldErrorPipe } from '@taiga-ui/kit'
import { POLYMORPHEUS_CONTEXT } from '@taiga-ui/polymorpheus'
import { PASSWORD } from 'src/app/components/password.component'
import { TuiInputModule, TuiInputPasswordModule } from '@taiga-ui/legacy'
import {
ApiService,
CifsBackupTarget,
CifsRecoverySource,
} from 'src/app/services/api.service'
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
} from '@taiga-ui/polymorpheus'
import { SERVERS, ServersResponse } from 'src/app/components/servers.component'
import { ApiService } from 'src/app/services/api.service'
interface Context {
cifs: CifsRecoverySource
recoveryPassword: string
export interface CifsResponse {
cifs: T.Cifs
serverId: string
password: string
}
@Component({
@@ -34,10 +35,10 @@ interface Context {
template: `
<form [formGroup]="form" (ngSubmit)="submit()">
<tui-input formControlName="hostname">
Hostname
Hostname *
<input
tuiTextfieldLegacy
placeholder="'My Computer' OR 'my-computer.local'"
placeholder="e.g. 'My Computer' OR 'my-computer.local'"
/>
</tui-input>
<tui-error
@@ -46,7 +47,7 @@ interface Context {
></tui-error>
<tui-input formControlName="path" class="input">
Path
Path *
<input tuiTextfieldLegacy placeholder="/Desktop/my-folder'" />
</tui-input>
<tui-error
@@ -55,7 +56,7 @@ interface Context {
></tui-error>
<tui-input formControlName="username" class="input">
Username
Username *
<input tuiTextfieldLegacy placeholder="Enter username" />
</tui-input>
<tui-error
@@ -108,7 +109,7 @@ export class CifsComponent {
private readonly api = inject(ApiService)
private readonly loader = inject(LoadingService)
private readonly context =
inject<TuiDialogContext<Context>>(POLYMORPHEUS_CONTEXT)
inject<TuiDialogContext<CifsResponse>>(POLYMORPHEUS_CONTEXT)
readonly form = new FormGroup({
hostname: new FormControl('', {
@@ -141,7 +142,6 @@ export class CifsComponent {
try {
const diskInfo = await this.api.verifyCifs({
...this.form.getRawValue(),
type: 'cifs',
password: this.form.value.password
? await this.api.encrypt(String(this.form.value.password))
: null,
@@ -149,35 +149,31 @@ export class CifsComponent {
loader.unsubscribe()
this.presentModalPassword(diskInfo)
this.selectServer(diskInfo)
} catch (e) {
loader.unsubscribe()
this.presentAlertFailed()
this.onFail()
}
}
private presentModalPassword(diskInfo: StartOSDiskInfo) {
const target: CifsBackupTarget = {
...this.form.getRawValue(),
mountable: true,
startOs: diskInfo,
}
private selectServer(servers: Record<string, StartOSDiskInfo>) {
this.dialogs
.open<string>(PASSWORD, {
label: 'Unlock Drive',
size: 's',
data: { target },
.open<ServersResponse>(SERVERS, {
label: 'Select Server to Restore',
data: {
servers: Object.keys(servers).map(id => ({ id, ...servers[id] })),
},
})
.subscribe(recoveryPassword => {
.subscribe(({ password, serverId }) => {
this.context.completeWith({
cifs: { ...this.form.getRawValue(), type: 'cifs' },
recoveryPassword,
cifs: { ...this.form.getRawValue() },
serverId,
password,
})
})
}
private presentAlertFailed() {
private onFail() {
this.dialogs
.open(
'Unable to connect to shared folder. Ensure (1) target computer is connected to LAN, (2) target folder is being shared, and (3) hostname, path, and credentials are accurate.',
@@ -189,3 +185,5 @@ export class CifsComponent {
.subscribe()
}
}
export const CIFS = new PolymorpheusComponent(CifsComponent)

View File

@@ -1,12 +1,5 @@
import {
Component,
Directive,
ElementRef,
inject,
NgZone,
OnInit,
} from '@angular/core'
import { WINDOW } from '@ng-web-apis/common'
import { Component, ElementRef, inject, NgZone, OnInit } from '@angular/core'
import { WA_WINDOW } from '@ng-web-apis/common'
// a higher fade factor will make the characters fade quicker
const FADE_FACTOR = 0.07
@@ -19,7 +12,7 @@ const FADE_FACTOR = 0.07
})
export class MatrixComponent implements OnInit {
private readonly ngZone = inject(NgZone)
private readonly window = inject(WINDOW)
private readonly window = inject(WA_WINDOW)
private readonly el: HTMLCanvasElement = inject(ElementRef).nativeElement
private readonly ctx = this.el.getContext('2d')!

View File

@@ -8,13 +8,9 @@ import {
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
} from '@taiga-ui/polymorpheus'
import {
CifsBackupTarget,
DiskBackupTarget,
} from 'src/app/services/api.service'
interface DialogData {
target?: CifsBackupTarget | DiskBackupTarget
passwordHash?: string
storageDrive?: boolean
}
@@ -73,24 +69,14 @@ export class PasswordComponent {
private readonly context =
inject<TuiDialogContext<string, DialogData>>(POLYMORPHEUS_CONTEXT)
readonly target = this.context.data.target
readonly storageDrive = this.context.data.storageDrive
readonly password = new FormControl('', { nonNullable: true })
readonly confirm = new FormControl('', { nonNullable: true })
get passwordError(): string | null {
if (!this.password.touched || this.target) return null
if (!this.storageDrive && !this.target?.['embassy-os'])
return 'No recovery target' // unreachable
if (this.password.value.length < 12)
return 'Must be 12 characters or greater'
if (this.password.value.length > 64)
return 'Must be less than 65 characters'
return null
return this.password.touched && this.password.value.length < 12
? 'Must be 12 characters or greater'
: null
}
get confirmError(): string | null {
@@ -107,9 +93,7 @@ export class PasswordComponent {
}
try {
const passwordHash = this.target!.startOs?.passwordHash || ''
argon2.verify(passwordHash, this.password.value)
argon2.verify(this.context.data.passwordHash || '', this.password.value)
this.context.completeWith(this.password.value)
} catch (e) {
this.errorService.handleError('Incorrect password provided')

View File

@@ -0,0 +1,46 @@
import { DatePipe } from '@angular/common'
import { Component, ElementRef, inject, input, Output } from '@angular/core'
import { StartOSDiskInfo } from '@start9labs/shared'
import { TuiDialogService, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout'
import { filter, fromEvent, switchMap } from 'rxjs'
import { PASSWORD } from 'src/app/components/password.component'
@Component({
standalone: true,
selector: 'button[server]',
template: `
<tui-icon icon="@tui.save" />
<span tuiTitle>
<strong>{{ server().hostname }}.local</strong>
<span tuiSubtitle>
<b>StartOS Version</b>
: {{ server().version }}
</span>
<span tuiSubtitle>
<b>Created</b>
: {{ server().timestamp | date: 'medium' }}
</span>
</span>
`,
styles: ':host { width: stretch; border-radius: var(--tui-radius-l); }',
hostDirectives: [TuiCell],
imports: [DatePipe, TuiIcon, TuiTitle],
})
export class ServerComponent {
private readonly dialogs = inject(TuiDialogService)
readonly server = input.required<StartOSDiskInfo>()
@Output()
readonly password = fromEvent(inject(ElementRef).nativeElement, 'click').pipe(
switchMap(() =>
this.dialogs.open<string>(PASSWORD, {
label: 'Unlock Drive',
size: 's',
data: { passwordHash: this.server().passwordHash },
}),
),
filter(Boolean),
)
}

View File

@@ -0,0 +1,37 @@
import { Component, inject } from '@angular/core'
import { TuiDialogContext } from '@taiga-ui/core'
import {
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
} from '@taiga-ui/polymorpheus'
import { ServerComponent } from 'src/app/components/server.component'
import { StartOSDiskInfoWithId } from 'src/app/services/api.service'
interface Data {
servers: StartOSDiskInfoWithId[]
}
export interface ServersResponse {
password: string
serverId: string
}
@Component({
standalone: true,
template: `
@for (server of context.data.servers; track $index) {
<button [server]="server" (password)="select($event, server.id)"></button>
}
`,
imports: [ServerComponent],
})
export class ServersComponent {
readonly context =
inject<TuiDialogContext<ServersResponse, Data>>(POLYMORPHEUS_CONTEXT)
select(password: string, serverId: string) {
this.context.completeWith({ serverId, password })
}
}
export const SERVERS = new PolymorpheusComponent(ServersComponent)