mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
fix: address todos (#2578)
This commit is contained in:
@@ -225,7 +225,6 @@ h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
hr,
|
||||
p {
|
||||
hr {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ import { AsyncPipe } from '@angular/common'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
Input,
|
||||
} from '@angular/core'
|
||||
import { TuiLetModule, tuiPure } from '@taiga-ui/cdk'
|
||||
@@ -22,11 +24,11 @@ import { Manifest } from '@start9labs/marketplace'
|
||||
standalone: true,
|
||||
selector: 'fieldset[appControls]',
|
||||
template: `
|
||||
@if (pkg.status.main.status === 'running') {
|
||||
@if (pkg().status.main.status === 'running') {
|
||||
<button
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconSquare"
|
||||
(click)="actions.stop(manifest)"
|
||||
(click)="actions.stop(manifest())"
|
||||
>
|
||||
Stop
|
||||
</button>
|
||||
@@ -34,7 +36,7 @@ import { Manifest } from '@start9labs/marketplace'
|
||||
<button
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconRotateCw"
|
||||
(click)="actions.restart(manifest)"
|
||||
(click)="actions.restart(manifest())"
|
||||
>
|
||||
Restart
|
||||
</button>
|
||||
@@ -43,8 +45,8 @@ import { Manifest } from '@start9labs/marketplace'
|
||||
*tuiLet="hasUnmet() | async as hasUnmet"
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconPlay"
|
||||
[disabled]="!pkg.status.configured"
|
||||
(click)="actions.start(manifest, !!hasUnmet)"
|
||||
[disabled]="!pkg().status.configured"
|
||||
(click)="actions.start(manifest(), !!hasUnmet)"
|
||||
>
|
||||
Start
|
||||
</button>
|
||||
@@ -52,39 +54,33 @@ import { Manifest } from '@start9labs/marketplace'
|
||||
<button
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconTool"
|
||||
(click)="actions.configure(manifest)"
|
||||
(click)="actions.configure(manifest())"
|
||||
>
|
||||
Configure
|
||||
</button>
|
||||
}
|
||||
|
||||
<app-ui-launch [pkg]="pkg" />
|
||||
<app-ui-launch [pkg]="pkg()" />
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [TuiButtonModule, UILaunchComponent, TuiLetModule, AsyncPipe],
|
||||
providers: [tuiButtonOptionsProvider({ size: 's', appearance: 'none' })],
|
||||
styles: ':host { padding: 0; border: none }',
|
||||
})
|
||||
export class ControlsComponent {
|
||||
private readonly errors = inject(DepErrorService)
|
||||
|
||||
@Input()
|
||||
pkg!: PackageDataEntry
|
||||
|
||||
get manifest(): Manifest {
|
||||
return getManifest(this.pkg)
|
||||
}
|
||||
|
||||
readonly actions = inject(ActionsService)
|
||||
|
||||
@tuiPure
|
||||
hasUnmet(): Observable<boolean> {
|
||||
const id = this.manifest.id
|
||||
return this.errors.getPkgDepErrors$(id).pipe(
|
||||
pkg = input.required<PackageDataEntry>()
|
||||
|
||||
readonly manifest = computed(() => getManifest(this.pkg()))
|
||||
readonly hasUnmet = computed(() =>
|
||||
this.errors.getPkgDepErrors$(this.manifest().id).pipe(
|
||||
map(errors =>
|
||||
Object.keys(this.pkg.currentDependencies)
|
||||
.map(id => !!(errors[id] as any)?.[id]) // @TODO-Alex fix
|
||||
Object.keys(this.pkg().currentDependencies)
|
||||
.map(id => !!(errors[id] as any)?.[id]) // @TODO fix type
|
||||
.some(Boolean),
|
||||
),
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ToManifestPipe } from '../../pipes/to-manifest'
|
||||
<th [style.width.rem]="3"></th>
|
||||
<th>Name</th>
|
||||
<th>Version</th>
|
||||
<th [style.width.rem]="12">Status</th>
|
||||
<th [style.width.rem]="13">Status</th>
|
||||
<th [style.width.rem]="8" [style.text-align]="'center'">Controls</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
Input,
|
||||
} from '@angular/core'
|
||||
import { tuiPure } from '@taiga-ui/cdk'
|
||||
import { TuiLoaderModule } from '@taiga-ui/core'
|
||||
import { TuiIconModule } from '@taiga-ui/experimental'
|
||||
@@ -35,8 +40,11 @@ import { InstallingProgressDisplayPipe } from '../service/pipes/install-progress
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [TuiIconModule, TuiLoaderModule],
|
||||
providers: [InstallingProgressDisplayPipe],
|
||||
})
|
||||
export class StatusComponent {
|
||||
private readonly pipe = inject(InstallingProgressDisplayPipe)
|
||||
|
||||
@Input()
|
||||
pkg!: PackageDataEntry
|
||||
|
||||
@@ -64,7 +72,7 @@ export class StatusComponent {
|
||||
|
||||
get status(): string {
|
||||
if (this.pkg.stateInfo.installingInfo) {
|
||||
return `Installing...${new InstallingProgressDisplayPipe().transform(this.pkg.stateInfo.installingInfo.progress.overall)}`
|
||||
return `Installing... ${this.pipe.transform(this.pkg.stateInfo.installingInfo.progress.overall)}`
|
||||
}
|
||||
|
||||
switch (this.getStatus(this.pkg).primary) {
|
||||
|
||||
@@ -43,17 +43,15 @@ import {
|
||||
</ng-template>
|
||||
</tui-hosted-dropdown>
|
||||
} @else {
|
||||
@if (interfaces[0]; as info) {
|
||||
<a
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconExternalLink"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
[attr.href]="getHref(info)"
|
||||
>
|
||||
{{ info.name }}
|
||||
</a>
|
||||
}
|
||||
<a
|
||||
tuiIconButton
|
||||
iconLeft="tuiIconExternalLink"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
[attr.href]="getHref(interfaces[0])"
|
||||
>
|
||||
{{ interfaces[0]?.name }}
|
||||
</a>
|
||||
}
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { inject, Injectable } from '@angular/core'
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
Injectable,
|
||||
} from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { TuiAlertService, TuiDialogService } from '@taiga-ui/core'
|
||||
import * as argon2 from '@start9labs/argon2'
|
||||
import { ErrorService, LoadingService } from '@start9labs/shared'
|
||||
import { TUI_PROMPT } from '@taiga-ui/kit'
|
||||
import { TUI_PROMPT, TuiCheckboxLabeledModule } from '@taiga-ui/kit'
|
||||
import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { filter, firstValueFrom, from, take } from 'rxjs'
|
||||
import { switchMap } from 'rxjs/operators'
|
||||
@@ -30,6 +37,8 @@ export class SettingsService {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly isTor = inject(ConfigService).isTor()
|
||||
|
||||
wipe = false
|
||||
|
||||
readonly settings: Record<string, readonly SettingBtn[]> = {
|
||||
General: [
|
||||
{
|
||||
@@ -122,19 +131,19 @@ export class SettingsService {
|
||||
await this.proxyService.presentModalSetOutboundProxy(proxy)
|
||||
}
|
||||
|
||||
// @TODO-Alex previous this was done in experimental settings using a template ref.
|
||||
private promptResetTor() {
|
||||
this.wipe = false
|
||||
this.dialogs
|
||||
.open(TUI_PROMPT, {
|
||||
label: this.isTor ? 'Warning' : 'Confirm',
|
||||
data: {
|
||||
content: '@TODO how to display a checkbox in here?',
|
||||
content: new PolymorpheusComponent(WipeComponent),
|
||||
yes: 'Reset',
|
||||
no: 'Cancel',
|
||||
},
|
||||
})
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => this.resetTor(true))
|
||||
.subscribe(() => this.resetTor(this.wipe))
|
||||
}
|
||||
|
||||
private async resetTor(wipeState: boolean) {
|
||||
@@ -258,3 +267,30 @@ export class SettingsService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
template: `
|
||||
<p>
|
||||
@if (isTor) {
|
||||
You are currently connected over Tor. If you reset the Tor daemon, you
|
||||
will lose connectivity until it comes back online.
|
||||
} @else {
|
||||
Reset Tor?
|
||||
}
|
||||
</p>
|
||||
<p>
|
||||
Optionally wipe state to forcibly acquire new guard nodes. It is
|
||||
recommended to try without wiping state first.
|
||||
</p>
|
||||
<tui-checkbox-labeled size="l" [(ngModel)]="service.wipe">
|
||||
Wipe state
|
||||
</tui-checkbox-labeled>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [TuiCheckboxLabeledModule, FormsModule],
|
||||
})
|
||||
class WipeComponent {
|
||||
readonly isTor = inject(ConfigService).isTor()
|
||||
readonly service = inject(SettingsService)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { NgIf } from '@angular/common'
|
||||
import { Component, inject, Input } from '@angular/core'
|
||||
import { RouterLink } from '@angular/router'
|
||||
import {
|
||||
@@ -27,17 +26,17 @@ import {
|
||||
TuiProgressModule,
|
||||
} from '@taiga-ui/kit'
|
||||
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { InstallingProgressPipe } from 'src/app/apps/portal/routes/service/pipes/install-progress.pipe'
|
||||
import { MarketplaceService } from 'src/app/services/marketplace.service'
|
||||
import {
|
||||
DataModel,
|
||||
InstalledState,
|
||||
PackageDataEntry,
|
||||
UpdatingState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { MarketplaceService } from 'src/app/services/marketplace.service'
|
||||
import { hasCurrentDeps } from 'src/app/util/has-deps'
|
||||
import { InstallingProgressPipe } from '../../../service/pipes/install-progress.pipe'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { getAllPackages } from 'src/app/util/get-package-data'
|
||||
import { hasCurrentDeps } from 'src/app/util/has-deps'
|
||||
|
||||
@Component({
|
||||
selector: 'updates-item',
|
||||
@@ -56,29 +55,30 @@ import { getAllPackages } from 'src/app/util/get-package-data'
|
||||
</div>
|
||||
<div [style.color]="'var(--tui-negative)'">{{ errors }}</div>
|
||||
</div>
|
||||
<tui-progress-circle
|
||||
*ngIf="localPkg.stateInfo.state === 'updating'; else button"
|
||||
style="color: var(--tui-positive)"
|
||||
[max]="100"
|
||||
[value]="
|
||||
(localPkg.stateInfo.installingInfo.progress.overall
|
||||
| installingProgress) || 0
|
||||
"
|
||||
/>
|
||||
<ng-template #button>
|
||||
<button
|
||||
*ngIf="ready; else queued"
|
||||
tuiButton
|
||||
@if (localPkg.stateInfo.state === 'updating') {
|
||||
<tui-progress-circle
|
||||
class="g-success"
|
||||
size="s"
|
||||
[appearance]="errors ? 'secondary-destructive' : 'primary'"
|
||||
(click.stop)="onClick()"
|
||||
>
|
||||
{{ errors ? 'Retry' : 'Update' }}
|
||||
</button>
|
||||
</ng-template>
|
||||
<ng-template #queued>
|
||||
<tui-loader [style.width.rem]="2" [inheritColor]="true" />
|
||||
</ng-template>
|
||||
[max]="1"
|
||||
[value]="
|
||||
(localPkg.stateInfo.installingInfo.progress.overall
|
||||
| installingProgress) || 0
|
||||
"
|
||||
/>
|
||||
} @else {
|
||||
@if (ready) {
|
||||
<button
|
||||
tuiButton
|
||||
size="s"
|
||||
[appearance]="errors ? 'destructive' : 'primary'"
|
||||
(click.stop)="onClick()"
|
||||
>
|
||||
{{ errors ? 'Retry' : 'Update' }}
|
||||
</button>
|
||||
} @else {
|
||||
<tui-loader [style.width.rem]="2" [inheritColor]="true" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<ng-template tuiAccordionItemContent>
|
||||
<strong>What's new</strong>
|
||||
@@ -114,7 +114,6 @@ import { getAllPackages } from 'src/app/util/get-package-data'
|
||||
],
|
||||
standalone: true,
|
||||
imports: [
|
||||
NgIf,
|
||||
RouterLink,
|
||||
EmverPipesModule,
|
||||
MarkdownPipeModule,
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
UpdatingState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { FilterUpdatesPipe } from './pipes/filter-updates.pipe'
|
||||
import { UpdatesItemComponent } from './components/item.component'
|
||||
import { FilterUpdatesPipe } from 'src/app/apps/portal/routes/system/updates/filter-updates.pipe'
|
||||
import { UpdatesItemComponent } from 'src/app/apps/portal/routes/system/updates/item.component'
|
||||
import { isInstalled, isUpdating } from 'src/app/util/get-package-data'
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -42,9 +42,12 @@ export class BadgeService {
|
||||
pairwise(),
|
||||
filter(([prev, curr]) =>
|
||||
Object.values(prev).some(p => {
|
||||
const id = getManifest(p).id
|
||||
!curr[id] ||
|
||||
const { id } = getManifest(p)
|
||||
|
||||
return (
|
||||
!curr[id] ||
|
||||
(p.stateInfo.installingInfo && !curr[id].stateInfo.installingInfo)
|
||||
)
|
||||
}),
|
||||
),
|
||||
map(([_, curr]) => curr),
|
||||
@@ -73,7 +76,6 @@ export class BadgeService {
|
||||
new Set<string>(),
|
||||
).size,
|
||||
),
|
||||
// @TODO-Alex shareReplay is preventing the badge from decrementing
|
||||
shareReplay(1),
|
||||
)
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ import { LocalStorageBootstrap } from './patch-db/local-storage-bootstrap'
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PatchMonitorService extends Observable<any> {
|
||||
// @TODO-Alex not happy with Observable<void>
|
||||
export class PatchMonitorService extends Observable<unknown> {
|
||||
private readonly stream$ = this.authService.isVerified$.pipe(
|
||||
tap(verified =>
|
||||
verified ? this.patch.start(this.bootstrapper) : this.patch.stop(),
|
||||
|
||||
@@ -24,9 +24,9 @@ export async function getAllPackages(
|
||||
}
|
||||
|
||||
export function getManifest(pkg: PackageDataEntry): Manifest {
|
||||
if (isInstalled(pkg) || isRemoving(pkg)) return pkg.stateInfo.manifest
|
||||
|
||||
return (pkg.stateInfo as InstallingState).installingInfo.newManifest
|
||||
return isInstalling(pkg)
|
||||
? pkg.stateInfo.installingInfo.newManifest
|
||||
: pkg.stateInfo.manifest!
|
||||
}
|
||||
|
||||
export function isInstalled(
|
||||
|
||||
@@ -523,19 +523,19 @@ button.g-action {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
.g-success {
|
||||
.g-success.g-success {
|
||||
color: var(--tui-success-fill);
|
||||
}
|
||||
|
||||
.g-warning {
|
||||
.g-warning.g-warning {
|
||||
color: var(--tui-warning-fill);
|
||||
}
|
||||
|
||||
.g-error {
|
||||
.g-error.g-error {
|
||||
color: var(--tui-error-fill);
|
||||
}
|
||||
|
||||
.g-info {
|
||||
.g-info.g-info {
|
||||
color: var(--tui-info-fill);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user