refactor: completely remove ionic

This commit is contained in:
waterplea
2024-04-05 12:06:02 +07:00
parent b2c8907635
commit 8594781780
291 changed files with 416 additions and 3365 deletions

View File

@@ -0,0 +1,42 @@
import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { RouterLink } from '@angular/router'
import { TuiAlertModule } from '@taiga-ui/core'
import { PatchDB } from 'patch-db-client'
import { Observable, Subject, merge, pairwise, map, endWith } from 'rxjs'
import { DataModel } from 'src/app/services/patch-db/data-model'
@Component({
standalone: true,
selector: 'notifications-toast',
template: `
<ng-template
[tuiAlert]="!!(visible$ | async)"
[tuiAlertOptions]="{ label: 'StartOS' }"
(tuiAlertChange)="onDismiss()"
>
New notifications
<a routerLink="/notifications" [queryParams]="{ toast: true }">View</a>
</ng-template>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiAlertModule, RouterLink, AsyncPipe],
})
export class NotificationsToastComponent {
private readonly dismiss$ = new Subject<boolean>()
readonly visible$: Observable<boolean> = merge(
this.dismiss$,
inject(PatchDB<DataModel>)
.watch$('serverInfo', 'unreadNotifications', 'count')
.pipe(
pairwise(),
map(([prev, cur]) => cur > prev),
endWith(false),
),
)
onDismiss() {
this.dismiss$.next(false)
}
}

View File

@@ -0,0 +1,90 @@
import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { SwUpdate } from '@angular/service-worker'
import { Emver, LoadingService } from '@start9labs/shared'
import { TuiAutoFocusModule } from '@taiga-ui/cdk'
import { TuiDialogModule } from '@taiga-ui/core'
import { TuiButtonModule } from '@taiga-ui/experimental'
import { PatchDB } from 'patch-db-client'
import { debounceTime, endWith, map, merge, Subject } from 'rxjs'
import { ConfigService } from 'src/app/services/config.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
@Component({
standalone: true,
selector: 'refresh-alert',
template: `
<!-- <ng-template-->
<!-- [tuiDialog]="show$ | async"-->
<!-- [tuiDialogOptions]="{ label: 'Refresh Needed', size: 's' }"-->
<!-- (tuiDialogChange)="onDismiss()"-->
<!-- >-->
<!-- Your user interface is cached and out of date. Hard refresh the page to-->
<!-- get the latest UI.-->
<!-- <ul>-->
<!-- <li>-->
<!-- <b>On Mac</b>-->
<!-- : cmd + shift + R-->
<!-- </li>-->
<!-- <li>-->
<!-- <b>On Linux/Windows</b>-->
<!-- : ctrl + shift + R-->
<!-- </li>-->
<!-- </ul>-->
<!-- <button-->
<!-- tuiButton-->
<!-- tuiAutoFocus-->
<!-- appearance="secondary"-->
<!-- style="float: right"-->
<!-- (click)="onDismiss()"-->
<!-- >-->
<!-- Ok-->
<!-- </button>-->
<!-- </ng-template>-->
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiDialogModule, AsyncPipe, TuiButtonModule, TuiAutoFocusModule],
})
export class RefreshAlertComponent {
private readonly updates = inject(SwUpdate)
private readonly loader = inject(LoadingService)
private readonly emver = inject(Emver)
private readonly config = inject(ConfigService)
private readonly dismiss$ = new Subject<boolean>()
readonly show$ = merge(
this.dismiss$,
inject(PatchDB<DataModel>)
.watch$('serverInfo', 'version')
.pipe(
map(version => !!this.emver.compare(this.config.version, version)),
endWith(false),
),
).pipe(debounceTime(0))
// @TODO use this like we did on 0344
onPwa = false
ngOnInit() {
this.onPwa = window.matchMedia('(display-mode: standalone)').matches
}
async pwaReload() {
const loader = this.loader.open('Reloading PWA...').subscribe()
try {
// attempt to update to the latest client version available
await this.updates.activateUpdate()
} catch (e) {
console.error('Error activating update from service worker: ', e)
} finally {
loader.unsubscribe()
// always reload, as this resolves most out of sync cases
window.location.reload()
}
}
onDismiss() {
this.dismiss$.next(false)
}
}

