mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
remove recovered services and drop reordering feature (#1829)
This commit is contained in:
committed by
Aiden McClelland
parent
35b220d7a5
commit
2ddd38796d
@@ -88,7 +88,10 @@ export class FilterPackagesPipe implements PipeTransform {
|
||||
return packages
|
||||
.filter(p => category === 'all' || p.categories.includes(category))
|
||||
.sort((a, b) => {
|
||||
return a['published-at'] > b['published-at'] ? -1 : 1
|
||||
return (
|
||||
new Date(b['published-at']).valueOf() -
|
||||
new Date(a['published-at']).valueOf()
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
<ion-note></ion-note>
|
||||
<ion-progress-bar></ion-progress-bar>
|
||||
<ion-radio></ion-radio>
|
||||
<ion-reorder></ion-reorder>
|
||||
<ion-row></ion-row>
|
||||
<ion-searchbar></ion-searchbar>
|
||||
<ion-segment></ion-segment>
|
||||
|
||||
@@ -71,7 +71,6 @@ const ICONS = [
|
||||
'remove',
|
||||
'remove-circle-outline',
|
||||
'remove-outline',
|
||||
'reorder-three',
|
||||
'rocket-outline',
|
||||
'save-outline',
|
||||
'shield-checkmark-outline',
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<ion-item>
|
||||
<ion-thumbnail slot="start">
|
||||
<img alt="" [src]="rec.icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h2>{{ rec.title }}</h2>
|
||||
<p>{{ rec.version | displayEmver }}</p>
|
||||
</ion-label>
|
||||
<ion-spinner *ngIf="loading$ | async; else actions"></ion-spinner>
|
||||
<ng-template #actions>
|
||||
<div slot="end">
|
||||
<ion-button fill="clear" color="danger" (click)="deleteRecovered(rec)">
|
||||
<ion-icon slot="icon-only" name="trash-outline"></ion-icon>
|
||||
<!-- Remove -->
|
||||
</ion-button>
|
||||
<ion-button fill="clear" color="success" (click)="install$.next(rec)">
|
||||
<ion-icon slot="icon-only" name="download-outline"></ion-icon>
|
||||
<!-- Install -->
|
||||
</ion-button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ion-item>
|
||||
@@ -1,110 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Inject,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { AlertController } from '@ionic/angular'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { from, merge, OperatorFunction, pipe, Subject } from 'rxjs'
|
||||
import { catchError, map, startWith, switchMap, tap } from 'rxjs/operators'
|
||||
import { RecoveredInfo } from 'src/app/util/parse-data-model'
|
||||
import { MarketplaceService } from 'src/app/services/marketplace.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-rec',
|
||||
templateUrl: 'app-list-rec.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AppListRecComponent {
|
||||
// Asynchronous actions initiators
|
||||
readonly install$ = new Subject<RecoveredInfo>()
|
||||
readonly delete$ = new Subject<RecoveredInfo>()
|
||||
|
||||
@Input()
|
||||
rec!: RecoveredInfo
|
||||
|
||||
@Output()
|
||||
readonly deleted = new EventEmitter<void>()
|
||||
|
||||
// Installing package
|
||||
readonly installing$ = this.install$.pipe(
|
||||
switchMap(({ id, version }) =>
|
||||
// Mapping each installation to API request
|
||||
this.marketplaceService
|
||||
.installPackage({
|
||||
id,
|
||||
'version-spec': `>=${version}`,
|
||||
'version-priority': 'min',
|
||||
})
|
||||
.pipe(
|
||||
// Mapping operation to true/false loading indication
|
||||
loading(this.errToast),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Deleting package
|
||||
readonly deleting$ = this.delete$.pipe(
|
||||
switchMap(({ id }) =>
|
||||
// Mapping each deletion to API request
|
||||
from(this.api.deleteRecoveredPackage({ id })).pipe(
|
||||
// Notifying parent component that package is removed from recovered items
|
||||
tap(() => this.deleted.emit()),
|
||||
// Mapping operation to true/false loading indication
|
||||
loading(this.errToast),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Merging both true/false loading indicators to a single stream
|
||||
readonly loading$ = merge(this.installing$, this.deleting$)
|
||||
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly alertCtrl: AlertController,
|
||||
@Inject(AbstractMarketplaceService)
|
||||
private readonly marketplaceService: MarketplaceService,
|
||||
) {}
|
||||
|
||||
async deleteRecovered(pkg: RecoveredInfo): Promise<void> {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Delete Data',
|
||||
message: `This action will permanently delete all data associated with ${pkg.title}.`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Delete',
|
||||
handler: () => {
|
||||
// Initiate deleting of 'pkg'
|
||||
this.delete$.next(pkg)
|
||||
},
|
||||
cssClass: 'enter-click',
|
||||
},
|
||||
],
|
||||
})
|
||||
await alert.present()
|
||||
}
|
||||
}
|
||||
|
||||
// Custom RxJS operator to turn asynchronous operation into a true/false loading indicator
|
||||
function loading(
|
||||
errToast: ErrorToastService,
|
||||
): OperatorFunction<unknown, boolean> {
|
||||
return pipe(
|
||||
// Show notification on error
|
||||
catchError(e => from(errToast.present(e))),
|
||||
// Map any result to false to stop loading indicator
|
||||
map(() => false),
|
||||
// Start operation with true
|
||||
startWith(true),
|
||||
)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<!-- header -->
|
||||
<ion-item-divider class="ion-padding-bottom">
|
||||
{{ reordering ? 'Reorder' : 'Installed Services' }}
|
||||
<ion-button
|
||||
*ngIf="pkgs.length > 1"
|
||||
slot="end"
|
||||
fill="clear"
|
||||
(click)="toggle()"
|
||||
strong
|
||||
>
|
||||
<ion-icon
|
||||
slot="start"
|
||||
[name]="reordering ? 'checkmark' : 'swap-vertical'"
|
||||
></ion-icon>
|
||||
{{ reordering ? 'Done' : 'Reorder' }}
|
||||
</ion-button>
|
||||
</ion-item-divider>
|
||||
|
||||
<!-- reordering -->
|
||||
<ion-list *ngIf="reordering; else grid">
|
||||
<ion-reorder-group disabled="false" (ionItemReorder)="reorder($any($event))">
|
||||
<ng-container *ngFor="let item of pkgs">
|
||||
<ion-item
|
||||
color="light"
|
||||
*ngIf="item | packageInfo | async as pkg"
|
||||
class="item"
|
||||
>
|
||||
<app-list-icon slot="start" [pkg]="pkg"></app-list-icon>
|
||||
<ion-thumbnail slot="start">
|
||||
<img alt="" [src]="pkg.entry['static-files'].icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h2>{{ pkg.entry.manifest.title }}</h2>
|
||||
<p>{{ pkg.entry.manifest.version | displayEmver }}</p>
|
||||
<status
|
||||
[rendering]="pkg.primaryRendering"
|
||||
[installProgress]="pkg.entry['install-progress']"
|
||||
weight="bold"
|
||||
size="small"
|
||||
[sigtermTimeout]="pkg.entry.manifest.main['sigterm-timeout']"
|
||||
></status>
|
||||
</ion-label>
|
||||
<ion-reorder slot="end">
|
||||
<ion-icon name="reorder-three" size="large"></ion-icon>
|
||||
</ion-reorder>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-reorder-group>
|
||||
</ion-list>
|
||||
|
||||
<!-- not reordering -->
|
||||
<ng-template #grid>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs" sizeXs="12" sizeXl="6">
|
||||
<app-list-pkg
|
||||
*ngIf="pkg | packageInfo | async as info"
|
||||
[pkg]="info"
|
||||
></app-list-pkg>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-template>
|
||||
@@ -1,3 +0,0 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { ItemReorderEventDetail } from '@ionic/core'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-reorder',
|
||||
templateUrl: 'app-list-reorder.component.html',
|
||||
styleUrls: ['app-list-reorder.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AppListReorderComponent {
|
||||
@Input()
|
||||
reordering = false
|
||||
|
||||
@Input()
|
||||
pkgs: readonly PackageDataEntry[] = []
|
||||
|
||||
@Output()
|
||||
readonly reorderingChange = new EventEmitter<boolean>()
|
||||
|
||||
@Output()
|
||||
readonly pkgsChange = new EventEmitter<readonly PackageDataEntry[]>()
|
||||
|
||||
toggle() {
|
||||
this.reordering = !this.reordering
|
||||
this.reorderingChange.emit(this.reordering)
|
||||
}
|
||||
|
||||
reorder({ detail }: CustomEvent<ItemReorderEventDetail>): void {
|
||||
this.pkgs = detail.complete([...this.pkgs])
|
||||
this.pkgsChange.emit(this.pkgs)
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,6 @@ import { UiPipeModule } from 'src/app/pipes/ui/ui.module'
|
||||
import { AppListIconComponent } from './app-list-icon/app-list-icon.component'
|
||||
import { AppListEmptyComponent } from './app-list-empty/app-list-empty.component'
|
||||
import { AppListPkgComponent } from './app-list-pkg/app-list-pkg.component'
|
||||
import { AppListRecComponent } from './app-list-rec/app-list-rec.component'
|
||||
import { AppListReorderComponent } from './app-list-reorder/app-list-reorder.component'
|
||||
import { PackageInfoPipe } from './package-info.pipe'
|
||||
|
||||
const routes: Routes = [
|
||||
@@ -42,8 +40,6 @@ const routes: Routes = [
|
||||
AppListIconComponent,
|
||||
AppListEmptyComponent,
|
||||
AppListPkgComponent,
|
||||
AppListRecComponent,
|
||||
AppListReorderComponent,
|
||||
PackageInfoPipe,
|
||||
],
|
||||
})
|
||||
|
||||
@@ -21,23 +21,20 @@
|
||||
></app-list-empty>
|
||||
|
||||
<ng-template #list>
|
||||
<app-list-reorder
|
||||
*ngIf="pkgs.length"
|
||||
[(pkgs)]="pkgs"
|
||||
[reordering]="reordering"
|
||||
(reorderingChange)="onReordering($event)"
|
||||
></app-list-reorder>
|
||||
<ion-item-divider class="ion-padding-bottom"
|
||||
>Installed Services</ion-item-divider
|
||||
>
|
||||
|
||||
<ng-container *ngIf="recoveredPkgs.length && !reordering">
|
||||
<ion-item-group>
|
||||
<ion-item-divider>Recovered Services</ion-item-divider>
|
||||
<app-list-rec
|
||||
*ngFor="let rec of recoveredPkgs"
|
||||
[rec]="rec"
|
||||
(deleted)="deleteRecovered(rec)"
|
||||
></app-list-rec>
|
||||
</ion-item-group>
|
||||
</ng-container>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs" sizeSm="12" sizeLg="6">
|
||||
<app-list-pkg
|
||||
*ngIf="pkg | packageInfo | async as info"
|
||||
[pkg]="info"
|
||||
></app-list-pkg>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
ion-item-divider {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { Observable } from 'rxjs'
|
||||
import { filter, map, switchMap, take, takeUntil, tap } from 'rxjs/operators'
|
||||
import { isEmptyObject, exists, DestroyService } from '@start9labs/shared'
|
||||
import { filter, takeUntil, tap } from 'rxjs/operators'
|
||||
import { DestroyService } from '@start9labs/shared'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { parseDataModel, RecoveredInfo } from 'src/app/util/parse-data-model'
|
||||
|
||||
@Component({
|
||||
selector: 'app-list',
|
||||
@@ -19,8 +17,6 @@ import { parseDataModel, RecoveredInfo } from 'src/app/util/parse-data-model'
|
||||
export class AppListPage {
|
||||
loading = true
|
||||
pkgs: readonly PackageDataEntry[] = []
|
||||
recoveredPkgs: readonly RecoveredInfo[] = []
|
||||
reordering = false
|
||||
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
@@ -29,62 +25,22 @@ export class AppListPage {
|
||||
) {}
|
||||
|
||||
get empty(): boolean {
|
||||
return !this.pkgs.length && isEmptyObject(this.recoveredPkgs)
|
||||
return !this.pkgs.length
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.patch
|
||||
.watch$()
|
||||
.watch$('package-data')
|
||||
.pipe(
|
||||
filter(data => exists(data) && !isEmptyObject(data)),
|
||||
take(1),
|
||||
map(parseDataModel),
|
||||
tap(({ pkgs, recoveredPkgs }) => {
|
||||
filter(pkgs => Object.keys(pkgs).length !== this.pkgs.length),
|
||||
tap(pkgs => {
|
||||
this.loading = false
|
||||
this.pkgs = pkgs
|
||||
this.recoveredPkgs = recoveredPkgs
|
||||
this.pkgs = Object.values(pkgs).sort((a, b) =>
|
||||
b.manifest.title > a.manifest.title ? -1 : 1,
|
||||
)
|
||||
}),
|
||||
switchMap(() => this.watchNewlyRecovered()),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
onReordering(reordering: boolean): void {
|
||||
if (!reordering) {
|
||||
this.setOrder()
|
||||
}
|
||||
|
||||
this.reordering = reordering
|
||||
}
|
||||
|
||||
deleteRecovered(rec: RecoveredInfo): void {
|
||||
this.recoveredPkgs = this.recoveredPkgs.filter(item => item !== rec)
|
||||
}
|
||||
|
||||
private watchNewlyRecovered(): Observable<unknown> {
|
||||
return this.patch.watch$('package-data').pipe(
|
||||
filter(pkgs => !!pkgs && Object.keys(pkgs).length !== this.pkgs.length),
|
||||
tap(pkgs => {
|
||||
const ids = Object.keys(pkgs)
|
||||
const newIds = ids.filter(
|
||||
id => !this.pkgs.find(pkg => pkg.manifest.id === id),
|
||||
)
|
||||
|
||||
// remove uninstalled
|
||||
const filtered = this.pkgs.filter(pkg => ids.includes(pkg.manifest.id))
|
||||
|
||||
// add new entry to beginning of array
|
||||
const added = newIds.map(id => pkgs[id])
|
||||
|
||||
this.pkgs = [...added, ...filtered]
|
||||
this.recoveredPkgs = this.recoveredPkgs.filter(rec => !pkgs[rec.id])
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
private setOrder(): void {
|
||||
const order = this.pkgs.map(pkg => pkg.manifest.id)
|
||||
this.api.setDbValue({ pointer: '/pkg-order', value: order })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ import { ActivatedRoute } from '@angular/router'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { ServerNameService } from 'src/app/services/server-name.service'
|
||||
import { Observable, of } from 'rxjs'
|
||||
import { take, tap } from 'rxjs/operators'
|
||||
import { isEmptyObject, ErrorToastService } from '@start9labs/shared'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { EOSService } from 'src/app/services/eos.service'
|
||||
import { LocalStorageService } from 'src/app/services/local-storage.service'
|
||||
import { OSUpdatePage } from 'src/app/modals/os-update/os-update.page'
|
||||
@@ -25,7 +24,6 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
styleUrls: ['server-show.page.scss'],
|
||||
})
|
||||
export class ServerShowPage {
|
||||
hasRecoveredPackage = false
|
||||
clicks = 0
|
||||
|
||||
readonly server$ = this.patch.watch$('server-info')
|
||||
@@ -48,34 +46,14 @@ export class ServerShowPage {
|
||||
private readonly authService: AuthService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.patch
|
||||
.watch$('recovered-packages')
|
||||
.pipe(
|
||||
take(1),
|
||||
tap(data => (this.hasRecoveredPackage = !isEmptyObject(data))),
|
||||
)
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
async updateEos(): Promise<void> {
|
||||
if (this.hasRecoveredPackage) {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Cannot Update',
|
||||
message:
|
||||
'You cannot update embassyOS when you have unresolved recovered services.',
|
||||
buttons: ['OK'],
|
||||
})
|
||||
await alert.present()
|
||||
} else {
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: {
|
||||
releaseNotes: this.eosService.eos?.['release-notes'],
|
||||
},
|
||||
component: OSUpdatePage,
|
||||
})
|
||||
modal.present()
|
||||
}
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: {
|
||||
releaseNotes: this.eosService.eos?.['release-notes'],
|
||||
},
|
||||
component: OSUpdatePage,
|
||||
})
|
||||
modal.present()
|
||||
}
|
||||
|
||||
async presentAlertLogout() {
|
||||
|
||||
@@ -749,7 +749,7 @@ export module Mock {
|
||||
icon: PROXY_ICON,
|
||||
},
|
||||
},
|
||||
'published-at': new Date().toISOString(),
|
||||
'published-at': new Date(new Date().valueOf() + 10).toISOString(),
|
||||
},
|
||||
},
|
||||
'btc-rpc-proxy': {
|
||||
|
||||
@@ -223,9 +223,6 @@ export module RR {
|
||||
export type UninstallPackageReq = { id: string } // package.uninstall
|
||||
export type UninstallPackageRes = null
|
||||
|
||||
export type DeleteRecoveredPackageReq = { id: string } // package.delete-recovered
|
||||
export type DeleteRecoveredPackageRes = null
|
||||
|
||||
export type DryConfigureDependencyReq = {
|
||||
'dependency-id': string
|
||||
'dependent-id': string
|
||||
|
||||
@@ -216,10 +216,6 @@ export abstract class ApiService {
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes>
|
||||
|
||||
abstract deleteRecoveredPackage(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes>
|
||||
|
||||
abstract sideloadPackage(
|
||||
params: RR.SideloadPackageReq,
|
||||
): Promise<RR.SideloadPacakgeRes>
|
||||
|
||||
@@ -364,12 +364,6 @@ export class LiveApiService extends ApiService {
|
||||
return this.rpcRequest({ method: 'package.stop', params })
|
||||
}
|
||||
|
||||
async deleteRecoveredPackage(
|
||||
params: RR.DeleteRecoveredPackageReq,
|
||||
): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
return this.rpcRequest({ method: 'package.delete-recovered', params })
|
||||
}
|
||||
|
||||
async uninstallPackage(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
|
||||
@@ -814,19 +814,6 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async deleteRecoveredPackage(
|
||||
params: RR.DeleteRecoveredPackageReq,
|
||||
): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
await pauseFor(2000)
|
||||
const patch: RemoveOperation[] = [
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/recovered-packages/${params.id}`,
|
||||
},
|
||||
]
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryConfigureDependency(
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes> {
|
||||
@@ -892,10 +879,6 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/package-data/${id}/install-progress`,
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/recovered-packages/${id}`,
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch2)
|
||||
}, 1000)
|
||||
|
||||
@@ -50,13 +50,6 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
hostname: 'random-words',
|
||||
},
|
||||
'recovered-packages': {
|
||||
'btc-rpc-proxy': {
|
||||
title: 'Bitcoin Proxy',
|
||||
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
||||
version: '0.2.2',
|
||||
},
|
||||
},
|
||||
'package-data': {
|
||||
bitcoind: {
|
||||
state: PackageState.Installed,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { BasicInfo } from 'src/app/pages/developer-routes/developer-menu/form-in
|
||||
export interface DataModel {
|
||||
'server-info': ServerInfo
|
||||
'package-data': { [id: string]: PackageDataEntry }
|
||||
'recovered-packages': { [id: string]: RecoveredPackageDataEntry }
|
||||
ui: UIData
|
||||
}
|
||||
|
||||
@@ -75,11 +74,6 @@ export enum ServerStatus {
|
||||
Updated = 'updated',
|
||||
BackingUp = 'backing-up',
|
||||
}
|
||||
export interface RecoveredPackageDataEntry {
|
||||
title: string
|
||||
icon: Url
|
||||
version: string
|
||||
}
|
||||
|
||||
export interface PackageDataEntry {
|
||||
state: PackageState
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
RecoveredPackageDataEntry,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export function parseDataModel(data: DataModel): ParsedData {
|
||||
const all: Record<string, PackageDataEntry> = JSON.parse(
|
||||
JSON.stringify(data['package-data']),
|
||||
)
|
||||
|
||||
// recovered packages (0.2.x)
|
||||
const recoveredPkgs = Object.entries(data['recovered-packages'])
|
||||
.filter(([id, _]) => !all[id])
|
||||
.map(([id, val]) => ({
|
||||
...val,
|
||||
id,
|
||||
}))
|
||||
|
||||
// installed packages
|
||||
const order = [...(data.ui['pkg-order'] || [])]
|
||||
const pkgs: PackageDataEntry[] = []
|
||||
// add known packages in preferential order
|
||||
order.forEach(id => {
|
||||
if (all[id]) {
|
||||
pkgs.push(all[id])
|
||||
|
||||
delete all[id]
|
||||
}
|
||||
})
|
||||
|
||||
// unshift unknown packages
|
||||
Object.values(all).forEach(pkg => {
|
||||
pkgs.unshift(pkg)
|
||||
})
|
||||
|
||||
return {
|
||||
pkgs,
|
||||
recoveredPkgs,
|
||||
}
|
||||
}
|
||||
|
||||
export interface RecoveredInfo extends RecoveredPackageDataEntry {
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ParsedData {
|
||||
pkgs: PackageDataEntry[]
|
||||
recoveredPkgs: RecoveredInfo[]
|
||||
}
|
||||
Reference in New Issue
Block a user