refactor: refactor updates page to get rid of ionic (#2459)

This commit is contained in:
Alex Inkin
2023-10-16 07:31:34 +04:00
committed by GitHub
parent df7a30bd14
commit 8034e5bbcb
31 changed files with 550 additions and 38 deletions

View File

@@ -7,7 +7,7 @@ import * as emver from '@start9labs/emver'
export class Emver {
constructor() {}
compare(lhs: string, rhs: string): number | null {
compare(lhs?: string, rhs?: string): number | null {
if (!lhs || !rhs) return null
return emver.compare(lhs, rhs)
}

View File

@@ -97,9 +97,7 @@ export class MenuComponent {
map(([marketplace, local]) =>
Object.entries(marketplace).reduce((list, [_, store]) => {
store?.packages.forEach(({ manifest: { id, version } }) => {
if (
this.emver.compare(version, local[id]?.manifest.version || '') === 1
)
if (this.emver.compare(version, local[id]?.manifest.version) === 1)
list.add(id)
})
return list

View File

@@ -1,12 +1,17 @@
<span class="link">
<tui-svg
*ngIf="icon.startsWith('tuiIcon'); else url"
class="icon"
[src]="icon"
></tui-svg>
<ng-template #url>
<img alt="" class="icon" [src]="icon" />
</ng-template>
<tui-badged-content [style.--tui-radius.rem]="1.5">
<tui-badge-alert *ngIf="badge" size="m" tuiSlot="top">
{{ badge }}
</tui-badge-alert>
<tui-svg
*ngIf="icon.startsWith('tuiIcon'); else url"
class="icon"
[src]="icon"
></tui-svg>
<ng-template #url>
<img alt="" class="icon" [src]="icon" />
</ng-template>
</tui-badged-content>
<label ticker class="title">{{ title }}</label>
</span>
<span *ngIf="isService" class="side">

View File

@@ -27,6 +27,7 @@
width: 2.5rem;
height: 2.5rem;
border-radius: 100%;
color: var(--tui-text-01-night);
}
tui-svg.icon {

View File

@@ -6,6 +6,10 @@ import {
inject,
Input,
} from '@angular/core'
import {
TuiBadgeAlertModule,
TuiBadgedContentModule,
} from '@taiga-ui/experimental'
import { RouterLink } from '@angular/router'
import { TickerModule } from '@start9labs/shared'
import {
@@ -32,6 +36,8 @@ import { toRouterLink } from '../../utils/to-router-link'
TuiDataListModule,
TuiSvgModule,
TickerModule,
TuiBadgedContentModule,
TuiBadgeAlertModule,
ActionsComponent,
],
})
@@ -50,6 +56,9 @@ export class CardComponent {
@Input()
actions: Record<string, readonly Action[]> = {}
@Input()
badge: number | null = null
get isService(): boolean {
return !this.id.includes('/')
}

View File

@@ -22,6 +22,7 @@
empty: empty
"
appCard
[badge]="item.key | toNotifications | async"
[drawerItem]="item.key"
[id]="item.key"
[title]="item.value.title"

View File

@@ -24,6 +24,7 @@ import { ServicesService } from '../../services/services.service'
import { toRouterLink } from '../../utils/to-router-link'
import { DrawerItemDirective } from './drawer-item.directive'
import { SYSTEM_UTILITIES } from '../../constants/system-utilities'
import { ToNotificationsPipe } from '../../pipes/to-notifications'
@Component({
selector: 'app-drawer',
@@ -34,6 +35,7 @@ import { SYSTEM_UTILITIES } from '../../constants/system-utilities'
imports: [
CommonModule,
FormsModule,
RouterLink,
TuiSvgModule,
TuiScrollbarModule,
TuiActiveZoneModule,
@@ -43,7 +45,7 @@ import { SYSTEM_UTILITIES } from '../../constants/system-utilities'
TuiFilterPipeModule,
CardComponent,
DrawerItemDirective,
RouterLink,
ToNotificationsPipe,
],
})
export class DrawerComponent {

View File

@@ -0,0 +1,26 @@
import { Component, Input } from '@angular/core'
import { TuiRepeatTimesModule } from '@taiga-ui/cdk'
@Component({
selector: 'skeleton-list',
template: `
<div *tuiRepeatTimes="let index of rows" class="g-action">
<div
class="tui-skeleton"
style="--tui-skeleton-radius: 100%; width: 2.5rem; height: 2.5rem"
[hidden]="!showAvatar"
></div>
<div class="tui-skeleton" style="width: 12rem; height: 0.75rem"></div>
<div
class="tui-skeleton"
style="width: 5rem; height: 0.75rem; margin-left: auto"
></div>
</div>
`,
standalone: true,
imports: [TuiRepeatTimesModule],
})
export class SkeletonListComponent {
@Input() rows = 3
@Input() showAvatar = false
}

View File

@@ -4,6 +4,10 @@ export const SYSTEM_UTILITIES: Record<string, { icon: string; title: string }> =
icon: 'tuiIconSaveLarge',
title: 'Backups',
},
'/portal/system/updates': {
icon: 'tuiIconGlobeLarge',
title: 'Updates',
},
'/portal/system/devices': {
icon: 'assets/img/icon_transparent.png',
title: 'Devices',

View File

@@ -0,0 +1,15 @@
import { inject, Pipe, PipeTransform } from '@angular/core'
import { NotificationsService } from '../services/notifications.service'
import { Observable } from 'rxjs'
@Pipe({
name: 'toNotifications',
standalone: true,
})
export class ToNotificationsPipe implements PipeTransform {
readonly notifications = inject(NotificationsService)
transform(id: string): Observable<number> {
return this.notifications.getNotifications(id)
}
}

View File

@@ -21,7 +21,7 @@ import { DesktopService } from '../../services/desktop.service'
})
export class DektopLoadingService extends Observable<boolean> {
private readonly desktop = inject(DesktopService)
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly patch = inject(PatchDB<DataModel>)
private readonly loading = this.patch.watch$('ui', 'desktop').pipe(
take(1),
tap(items => (this.desktop.items = items.filter(Boolean))),

View File

@@ -33,6 +33,7 @@
appCard
@tuiFadeIn
[id]="item"
[badge]="item | toNotifications | async"
[title]="desktopItem.title"
[icon]="desktopItem.icon"
[routerLink]="desktopItem.routerLink"

View File

@@ -10,12 +10,8 @@ import { EMPTY_QUERY, TUI_PARENT_STOP } from '@taiga-ui/cdk'
import { tuiFadeIn, tuiScaleIn } from '@taiga-ui/core'
import { TuiTileComponent, TuiTilesComponent } from '@taiga-ui/kit'
import { PatchDB } from 'patch-db-client'
import {
DataModel,
PackageDataEntry,
} from 'src/app/services/patch-db/data-model'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { DesktopService } from '../../services/desktop.service'
import { Observable } from 'rxjs'
import { DektopLoadingService } from './dektop-loading.service'
@Component({
@@ -29,8 +25,7 @@ export class DesktopComponent {
readonly desktop = inject(DesktopService)
readonly loading$ = inject(DektopLoadingService)
readonly packages$: Observable<Record<string, PackageDataEntry>> =
inject<PatchDB<DataModel>>(PatchDB).watch$('package-data')
readonly packages$ = inject(PatchDB<DataModel>).watch$('package-data')
@ViewChild(TuiTilesComponent)
readonly tile?: TuiTilesComponent

View File

@@ -8,6 +8,7 @@ import { TuiTilesModule } from '@taiga-ui/kit'
import { DesktopComponent } from './desktop.component'
import { CardComponent } from '../../components/card/card.component'
import { ToDesktopItemPipe } from '../../pipes/to-desktop-item'
import { ToNotificationsPipe } from '../../pipes/to-notifications'
import { DesktopItemDirective } from './desktop-item.directive'
const ROUTES: Routes = [
@@ -29,6 +30,7 @@ const ROUTES: Routes = [
RouterModule.forChild(ROUTES),
TuiFadeModule,
DragScrollerDirective,
ToNotificationsPipe,
],
declarations: [DesktopComponent],
exports: [DesktopComponent],

View File

@@ -2,9 +2,8 @@ import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { POLYMORPHEUS_CONTEXT } from '@tinkoff/ng-polymorpheus'
import { PatchDB } from 'patch-db-client'
import { Observable } from 'rxjs'
import { InterfaceAddressesComponentModule } from 'src/app/common/interface-addresses/interface-addresses.module'
import { InterfaceInfo } from 'src/app/services/patch-db/data-model'
import { DataModel } from 'src/app/services/patch-db/data-model'
interface Context {
packageId: string
@@ -27,7 +26,7 @@ interface Context {
export class ServiceInterfaceModal {
readonly context = inject<{ data: Context }>(POLYMORPHEUS_CONTEXT).data
readonly interfaceInfo$: Observable<InterfaceInfo> = inject(PatchDB).watch$(
readonly interfaceInfo$ = inject(PatchDB<DataModel>).watch$(
'package-data',
this.context.packageId,
'installed',

View File

@@ -36,7 +36,7 @@ export class ServiceComponent {
private readonly route = inject(ActivatedRoute)
private readonly router = inject(Router)
private readonly navigation = inject(NavigationService)
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly patch = inject(PatchDB<DataModel>)
readonly pkgId = getPkgId(this.route)

View File

@@ -3,11 +3,10 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { TuiForModule } from '@taiga-ui/cdk'
import { TuiSvgModule } from '@taiga-ui/core'
import { PatchDB } from 'patch-db-client'
import { from, map, Observable } from 'rxjs'
import { from, map } from 'rxjs'
import { CronJob } from 'cron'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { BackupJob } from 'src/app/services/api/api.types'
import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe'
@Component({
@@ -56,7 +55,7 @@ import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe'
imports: [CommonModule, TuiForModule, TuiSvgModule, GetBackupIconPipe],
})
export class BackupsUpcomingComponent {
readonly current$: Observable<BackupJob> = inject<PatchDB<DataModel>>(PatchDB)
readonly current$ = inject(PatchDB<DataModel>)
.watch$('server-info', 'status-info', 'current-backup', 'job')
.pipe(map(job => job || {}))

View File

@@ -78,7 +78,7 @@ interface Package {
],
})
export class BackupsBackupModal {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly patch = inject(PatchDB<DataModel>)
readonly context =
inject<TuiDialogContext<string[], { btnText: string }>>(
POLYMORPHEUS_CONTEXT,

View File

@@ -75,7 +75,7 @@ export class BackupsRecoverModal {
private readonly context =
inject<TuiDialogContext<void, RecoverData>>(POLYMORPHEUS_CONTEXT)
readonly packageData$ = inject<PatchDB<DataModel>>(PatchDB)
readonly packageData$ = inject(PatchDB<DataModel>)
.watch$('package-data')
.pipe(take(1))

View File

@@ -11,6 +11,13 @@ const ROUTES: Routes = [
import('./backups/backups.component').then(m => m.BackupsComponent),
data: toDesktopItem('/portal/system/backups'),
},
{
title: systemTabResolver,
path: 'updates',
loadComponent: () =>
import('./updates/updates.component').then(m => m.UpdatesComponent),
data: toDesktopItem('/portal/system/updates'),
},
{
title: systemTabResolver,
path: 'snek',

View File

@@ -0,0 +1,237 @@
import { NgIf } from '@angular/common'
import { Component, inject, Input } from '@angular/core'
import { RouterLink } from '@angular/router'
import {
AbstractMarketplaceService,
MarketplacePkg,
MimeTypePipeModule,
} from '@start9labs/marketplace'
import {
EmverPipesModule,
isEmptyObject,
LoadingService,
MarkdownPipeModule,
SafeLinksDirective,
SharedPipesModule,
} from '@start9labs/shared'
import {
TuiButtonModule,
TuiDialogService,
TuiLinkModule,
TuiLoaderModule,
TuiSvgModule,
} from '@taiga-ui/core'
import { TuiAvatarModule } from '@taiga-ui/experimental'
import {
TUI_PROMPT,
TuiAccordionModule,
TuiProgressModule,
} from '@taiga-ui/kit'
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
import { PatchDB } from 'patch-db-client'
import {
DataModel,
PackageDataEntry,
} 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 { ApiService } from 'src/app/services/api/embassy-api.service'
import { Breakages } from 'src/app/services/api/api.types'
import { getAllPackages } from 'src/app/util/get-package-data'
import { InstallProgressPipe } from '../pipes/install-progress.pipe'
@Component({
selector: 'updates-item',
template: `
<tui-accordion-item borders="top-bottom">
<div class="g-action">
<tui-avatar size="s" [src]="pkg | mimeType | trustUrl" />
<div [style.flex]="1">
<strong>{{ pkg.manifest.title }}</strong>
<div>
<!-- @TODO left side should be local['old-manifest'] (or whatever), not manifest. -->
{{ local.manifest.version || '' | displayEmver }}
<tui-svg src="tuiIconArrowRight"></tui-svg>
<span [style.color]="'var(--tui-positive)'">
{{ pkg.manifest.version | displayEmver }}
</span>
</div>
<div [style.color]="'var(--tui-negative)'">
{{ errors }}
</div>
</div>
<tui-progress-circle
*ngIf="local.state === 'updating'; else button"
style="color: var(--tui-positive)"
[max]="100"
[value]="local['install-progress'] | installProgress"
></tui-progress-circle>
<ng-template #button>
<button
*ngIf="ready; else queued"
tuiButton
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"></tui-loader>
</ng-template>
</div>
<ng-template tuiAccordionItemContent>
<strong>What's new</strong>
<p
safeLinks
[innerHTML]="pkg.manifest['release-notes'] | markdown | dompurify"
></p>
<a
tuiLink
iconAlign="right"
icon="tuiIconExternalLink"
[routerLink]="'/marketplace/' + pkg.manifest.id"
[queryParams]="{ url: url }"
>
View listing
</a>
</ng-template>
</tui-accordion-item>
`,
styles: [
`
:host {
display: block;
--tui-base-03: transparent;
&:not(:last-child) {
border-bottom: 1px solid var(--tui-clear);
}
}
`,
],
standalone: true,
imports: [
NgIf,
RouterLink,
EmverPipesModule,
MarkdownPipeModule,
MimeTypePipeModule,
NgDompurifyModule,
SafeLinksDirective,
SharedPipesModule,
TuiProgressModule,
TuiAccordionModule,
TuiAvatarModule,
TuiSvgModule,
TuiButtonModule,
TuiLinkModule,
TuiLoaderModule,
InstallProgressPipe,
],
})
export class UpdatesItemComponent {
private readonly api = inject(ApiService)
private readonly dialogs = inject(TuiDialogService)
private readonly loader = inject(LoadingService)
private readonly patch = inject(PatchDB<DataModel>)
private readonly marketplace = inject(
AbstractMarketplaceService,
) as MarketplaceService
@Input({ required: true })
pkg!: MarketplacePkg
@Input({ required: true })
local!: PackageDataEntry
@Input({ required: true })
url = ''
get errors(): string {
return this.marketplace.updateErrors[this.pkg.manifest.id]
}
get ready(): boolean {
return !this.marketplace.updateQueue[this.pkg.manifest.id]
}
async onClick() {
const { id, version } = this.pkg.manifest
delete this.marketplace.updateErrors[id]
this.marketplace.updateQueue[id] = true
if (await hasCurrentDeps(this.patch, this.local.manifest.id)) {
await this.dry()
} else {
await this.update()
}
}
private async dry() {
const { id, version } = this.pkg.manifest
const loader = this.loader
.open('Checking dependent services...')
.subscribe()
try {
const breakages = await this.api.dryUpdatePackage({
id,
version,
})
loader.unsubscribe()
if (isEmptyObject(breakages)) {
await this.update()
} else {
const proceed = await this.alert(breakages)
if (proceed) {
await this.update()
} else {
delete this.marketplace.updateQueue[id]
}
}
} catch (e: any) {
delete this.marketplace.updateQueue[id]
this.marketplace.updateErrors[id] = e.message
loader.unsubscribe()
}
}
private async update() {
const { id, version } = this.pkg.manifest
try {
await this.marketplace.installPackage(id, version, this.url)
delete this.marketplace.updateQueue[id]
} catch (e: any) {
delete this.marketplace.updateQueue[id]
this.marketplace.updateErrors[id] = e.message
}
}
private async alert(breakages: Breakages): Promise<boolean> {
const content: string = `As a result of updating ${this.pkg.manifest.title}, the following services will no longer work properly and may crash:<ul>`
const local = await getAllPackages(this.patch)
const bullets = Object.keys(breakages)
.map(id => `<li><b>${local[id].manifest.title}</b></li>`)
.join('')
return new Promise(async resolve => {
this.dialogs
.open<boolean>(TUI_PROMPT, {
label: 'Warning',
size: 's',
data: {
content: `${content}${bullets}</ul>`,
yes: 'Continue',
no: 'Cancel',
},
})
.subscribe(response => resolve(response))
})
}
}

View File

@@ -0,0 +1,27 @@
import { inject, Pipe, PipeTransform } from '@angular/core'
import { Emver } from '@start9labs/shared'
import { MarketplacePkg } from '@start9labs/marketplace'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@Pipe({
name: 'filterUpdates',
standalone: true,
})
export class FilterUpdatesPipe implements PipeTransform {
private readonly emver = inject(Emver)
transform(
pkgs?: MarketplacePkg[],
local?: Record<string, PackageDataEntry | undefined>,
): MarketplacePkg[] | null {
return (
pkgs?.filter(
({ manifest }) =>
this.emver.compare(
manifest.version,
local?.[manifest.id]?.manifest.version, // @TODO this won't work, need old version
) === 1,
) || null
)
}
}

View File

@@ -0,0 +1,13 @@
import { Pipe, PipeTransform } from '@angular/core'
import { InstallProgress } from 'src/app/services/patch-db/data-model'
import { packageLoadingProgress } from 'src/app/util/package-loading-progress'
@Pipe({
name: 'installProgress',
standalone: true,
})
export class InstallProgressPipe implements PipeTransform {
transform(installProgress?: InstallProgress): number {
return packageLoadingProgress(installProgress)?.totalProgress || 0
}
}

View File

@@ -0,0 +1,77 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import {
AbstractMarketplaceService,
StoreIconComponentModule,
} from '@start9labs/marketplace'
import { TuiForModule } from '@taiga-ui/cdk'
import { PatchDB } from 'patch-db-client'
import { combineLatest } from 'rxjs'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import { DataModel } 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 { SkeletonListComponent } from '../../../components/skeleton-list.component'
@Component({
template: `
<ng-container *ngIf="data$ | async as data">
<section *ngFor="let host of data.hosts">
<h3 class="g-title">
<store-icon
[url]="host.url"
[marketplace]="config.marketplace"
size="26px"
></store-icon>
{{ host.name }}
</h3>
<p
*ngIf="data.errors.includes(host.url)"
[style.color]="'var(--tui-negative)'"
>
Request Failed
</p>
<updates-item
*ngFor="
let pkg of data.mp[host.url]?.packages | filterUpdates : data.local;
else: loading;
empty: blank
"
[pkg]="pkg"
[local]="data.local[pkg.manifest.id]"
[url]="host.url"
></updates-item>
</section>
</ng-container>
<ng-template #blank><p>All services are up to date!</p></ng-template>
<ng-template #loading>
<skeleton-list [showAvatar]="true"></skeleton-list>
</ng-template>
`,
host: { class: 'g-page' },
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
CommonModule,
TuiForModule,
StoreIconComponentModule,
FilterUpdatesPipe,
UpdatesItemComponent,
SkeletonListComponent,
],
})
export class UpdatesComponent {
private readonly marketplace = inject(
AbstractMarketplaceService,
) as MarketplaceService
readonly config = inject(ConfigService)
readonly data$ = combineLatest({
hosts: this.marketplace.getKnownHosts$(true),
mp: this.marketplace.getMarketplace$(),
local: inject(PatchDB<DataModel>).watch$('package-data'),
errors: this.marketplace.getRequestErrors$(),
})
}

View File

@@ -0,0 +1,78 @@
import { inject, Injectable } from '@angular/core'
import { AbstractMarketplaceService } from '@start9labs/marketplace'
import { Emver } from '@start9labs/shared'
import { PatchDB } from 'patch-db-client'
import {
combineLatest,
EMPTY,
filter,
first,
map,
Observable,
pairwise,
startWith,
switchMap,
} from 'rxjs'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import { ConnectionService } from 'src/app/services/connection.service'
@Injectable({
providedIn: 'root',
})
export class NotificationsService {
private readonly emver = inject(Emver)
private readonly patch = inject(PatchDB<DataModel>)
private readonly marketplace = inject(
AbstractMarketplaceService,
) as MarketplaceService
private readonly local$ = inject(ConnectionService).connected$.pipe(
filter(Boolean),
switchMap(() => this.patch.watch$('package-data').pipe(first())),
switchMap(outer =>
this.patch.watch$('package-data').pipe(
pairwise(),
filter(([prev, curr]) =>
Object.values(prev).some(
p =>
!curr[p.manifest.id] ||
(p['install-progress'] &&
!curr[p.manifest.id]['install-progress']),
),
),
map(([_, curr]) => curr),
startWith(outer),
),
),
)
private readonly updates$ = combineLatest([
this.marketplace.getMarketplace$(true),
this.local$,
]).pipe(
map(
([marketplace, local]) =>
Object.entries(marketplace).reduce(
(list, [_, store]) =>
store?.packages.reduce(
(result, { manifest: { id, version } }) =>
this.emver.compare(version, local[id]?.manifest.version) === 1
? result.add(id)
: result,
list,
) || list,
new Set<string>(),
).size,
),
)
getNotifications(id: string): Observable<number> {
switch (id) {
case '/portal/system/updates':
return this.updates$
default:
return EMPTY
}
}
}

View File

@@ -10,7 +10,7 @@ import {
providedIn: 'root',
})
export class ServicesService extends Observable<readonly PackageDataEntry[]> {
private readonly services$ = inject<PatchDB<DataModel>>(PatchDB)
private readonly services$ = inject(PatchDB<DataModel>)
.watch$('package-data')
.pipe(
map(pkgs => Object.values(pkgs)),

View File

@@ -17,7 +17,7 @@ export class FilterUpdatesPipe implements PipeTransform {
({ manifest }) =>
this.emver.compare(
manifest.version,
local[manifest.id]?.manifest.version || '', // @TODO this won't work, need old version
local[manifest.id]?.manifest.version, // @TODO this won't work, need old version
) === 1,
)
}

View File

@@ -44,5 +44,6 @@ const routes: Routes = [
NgDompurifyModule,
TuiProgressModule,
],
exports: [FilterUpdatesPipe, InstallProgressPipe],
})
export class UpdatesPageModule {}

View File

@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { PatchDB } from 'patch-db-client'
import { Widget } from 'src/app/services/patch-db/data-model'
import { DataModel, Widget } from 'src/app/services/patch-db/data-model'
import {
POLYMORPHEUS_CONTEXT,
PolymorpheusComponent,
@@ -17,7 +17,7 @@ import { BUILT_IN_WIDGETS } from '../widgets'
export class AddWidgetComponent {
readonly context = inject<TuiDialogContext<Widget>>(POLYMORPHEUS_CONTEXT)
readonly installed$ = inject(PatchDB).watch$('ui', 'widgets')
readonly installed$ = inject(PatchDB<DataModel>).watch$('ui', 'widgets')
readonly widgets = BUILT_IN_WIDGETS

View File

@@ -1,7 +1,10 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { PatchDB } from 'patch-db-client'
import { map } from 'rxjs'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import {
DataModel,
PackageDataEntry,
} from 'src/app/services/patch-db/data-model'
import { PrimaryStatus } from 'src/app/services/pkg-status-rendering.service'
import { getPackageInfo } from 'src/app/util/get-package-info'
import { PkgInfo } from 'src/app/types/pkg-info'
@@ -21,7 +24,7 @@ export class HealthComponent {
'Transitioning',
] as const
readonly data$ = inject(PatchDB)
readonly data$ = inject(PatchDB<DataModel>)
.watch$('package-data')
.pipe(
map(data => {

View File

@@ -111,7 +111,19 @@ export const mockPatchData: DataModel = {
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
},
'package-data': {
bitcoind: Mock.bitcoind,
lnd: Mock.lnd,
bitcoind: {
...Mock.bitcoind,
manifest: {
...Mock.bitcoind.manifest,
version: '0.19.0',
},
},
lnd: {
...Mock.lnd,
manifest: {
...Mock.lnd.manifest,
version: '0.11.0',
},
},
},
}