adjust service marketplace button for installation source relevance (#1571)

* adjust service marketplace button for installation source relevance

* cleanup

* show marketplace name instead of url; cleanup from PR feedback

* fix spacing

* further cleanup
This commit is contained in:
Lucy C
2022-06-27 10:09:27 -06:00
committed by GitHub
parent 83755e93dc
commit 31952afe1e
7 changed files with 134 additions and 26 deletions

View File

@@ -36,3 +36,16 @@ export function debounce(delay: number = 300): MethodDecorator {
return descriptor return descriptor
} }
} }
export function removeTrailingSlash(word: string): string {
return word.replace(/\/+$/, '')
}
export function isValidHttpUrl(string: string): boolean {
try {
const _ = new URL(string)
return true
} catch (_) {
return false
}
}

View File

@@ -110,4 +110,12 @@ ion-modal::part(content) {
.montserrat { .montserrat {
font-family: 'Montserrat', sans-serif !important; font-family: 'Montserrat', sans-serif !important;
}
.color-success-shade {
color: var(--ion-color-success-shade)
}
.color-primary-shade {
color: var(--ion-color-primary-shade)
} }

View File

@@ -24,7 +24,9 @@
[dependencies]="dependencies" [dependencies]="dependencies"
></app-show-dependencies> ></app-show-dependencies>
<!-- ** menu ** --> <!-- ** menu ** -->
<app-show-menu [buttons]="pkg | toButtons"></app-show-menu> <app-show-menu
[buttons]="pkg | toButtons: (currentMarketplace$ | async): (altMarketplaceData$ | async)"
></app-show-menu>
</ng-container> </ng-container>
</ion-item-group> </ion-item-group>

View File

@@ -1,10 +1,11 @@
import { ChangeDetectionStrategy, Component } from '@angular/core' import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'
import { NavController } from '@ionic/angular' import { NavController } from '@ionic/angular'
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service' import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
import { import {
PackageDataEntry, PackageDataEntry,
PackageMainStatus, PackageMainStatus,
PackageState, PackageState,
UIMarketplaceData,
} from 'src/app/services/patch-db/data-model' } from 'src/app/services/patch-db/data-model'
import { import {
PackageStatus, PackageStatus,
@@ -17,6 +18,12 @@ import {
import { map, startWith, filter } from 'rxjs/operators' import { map, startWith, filter } from 'rxjs/operators'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { getPkgId } from '@start9labs/shared' import { getPkgId } from '@start9labs/shared'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import {
AbstractMarketplaceService,
Marketplace,
} from '@start9labs/marketplace'
import { Observable } from 'rxjs'
const STATES = [ const STATES = [
PackageState.Installing, PackageState.Installing,
@@ -53,6 +60,12 @@ export class AppShowPage {
), ),
) )
readonly currentMarketplace$: Observable<Marketplace> =
this.marketplaceService.getMarketplace()
readonly altMarketplaceData$: Observable<UIMarketplaceData | undefined> =
this.marketplaceService.getAltMarketplace()
readonly connectionFailure$ = this.connectionService readonly connectionFailure$ = this.connectionService
.watchFailure$() .watchFailure$()
.pipe(map(failure => failure !== ConnectionFailure.None)) .pipe(map(failure => failure !== ConnectionFailure.None))
@@ -62,7 +75,9 @@ export class AppShowPage {
private readonly navCtrl: NavController, private readonly navCtrl: NavController,
private readonly patch: PatchDbService, private readonly patch: PatchDbService,
private readonly connectionService: ConnectionService, private readonly connectionService: ConnectionService,
) { } @Inject(AbstractMarketplaceService)
private readonly marketplaceService: MarketplaceService,
) {}
isInstalled( isInstalled(
{ state }: PackageDataEntry, { state }: PackageDataEntry,

View File

@@ -2,12 +2,19 @@ import { Inject, Pipe, PipeTransform } from '@angular/core'
import { ActivatedRoute } from '@angular/router' import { ActivatedRoute } from '@angular/router'
import { DOCUMENT } from '@angular/common' import { DOCUMENT } from '@angular/common'
import { AlertController, ModalController, NavController } from '@ionic/angular' import { AlertController, ModalController, NavController } from '@ionic/angular'
import { MarkdownComponent } from '@start9labs/shared' import {
import { PackageDataEntry } from 'src/app/services/patch-db/data-model' isValidHttpUrl,
MarkdownComponent,
removeTrailingSlash,
} from '@start9labs/shared'
import {
PackageDataEntry,
UIMarketplaceData,
} from 'src/app/services/patch-db/data-model'
import { ModalService } from 'src/app/services/modal.service' import { ModalService } from 'src/app/services/modal.service'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { ApiService } from 'src/app/services/api/embassy-api.service'
import { from } from 'rxjs' import { from } from 'rxjs'
import { Marketplace } from '@start9labs/marketplace'
export interface Button { export interface Button {
title: string title: string
description: string description: string
@@ -30,7 +37,11 @@ export class ToButtonsPipe implements PipeTransform {
private readonly apiService: ApiService, private readonly apiService: ApiService,
) {} ) {}
transform(pkg: PackageDataEntry): Button[] { transform(
pkg: PackageDataEntry,
currentMarketplace: Marketplace | null,
altMarketplaces: UIMarketplaceData | null | undefined,
): Button[] {
const pkgTitle = pkg.manifest.title const pkgTitle = pkg.manifest.title
return [ return [
@@ -87,7 +98,7 @@ export class ToButtonsPipe implements PipeTransform {
icon: 'receipt-outline', icon: 'receipt-outline',
}, },
// view in marketplace // view in marketplace
this.viewInMarketplaceButton(pkg), this.viewInMarketplaceButton(pkg, currentMarketplace, altMarketplaces),
// donate // donate
{ {
action: () => this.donate(pkg), action: () => this.donate(pkg),
@@ -112,23 +123,53 @@ export class ToButtonsPipe implements PipeTransform {
await modal.present() await modal.present()
} }
private viewInMarketplaceButton(pkg: PackageDataEntry): Button { private viewInMarketplaceButton(
return pkg.installed?.['marketplace-url'] pkg: PackageDataEntry,
? { currentMarketplace: Marketplace | null,
action: () => altMarketplaces: UIMarketplaceData | null | undefined,
this.navCtrl.navigateForward([`marketplace/${pkg.manifest.id}`]), ): Button {
title: 'Marketplace', const pkgMarketplace = pkg.installed?.['marketplace-url']
description: 'View service in marketplace', // default button if package marketplace and current marketplace are the same
icon: 'storefront-outline', let button: Button = {
} title: 'Marketplace',
: { icon: 'storefront-outline',
disabled: true, action: () =>
action: () => {}, this.navCtrl.navigateForward([`marketplace/${pkg.manifest.id}`]),
title: 'Marketplace', disabled: false,
description: description: 'View service in marketplace',
'This package has been side-loaded and is not available in the Start9 Marketplace', }
icon: 'storefront-outline', if (!pkgMarketplace) {
button.disabled = true
button.description = 'This package was not installed from a marketplace.'
button.action = () => {}
} else if (
pkgMarketplace &&
currentMarketplace &&
removeTrailingSlash(pkgMarketplace) !==
removeTrailingSlash(currentMarketplace.url)
) {
// attempt to get name for pkg marketplace
let pkgTitle = removeTrailingSlash(pkgMarketplace)
if (altMarketplaces) {
const nameOptions = Object.values(
altMarketplaces['known-hosts'],
).filter(m => m.url === pkgTitle)
if (nameOptions.length) {
// if multiple of the same url exist, they will have the same name, so fine to grab first
pkgTitle = nameOptions[0].name
} }
}
let marketplaceTitle = removeTrailingSlash(currentMarketplace.url)
// if we found a name for the pkg marketplace, use the name of the currently connected marketplace
if (!isValidHttpUrl(pkgTitle)) {
marketplaceTitle = currentMarketplace.name
}
button.action = () =>
this.differentMarketplaceAction(pkgTitle, marketplaceTitle)
button.description = 'Service was installed from a different marketplace'
}
return button
} }
private async donate({ manifest }: PackageDataEntry): Promise<void> { private async donate({ manifest }: PackageDataEntry): Promise<void> {
@@ -143,4 +184,28 @@ export class ToButtonsPipe implements PipeTransform {
await alert.present() await alert.present()
} }
} }
private async differentMarketplaceAction(pkgM: string, currentM: string) {
const alert = await this.alertCtrl.create({
header: 'Marketplace Conflict',
message: `This service was installed from:
<br><br>
<span class="courier-new color-success-shade">${pkgM}</span>
<br><br>but you are currently connected to:<br><br>
<span class="courier-new color-primary-shade">${currentM}</span>
<br><br>
To view the marketplace listing for this service, visit your Marketplace Settings and change marketplaces.`,
buttons: [
{
text: 'Cancel',
role: 'cancel',
},
{
text: 'Go to Settings',
handler: () => this.navCtrl.navigateForward(['embassy/marketplaces']),
cssClass: 'enter-click',
},
],
})
await alert.present()
}
} }

View File

@@ -92,6 +92,10 @@ export class MarketplaceService extends AbstractMarketplaceService {
return this.marketplace$ return this.marketplace$
} }
getAltMarketplace(): Observable<UIMarketplaceData | undefined> {
return this.altMarketplaceData$
}
getCategories(): Observable<string[]> { getCategories(): Observable<string[]> {
return this.categories$ return this.categories$
} }

View File

@@ -1,6 +1,7 @@
export async function copyToClipboard (str: string): Promise<boolean> { export async function copyToClipboard(str: string): Promise<boolean> {
if (window.isSecureContext) { if (window.isSecureContext) {
return navigator.clipboard.writeText(str) return navigator.clipboard
.writeText(str)
.then(() => { .then(() => {
return true return true
}) })