View File

@@ -0,0 +1,86 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { TuiDialogContext, TuiSvgModule } from '@taiga-ui/core'
import {
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
} from '@tinkoff/ng-polymorpheus'
import { BackupReport } from 'src/app/services/api/api.types'
@Component({
template: `
<h3 class="g-title">Completed: {{ timestamp | date: 'medium' }}</h3>
<div class="g-action">
<div [style.flex]="1">
<strong>System data</strong>
<div [style.color]="system.color">{{ system.result }}</div>
</div>
<tui-svg [src]="system.icon" [style.color]="system.color"></tui-svg>
</div>
<div *ngFor="let pkg of report?.packages | keyvalue" class="g-action">
<div [style.flex]="1">
<strong>{{ pkg.key }}</strong>
<div [style.color]="getColor(pkg.value.error)">
{{ pkg.value.error ? 'Failed: ' + pkg.value.error : 'Succeeded' }}
</div>
</div>
<tui-svg
[src]="getIcon(pkg.value.error)"
[style.color]="getColor(pkg.value.error)"
></tui-svg>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, TuiSvgModule],
})
export class BackupsReportModal {
private readonly context =
inject<TuiDialogContext<void, { report: BackupReport; timestamp: string }>>(
POLYMORPHEUS_CONTEXT,
)
readonly system = this.getSystem()
get report(): BackupReport {
return this.context.data.report
}
get timestamp(): string {
return this.context.data.timestamp
}
getColor(error: unknown) {
return error ? 'var(--tui-negative)' : 'var(--tui-positive)'
}
getIcon(error: unknown) {
return error ? 'tuiIconMinusCircleLarge' : 'tuiIconCheckLarge'
}
private getSystem() {
if (!this.report.server.attempted) {
return {
result: 'Not Attempted',
icon: 'tuiIconMinusLarge',
color: 'var(--tui-text-02)',
}
}
if (this.report.server.error) {
return {
result: `Failed: ${this.report.server.error}`,
icon: 'tuiIconMinusCircleLarge',
color: 'var(--tui-negative)',
}
}
return {
result: 'Succeeded',
icon: 'tuiIconCheckLarge',
color: 'var(--tui-positive)',
}
}
}
export const REPORT = new PolymorpheusComponent(BackupsReportModal)

View File

@@ -0,0 +1,35 @@
import {
ChangeDetectionStrategy,
Component,
Directive,
Injectable,
} from '@angular/core'
import {
AbstractTuiPortalHostComponent,
AbstractTuiPortalService,
TuiDropdownPortalService,
} from '@taiga-ui/cdk'
@Injectable({ providedIn: `root` })
export class SidebarService extends AbstractTuiPortalService {}
@Directive({
selector: '[tuiSidebar]',
standalone: true,
providers: [
{ provide: TuiDropdownPortalService, useExisting: SidebarService },
],
})
export class SidebarDirective {}
@Component({
selector: 'sidebar-host',
template: '<ng-container #viewContainer></ng-container>',
styles: [':host { position: fixed; top: 0; }'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
providers: [
{ provide: AbstractTuiPortalService, useExisting: SidebarService },
],
})
export class SidebarHostComponent extends AbstractTuiPortalHostComponent {}

View File

@@ -0,0 +1,46 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'
@Component({
standalone: true,
selector: 'svg-definitions',
template: `
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="bevel-light">
<feFlood flood-color="white" flood-opacity="0.1" />
<feComposite in2="SourceAlpha" operator="out" />
<feGaussianBlur stdDeviation="0.5" result="blur" />
<feOffset dx="-1" dy="1" />
<feComposite operator="atop" in2="SourceGraphic" />
</filter>
<filter id="bevel-dark">
<feFlood flood-color="black" flood-opacity="0.3" />
<feComposite in2="SourceAlpha" operator="out" />
<feGaussianBlur stdDeviation="0.5" result="blur" />
<feOffset dx="1" dy="-1" />
<feComposite operator="atop" in2="SourceGraphic" />
</filter>
<filter id="round-corners">
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur" />
<feColorMatrix
in="blur"
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9"
result="flt_tag"
/>
<feComposite in="SourceGraphic" in2="flt_tag" operator="atop" />
</filter>
</defs>
</svg>
`,
styles: `
:host {
position: absolute;
width: 0;
height: 0;
visibility: hidden;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SvgDefinitionsComponent {}

View File

@@ -0,0 +1,21 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'
import { NotificationsToastComponent } from './notifications-toast.component'
import { RefreshAlertComponent } from './refresh-alert.component'
import { UpdateToastComponent } from './update-toast.component'
@Component({
standalone: true,
selector: 'toast-container',
template: `
<notifications-toast />
<refresh-alert />
<update-toast />
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
NotificationsToastComponent,
UpdateToastComponent,
RefreshAlertComponent,
],
})
export class ToastContainerComponent {}

View File

@@ -0,0 +1,79 @@
import { AsyncPipe } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { TuiAlertModule } from '@taiga-ui/core'
import { TuiButtonModule } from '@taiga-ui/experimental'
import { PatchDB } from 'patch-db-client'
import {
distinctUntilChanged,
endWith,
filter,
merge,
Observable,
Subject,
} from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
@Component({
standalone: true,
selector: 'update-toast',
template: `
<ng-template
[tuiAlert]="!!(visible$ | async)"
[tuiAlertOptions]="{
label: 'StartOS download complete!',
status: 'success',
autoClose: false
}"
(tuiAlertChange)="onDismiss()"
>
Restart your server for these updates to take effect. It can take several
minutes to come back online.
<div>
<button
tuiButton
appearance="secondary"
size="s"
style="margin-top: 8px"
(click)="restart()"
>
Restart
</button>
</div>
</ng-template>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiButtonModule, TuiAlertModule, AsyncPipe],
})
export class UpdateToastComponent {
private readonly api = inject(ApiService)
private readonly errorService = inject(ErrorService)
private readonly loader = inject(LoadingService)
private readonly dismiss$ = new Subject<boolean>()
readonly visible$: Observable<boolean> = merge(
this.dismiss$,
inject(PatchDB<DataModel>)
.watch$('serverInfo', 'statusInfo', 'updated')
.pipe(distinctUntilChanged(), filter(Boolean), endWith(false)),
)
onDismiss() {
this.dismiss$.next(false)
}
async restart(): Promise<void> {
this.onDismiss()
const loader = this.loader.open('Restarting...').subscribe()
try {
await this.api.restartServer({})
} catch (e: any) {
await this.errorService.handleError(e)
} finally {
await loader.unsubscribe()
}
}
}

View File

@@ -0,0 +1,49 @@
import { Component, inject, Inject } from '@angular/core'
import { TuiDialogContext } from '@taiga-ui/core'
import { TuiButtonModule } from '@taiga-ui/experimental'
import { POLYMORPHEUS_CONTEXT } from '@tinkoff/ng-polymorpheus'
@Component({
standalone: true,
template: `
<h3>
This release:
<em>0.3.5</em>
</h3>
<p>
View the complete
<a
href="https://github.com/Start9Labs/start-os/releases/tag/v0.3.5"
target="_blank"
noreferrer
>
release notes
</a>
for more details.
</p>
<h5>Highlights</h5>
<ul class="spaced-list">
<li>
This release contains significant under-the-hood improvements to
performance and reliability
</li>
<li>Ditch Docker, replace with Podman</li>
<li>Remove locking behavior from PatchDB and optimize</li>
<li>Boost efficiency of service manager</li>
<li>Require HTTPS on LAN, and improve setup flow for trusting Root CA</li>
<li>Better default privacy settings for Firefox kiosk mode</li>
<li>Eliminate memory leak from Javascript runtime</li>
<li>Other small bug fixes</li>
<li>Update license to MIT</li>
</ul>
<p [style.text-align]="'center'">
<button tuiButton (click)="context.$implicit.complete()">Begin</button>
</p>
`,
styles: 'li { margin-bottom: 0.5rem }',
imports: [TuiButtonModule],
})
export class WelcomeComponent {
readonly context = inject<TuiDialogContext>(POLYMORPHEUS_CONTEXT)
}