mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
feature/marketplace icons (#1921)
* add registry icons, update links, clean up code (#1913) * add registry icons, update links, clean up code * remove seeding of registry icon and name * fix install wizard copy Co-authored-by: Lucy C <12953208+elvece@users.noreply.github.com> * remove references to bep and chime * fix shutdown language and remove chime from initializing screen * fix type error Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com> Co-authored-by: Lucy C <12953208+elvece@users.noreply.github.com> Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
@@ -38,7 +38,7 @@ export class SnekDirective {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.setDbValue(
|
||||
await this.embassyApi.setDbValue<number>(
|
||||
['gaming', 'snake', 'high-score'],
|
||||
data.highScore,
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
a folder on another computer that is connected to the same network
|
||||
as your Embassy. View the
|
||||
<a
|
||||
href="https://start9.com/latest/user-manual/backups/cifs-setup"
|
||||
href="https://docs.start9.com/latest/user-manual/backups/backup-create"
|
||||
target="_blank"
|
||||
noreferrer
|
||||
style="text-decoration: none"
|
||||
@@ -109,7 +109,7 @@
|
||||
a physcial drive that is plugged directly into your Embassy. View
|
||||
the
|
||||
<a
|
||||
href="https://start9.com/latest/user-manual/backups/backups-create/#backup-using-a-physical-drive"
|
||||
href="https://docs.start9.com/latest/user-manual/backups/backup-setup/backup-physical"
|
||||
target="_blank"
|
||||
noreferrer
|
||||
style="text-decoration: none"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Marketplace Settings</ion-title>
|
||||
<ion-title>Change Registry</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="dismiss()">
|
||||
<ion-icon slot="icon-only" name="close"></ion-icon>
|
||||
@@ -11,19 +11,20 @@
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item-group *ngIf="marketplace$ | async as m">
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
Connect to a standard marketplaces or an alternative marketplace.
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider>Standard Marketplaces</ion-item-divider>
|
||||
<ion-item-divider>Default Registries</ion-item-divider>
|
||||
<ion-item
|
||||
*ngFor="let s of m.standard"
|
||||
detail="false"
|
||||
[button]="s.url !== m.selected"
|
||||
(click)="s.url === m.selected ? '' : presentAction(s)"
|
||||
>
|
||||
<ion-avatar slot="start">
|
||||
<img [src]="'data:image/png;base64,' + s.icon | trustUrl" alt="" />
|
||||
</ion-avatar>
|
||||
<ion-label>
|
||||
<h2>{{ s.name }}</h2>
|
||||
<p>{{ s.url }}</p>
|
||||
</ion-label>
|
||||
<ion-icon
|
||||
*ngIf="s.url === m.selected"
|
||||
slot="end"
|
||||
@@ -31,18 +32,14 @@
|
||||
name="checkmark"
|
||||
color="success"
|
||||
></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ s.name }}</h2>
|
||||
<p>{{ s.url }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider>Alt Marketplaces</ion-item-divider>
|
||||
<ion-item-divider>Custom Registries</ion-item-divider>
|
||||
<ion-item button detail="false" (click)="presentModalAdd()">
|
||||
<ion-icon slot="start" name="add" color="dark"></ion-icon>
|
||||
<ion-label>
|
||||
<ion-text color="dark">
|
||||
<b>Add Alt Marketplace</b>
|
||||
<b>Add custom registry</b>
|
||||
</ion-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
@@ -53,6 +50,11 @@
|
||||
[button]="a.url !== m.selected"
|
||||
(click)="a.url === m.selected ? '' : presentAction(a, true)"
|
||||
>
|
||||
<ion-icon slot="start" name="storefront-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ a.name }}</h2>
|
||||
<p>{{ a.url }}</p>
|
||||
</ion-label>
|
||||
<ion-icon
|
||||
*ngIf="a.url === m.selected"
|
||||
slot="end"
|
||||
@@ -60,10 +62,6 @@
|
||||
name="checkmark"
|
||||
color="success"
|
||||
></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ a.name }}</h2>
|
||||
<p>{{ a.url }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
||||
|
||||
@@ -7,7 +7,10 @@ import {
|
||||
} from '@ionic/angular'
|
||||
import { ActionSheetButton } from '@ionic/core'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||
import {
|
||||
AbstractMarketplaceService,
|
||||
StoreIdentifier,
|
||||
} from '@start9labs/marketplace'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
@@ -30,14 +33,14 @@ export class MarketplaceSettingsPage {
|
||||
const hosts = Object.entries(m['known-hosts'])
|
||||
|
||||
const standard = hosts
|
||||
.map(([url, name]) => {
|
||||
return { url, name }
|
||||
.map(([url, info]) => {
|
||||
return { url, ...info }
|
||||
})
|
||||
.slice(0, 2) // 0 and 1 will always be prod and community
|
||||
|
||||
const alt = hosts
|
||||
.map(([url, name]) => {
|
||||
return { url, name }
|
||||
.map(([url, info]) => {
|
||||
return { url, ...info }
|
||||
})
|
||||
.slice(2) // 2 and beyond will always be alts
|
||||
|
||||
@@ -91,7 +94,7 @@ export class MarketplaceSettingsPage {
|
||||
}
|
||||
|
||||
async presentAction(
|
||||
{ url, name }: { url: string; name: string },
|
||||
{ url, name }: { url: string; name?: string },
|
||||
canDelete = false,
|
||||
) {
|
||||
const buttons: ActionSheetButton[] = [
|
||||
@@ -108,7 +111,7 @@ export class MarketplaceSettingsPage {
|
||||
text: 'Delete',
|
||||
role: 'destructive',
|
||||
handler: () => {
|
||||
this.presentAlertDelete(url, name)
|
||||
this.presentAlertDelete(url, name!)
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -146,7 +149,7 @@ export class MarketplaceSettingsPage {
|
||||
url: string,
|
||||
loader?: HTMLIonLoadingElement,
|
||||
): Promise<void> {
|
||||
const message = 'Changing Marketplace...'
|
||||
const message = 'Changing Registry...'
|
||||
if (!loader) {
|
||||
loader = await this.loadingCtrl.create({ message })
|
||||
await loader.present()
|
||||
@@ -155,7 +158,7 @@ export class MarketplaceSettingsPage {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.api.setDbValue(['marketplace', 'selected-url'], url)
|
||||
await this.api.setDbValue<string>(['marketplace', 'selected-url'], url)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -204,14 +207,17 @@ export class MarketplaceSettingsPage {
|
||||
loader.message = 'Validating marketplace...'
|
||||
await loader.present()
|
||||
|
||||
const { name } = await firstValueFrom(
|
||||
const { name, icon } = await firstValueFrom(
|
||||
this.marketplaceService.fetchInfo$(url),
|
||||
)
|
||||
|
||||
// Save
|
||||
loader.message = 'Saving...'
|
||||
|
||||
await this.api.setDbValue(['marketplace', 'known-hosts', url], name)
|
||||
await this.api.setDbValue<StoreIdentifier>(
|
||||
['marketplace', 'known-hosts', url],
|
||||
{ name, icon },
|
||||
)
|
||||
}
|
||||
|
||||
private async delete(url: string): Promise<void> {
|
||||
@@ -224,7 +230,7 @@ export class MarketplaceSettingsPage {
|
||||
this.patch.watch$('ui', 'marketplace', 'known-hosts'),
|
||||
)
|
||||
|
||||
const filtered = Object.keys(hosts)
|
||||
const filtered: { [url: string]: StoreIdentifier } = Object.keys(hosts)
|
||||
.filter(key => key !== url)
|
||||
.reduce((prev, curr) => {
|
||||
const name = hosts[curr]
|
||||
@@ -235,7 +241,10 @@ export class MarketplaceSettingsPage {
|
||||
}, {})
|
||||
|
||||
try {
|
||||
await this.api.setDbValue(['marketplace', 'known-hosts'], filtered)
|
||||
await this.api.setDbValue<{ [url: string]: StoreIdentifier }>(
|
||||
['marketplace', 'known-hosts'],
|
||||
filtered,
|
||||
)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -247,12 +256,12 @@ export class MarketplaceSettingsPage {
|
||||
function getMarketplaceValueSpec(): ValueSpecObject {
|
||||
return {
|
||||
type: 'object',
|
||||
name: 'Add Marketplace',
|
||||
name: 'Add Custom Registry',
|
||||
spec: {
|
||||
url: {
|
||||
type: 'string',
|
||||
name: 'URL',
|
||||
description: 'The fully-qualified URL of the alt marketplace.',
|
||||
description: 'A fully-qualified URL of the custom registry',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
|
||||
@@ -24,10 +24,12 @@
|
||||
</p>
|
||||
<h6>Highlights</h6>
|
||||
<ul class="spaced-list">
|
||||
<li>Kiosk mode</li>
|
||||
<li>x86_64 architecture compatibility</li>
|
||||
<li>Community marketplaces</li>
|
||||
<li>New update all tab</li>
|
||||
<li>Kiosk mode - use your Embassy with monitor, keyboard, and mouse</li>
|
||||
<li>Community Registry now included in Marketplace</li>
|
||||
<li>
|
||||
"Updates" tab - view all service updates from all registries in one place
|
||||
</li>
|
||||
<li>Various UI/UX improvements</li>
|
||||
<li>Various bugfixes and optimizations</li>
|
||||
</ul>
|
||||
|
||||
@@ -161,7 +161,7 @@ export class AppActionsPage {
|
||||
try {
|
||||
await this.embassyApi.uninstallPackage({ id: this.pkgId })
|
||||
this.embassyApi
|
||||
.setDbValue(['ack-instructions', this.pkgId], false)
|
||||
.setDbValue<boolean>(['ack-instructions', this.pkgId], false)
|
||||
.catch(e => console.error('Failed to mark instructions as unseen', e))
|
||||
this.navCtrl.navigateRoot('/services')
|
||||
} catch (e: any) {
|
||||
|
||||
@@ -10,13 +10,26 @@
|
||||
<p>{{ manifest.version | displayEmver }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="copy(manifest['git-hash'])">
|
||||
<ion-item
|
||||
*ngIf="manifest['git-hash'] as gitHash; else noHash"
|
||||
button
|
||||
detail="false"
|
||||
(click)="copy(gitHash)"
|
||||
>
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>{{ manifest['git-hash'] }}</p>
|
||||
<p>{{ gitHash }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="copy-outline"></ion-icon>
|
||||
</ion-item>
|
||||
<ng-template #noHash>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h2>Git Hash</h2>
|
||||
<p>Unknown</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
<ion-item button detail="false" (click)="presentModalLicense()">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
|
||||
@@ -109,7 +109,7 @@ export class ToButtonsPipe implements PipeTransform {
|
||||
|
||||
private async presentModalInstructions(pkg: PackageDataEntry) {
|
||||
this.apiService
|
||||
.setDbValue(['ack-instructions', pkg.manifest.id], true)
|
||||
.setDbValue<boolean>(['ack-instructions', pkg.manifest.id], true)
|
||||
.catch(e => console.error('Failed to mark instructions as seen', e))
|
||||
|
||||
const modal = await this.modalCtrl.create({
|
||||
@@ -130,19 +130,19 @@ export class ToButtonsPipe implements PipeTransform {
|
||||
const queryParams = url ? { url } : {}
|
||||
|
||||
let button: Button = {
|
||||
title: 'Marketplace',
|
||||
title: 'Marketplace Listing',
|
||||
icon: 'storefront-outline',
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward([`marketplace/${pkg.manifest.id}`], {
|
||||
queryParams,
|
||||
}),
|
||||
disabled: false,
|
||||
description: 'View service in marketplace',
|
||||
description: 'View service in the marketplace',
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
button.disabled = true
|
||||
button.description = 'This package was not installed from a marketplace.'
|
||||
button.description = 'This package was not installed from the marketplace'
|
||||
button.action = () => {}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,10 @@ export class DevConfigPage {
|
||||
async save() {
|
||||
this.saving = true
|
||||
try {
|
||||
await this.api.setDbValue(['dev', this.projectId, 'config'], this.code)
|
||||
await this.api.setDbValue<string>(
|
||||
['dev', this.projectId, 'config'],
|
||||
this.code,
|
||||
)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
|
||||
@@ -56,7 +56,7 @@ export class DevInstructionsPage {
|
||||
async save() {
|
||||
this.saving = true
|
||||
try {
|
||||
await this.api.setDbValue(
|
||||
await this.api.setDbValue<string>(
|
||||
['dev', this.projectId, 'instructions'],
|
||||
this.code,
|
||||
)
|
||||
|
||||
@@ -148,7 +148,11 @@ export class DeveloperListPage {
|
||||
.replace(/warning:/g, '# Optional\n warning:')
|
||||
|
||||
const def = { name, config, instructions: SAMPLE_INSTUCTIONS }
|
||||
await this.api.setDbValue(['dev', id], def)
|
||||
await this.api.setDbValue<{
|
||||
name: string
|
||||
config: string
|
||||
instructions: string
|
||||
}>(['dev', id], def)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -184,7 +188,7 @@ export class DeveloperListPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.api.setDbValue(['dev', id, 'name'], newName)
|
||||
await this.api.setDbValue<string>(['dev', id, 'name'], newName)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -201,7 +205,7 @@ export class DeveloperListPage {
|
||||
try {
|
||||
const devDataToSave: DevData = JSON.parse(JSON.stringify(this.devData))
|
||||
delete devDataToSave[id]
|
||||
await this.api.setDbValue(['dev'], devDataToSave)
|
||||
await this.api.setDbValue<DevData>(['dev'], devDataToSave)
|
||||
} catch (e: any) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
|
||||
@@ -55,7 +55,7 @@ export class DeveloperMenuPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.api.setDbValue(
|
||||
await this.api.setDbValue<BasicInfo>(
|
||||
['dev', this.projectId, 'basic-info'],
|
||||
basicInfo,
|
||||
)
|
||||
|
||||
@@ -151,7 +151,7 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
type: 'string',
|
||||
name: 'Support Site',
|
||||
description: 'URL to the support site / channel for the project',
|
||||
placeholder: 'e.g. www.start9labs.com',
|
||||
placeholder: 'e.g. start9.com/support',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
@@ -161,7 +161,7 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
type: 'string',
|
||||
name: 'Marketing Site',
|
||||
description: 'URL to the marketing site / channel for the project',
|
||||
placeholder: 'e.g. www.start9labs.com',
|
||||
placeholder: 'e.g. start9.com',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
|
||||
@@ -23,10 +23,20 @@
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col size="12">
|
||||
<h1 class="heading montserrat ion-text-center">{{ details.name }}</h1>
|
||||
<div class="heading">
|
||||
<img
|
||||
*ngIf="details.icon; else noIcon"
|
||||
[src]="'data:image/png;base64,' + details.icon | trustUrl"
|
||||
alt=""
|
||||
/>
|
||||
<ng-template #noIcon>
|
||||
<ion-icon name="storefront-outline"></ion-icon>
|
||||
</ng-template>
|
||||
<h1 class="montserrat ion-text-center">{{ details.name }}</h1>
|
||||
</div>
|
||||
<ion-button fill="clear" (click)="presentModalMarketplaceSettings()">
|
||||
<ion-icon slot="start" name="repeat-outline"></ion-icon>
|
||||
Switch Marketplaces
|
||||
Change
|
||||
</ion-button>
|
||||
<marketplace-search [(query)]="query"></marketplace-search>
|
||||
</ion-col>
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
.heading {
|
||||
font-size: 42px;
|
||||
$icon-size: 64px;
|
||||
margin-top: 32px;
|
||||
img {
|
||||
max-width: $icon-size;
|
||||
}
|
||||
h1 {
|
||||
font-size: 42px;
|
||||
}
|
||||
ion-icon {
|
||||
font-size: $icon-size;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
|
||||
@@ -30,35 +30,36 @@ export class MarketplaceListPage {
|
||||
readonly localPkgs$ = this.patch.watch$('package-data')
|
||||
|
||||
readonly details$ = this.marketplaceService.getSelectedHost$().pipe(
|
||||
map(({ url, name }) => {
|
||||
map(({ url, name, icon }) => {
|
||||
let color: string
|
||||
let description: string
|
||||
switch (url) {
|
||||
case 'https://registry.start9.com/':
|
||||
color = 'success'
|
||||
description =
|
||||
'Services in this marketplace are packaged and maintained by the Start9 team. If you experience an issue or have a questions related to a service in this marketplace, one of our dedicated support staff will be happy to assist you.'
|
||||
'Services from this registry are packaged and maintained by the Start9 team. If you experience an issue or have a questions related to a service from this registry, one of our dedicated support staff will be happy to assist you.'
|
||||
break
|
||||
case 'https://beta-registry-0-3.start9labs.com/':
|
||||
case 'https://beta-registry.start9.com/':
|
||||
color = 'primary'
|
||||
description =
|
||||
'Services in this marketplace are undergoing active testing and may contain bugs. <b>Install at your own risk</b>. If you discover a bug or have a suggestion for improvement, please report it to the Start9 team in our community testing channel on Matrix.'
|
||||
'Services from this registry are undergoing active testing and may contain bugs. <b>Install at your own risk</b>. If you discover a bug or have a suggestion for improvement, please report it to the Start9 team in our community testing channel on Matrix.'
|
||||
break
|
||||
case 'https://community.start9labs.com/':
|
||||
case 'https://community-registry.start9.com/':
|
||||
color = 'tertiary'
|
||||
description =
|
||||
'Services in this marketplace are packaged and maintained by members of the Start9 community. <b>Install at your own risk</b>. If you experience an issue or have a question related to a service in this marketplace, please reach out to the package developer for assistance.'
|
||||
'Services from this registry are packaged and maintained by members of the Start9 community. <b>Install at your own risk</b>. If you experience an issue or have a question related to a service in this marketplace, please reach out to the package developer for assistance.'
|
||||
break
|
||||
default:
|
||||
// alt marketplace
|
||||
color = 'warning'
|
||||
description =
|
||||
'Warning. This is an <b>Alternative</b> Marketplace. Start9 cannot verify the integrity or functionality of services in this marketplace, and they may cause harm to your system. <b>Install at your own risk</b>.'
|
||||
'Warning. This is a <b>Custom</b> Registry. Start9 cannot verify the integrity or functionality of services from this registry, and they may cause harm to your system. <b>Install at your own risk</b>.'
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
url,
|
||||
icon,
|
||||
color,
|
||||
description,
|
||||
}
|
||||
|
||||
@@ -99,11 +99,12 @@ export class MarketplaceShowControlsComponent {
|
||||
this.patch.watch$('ui', 'marketplace'),
|
||||
)
|
||||
|
||||
const name = marketplaces['known-hosts'][url] || url
|
||||
const name: string = marketplaces['known-hosts'][url]?.name || url
|
||||
|
||||
let originalName: string | undefined
|
||||
if (originalUrl) {
|
||||
originalName = marketplaces['known-hosts'][originalUrl] || originalUrl
|
||||
originalName =
|
||||
marketplaces['known-hosts'][originalUrl]?.name || originalUrl
|
||||
}
|
||||
|
||||
return new Promise(async resolve => {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</ol>
|
||||
View the full
|
||||
<a
|
||||
href="https://start9.com/latest/user-manual/connecting/connecting-lan"
|
||||
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>instructions</a
|
||||
|
||||
@@ -178,7 +178,7 @@ export class ServerShowPage {
|
||||
async presentAlertRepairDisk() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Warning',
|
||||
message: `<p>This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action.</p><p>If anything happens to the device during the reboot (between the bep and chime), such as losing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem <i>will</i> be in an unrecoverable state. Please proceed with caution.</p>`,
|
||||
message: `<p>This action will attempt to preform a disk repair operation and system reboot. No data will be deleted. This action should only be executed if directed by a Start9 support specialist. We recommend backing up your device before preforming this action.</p><p>If anything happens to the device during the reboot, such as losing power, a power surge, unplugging the drive, or unplugging the Embassy, the filesystem <i>will</i> be in an unrecoverable state. Please proceed with caution.</p>`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
@@ -223,7 +223,7 @@ export class ServerShowPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.setDbValue([key], value)
|
||||
await this.embassyApi.setDbValue<string>([key], value)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
@@ -333,7 +333,7 @@ export class ServerShowPage {
|
||||
private async presentAlertInProgress(verb: string, message: string) {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: `${verb} In Progress...`,
|
||||
message: `Stopping all services gracefully. This can take a while.<br /><br />Your Embassy will then <b>♫ play a melody ♫</b> and become unreachable${message}`,
|
||||
message: `Stopping all services gracefully. This can take a while.<br /><br />If you have a speaker, your Embassy will <b>♫ play a melody ♫</b> before shutting down. Your Embassy will then become unreachable${message}`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'OK',
|
||||
@@ -484,7 +484,7 @@ export class ServerShowPage {
|
||||
icon: 'map-outline',
|
||||
action: () =>
|
||||
window.open(
|
||||
'https://start9.com/latest/user-manual/',
|
||||
'https://docs.start9.com/latest/user-manual',
|
||||
'_blank',
|
||||
'noreferrer',
|
||||
),
|
||||
@@ -497,7 +497,7 @@ export class ServerShowPage {
|
||||
icon: 'chatbubbles-outline',
|
||||
action: () =>
|
||||
window.open(
|
||||
'https://start9.com/latest/support/contact/',
|
||||
'https://docs.start9.com/latest/support/contact',
|
||||
'_blank',
|
||||
'noreferrer',
|
||||
),
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
export class SSHKeysPage {
|
||||
loading = true
|
||||
sshKeys: SSHKey[] = []
|
||||
readonly docsUrl = 'https://start9.com/latest/user-manual/ssh'
|
||||
readonly docsUrl = 'https://docs.start9.com/latest/user-manual/ssh'
|
||||
|
||||
constructor(
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
Ethernet cable and move the device anywhere you want. Embassy will
|
||||
automatically connect to available networks.
|
||||
<a
|
||||
href="https://start9.com/latest/user-manual/wifi"
|
||||
href="https://docs.start9.com/latest/user-manual/wifi"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>View instructions</a
|
||||
|
||||
@@ -10,7 +10,14 @@
|
||||
<ion-content class="ion-padding">
|
||||
<ion-item-group *ngIf="data$ | async as data">
|
||||
<ng-container *ngFor="let host of data.hosts | keyvalue">
|
||||
<ion-item-divider> {{ host.value }} </ion-item-divider>
|
||||
<ion-item-divider>
|
||||
{{ host.value.name }}
|
||||
<img
|
||||
style="max-width: 24px"
|
||||
[src]="'data:image/png;base64,' + host.value.icon | trustUrl"
|
||||
alt=""
|
||||
/>
|
||||
</ion-item-divider>
|
||||
|
||||
<div class="ion-padding-start ion-padding-bottom">
|
||||
<ion-item *ngIf="data.errors.includes(host.key)">
|
||||
@@ -25,7 +32,7 @@
|
||||
>
|
||||
<ion-item *ngFor="let pkg of updates">
|
||||
<ng-container *ngIf="data.localPkgs[pkg.manifest.id] as local">
|
||||
<ion-avatar slot="start">
|
||||
<ion-avatar slot="start" class="service-avatar">
|
||||
<img [src]="'data:image/png;base64,' + pkg.icon | trustUrl" />
|
||||
</ion-avatar>
|
||||
<ion-label>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ion-avatar {
|
||||
.service-avatar {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Marketplace,
|
||||
MarketplaceManifest,
|
||||
MarketplacePkg,
|
||||
StoreIdentifier,
|
||||
} from '@start9labs/marketplace'
|
||||
import { Emver } from '@start9labs/shared'
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
@@ -19,7 +20,7 @@ import { combineLatest, Observable } from 'rxjs'
|
||||
import { PrimaryRendering } from '../../services/pkg-status-rendering.service'
|
||||
|
||||
interface UpdatesData {
|
||||
hosts: Record<string, string>
|
||||
hosts: Record<string, StoreIdentifier>
|
||||
marketplace: Marketplace
|
||||
localPkgs: Record<string, PackageDataEntry>
|
||||
errors: string[]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -348,7 +348,6 @@ export module Mock {
|
||||
id: 'lnd',
|
||||
title: 'Lightning Network Daemon',
|
||||
version: '0.11.1',
|
||||
'git-hash': 'lalalalalala',
|
||||
description: {
|
||||
short: 'A bolt spec compliant client.',
|
||||
long: 'More info about LND. More info about LND. More info about LND.',
|
||||
|
||||
@@ -16,7 +16,7 @@ export module RR {
|
||||
|
||||
export type GetDumpRes = Dump<DataModel>
|
||||
|
||||
export type SetDBValueReq = { pointer: string; value: any } // db.put.ui
|
||||
export type SetDBValueReq<T> = { pointer: string; value: T } // db.put.ui
|
||||
export type SetDBValueRes = null
|
||||
|
||||
// auth
|
||||
|
||||
@@ -18,9 +18,9 @@ export abstract class ApiService {
|
||||
|
||||
// db
|
||||
|
||||
abstract setDbValue(
|
||||
abstract setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: any,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes>
|
||||
|
||||
// auth
|
||||
|
||||
@@ -54,12 +54,12 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// db
|
||||
|
||||
async setDbValue(
|
||||
async setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: any,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes> {
|
||||
const pointer = pathFromArray(pathArr)
|
||||
const params: RR.SetDBValueReq = { pointer, value }
|
||||
const params: RR.SetDBValueReq<T> = { pointer, value }
|
||||
return this.rpcRequest({ method: 'db.put.ui', params })
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ import { mockPatchData } from './mock-patch'
|
||||
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { ConnectionService } from '../connection.service'
|
||||
import { StoreInfo } from '@start9labs/marketplace'
|
||||
import { COMMUNITY_REGISTRY, START9_REGISTRY } from './api-icons'
|
||||
|
||||
const PROGRESS: InstallProgress = {
|
||||
size: 120,
|
||||
@@ -93,12 +95,12 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// db
|
||||
|
||||
async setDbValue(
|
||||
async setDbValue<T>(
|
||||
pathArr: Array<string | number>,
|
||||
value: any,
|
||||
value: T,
|
||||
): Promise<RR.SetDBValueRes> {
|
||||
const pointer = pathFromArray(pathArr)
|
||||
const params: RR.SetDBValueReq = { pointer, value }
|
||||
const params: RR.SetDBValueReq<T> = { pointer, value }
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -280,8 +282,9 @@ export class MockApiService extends ApiService {
|
||||
await pauseFor(2000)
|
||||
|
||||
if (path === '/package/v0/info') {
|
||||
return {
|
||||
name: 'Dark69',
|
||||
const info: StoreInfo = {
|
||||
name: 'Start9 Registry',
|
||||
icon: START9_REGISTRY,
|
||||
categories: [
|
||||
'bitcoin',
|
||||
'lightning',
|
||||
@@ -292,6 +295,7 @@ export class MockApiService extends ApiService {
|
||||
'alt coin',
|
||||
],
|
||||
}
|
||||
return info
|
||||
} else if (path === '/package/v0/index') {
|
||||
return Mock.MarketplacePkgsList
|
||||
} else if (path.startsWith('/package/v0/release-notes')) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { COMMUNITY_REGISTRY, START9_REGISTRY } from './api-icons'
|
||||
import { Mock } from './api.fixures'
|
||||
|
||||
export const mockPatchData: DataModel = {
|
||||
@@ -17,9 +18,16 @@ export const mockPatchData: DataModel = {
|
||||
marketplace: {
|
||||
'selected-url': 'https://registry.start9.com/',
|
||||
'known-hosts': {
|
||||
'https://registry.start9.com/': 'Start9 Marketplace',
|
||||
'https://community-registry.start9.com/': 'Community Marketplace',
|
||||
'https://dark9-marketplace.com/': 'Dark9',
|
||||
'https://registry.start9.com/': {
|
||||
name: 'Start9 Registry',
|
||||
icon: START9_REGISTRY,
|
||||
},
|
||||
'https://community-registry.start9.com/': {
|
||||
icon: COMMUNITY_REGISTRY,
|
||||
},
|
||||
'https://dark9-marketplace.com/': {
|
||||
name: 'Dark9',
|
||||
},
|
||||
},
|
||||
},
|
||||
dev: {},
|
||||
@@ -453,7 +461,6 @@ export const mockPatchData: DataModel = {
|
||||
id: 'lnd',
|
||||
title: 'Lightning Network Daemon',
|
||||
version: '0.11.1',
|
||||
'git-hash': 'lalalalalala',
|
||||
description: {
|
||||
short: 'A bolt spec compliant client.',
|
||||
long: 'More info about LND. More info about LND. More info about LND.',
|
||||
|
||||
@@ -19,7 +19,7 @@ const {
|
||||
})
|
||||
export class ConfigService {
|
||||
origin = removePort(removeProtocol(window.origin))
|
||||
version = require('../../../../../package.json').version
|
||||
version = require('../../../../../package.json').version as string
|
||||
useMocks = useMocks
|
||||
mocks = mocks
|
||||
targetArch = targetArch
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
StoreData,
|
||||
Marketplace,
|
||||
StoreInfo,
|
||||
StoreIdentifier,
|
||||
} from '@start9labs/marketplace'
|
||||
import {
|
||||
BehaviorSubject,
|
||||
@@ -28,7 +29,6 @@ import {
|
||||
shareReplay,
|
||||
startWith,
|
||||
switchMap,
|
||||
tap,
|
||||
} from 'rxjs/operators'
|
||||
import { getNewEntries } from '@start9labs/shared'
|
||||
|
||||
@@ -44,19 +44,19 @@ export class MarketplaceService implements AbstractMarketplaceService {
|
||||
distinctUntilKeyChanged('selected-url'),
|
||||
map(data => ({
|
||||
url: data['selected-url'],
|
||||
name: data['known-hosts'][data['selected-url']],
|
||||
...data['known-hosts'][data['selected-url']],
|
||||
})),
|
||||
shareReplay(1),
|
||||
)
|
||||
|
||||
private readonly marketplace$ = this.knownHosts$.pipe(
|
||||
startWith<Record<string, string>>({}),
|
||||
startWith<Record<string, StoreIdentifier>>({}),
|
||||
pairwise(),
|
||||
mergeMap(([prev, curr]) => from(Object.entries(getNewEntries(prev, curr)))),
|
||||
mergeMap(([url, name]) =>
|
||||
mergeMap(([url, registry]) =>
|
||||
this.fetchStore$(url).pipe(
|
||||
map<StoreData, [string, StoreData | null]>(data => {
|
||||
if (data.info) this.updateName(url, name, data.info.name)
|
||||
if (data.info) this.updateStoreIdentifier(url, registry, data.info)
|
||||
|
||||
return [url, data]
|
||||
}),
|
||||
@@ -85,11 +85,11 @@ export class MarketplaceService implements AbstractMarketplaceService {
|
||||
private readonly patch: PatchDB<DataModel>,
|
||||
) {}
|
||||
|
||||
getKnownHosts$(): Observable<Record<string, string>> {
|
||||
getKnownHosts$(): Observable<Record<string, StoreIdentifier>> {
|
||||
return this.knownHosts$
|
||||
}
|
||||
|
||||
getSelectedHost$(): Observable<{ url: string; name: string }> {
|
||||
getSelectedHost$(): Observable<StoreIdentifier & { url: string }> {
|
||||
return this.selectedHost$
|
||||
}
|
||||
|
||||
@@ -233,13 +233,16 @@ export class MarketplaceService implements AbstractMarketplaceService {
|
||||
)
|
||||
}
|
||||
|
||||
private async updateName(
|
||||
private async updateStoreIdentifier(
|
||||
url: string,
|
||||
name: string,
|
||||
newName: string,
|
||||
oldInfo: StoreIdentifier,
|
||||
newInfo: StoreIdentifier,
|
||||
): Promise<void> {
|
||||
if (name !== newName) {
|
||||
this.api.setDbValue(['marketplace', 'known-hosts', url], newName)
|
||||
if (oldInfo.name !== newInfo.name || oldInfo.icon !== newInfo.icon) {
|
||||
this.api.setDbValue<StoreIdentifier>(
|
||||
['marketplace', 'known-hosts', url],
|
||||
newInfo,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ export class PatchDataService extends Observable<DataModel> {
|
||||
backdropDismiss: false,
|
||||
})
|
||||
modal.onWillDismiss().then(() => {
|
||||
this.embassyApi.setDbValue(['ack-welcome'], this.config.version).catch()
|
||||
this.embassyApi
|
||||
.setDbValue<string>(['ack-welcome'], this.config.version)
|
||||
.catch()
|
||||
})
|
||||
|
||||
await modal.present()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { Url } from '@start9labs/shared'
|
||||
import { MarketplaceManifest } from '@start9labs/marketplace'
|
||||
import { MarketplaceManifest, StoreIdentifier } from '@start9labs/marketplace'
|
||||
import { BasicInfo } from 'src/app/pages/developer-routes/developer-menu/form-info'
|
||||
|
||||
export interface DataModel {
|
||||
@@ -26,9 +26,9 @@ export interface UIData {
|
||||
export interface UIMarketplaceData {
|
||||
'selected-url': string
|
||||
'known-hosts': {
|
||||
'https://registry.start9.com/': string
|
||||
'https://community-registry.start9.com/': string
|
||||
[url: string]: string
|
||||
'https://registry.start9.com/': StoreIdentifier
|
||||
'https://community-registry.start9.com/': StoreIdentifier
|
||||
[url: string]: StoreIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user