Multiple bugs and styling (#1975)

* remove updates from marketplace, fix search, link updates to marketplace, styling

* add dependency checks and error handling to updates tab

* add circle around back buttons
This commit is contained in:
Matt Hill
2022-11-26 13:18:10 -07:00
committed by Aiden McClelland
parent 9146c31abf
commit 2336e36314
15 changed files with 388 additions and 336 deletions

View File

@@ -2,12 +2,8 @@
*ngFor="let cat of categories" *ngFor="let cat of categories"
fill="clear" fill="clear"
class="category" class="category"
[color]="cat === 'updates' && updatesAvailable ? 'success' : undefined" [class.category_selected]="cat === category && !disableCategories"
[class.category_selected]="cat === category"
(click)="switchCategory(cat)" (click)="switchCategory(cat)"
> >
{{ cat }} {{ cat }}
<span *ngIf="cat === 'updates' && updatesAvailable">
&nbsp; ({{ updatesAvailable }})
</span>
</ion-button> </ion-button>

View File

@@ -23,7 +23,7 @@ export class CategoriesComponent {
category = '' category = ''
@Input() @Input()
updatesAvailable = 0 disableCategories = false
@Output() @Output()
readonly categoryChange = new EventEmitter<string>() readonly categoryChange = new EventEmitter<string>()

View File

@@ -1,110 +1,108 @@
<ion-item-divider>Additional Info</ion-item-divider> <ion-item-divider>Additional Info</ion-item-divider>
<ion-card *ngIf="pkg.manifest as manifest"> <ion-grid *ngIf="pkg.manifest as manifest">
<ion-grid> <ion-row>
<ion-row> <ion-col sizeXs="12" sizeMd="6">
<ion-col sizeXs="12" sizeMd="6"> <ion-item-group>
<ion-item-group> <ion-item
<ion-item *ngIf="manifest['git-hash'] as gitHash; else noHash"
*ngIf="manifest['git-hash'] as gitHash; else noHash" button
button detail="false"
detail="false" (click)="copy(gitHash)"
(click)="copy(gitHash)" >
> <ion-label>
<h2>Git Hash</h2>
<p>{{ gitHash }}</p>
</ion-label>
<ion-icon slot="end" name="copy-outline"></ion-icon>
</ion-item>
<ng-template #noHash>
<ion-item>
<ion-label> <ion-label>
<h2>Git Hash</h2> <h2>Git Hash</h2>
<p>{{ gitHash }}</p> <p>Unknown</p>
</ion-label> </ion-label>
<ion-icon slot="end" name="copy-outline"></ion-icon>
</ion-item> </ion-item>
<ng-template #noHash> </ng-template>
<ion-item> <ion-item button detail="false" (click)="presentAlertVersions()">
<ion-label> <ion-label>
<h2>Git Hash</h2> <h2>Other Versions</h2>
<p>Unknown</p> <p>Click to view other versions</p>
</ion-label> </ion-label>
</ion-item> <ion-icon slot="end" name="chevron-forward"></ion-icon>
</ng-template> </ion-item>
<ion-item button detail="false" (click)="presentAlertVersions()"> <ion-item button detail="false" (click)="presentModalMd('license')">
<ion-label> <ion-label>
<h2>Other Versions</h2> <h2>License</h2>
<p>Click to view other versions</p> <p>{{ manifest.license }}</p>
</ion-label> </ion-label>
<ion-icon slot="end" name="chevron-forward"></ion-icon> <ion-icon slot="end" name="chevron-forward"></ion-icon>
</ion-item> </ion-item>
<ion-item button detail="false" (click)="presentModalMd('license')"> <ion-item
<ion-label> button
<h2>License</h2> detail="false"
<p>{{ manifest.license }}</p> (click)="presentModalMd('instructions')"
</ion-label> >
<ion-icon slot="end" name="chevron-forward"></ion-icon> <ion-label>
</ion-item> <h2>Instructions</h2>
<ion-item <p>Click to view instructions</p>
button </ion-label>
detail="false" <ion-icon slot="end" name="chevron-forward"></ion-icon>
(click)="presentModalMd('instructions')" </ion-item>
> </ion-item-group>
<ion-label> </ion-col>
<h2>Instructions</h2> <ion-col sizeXs="12" sizeMd="6">
<p>Click to view instructions</p> <ion-item-group>
</ion-label> <ion-item
<ion-icon slot="end" name="chevron-forward"></ion-icon> [href]="manifest['upstream-repo']"
</ion-item> target="_blank"
</ion-item-group> rel="noreferrer"
</ion-col> detail="false"
<ion-col sizeXs="12" sizeMd="6"> >
<ion-item-group> <ion-label>
<ion-item <h2>Source Repository</h2>
[href]="manifest['upstream-repo']" <p>{{ manifest['upstream-repo'] }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> <ion-item
<ion-label> [href]="manifest['wrapper-repo']"
<h2>Source Repository</h2> target="_blank"
<p>{{ manifest['upstream-repo'] }}</p> rel="noreferrer"
</ion-label> detail="false"
<ion-icon slot="end" name="open-outline"></ion-icon> >
</ion-item> <ion-label>
<ion-item <h2>Wrapper Repository</h2>
[href]="manifest['wrapper-repo']" <p>{{ manifest['wrapper-repo'] }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> <ion-item
<ion-label> [href]="manifest['support-site']"
<h2>Wrapper Repository</h2> [disabled]="!manifest['support-site']"
<p>{{ manifest['wrapper-repo'] }}</p> target="_blank"
</ion-label> rel="noreferrer"
<ion-icon slot="end" name="open-outline"></ion-icon> detail="false"
</ion-item> >
<ion-item <ion-label>
[href]="manifest['support-site']" <h2>Support Site</h2>
[disabled]="!manifest['support-site']" <p>{{ manifest['support-site'] || 'Not provided' }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> <ion-item
<ion-label> [href]="manifest['marketing-site']"
<h2>Support Site</h2> [disabled]="!manifest['marketing-site']"
<p>{{ manifest['support-site'] || 'Not provided' }}</p> target="_blank"
</ion-label> rel="noreferrer"
<ion-icon slot="end" name="open-outline"></ion-icon> detail="false"
</ion-item> >
<ion-item <ion-label>
[href]="manifest['marketing-site']" <h2>Marketing Site</h2>
[disabled]="!manifest['marketing-site']" <p>{{ manifest['marketing-site'] || 'Not provided' }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> </ion-item-group>
<ion-label> </ion-col>
<h2>Marketing Site</h2> </ion-row>
<p>{{ manifest['marketing-site'] || 'Not provided' }}</p> </ion-grid>
</ion-label>
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-item>
</ion-item-group>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>

View File

@@ -1,6 +1,6 @@
import { NgModule, Pipe, PipeTransform } from '@angular/core' import { NgModule, Pipe, PipeTransform } from '@angular/core'
import { Emver } from '@start9labs/shared' import { Emver } from '@start9labs/shared'
import { MarketplaceManifest, MarketplacePkg } from '../types' import { MarketplacePkg } from '../types'
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
@Pipe({ @Pipe({
@@ -13,75 +13,40 @@ export class FilterPackagesPipe implements PipeTransform {
packages: MarketplacePkg[], packages: MarketplacePkg[],
query: string, query: string,
category: string, category: string,
local: Record<string, { manifest: MarketplaceManifest }> = {},
): MarketplacePkg[] { ): MarketplacePkg[] {
// query // query
if (query) { if (query) {
let options: Fuse.IFuseOptions<MarketplacePkg> = { let options: Fuse.IFuseOptions<MarketplacePkg> = {
includeScore: true, includeScore: true,
includeMatches: true, includeMatches: true,
ignoreLocation: true,
useExtendedSearch: true,
keys: [
{
name: 'manifest.title',
weight: 1,
},
{
name: 'manifest.id',
weight: 0.5,
},
{
name: 'manifest.description.short',
weight: 0.4,
},
{
name: 'manifest.description.long',
weight: 0.1,
},
],
} }
if (query.length < 4) { query = `'${query}`
options = {
...options,
threshold: 0,
location: 0,
distance: 1,
keys: [
{
name: 'manifest.title',
weight: 1,
},
{
name: 'manifest.id',
weight: 0.5,
},
],
}
} else {
options = {
...options,
ignoreLocation: true,
useExtendedSearch: true,
keys: [
{
name: 'manifest.title',
weight: 1,
},
{
name: 'manifest.id',
weight: 0.5,
},
{
name: 'manifest.description.short',
weight: 0.4,
},
{
name: 'manifest.description.long',
weight: 0.1,
},
],
}
query = `'${query}`
}
const fuse = new Fuse(packages, options) const fuse = new Fuse(packages, options)
return fuse.search(query).map(p => p.item) return fuse.search(query).map(p => p.item)
} }
// updates
if (category === 'updates') {
return packages.filter(
({ manifest }) =>
local[manifest.id] &&
this.emver.compare(
manifest.version,
local[manifest.id].manifest.version,
) === 1,
)
}
// category // category
return packages return packages
.filter(p => category === 'all' || p.categories.includes(category)) .filter(p => category === 'all' || p.categories.includes(category))

View File

@@ -8,7 +8,6 @@ import { StatusComponentModule } from 'src/app/components/status/status.componen
import { AppConfigPageModule } from 'src/app/modals/app-config/app-config.module' import { AppConfigPageModule } from 'src/app/modals/app-config/app-config.module'
import { LaunchablePipeModule } from 'src/app/pipes/launchable/launchable.module' import { LaunchablePipeModule } from 'src/app/pipes/launchable/launchable.module'
import { UiPipeModule } from 'src/app/pipes/ui/ui.module' import { UiPipeModule } from 'src/app/pipes/ui/ui.module'
import { AppShowHeaderComponent } from './components/app-show-header/app-show-header.component'
import { AppShowProgressComponent } from './components/app-show-progress/app-show-progress.component' import { AppShowProgressComponent } from './components/app-show-progress/app-show-progress.component'
import { AppShowStatusComponent } from './components/app-show-status/app-show-status.component' import { AppShowStatusComponent } from './components/app-show-status/app-show-status.component'
import { AppShowDependenciesComponent } from './components/app-show-dependencies/app-show-dependencies.component' import { AppShowDependenciesComponent } from './components/app-show-dependencies/app-show-dependencies.component'
@@ -38,7 +37,6 @@ const routes: Routes = [
ToButtonsPipe, ToButtonsPipe,
ToDependenciesPipe, ToDependenciesPipe,
ToStatusPipe, ToStatusPipe,
AppShowHeaderComponent,
AppShowProgressComponent, AppShowProgressComponent,
AppShowStatusComponent, AppShowStatusComponent,
AppShowDependenciesComponent, AppShowDependenciesComponent,

View File

@@ -1,7 +1,20 @@
<ng-container *ngIf="pkg$ | async as pkg"> <ion-header>
<app-show-header [pkg]="pkg"></app-show-header> <ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="services"></ion-back-button>
</ion-buttons>
<ion-title>Service Details</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ng-container *ngIf="pkg$ | async as pkg">
<div class="ion-text-center ion-padding-top">
<img [src]="pkg['static-files'].icon" alt="" style="width: 84px" />
<h1>{{ pkg.manifest.title }}</h1>
<h4>{{ pkg.manifest.version | displayEmver }}</h4>
</div>
<ion-content>
<!-- ** installing, updating, restoring ** --> <!-- ** installing, updating, restoring ** -->
<ng-container *ngIf="showProgress(pkg); else installed"> <ng-container *ngIf="showProgress(pkg); else installed">
<app-show-progress <app-show-progress
@@ -73,5 +86,5 @@
</ion-grid> </ion-grid>
</ng-template> </ng-template>
</ng-template> </ng-template>
</ion-content> </ng-container>
</ng-container> </ion-content>

View File

@@ -1,85 +1,83 @@
<ion-item-divider>Additional Info</ion-item-divider> <ion-item-divider>Additional Info</ion-item-divider>
<ion-card *ngIf="pkg.manifest as manifest"> <ion-grid *ngIf="pkg.manifest as manifest">
<ion-grid> <ion-row>
<ion-row> <ion-col sizeXs="12" sizeMd="6">
<ion-col sizeXs="12" sizeMd="6"> <ion-item-group>
<ion-item-group> <ion-item>
<ion-label>
<h2>Version</h2>
<p>{{ manifest.version | displayEmver }}</p>
</ion-label>
</ion-item>
<ion-item
*ngIf="manifest['git-hash'] as gitHash; else noHash"
button
detail="false"
(click)="copy(gitHash)"
>
<ion-label>
<h2>Git Hash</h2>
<p>{{ gitHash }}</p>
</ion-label>
<ion-icon slot="end" name="copy-outline"></ion-icon>
</ion-item>
<ng-template #noHash>
<ion-item> <ion-item>
<ion-label>
<h2>Version</h2>
<p>{{ manifest.version | displayEmver }}</p>
</ion-label>
</ion-item>
<ion-item
*ngIf="manifest['git-hash'] as gitHash; else noHash"
button
detail="false"
(click)="copy(gitHash)"
>
<ion-label> <ion-label>
<h2>Git Hash</h2> <h2>Git Hash</h2>
<p>{{ gitHash }}</p> <p>Unknown</p>
</ion-label> </ion-label>
<ion-icon slot="end" name="copy-outline"></ion-icon>
</ion-item> </ion-item>
<ng-template #noHash> </ng-template>
<ion-item> <ion-item button detail="false" (click)="presentModalLicense()">
<ion-label> <ion-label>
<h2>Git Hash</h2> <h2>License</h2>
<p>Unknown</p> <p>{{ manifest.license }}</p>
</ion-label> </ion-label>
</ion-item> <ion-icon slot="end" name="chevron-forward"></ion-icon>
</ng-template> </ion-item>
<ion-item button detail="false" (click)="presentModalLicense()"> </ion-item-group>
<ion-label> </ion-col>
<h2>License</h2> <ion-col sizeXs="12" sizeMd="6">
<p>{{ manifest.license }}</p> <ion-item-group>
</ion-label> <ion-item
<ion-icon slot="end" name="chevron-forward"></ion-icon> [href]="manifest['upstream-repo']"
</ion-item> target="_blank"
</ion-item-group> rel="noreferrer"
</ion-col> detail="false"
<ion-col sizeXs="12" sizeMd="6"> >
<ion-item-group> <ion-label>
<ion-item <h2>Source Repository</h2>
[href]="manifest['upstream-repo']" <p>{{ manifest['upstream-repo'] }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> <ion-item
<ion-label> [href]="manifest['wrapper-repo']"
<h2>Source Repository</h2> target="_blank"
<p>{{ manifest['upstream-repo'] }}</p> rel="noreferrer"
</ion-label> detail="false"
<ion-icon slot="end" name="open-outline"></ion-icon> >
</ion-item> <ion-label>
<ion-item <h2>Wrapper Repository</h2>
[href]="manifest['wrapper-repo']" <p>{{ manifest['wrapper-repo'] }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> <ion-item
<ion-label> [href]="manifest['support-site']"
<h2>Wrapper Repository</h2> [disabled]="!manifest['support-site']"
<p>{{ manifest['wrapper-repo'] }}</p> target="_blank"
</ion-label> rel="noreferrer"
<ion-icon slot="end" name="open-outline"></ion-icon> detail="false"
</ion-item> >
<ion-item <ion-label>
[href]="manifest['support-site']" <h2>Support Site</h2>
[disabled]="!manifest['support-site']" <p>{{ manifest['support-site'] || 'Not provided' }}</p>
target="_blank" </ion-label>
rel="noreferrer" <ion-icon slot="end" name="open-outline"></ion-icon>
detail="false" </ion-item>
> </ion-item-group>
<ion-label> </ion-col>
<h2>Support Site</h2> </ion-row>
<p>{{ manifest['support-site'] || 'Not provided' }}</p> </ion-grid>
</ion-label>
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-item>
</ion-item-group>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>

View File

@@ -1,21 +0,0 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="services"></ion-back-button>
</ion-buttons>
<ion-item lines="none" color="light">
<ion-avatar slot="start">
<img [src]="pkg['static-files'].icon" alt="" />
</ion-avatar>
<ion-label>
<h1
class="montserrat"
[class.less-large]="pkg.manifest.title.length > 20"
>
{{ pkg.manifest.title }}
</h1>
<h2>{{ pkg.manifest.version | displayEmver }}</h2>
</ion-label>
</ion-item>
</ion-toolbar>
</ion-header>

View File

@@ -1,13 +0,0 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@Component({
selector: 'app-show-header',
templateUrl: './app-show-header.component.html',
styleUrls: ['./app-show-header.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppShowHeaderComponent {
@Input()
pkg!: PackageDataEntry
}

View File

@@ -36,46 +36,35 @@
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col size="12"> <ion-col size="12">
<ng-container *ngIf="store$ | async as store; else loading"> <ng-container *ngIf="store$ | async as store; else loading">
<ng-container *ngIf="localPkgs$ | async as localPkgs"> <marketplace-categories
<marketplace-categories [categories]="store.categories"
[categories]="store.categories" [category]="category"
[category]="category" [disableCategories]="!!query"
[updatesAvailable]=" (categoryChange)="onCategoryChange($event)"
(store.packages | filterPackages: '':'updates':localPkgs).length ></marketplace-categories>
"
(categoryChange)="onCategoryChange($event)"
></marketplace-categories>
<div class="divider"></div> <div class="divider"></div>
<ion-grid <ion-grid
*ngIf="store.packages | filterPackages: query:category:localPkgs as filtered" *ngIf="store.packages | filterPackages: query:category as filtered"
> >
<div <ion-row *ngIf="localPkgs$ | async as localPkgs">
*ngIf="!filtered.length && category === 'updates'" <ion-col
class="ion-padding" *ngFor="let pkg of filtered"
sizeXs="12"
sizeSm="12"
sizeMd="6"
> >
<h1>All services are up to date!</h1> <marketplace-item [pkg]="pkg">
</div> <marketplace-status
class="status"
<ion-row> [version]="pkg.manifest.version"
<ion-col [localPkg]="localPkgs[pkg.manifest.id]"
*ngFor="let pkg of filtered" ></marketplace-status>
sizeXs="12" </marketplace-item>
sizeSm="12" </ion-col>
sizeMd="6" </ion-row>
> </ion-grid>
<marketplace-item [pkg]="pkg">
<marketplace-status
class="status"
[version]="pkg.manifest.version"
[localPkg]="localPkgs[pkg.manifest.id]"
></marketplace-status>
</marketplace-item>
</ion-col>
</ion-row>
</ion-grid>
</ng-container>
</ng-container> </ng-container>
<ng-template #loading> <ng-template #loading>

View File

@@ -30,11 +30,19 @@
> >
<ion-item *ngFor="let pkg of updates"> <ion-item *ngFor="let pkg of updates">
<ng-container *ngIf="data.localPkgs[pkg.manifest.id] as local"> <ng-container *ngIf="data.localPkgs[pkg.manifest.id] as local">
<ion-avatar slot="start" class="service-avatar"> <ion-avatar
class="service-avatar"
(click)="viewInMarketplace(local)"
>
<img [src]="'data:image/png;base64,' + pkg.icon | trustUrl" /> <img [src]="'data:image/png;base64,' + pkg.icon | trustUrl" />
</ion-avatar> </ion-avatar>
<ion-label> <ion-label>
<h1>{{ pkg.manifest.title }}</h1> <h1
(click)="viewInMarketplace(local)"
style="cursor: pointer"
>
{{ pkg.manifest.title }}
</h1>
<h2 class="inline"> <h2 class="inline">
<span>{{ local.manifest.version }}</span> <span>{{ local.manifest.version }}</span>
&nbsp;<ion-icon name="arrow-forward"></ion-icon>&nbsp; &nbsp;<ion-icon name="arrow-forward"></ion-icon>&nbsp;
@@ -43,6 +51,9 @@
</ion-text> </ion-text>
</h2> </h2>
<p [innerHTML]="pkg.manifest['release-notes'] | markdown"></p> <p [innerHTML]="pkg.manifest['release-notes'] | markdown"></p>
<p *ngIf="errors[pkg.manifest.id] as error">
<ion-text color="danger">{{ error }}</ion-text>
</p>
</ion-label> </ion-label>
<div slot="end"> <div slot="end">
@@ -62,11 +73,11 @@
></ion-spinner> ></ion-spinner>
<ng-template #updateBtn> <ng-template #updateBtn>
<ion-button <ion-button
(click)="update(pkg.manifest.id, host.url)" (click)="tryUpdate(pkg.manifest, host.url, local)"
color="dark" [color]="errors[pkg.manifest.id] ? 'danger' : 'dark'"
strong strong
> >
Update {{ errors[pkg.manifest.id] ? 'Retry' : 'Update' }}
</ion-button> </ion-button>
</ng-template> </ng-template>
</ng-template> </ng-template>

View File

@@ -1,6 +1,7 @@
.service-avatar { .service-avatar {
position: absolute; position: absolute;
top: 6px; top: 6px;
cursor: pointer;
} }
ion-label { ion-label {

View File

@@ -14,10 +14,18 @@ import {
MarketplacePkg, MarketplacePkg,
StoreIdentity, StoreIdentity,
} from '@start9labs/marketplace' } from '@start9labs/marketplace'
import { Emver } from '@start9labs/shared' import { Emver, isEmptyObject } from '@start9labs/shared'
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { combineLatest, Observable } from 'rxjs' import { combineLatest, Observable } from 'rxjs'
import { PrimaryRendering } from '../../services/pkg-status-rendering.service' import { PrimaryRendering } from '../../services/pkg-status-rendering.service'
import {
AlertController,
LoadingController,
NavController,
} from '@ionic/angular'
import { hasCurrentDeps } from 'src/app/util/has-deps'
import { getAllPackages } from 'src/app/util/get-package-data'
import { Breakages } from 'src/app/services/api/api.types'
interface UpdatesData { interface UpdatesData {
hosts: StoreIdentity[] hosts: StoreIdentity[]
@@ -33,6 +41,7 @@ interface UpdatesData {
}) })
export class UpdatesPage { export class UpdatesPage {
queued: Record<string, boolean> = {} queued: Record<string, boolean> = {}
errors: Record<string, string> = {}
readonly data$: Observable<UpdatesData> = combineLatest({ readonly data$: Observable<UpdatesData> = combineLatest({
hosts: this.marketplaceService.getKnownHosts$(), hosts: this.marketplaceService.getKnownHosts$(),
@@ -49,11 +58,115 @@ export class UpdatesPage {
private readonly marketplaceService: MarketplaceService, private readonly marketplaceService: MarketplaceService,
private readonly api: ApiService, private readonly api: ApiService,
private readonly patch: PatchDB<DataModel>, private readonly patch: PatchDB<DataModel>,
private readonly navCtrl: NavController,
private readonly loadingCtrl: LoadingController,
private readonly alertCtrl: AlertController,
) {} ) {}
async update(id: string, url: string): Promise<void> { viewInMarketplace(pkg: PackageDataEntry) {
const url = pkg.installed?.['marketplace-url']
const queryParams = url ? { url } : {}
this.navCtrl.navigateForward([`marketplace/${pkg.manifest.id}`], {
queryParams,
})
}
async tryUpdate(
manifest: MarketplaceManifest,
url: string,
local: PackageDataEntry,
): Promise<void> {
const { id, version } = manifest
delete this.errors[id]
this.queued[id] = true this.queued[id] = true
this.api.installPackage({ id, 'marketplace-url': url })
if (hasCurrentDeps(local)) {
this.dryUpdate(manifest, url)
} else {
this.update(id, version, url)
}
}
private async dryUpdate(manifest: MarketplaceManifest, url: string) {
const loader = await this.loadingCtrl.create({
message: 'Checking dependent services...',
})
await loader.present()
const { id, version } = manifest
try {
const breakages = await this.api.dryUpdatePackage({
id,
version: `${version}`,
})
await loader.dismiss()
if (isEmptyObject(breakages)) {
this.update(id, version, url)
} else {
const proceed = await this.presentAlertBreakages(
manifest.title,
breakages,
)
if (proceed) {
this.update(id, version, url)
} else {
delete this.queued[id]
}
}
} catch (e: any) {
delete this.queued[id]
this.errors[id] = e.message
}
}
private async presentAlertBreakages(
title: string,
breakages: Breakages,
): Promise<boolean> {
let message: string = `As a result of updating ${title}, the following services will no longer work properly and may crash:<ul>`
const localPkgs = await getAllPackages(this.patch)
const bullets = Object.keys(breakages).map(id => {
const title = localPkgs[id].manifest.title
return `<li><b>${title}</b></li>`
})
message = `${message}${bullets.join('')}</ul>`
return new Promise(async resolve => {
const alert = await this.alertCtrl.create({
header: 'Warning',
message,
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: () => {
resolve(false)
},
},
{
text: 'Continue',
handler: () => {
resolve(true)
},
cssClass: 'enter-click',
},
],
cssClass: 'alert-warning-message',
})
await alert.present()
})
}
private update(id: string, version: string, url: string) {
this.marketplaceService.installPackage(id, version, url).catch(e => {
delete this.queued[id]
this.errors[id] = e.message
})
} }
} }

View File

@@ -155,6 +155,13 @@ img {
border-radius: 100%; border-radius: 100%;
} }
ion-back-button {
margin-left: 16px;
&::part(native) {
border: 1px solid white;
}
}
ion-card-title { ion-card-title {
font-family: 'Montserrat'; font-family: 'Montserrat';
} }