mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
fix: fix merge issues for setup-wizard project
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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')!
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user