mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
fix marketplace dependency show and chaching
This commit is contained in:
committed by
Aiden McClelland
parent
a3e307dd38
commit
d92bccdc45
@@ -68,7 +68,7 @@
|
|||||||
<ion-icon name="arrow-up"></ion-icon>
|
<ion-icon name="arrow-up"></ion-icon>
|
||||||
<ion-icon name="briefcase-outline"></ion-icon>
|
<ion-icon name="briefcase-outline"></ion-icon>
|
||||||
<ion-icon name="bookmark-outline"></ion-icon>
|
<ion-icon name="bookmark-outline"></ion-icon>
|
||||||
<ion-icon name="checkmark-outline"></ion-icon>
|
<ion-icon name="checkmark"></ion-icon>
|
||||||
<ion-icon name="chevron-down"></ion-icon>
|
<ion-icon name="chevron-down"></ion-icon>
|
||||||
<ion-icon name="chevron-up"></ion-icon>
|
<ion-icon name="chevron-up"></ion-icon>
|
||||||
<ion-icon name="chevron-forward"></ion-icon> <!-- needed for detail="true" on ion-item button -->
|
<ion-icon name="chevron-forward"></ion-icon> <!-- needed for detail="true" on ion-item button -->
|
||||||
@@ -106,8 +106,8 @@
|
|||||||
<ion-icon name="qr-code-outline"></ion-icon>
|
<ion-icon name="qr-code-outline"></ion-icon>
|
||||||
<ion-icon name="receipt-outline"></ion-icon>
|
<ion-icon name="receipt-outline"></ion-icon>
|
||||||
<ion-icon name="refresh"></ion-icon>
|
<ion-icon name="refresh"></ion-icon>
|
||||||
<ion-icon name="reload-outline"></ion-icon>
|
<ion-icon name="reload"></ion-icon>
|
||||||
<ion-icon name="remove-outline"></ion-icon>
|
<ion-icon name="remove"></ion-icon>
|
||||||
<ion-icon name="save-outline"></ion-icon>
|
<ion-icon name="save-outline"></ion-icon>
|
||||||
<ion-icon name="shield-checkmark-outline"></ion-icon>
|
<ion-icon name="shield-checkmark-outline"></ion-icon>
|
||||||
<ion-icon name="storefront-outline"></ion-icon>
|
<ion-icon name="storefront-outline"></ion-icon>
|
||||||
|
|||||||
@@ -63,13 +63,13 @@
|
|||||||
<ion-item *ngFor="let health of healthChecks | keyvalue : asIsOrder">
|
<ion-item *ngFor="let health of healthChecks | keyvalue : asIsOrder">
|
||||||
<ng-container *ngIf="$any(health.value).result as result">
|
<ng-container *ngIf="$any(health.value).result as result">
|
||||||
<ion-spinner class="icon-spinner" color="warning" slot="start" *ngIf="['starting', 'loading'] | includes : result"></ion-spinner>
|
<ion-spinner class="icon-spinner" color="warning" slot="start" *ngIf="['starting', 'loading'] | includes : result"></ion-spinner>
|
||||||
<ion-icon slot="start" *ngIf="result === 'success'" name="checkmark-outline" color="success"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === 'success'" name="checkmark" color="success"></ion-icon>
|
||||||
<ion-icon slot="start" *ngIf="result === 'failure'" name="close" color="danger"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === 'failure'" name="warning" color="warning"></ion-icon>
|
||||||
<ion-icon slot="start" *ngIf="result === 'disabled'" name="remove-outline" color="dark"></ion-icon>
|
<ion-icon slot="start" *ngIf="result === 'disabled'" name="remove" color="dark"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p>{{ health.key }}</p>
|
<h2 style="font-weight: bold;">{{ health.key }}</h2>
|
||||||
<h2>{{ result }}</h2>
|
<h2>Result: {{ result | titlecase }}</h2>
|
||||||
<p *ngIf="result === 'failure'"><ion-text color="danger">{{ $any(health.value).error }}</ion-text></p>
|
<p *ngIf="result === 'failure'"><ion-text color="warning">{{ $any(health.value).error }}</ion-text></p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
@@ -84,9 +84,14 @@
|
|||||||
<img [src]="dep.value.icon" />
|
<img [src]="dep.value.icon" />
|
||||||
</ion-thumbnail>
|
</ion-thumbnail>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2 style="font-family: 'Montserrat'">{{ dep.value.title }}</h2>
|
<h2 class="inline" style="font-family: 'Montserrat'">
|
||||||
|
<ion-icon *ngIf="!!dep.value.errorText" slot="start" name="warning" color="warning"></ion-icon>
|
||||||
|
{{ dep.value.title }}
|
||||||
|
</h2>
|
||||||
<p>{{ dep.value.version | displayEmver }}</p>
|
<p>{{ dep.value.version | displayEmver }}</p>
|
||||||
<p><ion-text [color]="!!dep.value.errorText ? 'warning' : 'success'">{{ dep.value.errorText || 'satisfied' }}</ion-text></p>
|
<p>
|
||||||
|
<ion-text [color]="!!dep.value.errorText ? 'warning' : 'success'">{{ dep.value.errorText || 'satisfied' }}</ion-text>
|
||||||
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-spinner *ngIf="dep.value.spinnerColor" slot="end" [color]="dep.value.spinnerColor" style="height: 3vh; width: 3vh"></ion-spinner>
|
<ion-spinner *ngIf="dep.value.spinnerColor" slot="end" [color]="dep.value.spinnerColor" style="height: 3vh; width: 3vh"></ion-spinner>
|
||||||
<ion-button *ngIf="dep.value.actionText" slot="end" fill="clear">
|
<ion-button *ngIf="dep.value.actionText" slot="end" fill="clear">
|
||||||
|
|||||||
@@ -11,4 +11,14 @@
|
|||||||
.icon-spinner {
|
.icon-spinner {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
* {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
ion-icon {
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -391,7 +391,7 @@ export class AppShowPage {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: () => this.donate(),
|
action: () => this.donate(),
|
||||||
title: `Donate to ${this.pkg.manifest.title}`,
|
title: 'Donate',
|
||||||
icon: 'logo-bitcoin',
|
icon: 'logo-bitcoin',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -24,15 +24,19 @@ export class AppReleaseNotes {
|
|||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||||
try {
|
try {
|
||||||
|
const promises = []
|
||||||
if (!this.marketplaceService.releaseNotes[this.pkgId]) {
|
if (!this.marketplaceService.releaseNotes[this.pkgId]) {
|
||||||
await this.marketplaceService.getReleaseNotes(this.pkgId)
|
promises.push(this.marketplaceService.getReleaseNotes(this.pkgId))
|
||||||
}
|
}
|
||||||
|
if (!this.marketplaceService.pkgs.length) {
|
||||||
|
promises.push(this.marketplaceService.load())
|
||||||
|
}
|
||||||
|
await Promise.all(promises)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errToast.present(e)
|
this.errToast.present(e)
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit () {
|
ngAfterViewInit () {
|
||||||
|
|||||||
@@ -11,19 +11,22 @@
|
|||||||
|
|
||||||
<ion-grid style="padding-bottom: 32px;">
|
<ion-grid style="padding-bottom: 32px;">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col sizeMd="6" offset-md="3">
|
<ion-col sizeSm="8" offset-sm="2">
|
||||||
<ion-toolbar color="transparent">
|
<ion-toolbar color="transparent">
|
||||||
<ion-searchbar enterkeyhint="search" color="dark" (keyup.enter)="search()" debounce="300" [(ngModel)]="query"></ion-searchbar>
|
<ion-searchbar
|
||||||
<ion-button style="height: 42px;" slot="end" color="primary" fill="solid" (click)="search()">
|
enterkeyhint="search"
|
||||||
<ion-icon slot="icon-only" name="search-outline"></ion-icon>
|
color="dark"
|
||||||
</ion-button>
|
debounce="250"
|
||||||
|
[(ngModel)]="query"
|
||||||
|
(ionChange)="search()"
|
||||||
|
></ion-searchbar>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
</ion-grid>
|
</ion-grid>
|
||||||
|
|
||||||
<!-- page loading -->
|
<!-- loading -->
|
||||||
<ng-container *ngIf="pageLoading; else pageLoaded">
|
<ng-container *ngIf="loading; else pageLoaded">
|
||||||
<div class="scrollable ion-text-center">
|
<div class="scrollable ion-text-center">
|
||||||
<ion-button *ngFor="let cat of ['', '', '', '', '', '', '']" fill="clear">
|
<ion-button *ngFor="let cat of ['', '', '', '', '', '', '']" fill="clear">
|
||||||
<ion-skeleton-text animated style="width: 80px; border-radius: 0;"></ion-skeleton-text>
|
<ion-skeleton-text animated style="width: 80px; border-radius: 0;"></ion-skeleton-text>
|
||||||
@@ -33,11 +36,11 @@
|
|||||||
<div class="divider" style="margin: 24px 0;"></div>
|
<div class="divider" style="margin: 24px 0;"></div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- page loaded -->
|
<!-- loaded -->
|
||||||
<ng-template #pageLoaded>
|
<ng-template #pageLoaded>
|
||||||
<div class="scrollable ion-text-center">
|
<div class="scrollable ion-text-center">
|
||||||
<ion-button
|
<ion-button
|
||||||
*ngFor="let cat of data.categories"
|
*ngFor="let cat of categories"
|
||||||
fill="clear"
|
fill="clear"
|
||||||
[class]="cat === category ? 'selected' : 'dim'"
|
[class]="cat === category ? 'selected' : 'dim'"
|
||||||
(click)="switchCategory(cat)"
|
(click)="switchCategory(cat)"
|
||||||
@@ -49,8 +52,8 @@
|
|||||||
<div class="divider" style="margin: 24px;"></div>
|
<div class="divider" style="margin: 24px;"></div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<!-- packages loading -->
|
<!-- loading -->
|
||||||
<ng-container *ngIf="pkgsLoading; else pkgsLoaded">
|
<ng-container *ngIf="loading; else pkgsLoaded">
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let pkg of ['', '', '', '']" sizeXs="12" sizeSm="12" sizeMd="6">
|
<ion-col *ngFor="let pkg of ['', '', '', '']" sizeXs="12" sizeSm="12" sizeMd="6">
|
||||||
@@ -73,15 +76,15 @@
|
|||||||
<ng-template #pkgsLoaded>
|
<ng-template #pkgsLoaded>
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngIf="eos && category === 'featured'" sizeXs="12" sizeSm="12" sizeMd="6">
|
<ion-col *ngIf="marketplaceService.eos && category === 'featured'" sizeXs="12" sizeSm="12" sizeMd="6">
|
||||||
<ion-item button class="eos-item" (click)="updateEos()">
|
<ion-item button class="eos-item" (click)="updateEos()">
|
||||||
<ion-thumbnail slot="start">
|
<ion-thumbnail slot="start">
|
||||||
<img src="assets/img/icon.png" />
|
<img src="assets/img/icon.png" />
|
||||||
</ion-thumbnail>
|
</ion-thumbnail>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h3>Now Available...</h3>
|
<h3>Now Available...</h3>
|
||||||
<h2>Embassy OS {{ eos.version }}</h2>
|
<h2>Embassy OS {{ marketplaceService.eos.version }}</h2>
|
||||||
<p>{{ eos.headline }}</p>
|
<p>{{ marketplaceService.eos.headline }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, ViewChild } from '@angular/core'
|
import { Component, ViewChild } from '@angular/core'
|
||||||
import { MarketplaceData, MarketplaceEOS, MarketplacePkg } from 'src/app/services/api/api.types'
|
import { MarketplacePkg } from 'src/app/services/api/api.types'
|
||||||
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
||||||
import { IonContent, ModalController } from '@ionic/angular'
|
import { IonContent, ModalController } from '@ionic/angular'
|
||||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||||
@@ -7,9 +7,7 @@ import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-m
|
|||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||||
import { MarketplaceService } from '../marketplace.service'
|
import { MarketplaceService } from '../marketplace.service'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
|
||||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { pauseFor } from 'src/app/util/misc.util'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-list',
|
selector: 'marketplace-list',
|
||||||
@@ -17,30 +15,25 @@ import { pauseFor } from 'src/app/util/misc.util'
|
|||||||
styleUrls: ['./marketplace-list.page.scss'],
|
styleUrls: ['./marketplace-list.page.scss'],
|
||||||
})
|
})
|
||||||
export class MarketplaceListPage {
|
export class MarketplaceListPage {
|
||||||
|
PackageState = PackageState
|
||||||
|
|
||||||
@ViewChild(IonContent) content: IonContent
|
@ViewChild(IonContent) content: IonContent
|
||||||
|
|
||||||
|
pkgs: MarketplacePkg[] = []
|
||||||
|
categories: string[]
|
||||||
localPkgs: { [id: string]: PackageDataEntry } = { }
|
localPkgs: { [id: string]: PackageDataEntry } = { }
|
||||||
|
|
||||||
pageLoading = true
|
|
||||||
pkgsLoading = true
|
|
||||||
|
|
||||||
category = 'featured'
|
category = 'featured'
|
||||||
query: string
|
query: string
|
||||||
|
loading = true
|
||||||
data: MarketplaceData
|
|
||||||
eos: MarketplaceEOS
|
|
||||||
pkgs: MarketplacePkg[] = []
|
|
||||||
|
|
||||||
PackageState = PackageState
|
|
||||||
|
|
||||||
subs: Subscription[] = []
|
subs: Subscription[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly marketplaceService: MarketplaceService,
|
|
||||||
private readonly api: ApiService,
|
|
||||||
private readonly modalCtrl: ModalController,
|
private readonly modalCtrl: ModalController,
|
||||||
private readonly errToast: ErrorToastService,
|
private readonly errToast: ErrorToastService,
|
||||||
private readonly wizardBaker: WizardBaker,
|
private readonly wizardBaker: WizardBaker,
|
||||||
public readonly patch: PatchDbService,
|
private readonly patch: PatchDbService,
|
||||||
|
public readonly marketplaceService: MarketplaceService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
@@ -54,26 +47,21 @@ export class MarketplaceListPage {
|
|||||||
]
|
]
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [data, eos] = await Promise.all([
|
if (!this.marketplaceService.pkgs.length) {
|
||||||
this.api.getMarketplaceData({ }),
|
await this.marketplaceService.load()
|
||||||
this.api.getEos({ }),
|
}
|
||||||
this.marketplaceService.getAllPkgs(),
|
|
||||||
])
|
|
||||||
this.eos = eos
|
|
||||||
this.data = data
|
|
||||||
|
|
||||||
this.pkgsLoading = false
|
|
||||||
this.getPkgs()
|
|
||||||
|
|
||||||
// category should start as first item in array
|
// category should start as first item in array
|
||||||
// remove here then add at beginning
|
// remove here then add at beginning
|
||||||
const filterdCategories = this.data.categories.filter(cat => this.category !== cat)
|
const filterdCategories = this.marketplaceService.data.categories.filter(cat => this.category !== cat)
|
||||||
this.data.categories = [this.category, 'updates'].concat(filterdCategories).concat(['all'])
|
this.categories = [this.category, 'updates'].concat(filterdCategories).concat(['all'])
|
||||||
|
|
||||||
|
this.filterPkgs()
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.errToast.present(e)
|
this.errToast.present(e)
|
||||||
} finally {
|
} finally {
|
||||||
this.pageLoading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,35 +74,44 @@ export class MarketplaceListPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async search (): Promise<void> {
|
async search (): Promise<void> {
|
||||||
// you can actually press enter and run code before the data binds to this.category
|
|
||||||
await pauseFor(200)
|
|
||||||
this.category = undefined
|
this.category = undefined
|
||||||
await this.getPkgs()
|
await this.filterPkgs()
|
||||||
|
}
|
||||||
|
|
||||||
|
async switchCategory (category: string): Promise<void> {
|
||||||
|
this.category = category
|
||||||
|
this.query = undefined
|
||||||
|
this.filterPkgs()
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateEos (): Promise<void> {
|
async updateEos (): Promise<void> {
|
||||||
|
const { version, headline, 'release-notes': releaseNotes } = this.marketplaceService.eos
|
||||||
|
|
||||||
await wizardModal(
|
await wizardModal(
|
||||||
this.modalCtrl,
|
this.modalCtrl,
|
||||||
this.wizardBaker.updateOS({
|
this.wizardBaker.updateOS({
|
||||||
version: this.eos.version,
|
version,
|
||||||
headline: this.eos.headline,
|
headline,
|
||||||
releaseNotes: this.eos['release-notes'],
|
releaseNotes,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getPkgs (): Promise<void> {
|
private async filterPkgs (): Promise<void> {
|
||||||
if (this.category === 'updates') {
|
if (this.category === 'updates') {
|
||||||
this.pkgs = this.marketplaceService.allPkgs.filter(pkg => {
|
this.pkgs = this.marketplaceService.pkgs.filter(pkg => {
|
||||||
return this.localPkgs[pkg.manifest.id] && pkg.manifest.version !== this.localPkgs[pkg.manifest.id].manifest.version
|
const { id, version } = pkg.manifest
|
||||||
|
return this.localPkgs[id] && version !== this.localPkgs[id].manifest.version
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.pkgs = this.marketplaceService.allPkgs.filter(pkg => {
|
this.pkgs = this.marketplaceService.pkgs.filter(pkg => {
|
||||||
|
const { id, title, description } = pkg.manifest
|
||||||
if (this.query) {
|
if (this.query) {
|
||||||
return pkg.manifest.id.toUpperCase().includes(this.query.toUpperCase()) ||
|
const query = this.query.toUpperCase()
|
||||||
pkg.manifest.title.toUpperCase().includes(this.query.toUpperCase()) ||
|
return id.toUpperCase().includes(query) ||
|
||||||
pkg.manifest.description.short.toUpperCase().includes(this.query.toUpperCase()) ||
|
title.toUpperCase().includes(query) ||
|
||||||
pkg.manifest.description.long.toUpperCase().includes(this.query.toUpperCase())
|
description.short.toUpperCase().includes(query) ||
|
||||||
|
description.long.toUpperCase().includes(query)
|
||||||
} else {
|
} else {
|
||||||
if (this.category === 'all' || !this.category) {
|
if (this.category === 'all' || !this.category) {
|
||||||
return true
|
return true
|
||||||
@@ -125,10 +122,4 @@ export class MarketplaceListPage {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async switchCategory (category: string): Promise<void> {
|
|
||||||
this.category = category
|
|
||||||
this.query = undefined
|
|
||||||
await this.getPkgs()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,192 +12,190 @@
|
|||||||
<text-spinner *ngIf="loading; else loaded" text="Loading Package"></text-spinner>
|
<text-spinner *ngIf="loading; else loaded" text="Loading Package"></text-spinner>
|
||||||
|
|
||||||
<ng-template #loaded>
|
<ng-template #loaded>
|
||||||
<ng-container *ngIf="marketplaceService.pkgs[pkgId] as pkg">
|
<ion-grid>
|
||||||
<ion-grid>
|
<ion-row>
|
||||||
<ion-row>
|
<ion-col sizeXs="12" sizeSm="12" sizeMd="9" sizeLg="9" sizeXl="9">
|
||||||
<ion-col sizeXs="12" sizeSm="12" sizeMd="9" sizeLg="9" sizeXl="9">
|
<div class="header">
|
||||||
<div class="header">
|
<img [src]="pkg.icon" />
|
||||||
<img [src]="pkg.icon" />
|
<div class="header-text">
|
||||||
<div class="header-text">
|
<h1 class="header-title">{{ pkg.manifest.title }}</h1>
|
||||||
<h1 class="header-title">{{ pkg.manifest.title }}</h1>
|
<p class="header-version">{{ pkg.manifest.version | displayEmver }}</p>
|
||||||
<p class="header-version">{{ pkg.manifest.version | displayEmver }}</p>
|
<div class="header-status">
|
||||||
<div class="header-status">
|
<!-- no localPkg -->
|
||||||
<!-- no localPkg -->
|
<p *ngIf="!localPkg; else local">Not Installed</p>
|
||||||
<p *ngIf="!localPkg; else local">
|
<!-- localPkg -->
|
||||||
Not Installed
|
<ng-template #local>
|
||||||
|
<!-- installed -->
|
||||||
|
<p *ngIf="localPkg.state === PackageState.Installed">
|
||||||
|
<ion-text *ngIf="(pkg.manifest.version | compareEmver : localPkg.manifest.version) === 0" color="success">Installed</ion-text>
|
||||||
|
<ion-text *ngIf="(pkg.manifest.version | compareEmver : localPkg.manifest.version) === 1" color="warning">Update Available</ion-text>
|
||||||
</p>
|
</p>
|
||||||
<!-- localPkg -->
|
<!-- installing, updating -->
|
||||||
<ng-template #local>
|
<p *ngIf="[PackageState.Installing, PackageState.Updating] | includes : localPkg.state">
|
||||||
<!-- installed -->
|
<ion-text color="primary">{{ localPkg.state | titlecase }}...{{ (localPkg['install-progress'] | installState).totalProgress }}%</ion-text>
|
||||||
<p *ngIf="localPkg.state === PackageState.Installed">
|
</p>
|
||||||
<ion-text *ngIf="(pkg.manifest.version | compareEmver : localPkg.manifest.version) === 0" color="success">Installed</ion-text>
|
<!-- removing -->
|
||||||
<ion-text *ngIf="(pkg.manifest.version | compareEmver : localPkg.manifest.version) === 1" color="warning">Update Available</ion-text>
|
<p *ngIf="localPkg.state === PackageState.Removing">
|
||||||
</p>
|
<ion-text color="warning">{{ localPkg.state | titlecase }}</ion-text>
|
||||||
<!-- installing, updating -->
|
<ion-spinner name="dots" color="warning"></ion-spinner>
|
||||||
<p *ngIf="[PackageState.Installing, PackageState.Updating] | includes : localPkg.state">
|
</p>
|
||||||
<ion-text color="primary">{{ localPkg.state | titlecase }}...{{ (localPkg['install-progress'] | installState).totalProgress }}%</ion-text>
|
</ng-template>
|
||||||
</p>
|
|
||||||
<!-- removing -->
|
|
||||||
<p *ngIf="localPkg.state === PackageState.Removing">
|
|
||||||
<ion-text color="warning">{{ localPkg.state | titlecase }}</ion-text>
|
|
||||||
<ion-spinner name="dots" color="warning"></ion-spinner>
|
|
||||||
</p>
|
|
||||||
</ng-template>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ion-col>
|
</div>
|
||||||
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
</ion-col>
|
||||||
<!-- no localPkg -->
|
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
||||||
<ion-button *ngIf="!localPkg" expand="block" (click)="tryInstall()">
|
<!-- no localPkg -->
|
||||||
Install
|
<ion-button *ngIf="!localPkg" expand="block" (click)="tryInstall()">
|
||||||
</ion-button>
|
Install
|
||||||
<!-- localPkg -->
|
</ion-button>
|
||||||
<ng-container *ngIf="localPkg">
|
<!-- localPkg -->
|
||||||
<!-- not installing, updating, or removing -->
|
<ng-container *ngIf="localPkg">
|
||||||
<ng-container *ngIf="localPkg.state === PackageState.Installed">
|
<!-- not installing, updating, or removing -->
|
||||||
<ion-button *ngIf="(localPkg.manifest.version | compareEmver : pkg.manifest.version) === -1" expand="block" (click)="presentModal('update')">
|
<ng-container *ngIf="localPkg.state === PackageState.Installed">
|
||||||
Update
|
<ion-button *ngIf="(localPkg.manifest.version | compareEmver : pkg.manifest.version) === -1" expand="block" (click)="presentModal('update')">
|
||||||
</ion-button>
|
Update
|
||||||
<ion-button *ngIf="(localPkg.manifest.version | compareEmver : pkg.manifest.version) === 1" expand="block" color="warning" (click)="presentModal('downgrade')">
|
</ion-button>
|
||||||
Downgrade
|
<ion-button *ngIf="(localPkg.manifest.version | compareEmver : pkg.manifest.version) === 1" expand="block" color="warning" (click)="presentModal('downgrade')">
|
||||||
</ion-button>
|
Downgrade
|
||||||
</ng-container>
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row *ngIf="localPkg">
|
||||||
|
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
||||||
|
<ion-button expand="block" fill="outline" color="primary" [routerLink]="['/services', pkg.manifest.id]">
|
||||||
|
View Service
|
||||||
|
</ion-button>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
|
||||||
|
<!-- recommendation -->
|
||||||
|
<ion-item *ngIf="rec && showRec" class="rec-item">
|
||||||
|
<ion-label>
|
||||||
|
<h2 style="display: flex; align-items: center;">
|
||||||
|
<ion-thumbnail style="height: 3vh; width: 3vh; margin: 5px" slot="start">
|
||||||
|
<img [src]="rec.dependentIcon" [alt]="rec.dependentTitle"/>
|
||||||
|
</ion-thumbnail>
|
||||||
|
<ion-text style="margin: 5px; font-family: 'Montserrat'; font-size: smaller;">{{ rec.dependentTitle }}</ion-text>
|
||||||
|
</h2>
|
||||||
|
<div style="margin: 7px 5px;">
|
||||||
|
<p style="color: var(--ion-color-dark); font-size: small">{{ rec.description }}</p>
|
||||||
|
<p *ngIf="pkg.manifest.version | satisfiesEmver: rec.version" class="recommendation-text">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is compatible.</p>
|
||||||
|
<p *ngIf="!(pkg.manifest.version | satisfiesEmver: rec.version)" class="recommendation-text recommendation-error">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is NOT compatible.</p>
|
||||||
|
<ion-button style="position: absolute; right: 0; top: 0" fill="clear" (click)="dismissRec()">
|
||||||
|
<ion-icon name="close"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item-group>
|
||||||
|
<!-- release notes -->
|
||||||
|
<ion-item-divider>
|
||||||
|
New in {{ pkg.manifest.version | displayEmver }}
|
||||||
|
<ion-button [routerLink]="['notes']" style="position: absolute; right: 10px;" fill="clear" color="dark">
|
||||||
|
All Release Notes
|
||||||
|
<ion-icon slot="end" name="arrow-forward-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-divider>
|
||||||
|
<ion-item lines="none" color="transparent">
|
||||||
|
<ion-label>
|
||||||
|
<div id='release-notes' [innerHTML]="pkg.manifest['release-notes'] | markdown"></div>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<!-- description -->
|
||||||
|
<ion-item-divider>Description</ion-item-divider>
|
||||||
|
<ion-item lines="none" color="transparent">
|
||||||
|
<ion-label>
|
||||||
|
<div id="release-notes" class="release-notes">{{ pkg.manifest.description.long }}</div>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<!-- dependencies -->
|
||||||
|
<ng-container *ngIf="!(pkg.manifest.dependencies | empty)">
|
||||||
|
<ion-item-divider>Dependencies</ion-item-divider>
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col *ngFor="let dep of pkg.manifest.dependencies | keyvalue" sizeSm="12" sizeMd="6">
|
||||||
|
<ion-item [routerLink]="['/marketplace', dep.key]">
|
||||||
|
<ion-thumbnail slot="start">
|
||||||
|
<img [src]="pkg['dependency-metadata'][dep.key].icon" />
|
||||||
|
</ion-thumbnail>
|
||||||
|
<ion-label>
|
||||||
|
<h2>
|
||||||
|
{{ pkg['dependency-metadata'][dep.key].title }}
|
||||||
|
<span *ngIf="dep.value.requirement.type === 'required'"> (required)</span>
|
||||||
|
<span *ngIf="dep.value.requirement.type === 'opt-out'"> (required by default)</span>
|
||||||
|
<span *ngIf="dep.value.requirement.type === 'opt-in'"> (optional)</span>
|
||||||
|
</h2>
|
||||||
|
<p style="font-size: small">{{ dep.value.version | displayEmver }}</p>
|
||||||
|
<p>{{ dep.value.description }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</ng-container>
|
||||||
|
</ion-item-group>
|
||||||
|
|
||||||
|
<ion-item-divider>Additional Info</ion-item-divider>
|
||||||
|
<ion-card>
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col sizeSm="12" sizeMd="6">
|
||||||
|
<ion-item-group>
|
||||||
|
<ion-item button detail="false" (click)="presentAlertVersions()">
|
||||||
|
<ion-label>
|
||||||
|
<h2>Other Versions</h2>
|
||||||
|
<p>Click to view other versions</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||||
|
<ion-label>
|
||||||
|
<h2>License</h2>
|
||||||
|
<p>{{ pkg.manifest.license }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item button detail="false" (click)="presentModalMd('instructions')">
|
||||||
|
<ion-label>
|
||||||
|
<h2>Instructions</h2>
|
||||||
|
<p>Click to view instructions</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-group>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
<ion-col sizeSm="12" sizeMd="6">
|
||||||
<ion-row *ngIf="localPkg">
|
<ion-item-group>
|
||||||
<ion-col sizeXl="3" sizeLg="3" sizeMd="3" sizeSm="12" sizeXs="12" class="ion-align-self-center">
|
<ion-item [href]="pkg.manifest['upstream-repo']" target="_blank" rel="noreferrer" detail="false">
|
||||||
<ion-button expand="block" fill="outline" color="primary" [routerLink]="['/services', pkg.manifest.id]">
|
<ion-label>
|
||||||
View Service
|
<h2>Source Repository</h2>
|
||||||
</ion-button>
|
<p>{{ pkg.manifest['upstream-repo'] }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item [href]="pkg.manifest['wrapper-repo']" target="_blank" rel="noreferrer" detail="false">
|
||||||
|
<ion-label>
|
||||||
|
<h2>Wrapper Repository</h2>
|
||||||
|
<p>{{ pkg.manifest['wrapper-repo'] }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item [href]="pkg.manifest['support-site']" target="_blank" rel="noreferrer" detail="false">
|
||||||
|
<ion-label>
|
||||||
|
<h2>Support Site</h2>
|
||||||
|
<p>{{ pkg.manifest['support-site'] }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" name="open-outline"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-group>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
</ion-grid>
|
</ion-grid>
|
||||||
|
</ion-card>
|
||||||
<!-- recommendation -->
|
|
||||||
<ion-item *ngIf="rec && showRec" class="rec-item">
|
|
||||||
<ion-label>
|
|
||||||
<h2 style="display: flex; align-items: center;">
|
|
||||||
<ion-thumbnail style="height: 3vh; width: 3vh; margin: 5px" slot="start">
|
|
||||||
<img [src]="rec.dependentIcon" [alt]="rec.dependentTitle"/>
|
|
||||||
</ion-thumbnail>
|
|
||||||
<ion-text style="margin: 5px; font-family: 'Montserrat'; font-size: smaller;">{{ rec.dependentTitle }}</ion-text>
|
|
||||||
</h2>
|
|
||||||
<div style="margin: 7px 5px;">
|
|
||||||
<p style="color: var(--ion-color-dark); font-size: small">{{ rec.description }}</p>
|
|
||||||
<p *ngIf="pkg.manifest.version | satisfiesEmver: rec.version" class="recommendation-text">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is compatible.</p>
|
|
||||||
<p *ngIf="!(pkg.manifest.version | satisfiesEmver: rec.version)" class="recommendation-text recommendation-error">{{ pkg.manifest.title }} version {{ pkg.manifest.version | displayEmver }} is NOT compatible.</p>
|
|
||||||
<ion-button style="position: absolute; right: 0; top: 0" fill="clear" (click)="dismissRec()">
|
|
||||||
<ion-icon name="close"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</div>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
|
|
||||||
<ion-item-group>
|
|
||||||
<!-- release notes -->
|
|
||||||
<ion-item-divider>
|
|
||||||
New in {{ pkg.manifest.version | displayEmver }}
|
|
||||||
<ion-button [routerLink]="['notes']" style="position: absolute; right: 10px;" fill="clear" color="dark">
|
|
||||||
All Release Notes
|
|
||||||
<ion-icon slot="end" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</ion-item-divider>
|
|
||||||
<ion-item lines="none" color="transparent">
|
|
||||||
<ion-label>
|
|
||||||
<div id='release-notes' [innerHTML]="pkg.manifest['release-notes'] | markdown"></div>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
<!-- description -->
|
|
||||||
<ion-item-divider>Description</ion-item-divider>
|
|
||||||
<ion-item lines="none" color="transparent">
|
|
||||||
<ion-label>
|
|
||||||
<div id="release-notes" class="release-notes">{{ pkg.manifest.description.long }}</div>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
<!-- dependencies -->
|
|
||||||
<ng-container *ngIf="!(pkg.manifest.dependencies | empty)">
|
|
||||||
<ion-item-divider>Dependencies</ion-item-divider>
|
|
||||||
<ion-grid>
|
|
||||||
<ion-row>
|
|
||||||
<ion-col *ngFor="let dep of pkg.manifest.dependencies | keyvalue" sizeSm="12" sizeMd="6">
|
|
||||||
<ion-item *ngIf="!dep.value.optional" [routerLink]="['/marketplace', dep.key]">
|
|
||||||
<ion-thumbnail slot="start">
|
|
||||||
<img [src]="pkg['dependency-metadata'][dep.key].icon" />
|
|
||||||
</ion-thumbnail>
|
|
||||||
<ion-label>
|
|
||||||
<h2>
|
|
||||||
{{ pkg['dependency-metadata'][dep.key].title }}
|
|
||||||
<span *ngIf="dep.value.recommended"> (recommended)</span>
|
|
||||||
</h2>
|
|
||||||
<p style="font-size: small">{{ dep.value.version | displayEmver }}</p>
|
|
||||||
<p>{{ dep.value.description }}</p>
|
|
||||||
</ion-label>
|
|
||||||
</ion-item>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
</ng-container>
|
|
||||||
</ion-item-group>
|
|
||||||
|
|
||||||
<ion-item-divider>Additional Info</ion-item-divider>
|
|
||||||
<ion-card>
|
|
||||||
<ion-grid>
|
|
||||||
<ion-row>
|
|
||||||
<ion-col sizeSm="12" sizeMd="6">
|
|
||||||
<ion-item-group>
|
|
||||||
<ion-item button detail="false" (click)="presentAlertVersions()">
|
|
||||||
<ion-label>
|
|
||||||
<h2>Other Versions</h2>
|
|
||||||
<p>Click to view other versions</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
|
||||||
<ion-label>
|
|
||||||
<h2>License</h2>
|
|
||||||
<p>{{ pkg.manifest.license }}</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item button detail="false" (click)="presentModalMd('instructions')">
|
|
||||||
<ion-label>
|
|
||||||
<h2>Instructions</h2>
|
|
||||||
<p>Click to view instructions</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
</ion-item-group>
|
|
||||||
</ion-col>
|
|
||||||
<ion-col sizeSm="12" sizeMd="6">
|
|
||||||
<ion-item-group>
|
|
||||||
<ion-item [href]="pkg.manifest['upstream-repo']" target="_blank" rel="noreferrer" detail="false">
|
|
||||||
<ion-label>
|
|
||||||
<h2>Source Repository</h2>
|
|
||||||
<p>{{ pkg.manifest['upstream-repo'] }}</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item [href]="pkg.manifest['wrapper-repo']" target="_blank" rel="noreferrer" detail="false">
|
|
||||||
<ion-label>
|
|
||||||
<h2>Wrapper Repository</h2>
|
|
||||||
<p>{{ pkg.manifest['wrapper-repo'] }}</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item [href]="pkg.manifest['support-site']" target="_blank" rel="noreferrer" detail="false">
|
|
||||||
<ion-label>
|
|
||||||
<h2>Support Site</h2>
|
|
||||||
<p>{{ pkg.manifest['support-site'] }}</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-icon slot="end" name="open-outline"></ion-icon>
|
|
||||||
</ion-item>
|
|
||||||
</ion-item-group>
|
|
||||||
</ion-col>
|
|
||||||
</ion-row>
|
|
||||||
</ion-grid>
|
|
||||||
</ion-card>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { MarketplaceService } from '../marketplace.service'
|
|||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { MarkdownPage } from 'src/app/modals/markdown/markdown.page'
|
import { MarkdownPage } from 'src/app/modals/markdown/markdown.page'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
|
import { MarketplacePkg } from 'src/app/services/api/api.types'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-show',
|
selector: 'marketplace-show',
|
||||||
@@ -23,11 +24,11 @@ export class MarketplaceShowPage {
|
|||||||
@ViewChild(IonContent) content: IonContent
|
@ViewChild(IonContent) content: IonContent
|
||||||
loading = true
|
loading = true
|
||||||
pkgId: string
|
pkgId: string
|
||||||
|
pkg: MarketplacePkg
|
||||||
localPkg: PackageDataEntry
|
localPkg: PackageDataEntry
|
||||||
PackageState = PackageState
|
PackageState = PackageState
|
||||||
rec: Recommendation | null = null
|
rec: Recommendation | null = null
|
||||||
showRec = true
|
showRec = true
|
||||||
|
|
||||||
subs: Subscription[] = []
|
subs: Subscription[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
@@ -41,7 +42,7 @@ export class MarketplaceShowPage {
|
|||||||
private readonly emver: Emver,
|
private readonly emver: Emver,
|
||||||
private readonly patch: PatchDbService,
|
private readonly patch: PatchDbService,
|
||||||
private readonly embassyApi: ApiService,
|
private readonly embassyApi: ApiService,
|
||||||
public readonly marketplaceService: MarketplaceService,
|
private readonly marketplaceService: MarketplaceService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
@@ -57,10 +58,18 @@ export class MarketplaceShowPage {
|
|||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
|
|
||||||
if (this.marketplaceService.pkgs[this.pkgId]) {
|
try {
|
||||||
|
if (!this.marketplaceService.pkgs.length) {
|
||||||
|
await this.marketplaceService.load()
|
||||||
|
}
|
||||||
|
this.pkg = this.marketplaceService.pkgs.find(pkg => pkg.manifest.id === this.pkgId)
|
||||||
|
if (!this.pkg) {
|
||||||
|
throw new Error(`Service with ID "${this.pkgId}" not found.`)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.errToast.present(e)
|
||||||
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
} else {
|
|
||||||
this.getPkg()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,27 +81,16 @@ export class MarketplaceShowPage {
|
|||||||
this.subs.forEach(sub => sub.unsubscribe())
|
this.subs.forEach(sub => sub.unsubscribe())
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPkg (version?: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
await this.marketplaceService.getPkg(this.pkgId, version)
|
|
||||||
} catch (e) {
|
|
||||||
this.errToast.present(e)
|
|
||||||
} finally {
|
|
||||||
await pauseFor(100)
|
|
||||||
this.loading = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async presentAlertVersions () {
|
async presentAlertVersions () {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
header: 'Versions',
|
header: 'Versions',
|
||||||
inputs: this.marketplaceService.pkgs[this.pkgId].versions.sort((a, b) => -1 * this.emver.compare(a, b)).map(v => {
|
inputs: this.pkg.versions.sort((a, b) => -1 * this.emver.compare(a, b)).map(v => {
|
||||||
return {
|
return {
|
||||||
name: v, // for CSS
|
name: v, // for CSS
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
label: displayEmver(v), // appearance on screen
|
label: displayEmver(v), // appearance on screen
|
||||||
value: v, // literal SEM version value
|
value: v, // literal SEM version value
|
||||||
checked: this.marketplaceService.pkgs[this.pkgId].manifest.version === v,
|
checked: this.pkg.manifest.version === v,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
buttons: [
|
buttons: [
|
||||||
@@ -116,7 +114,7 @@ export class MarketplaceShowPage {
|
|||||||
const modal = await this.modalCtrl.create({
|
const modal = await this.modalCtrl.create({
|
||||||
componentProps: {
|
componentProps: {
|
||||||
title,
|
title,
|
||||||
contentUrl: this.marketplaceService.pkgs[this.pkgId][title],
|
contentUrl: this.pkg[title],
|
||||||
},
|
},
|
||||||
component: MarkdownPage,
|
component: MarkdownPage,
|
||||||
})
|
})
|
||||||
@@ -125,7 +123,7 @@ export class MarketplaceShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async tryInstall () {
|
async tryInstall () {
|
||||||
const { id, title, version, alerts } = this.marketplaceService.pkgs[this.pkgId].manifest
|
const { id, title, version, alerts } = this.pkg.manifest
|
||||||
|
|
||||||
if (!alerts.install) {
|
if (!alerts.install) {
|
||||||
await this.install(id, version)
|
await this.install(id, version)
|
||||||
@@ -152,7 +150,7 @@ export class MarketplaceShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async presentModal (action: 'update' | 'downgrade') {
|
async presentModal (action: 'update' | 'downgrade') {
|
||||||
const { id, title, version, dependencies, alerts } = this.marketplaceService.pkgs[this.pkgId].manifest
|
const { id, title, version, dependencies, alerts } = this.pkg.manifest
|
||||||
const value = {
|
const value = {
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
@@ -177,6 +175,18 @@ export class MarketplaceShowPage {
|
|||||||
this.showRec = false
|
this.showRec = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getPkg (version?: string): Promise<void> {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
this.pkg = await this.marketplaceService.getPkg(this.pkgId, version)
|
||||||
|
} catch (e) {
|
||||||
|
this.errToast.present(e)
|
||||||
|
} finally {
|
||||||
|
await pauseFor(100)
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async install (id: string, version?: string): Promise<void> {
|
private async install (id: string, version?: string): Promise<void> {
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
spinner: 'lines',
|
spinner: 'lines',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { MarketplacePkg } from 'src/app/services/api/api.types'
|
import { MarketplaceData, MarketplaceEOS, MarketplacePkg } from 'src/app/services/api/api.types'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { Emver } from 'src/app/services/emver.service'
|
import { Emver } from 'src/app/services/emver.service'
|
||||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||||
@@ -8,9 +8,9 @@ import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
|||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class MarketplaceService {
|
export class MarketplaceService {
|
||||||
allPkgs: MarketplacePkg[] = []
|
data: MarketplaceData
|
||||||
pkgs: { [id: string]: MarketplacePkg } = { }
|
eos: MarketplaceEOS
|
||||||
updates: MarketplacePkg[] = []
|
pkgs: MarketplacePkg[] = []
|
||||||
releaseNotes: { [id: string]: {
|
releaseNotes: { [id: string]: {
|
||||||
[version: string]: string
|
[version: string]: string
|
||||||
} } = { }
|
} } = { }
|
||||||
@@ -20,61 +20,55 @@ export class MarketplaceService {
|
|||||||
private readonly emver: Emver,
|
private readonly emver: Emver,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async getUpdates (localPkgs: { [id: string]: PackageDataEntry }) : Promise<void> {
|
async load (): Promise<void> {
|
||||||
const idAndCurrentVersions = Object.keys(localPkgs).map(key => ({ id: key, version: localPkgs[key].manifest.version }))
|
const [data, eos, pkgs] = await Promise.all([
|
||||||
const latestPkgs = (await this.api.getMarketplacePkgs({
|
this.api.getMarketplaceData({ }),
|
||||||
ids: idAndCurrentVersions,
|
this.api.getEos({ }),
|
||||||
}))
|
this.getPkgs(1, 100),
|
||||||
|
])
|
||||||
|
this.data = data
|
||||||
|
this.eos = eos
|
||||||
|
this.pkgs = pkgs
|
||||||
|
}
|
||||||
|
|
||||||
const updates = latestPkgs.filter(latestPkg => {
|
async getUpdates (localPkgs: { [id: string]: PackageDataEntry }) : Promise<MarketplacePkg[]> {
|
||||||
|
const idAndCurrentVersions = Object.keys(localPkgs).map(key => ({ id: key, version: localPkgs[key].manifest.version }))
|
||||||
|
const latestPkgs = await this.api.getMarketplacePkgs({
|
||||||
|
ids: idAndCurrentVersions,
|
||||||
|
})
|
||||||
|
|
||||||
|
return latestPkgs.filter(latestPkg => {
|
||||||
const latestVersion = latestPkg.manifest.version
|
const latestVersion = latestPkg.manifest.version
|
||||||
const curVersion = localPkgs[latestPkg.manifest.id]?.manifest.version
|
const curVersion = localPkgs[latestPkg.manifest.id]?.manifest.version
|
||||||
return !!curVersion && this.emver.compare(latestVersion, curVersion) === 1
|
return !!curVersion && this.emver.compare(latestVersion, curVersion) === 1
|
||||||
})
|
})
|
||||||
|
|
||||||
this.updates = updates
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllPkgs (): Promise<void> {
|
async getPkg (id: string, version?: string): Promise<MarketplacePkg> {
|
||||||
if (this.allPkgs.length) return
|
|
||||||
|
|
||||||
this.allPkgs = await this.getPkgs(
|
|
||||||
undefined,
|
|
||||||
null,
|
|
||||||
1,
|
|
||||||
100000,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPkgs (category: string, query: string, page: number, perPage: number) : Promise<MarketplacePkg[]> {
|
|
||||||
const pkgs = await this.api.getMarketplacePkgs({
|
|
||||||
category: category !== 'all' ? category : undefined,
|
|
||||||
query,
|
|
||||||
page: String(page),
|
|
||||||
'per-page': String(perPage),
|
|
||||||
})
|
|
||||||
this.pkgs = pkgs.reduce((cur, val) => {
|
|
||||||
cur[val.manifest.id] = val
|
|
||||||
return cur
|
|
||||||
}, { })
|
|
||||||
return pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPkg (id: string, version?: string): Promise<void> {
|
|
||||||
const pkgs = await this.api.getMarketplacePkgs({
|
const pkgs = await this.api.getMarketplacePkgs({
|
||||||
ids: [{ id, version: version || '*' }],
|
ids: [{ id, version: version || '*' }],
|
||||||
})
|
})
|
||||||
const pkg = pkgs.find(pkg => pkg.manifest.id == id)
|
const pkg = pkgs.find(pkg => pkg.manifest.id == id)
|
||||||
if (pkg) {
|
|
||||||
this.pkgs[id] = pkg
|
if (!pkg) {
|
||||||
|
throw new Error(`No results for ${id}${version ? ' ' + version : ''}`)
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`No results for ${id}${version ? ' ' + version : ''}.`)
|
return pkg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getReleaseNotes (id: string): Promise<void> {
|
async getReleaseNotes (id: string): Promise<void> {
|
||||||
this.releaseNotes[id] = await this.api.getReleaseNotes({ id })
|
this.releaseNotes[id] = await this.api.getReleaseNotes({ id })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getPkgs (page: number, perPage: number) : Promise<MarketplacePkg[]> {
|
||||||
|
const pkgs = await this.api.getMarketplacePkgs({
|
||||||
|
page: String(page),
|
||||||
|
'per-page': String(perPage),
|
||||||
|
})
|
||||||
|
|
||||||
|
return pkgs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item button (click)="presentModalName()">
|
<ion-item button (click)="presentModalName()">
|
||||||
<ion-label>{{ fields['name'].name }}</ion-label>
|
<ion-label>{{ fields['name'].name }}</ion-label>
|
||||||
<ion-note slot="end">{{ patch.data.ui.name }}</ion-note>
|
<ion-note slot="end">{{ patch.data.ui.name || defaultName }}</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { ErrorToastService } from 'src/app/services/error-toast.service'
|
|||||||
export class PreferencesPage {
|
export class PreferencesPage {
|
||||||
@ViewChild(IonContent) content: IonContent
|
@ViewChild(IonContent) content: IonContent
|
||||||
fields = fields
|
fields = fields
|
||||||
|
defaultName: string
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly modalCtrl: ModalController,
|
private readonly modalCtrl: ModalController,
|
||||||
@@ -23,6 +24,10 @@ export class PreferencesPage {
|
|||||||
public readonly patch: PatchDbService,
|
public readonly patch: PatchDbService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.defaultName = `Embassy-${this.patch.data['server-info'].id}`
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit () {
|
ngAfterViewInit () {
|
||||||
this.content.scrollToPoint(undefined, 1)
|
this.content.scrollToPoint(undefined, 1)
|
||||||
}
|
}
|
||||||
@@ -34,11 +39,11 @@ export class PreferencesPage {
|
|||||||
message: 'This is for your reference only.',
|
message: 'This is for your reference only.',
|
||||||
label: 'Device Name',
|
label: 'Device Name',
|
||||||
useMask: false,
|
useMask: false,
|
||||||
placeholder: this.patch.data['server-info'].id,
|
placeholder: this.defaultName,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
value: this.patch.data.ui.name,
|
value: this.patch.data.ui.name,
|
||||||
buttonText: 'Save',
|
buttonText: 'Save',
|
||||||
submitFn: async (value: string) => await this.setDbValue('name', value || this.patch.data['server-info'].id),
|
submitFn: async (value: string) => await this.setDbValue('name', value || this.defaultName),
|
||||||
},
|
},
|
||||||
cssClass: 'alertlike-modal',
|
cssClass: 'alertlike-modal',
|
||||||
presentingElement: await this.modalCtrl.getTop(),
|
presentingElement: await this.modalCtrl.getTop(),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>{{ patch.data.ui.name || patch.data['server-info'].id }}</ion-title>
|
<ion-title>{{ patch.data.ui.name || "Embassy-" + patch.data['server-info'].id }}</ion-title>
|
||||||
<ion-buttons slot="end">
|
<ion-buttons slot="end">
|
||||||
<badge-menu-button></badge-menu-button>
|
<badge-menu-button></badge-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export class ServerShowPage {
|
|||||||
'Power': [
|
'Power': [
|
||||||
{
|
{
|
||||||
title: 'Restart',
|
title: 'Restart',
|
||||||
icon: 'reload-outline',
|
icon: 'reload',
|
||||||
action: () => this.presentAlertRestart(),
|
action: () => this.presentAlertRestart(),
|
||||||
detail: false,
|
detail: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -262,9 +262,11 @@ export module Mock {
|
|||||||
dependencies: {
|
dependencies: {
|
||||||
'bitcoind': {
|
'bitcoind': {
|
||||||
version: '=0.21.0',
|
version: '=0.21.0',
|
||||||
|
requirement: {
|
||||||
|
type: 'opt-out',
|
||||||
|
how: 'You can use an external node if you prefer.',
|
||||||
|
},
|
||||||
description: 'LND needs bitcoin to live.',
|
description: 'LND needs bitcoin to live.',
|
||||||
optional: null,
|
|
||||||
recommended: true,
|
|
||||||
critical: true,
|
critical: true,
|
||||||
config: {
|
config: {
|
||||||
check: {
|
check: {
|
||||||
@@ -294,8 +296,10 @@ export module Mock {
|
|||||||
'bitcoin-proxy': {
|
'bitcoin-proxy': {
|
||||||
version: '>=0.2.2',
|
version: '>=0.2.2',
|
||||||
description: 'As long as Bitcoin is pruned, LND needs Bitcoin Proxy to fetch block over the P2P network.',
|
description: 'As long as Bitcoin is pruned, LND needs Bitcoin Proxy to fetch block over the P2P network.',
|
||||||
optional: null,
|
requirement: {
|
||||||
recommended: true,
|
type: 'opt-in',
|
||||||
|
how: 'You can choose to use Bitcoin Proxy for permission management',
|
||||||
|
},
|
||||||
critical: true,
|
critical: true,
|
||||||
config: {
|
config: {
|
||||||
check: {
|
check: {
|
||||||
@@ -410,8 +414,9 @@ export module Mock {
|
|||||||
'bitcoind': {
|
'bitcoind': {
|
||||||
version: '>=0.20.0',
|
version: '>=0.20.0',
|
||||||
description: 'Bitcoin Proxy requires a Bitcoin node.',
|
description: 'Bitcoin Proxy requires a Bitcoin node.',
|
||||||
optional: null,
|
requirement: {
|
||||||
recommended: true,
|
type: 'required',
|
||||||
|
},
|
||||||
critical: false,
|
critical: false,
|
||||||
config: {
|
config: {
|
||||||
check: {
|
check: {
|
||||||
|
|||||||
@@ -344,8 +344,15 @@ export interface DependencyInfo {
|
|||||||
|
|
||||||
export interface DependencyEntry {
|
export interface DependencyEntry {
|
||||||
version: string
|
version: string
|
||||||
optional: string | null
|
requirement: {
|
||||||
recommended: boolean
|
type: 'opt-in'
|
||||||
|
how: string
|
||||||
|
} | {
|
||||||
|
type: 'opt-out'
|
||||||
|
how: string
|
||||||
|
} | {
|
||||||
|
type: 'required'
|
||||||
|
}
|
||||||
description: string | null
|
description: string | null
|
||||||
critical: boolean,
|
critical: boolean,
|
||||||
config: {
|
config: {
|
||||||
|
|||||||
@@ -38,21 +38,18 @@ export class StartupAlertsService {
|
|||||||
shouldRun: () => this.shouldRunOsWelcome(),
|
shouldRun: () => this.shouldRunOsWelcome(),
|
||||||
check: async () => true,
|
check: async () => true,
|
||||||
display: () => this.displayOsWelcome(),
|
display: () => this.displayOsWelcome(),
|
||||||
hasRun: this.config.skipStartupAlerts,
|
|
||||||
}
|
}
|
||||||
const osUpdate: Check<RR.GetMarketplaceEOSRes | undefined> = {
|
const osUpdate: Check<RR.GetMarketplaceEOSRes | undefined> = {
|
||||||
name: 'osUpdate',
|
name: 'osUpdate',
|
||||||
shouldRun: () => this.shouldRunOsUpdateCheck(),
|
shouldRun: () => this.shouldRunOsUpdateCheck(),
|
||||||
check: () => this.osUpdateCheck(),
|
check: () => this.osUpdateCheck(),
|
||||||
display: pkg => this.displayOsUpdateCheck(pkg),
|
display: pkg => this.displayOsUpdateCheck(pkg),
|
||||||
hasRun: this.config.skipStartupAlerts,
|
|
||||||
}
|
}
|
||||||
const pkgsUpdate: Check<boolean> = {
|
const pkgsUpdate: Check<boolean> = {
|
||||||
name: 'pkgsUpdate',
|
name: 'pkgsUpdate',
|
||||||
shouldRun: () => this.shouldRunAppsCheck(),
|
shouldRun: () => this.shouldRunAppsCheck(),
|
||||||
check: () => this.appsCheck(),
|
check: () => this.appsCheck(),
|
||||||
display: () => this.displayAppsCheck(),
|
display: () => this.displayAppsCheck(),
|
||||||
hasRun: this.config.skipStartupAlerts,
|
|
||||||
}
|
}
|
||||||
this.checks = [osWelcome, osUpdate, pkgsUpdate]
|
this.checks = [osWelcome, osUpdate, pkgsUpdate]
|
||||||
}
|
}
|
||||||
@@ -70,7 +67,7 @@ export class StartupAlertsService {
|
|||||||
.subscribe(async data => {
|
.subscribe(async data => {
|
||||||
this.data = data
|
this.data = data
|
||||||
await this.checks
|
await this.checks
|
||||||
.filter(c => !c.hasRun && c.shouldRun())
|
.filter(c => !this.config.skipStartupAlerts && c.shouldRun())
|
||||||
// returning true in the below block means to continue to next modal
|
// returning true in the below block means to continue to next modal
|
||||||
// returning false means to skip all subsequent modals
|
// returning false means to skip all subsequent modals
|
||||||
.reduce(async (previousDisplay, c) => {
|
.reduce(async (previousDisplay, c) => {
|
||||||
@@ -81,7 +78,7 @@ export class StartupAlertsService {
|
|||||||
console.error(`Exception in ${c.name} check:`, e)
|
console.error(`Exception in ${c.name} check:`, e)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
c.hasRun = true
|
|
||||||
const displayRes = await previousDisplay
|
const displayRes = await previousDisplay
|
||||||
|
|
||||||
if (!checkRes) return true
|
if (!checkRes) return true
|
||||||
@@ -113,8 +110,8 @@ export class StartupAlertsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async appsCheck (): Promise<boolean> {
|
private async appsCheck (): Promise<boolean> {
|
||||||
await this.marketplaceService.getUpdates(this.data['package-data'])
|
const updates = await this.marketplaceService.getUpdates(this.data['package-data'])
|
||||||
return !!this.marketplaceService.updates.length
|
return !!updates.length
|
||||||
}
|
}
|
||||||
|
|
||||||
private async displayOsWelcome (): Promise<boolean> {
|
private async displayOsWelcome (): Promise<boolean> {
|
||||||
@@ -220,8 +217,6 @@ type Check<T> = {
|
|||||||
// display an alert based on the result of the check.
|
// display an alert based on the result of the check.
|
||||||
// return false if subsequent modals should not be displayed
|
// return false if subsequent modals should not be displayed
|
||||||
display: (a: T) => Promise<boolean>
|
display: (a: T) => Promise<boolean>
|
||||||
// tracks if this check has run in this app instance.
|
|
||||||
hasRun: boolean
|
|
||||||
// for logging purposes
|
// for logging purposes
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user