mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
add descriptions to marketplace list page (#1812)
* add descriptions to marketplace list page * clean up unused styling * rip descriptions from registry marketplace, use binary choice custom default and alternative messages * cleanup * fix selected type and remove uneeded conditional * conditional color * cleanup * better comparision of marketplace url duplicates * add logic to handle marketplace description display based on url * decrease font size * abstract helper fn to get url hostname; add error toast when adding duplicate marketplace * move helper function to more appropriate file location * rework marketplace list and don't worry about patch db firing before bootstrapped * remove aes-js * reinstall aes just to please things for now Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
1449
frontend/package-lock.json
generated
1449
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@
|
|||||||
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
||||||
"@start9labs/argon2": "^0.1.0",
|
"@start9labs/argon2": "^0.1.0",
|
||||||
"@start9labs/emver": "^0.1.5",
|
"@start9labs/emver": "^0.1.5",
|
||||||
|
"@types/aes-js": "^3.1.1",
|
||||||
"aes-js": "^3.1.2",
|
"aes-js": "^3.1.2",
|
||||||
"ansi-to-html": "^0.7.2",
|
"ansi-to-html": "^0.7.2",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
@@ -66,7 +67,6 @@
|
|||||||
"@angular/compiler-cli": "^14.1.0",
|
"@angular/compiler-cli": "^14.1.0",
|
||||||
"@angular/language-service": "^14.1.0",
|
"@angular/language-service": "^14.1.0",
|
||||||
"@ionic/cli": "^6.19.0",
|
"@ionic/cli": "^6.19.0",
|
||||||
"@types/aes-js": "^3.1.1",
|
|
||||||
"@types/dompurify": "^2.3.3",
|
"@types/dompurify": "^2.3.3",
|
||||||
"@types/estree": "^0.0.51",
|
"@types/estree": "^0.0.51",
|
||||||
"@types/js-yaml": "^4.0.5",
|
"@types/js-yaml": "^4.0.5",
|
||||||
|
|||||||
@@ -49,3 +49,7 @@ export function isValidHttpUrl(string: string): boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getUrlHostname(url: string): string {
|
||||||
|
return new URL(url).hostname
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
>
|
>
|
||||||
<ion-menu contentId="main-content" type="overlay">
|
<ion-menu contentId="main-content" type="overlay">
|
||||||
<ion-content color="light" scrollY="false">
|
<ion-content color="light" scrollY="false">
|
||||||
<app-menu></app-menu>
|
<app-menu *ngIf="authService.isVerified$ | async"></app-menu>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-menu>
|
</ion-menu>
|
||||||
<ion-router-outlet id="main-content"></ion-router-outlet>
|
<ion-router-outlet id="main-content"></ion-router-outlet>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '@angular/core'
|
import { Component } from '@angular/core'
|
||||||
import { ModalController } from '@ionic/angular'
|
import { ModalController } from '@ionic/angular'
|
||||||
import { filter, map, take } from 'rxjs/operators'
|
import { map, take } from 'rxjs/operators'
|
||||||
import { DataModel, PackageState } from 'src/app/services/patch-db/data-model'
|
import { DataModel, PackageState } from 'src/app/services/patch-db/data-model'
|
||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
|
|
||||||
@@ -29,7 +29,6 @@ export class BackupSelectPage {
|
|||||||
this.patch
|
this.patch
|
||||||
.watch$('package-data')
|
.watch$('package-data')
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(Boolean),
|
|
||||||
map(pkgs => {
|
map(pkgs => {
|
||||||
return Object.values(pkgs).map(pkg => {
|
return Object.values(pkgs).map(pkg => {
|
||||||
const { id, title } = pkg.manifest
|
const { id, title } = pkg.manifest
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ 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 {
|
import { getUrlHostname, MarkdownComponent } from '@start9labs/shared'
|
||||||
isValidHttpUrl,
|
|
||||||
MarkdownComponent,
|
|
||||||
removeTrailingSlash,
|
|
||||||
} from '@start9labs/shared'
|
|
||||||
import {
|
import {
|
||||||
DataModel,
|
DataModel,
|
||||||
PackageDataEntry,
|
PackageDataEntry,
|
||||||
@@ -144,7 +140,7 @@ export class ToButtonsPipe implements PipeTransform {
|
|||||||
currentMarketplace: Marketplace | null,
|
currentMarketplace: Marketplace | null,
|
||||||
altMarketplaces: UIMarketplaceData | null | undefined,
|
altMarketplaces: UIMarketplaceData | null | undefined,
|
||||||
): Button {
|
): Button {
|
||||||
const pkgMarketplace = pkg.installed?.['marketplace-url']
|
const pkgMarketplaceUrl = pkg.installed?.['marketplace-url']
|
||||||
// default button if package marketplace and current marketplace are the same
|
// default button if package marketplace and current marketplace are the same
|
||||||
let button: Button = {
|
let button: Button = {
|
||||||
title: 'Marketplace',
|
title: 'Marketplace',
|
||||||
@@ -154,37 +150,32 @@ export class ToButtonsPipe implements PipeTransform {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
description: 'View service in marketplace',
|
description: 'View service in marketplace',
|
||||||
}
|
}
|
||||||
if (!pkgMarketplace) {
|
if (!pkgMarketplaceUrl) {
|
||||||
button.disabled = true
|
button.disabled = true
|
||||||
button.description = 'This package was not installed from a marketplace.'
|
button.description = 'This package was not installed from a marketplace.'
|
||||||
button.action = () => {}
|
button.action = () => {}
|
||||||
} else if (
|
} else if (
|
||||||
pkgMarketplace &&
|
pkgMarketplaceUrl &&
|
||||||
currentMarketplace &&
|
currentMarketplace &&
|
||||||
removeTrailingSlash(pkgMarketplace) !==
|
getUrlHostname(pkgMarketplaceUrl) !==
|
||||||
removeTrailingSlash(currentMarketplace.url)
|
getUrlHostname(currentMarketplace.url)
|
||||||
) {
|
) {
|
||||||
// attempt to get name for pkg marketplace
|
// attempt to get name for pkg marketplace
|
||||||
let pkgTitle = removeTrailingSlash(pkgMarketplace)
|
let pkgMarketplaceName = getUrlHostname(pkgMarketplaceUrl)
|
||||||
if (altMarketplaces) {
|
if (altMarketplaces) {
|
||||||
const nameOptions = Object.values(
|
const pkgMarketplaces = Object.values(
|
||||||
altMarketplaces['known-hosts'],
|
altMarketplaces['known-hosts'],
|
||||||
).filter(m => m.url === pkgTitle)
|
).filter(m => getUrlHostname(m.url) === pkgMarketplaceName)
|
||||||
if (nameOptions.length) {
|
if (pkgMarketplaces.length) {
|
||||||
// if multiple of the same url exist, they will have the same name, so fine to grab first
|
// if multiple of the same url exist, they will have the same name, so fine to grab first
|
||||||
pkgTitle = nameOptions[0].name
|
pkgMarketplaceName = pkgMarketplaces[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 = () =>
|
button.action = () =>
|
||||||
this.differentMarketplaceAction(
|
this.differentMarketplaceAction(
|
||||||
pkgTitle,
|
pkgMarketplaceName,
|
||||||
marketplaceTitle,
|
currentMarketplace.name,
|
||||||
pkg.manifest.id,
|
pkg.manifest.id,
|
||||||
)
|
)
|
||||||
button.description = 'Service was installed from a different marketplace'
|
button.description = 'Service was installed from a different marketplace'
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<h1 class="heading montserrat ion-text-center">{{ name }}</h1>
|
|
||||||
|
|
||||||
<marketplace-search [(query)]="query"></marketplace-search>
|
|
||||||
|
|
||||||
<ng-container *ngIf="pkgs && categories; else loading">
|
|
||||||
<marketplace-categories
|
|
||||||
[categories]="categories"
|
|
||||||
[category]="category"
|
|
||||||
[updatesAvailable]="(pkgs | filterPackages: '':'updates':localPkgs).length"
|
|
||||||
(categoryChange)="onCategoryChange($event)"
|
|
||||||
></marketplace-categories>
|
|
||||||
|
|
||||||
<div class="divider"></div>
|
|
||||||
|
|
||||||
<ion-grid *ngIf="pkgs | filterPackages: query:category:localPkgs as filtered">
|
|
||||||
<div *ngIf="!filtered.length && category === 'updates'" class="ion-padding">
|
|
||||||
<h1>All services are up to date!</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ion-row>
|
|
||||||
<ion-col *ngFor="let pkg of filtered" sizeXs="12" sizeSm="12" sizeMd="6">
|
|
||||||
<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-template #loading>
|
|
||||||
<marketplace-skeleton></marketplace-skeleton>
|
|
||||||
</ng-template>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
.heading {
|
|
||||||
font-size: 42px;
|
|
||||||
margin: 32px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.divider {
|
|
||||||
margin: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ion-padding {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
|
||||||
import { MarketplacePkg } from '@start9labs/marketplace'
|
|
||||||
|
|
||||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'marketplace-list-content',
|
|
||||||
templateUrl: 'marketplace-list-content.component.html',
|
|
||||||
styleUrls: ['./marketplace-list-content.component.scss'],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
||||||
})
|
|
||||||
export class MarketplaceListContentComponent {
|
|
||||||
@Input()
|
|
||||||
pkgs: MarketplacePkg[] | null = null
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
localPkgs: Record<string, PackageDataEntry> = {}
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
categories: Set<string> | null = null
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
name = ''
|
|
||||||
|
|
||||||
category = 'featured'
|
|
||||||
query = ''
|
|
||||||
|
|
||||||
onCategoryChange(category: string): void {
|
|
||||||
this.category = category
|
|
||||||
this.query = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||||
import { MarketplaceStatusModule } from '../marketplace-status/marketplace-status.module'
|
import { MarketplaceStatusModule } from '../marketplace-status/marketplace-status.module'
|
||||||
import { MarketplaceListPage } from './marketplace-list.page'
|
import { MarketplaceListPage } from './marketplace-list.page'
|
||||||
import { MarketplaceListContentComponent } from './marketplace-list-content/marketplace-list-content.component'
|
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
@@ -39,7 +38,7 @@ const routes: Routes = [
|
|||||||
SearchModule,
|
SearchModule,
|
||||||
SkeletonModule,
|
SkeletonModule,
|
||||||
],
|
],
|
||||||
declarations: [MarketplaceListPage, MarketplaceListContentComponent],
|
declarations: [MarketplaceListPage],
|
||||||
exports: [MarketplaceListPage, MarketplaceListContentComponent],
|
exports: [MarketplaceListPage],
|
||||||
})
|
})
|
||||||
export class MarketplaceListPageModule {}
|
export class MarketplaceListPageModule {}
|
||||||
|
|||||||
@@ -7,10 +7,76 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding">
|
<ion-content class="ion-padding">
|
||||||
<marketplace-list-content
|
<ion-grid *ngIf="details$ | async as details">
|
||||||
[localPkgs]="(localPkgs$ | async) || {}"
|
<ion-row>
|
||||||
[pkgs]="pkgs$ | async"
|
<ion-col size-lg="10" offset-lg="1" size-sm="12">
|
||||||
[categories]="categories$ | async"
|
<ion-item class="description" [color]="details.color">
|
||||||
[name]="(name$ | async) || ''"
|
<ion-icon
|
||||||
></marketplace-list-content>
|
text-wrap
|
||||||
|
size="large"
|
||||||
|
name="information-circle-outline"
|
||||||
|
></ion-icon>
|
||||||
|
<ion-label [innerHtml]="details.description"></ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="12">
|
||||||
|
<h1 class="heading montserrat ion-text-center">{{ details.name }}</h1>
|
||||||
|
<p style="margin-top: 0">{{ details.url }}</p>
|
||||||
|
<marketplace-search [(query)]="query"></marketplace-search>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row class="ion-align-items-center">
|
||||||
|
<ion-col size="12">
|
||||||
|
<ng-container *ngIf="pkgs$ | async as pkgs; else loading">
|
||||||
|
<ng-container *ngIf="localPkgs$ | async as localPkgs">
|
||||||
|
<marketplace-categories
|
||||||
|
*ngIf="categories$ | async as categories"
|
||||||
|
[categories]="categories"
|
||||||
|
[category]="category"
|
||||||
|
[updatesAvailable]="
|
||||||
|
(pkgs | filterPackages: '':'updates':localPkgs).length
|
||||||
|
"
|
||||||
|
(categoryChange)="onCategoryChange($event)"
|
||||||
|
></marketplace-categories>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
|
<ion-grid
|
||||||
|
*ngIf="pkgs | filterPackages: query:category:localPkgs as filtered"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
*ngIf="!filtered.length && category === 'updates'"
|
||||||
|
class="ion-padding"
|
||||||
|
>
|
||||||
|
<h1>All services are up to date!</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-row>
|
||||||
|
<ion-col
|
||||||
|
*ngFor="let pkg of filtered"
|
||||||
|
sizeXs="12"
|
||||||
|
sizeSm="12"
|
||||||
|
sizeMd="6"
|
||||||
|
>
|
||||||
|
<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-template #loading>
|
||||||
|
<marketplace-skeleton></marketplace-skeleton>
|
||||||
|
</ng-template>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
.heading {
|
||||||
|
font-size: 42px;
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ion-padding {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1000px) {
|
||||||
|
ion-label {
|
||||||
|
::ng-deep p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +1,65 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
import { ChangeDetectionStrategy, Component } from '@angular/core'
|
||||||
import { map } from 'rxjs/operators'
|
|
||||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||||
|
import { getUrlHostname } from '@start9labs/shared'
|
||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
import { ConnectionService } from 'src/app/services/connection.service'
|
import { map } from 'rxjs'
|
||||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'marketplace-list',
|
selector: 'marketplace-list',
|
||||||
templateUrl: './marketplace-list.page.html',
|
templateUrl: 'marketplace-list.page.html',
|
||||||
|
styleUrls: ['./marketplace-list.page.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class MarketplaceListPage {
|
export class MarketplaceListPage {
|
||||||
readonly connected$ = this.connectionService.connected$
|
|
||||||
|
|
||||||
readonly localPkgs$ = this.patch.watch$('package-data')
|
readonly localPkgs$ = this.patch.watch$('package-data')
|
||||||
|
|
||||||
readonly categories$ = this.marketplaceService.getCategories()
|
readonly categories$ = this.marketplaceService.getCategories()
|
||||||
|
|
||||||
readonly pkgs$ = this.marketplaceService.getPackages()
|
readonly pkgs$ = this.marketplaceService.getPackages()
|
||||||
|
readonly details$ = this.marketplaceService.getMarketplace().pipe(
|
||||||
|
map(d => {
|
||||||
|
let color: string
|
||||||
|
let description: string
|
||||||
|
switch (getUrlHostname(d.url)) {
|
||||||
|
case '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.'
|
||||||
|
break
|
||||||
|
case 'beta-registry-0-3.start9labs.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.'
|
||||||
|
break
|
||||||
|
case 'community.start9labs.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.'
|
||||||
|
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>.'
|
||||||
|
}
|
||||||
|
|
||||||
readonly name$ = this.marketplaceService
|
return {
|
||||||
.getMarketplace()
|
...d,
|
||||||
.pipe(map(({ name }) => name))
|
color,
|
||||||
|
description,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly patch: PatchDB<DataModel>,
|
private readonly patch: PatchDB<DataModel>,
|
||||||
private readonly marketplaceService: AbstractMarketplaceService,
|
private readonly marketplaceService: AbstractMarketplaceService,
|
||||||
private readonly connectionService: ConnectionService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
category = 'featured'
|
||||||
|
query = ''
|
||||||
|
|
||||||
|
onCategoryChange(category: string): void {
|
||||||
|
this.category = category
|
||||||
|
this.query = ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import {
|
|||||||
ModalController,
|
ModalController,
|
||||||
} from '@ionic/angular'
|
} from '@ionic/angular'
|
||||||
import { ActionSheetButton } from '@ionic/core'
|
import { ActionSheetButton } from '@ionic/core'
|
||||||
import { DestroyService, ErrorToastService } from '@start9labs/shared'
|
import {
|
||||||
|
DestroyService,
|
||||||
|
ErrorToastService,
|
||||||
|
getUrlHostname,
|
||||||
|
} from '@start9labs/shared'
|
||||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
||||||
@@ -244,8 +248,8 @@ export class MarketplacesPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no-op on duplicates
|
// no-op on duplicates
|
||||||
const currentUrls = this.marketplaces.map(mp => mp.url)
|
const currentUrls = this.marketplaces.map(mp => getUrlHostname(mp.url))
|
||||||
if (currentUrls.includes(new URL(url).hostname)) return
|
if (currentUrls.includes(getUrlHostname(url))) return
|
||||||
|
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
message: 'Validating Marketplace...',
|
message: 'Validating Marketplace...',
|
||||||
@@ -288,8 +292,11 @@ export class MarketplacesPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no-op on duplicates
|
// no-op on duplicates
|
||||||
const currentUrls = this.marketplaces.map(mp => mp.url)
|
const currentUrls = this.marketplaces.map(mp => getUrlHostname(mp.url))
|
||||||
if (currentUrls.includes(new URL(url).hostname)) return
|
if (currentUrls.includes(getUrlHostname(url))) {
|
||||||
|
this.errToast.present({ message: 'Marketplace already added' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
message: 'Validating Marketplace...',
|
message: 'Validating Marketplace...',
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
PipeTransform,
|
PipeTransform,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
import { filter, take } from 'rxjs/operators'
|
import { take } from 'rxjs/operators'
|
||||||
import {
|
import {
|
||||||
DataModel,
|
DataModel,
|
||||||
PackageMainStatus,
|
PackageMainStatus,
|
||||||
@@ -18,9 +18,7 @@ import { Observable } from 'rxjs'
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class BackingUpComponent {
|
export class BackingUpComponent {
|
||||||
readonly pkgs$ = this.patch
|
readonly pkgs$ = this.patch.watch$('package-data').pipe(take(1))
|
||||||
.watch$('package-data')
|
|
||||||
.pipe(filter(Boolean), take(1))
|
|
||||||
readonly backupProgress$ = this.patch.watch$(
|
readonly backupProgress$ = this.patch.watch$(
|
||||||
'server-info',
|
'server-info',
|
||||||
'status-info',
|
'status-info',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ActivatedRoute } from '@angular/router'
|
|||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
import { ServerNameService } from 'src/app/services/server-name.service'
|
import { ServerNameService } from 'src/app/services/server-name.service'
|
||||||
import { Observable, of } from 'rxjs'
|
import { Observable, of } from 'rxjs'
|
||||||
import { filter, take, tap } from 'rxjs/operators'
|
import { take, tap } from 'rxjs/operators'
|
||||||
import { isEmptyObject, ErrorToastService } from '@start9labs/shared'
|
import { isEmptyObject, ErrorToastService } from '@start9labs/shared'
|
||||||
import { EOSService } from 'src/app/services/eos.service'
|
import { EOSService } from 'src/app/services/eos.service'
|
||||||
import { LocalStorageService } from 'src/app/services/local-storage.service'
|
import { LocalStorageService } from 'src/app/services/local-storage.service'
|
||||||
@@ -52,7 +52,6 @@ export class ServerShowPage {
|
|||||||
this.patch
|
this.patch
|
||||||
.watch$('recovered-packages')
|
.watch$('recovered-packages')
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(Boolean),
|
|
||||||
take(1),
|
take(1),
|
||||||
tap(data => (this.hasRecoveredPackage = !isEmptyObject(data))),
|
tap(data => (this.hasRecoveredPackage = !isEmptyObject(data))),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1786,7 +1786,7 @@ export module Mock {
|
|||||||
},
|
},
|
||||||
'current-dependencies': {},
|
'current-dependencies': {},
|
||||||
'dependency-info': {},
|
'dependency-info': {},
|
||||||
'marketplace-url': 'marketplace-url.com',
|
'marketplace-url': 'https://marketplace-url.com',
|
||||||
'developer-key': 'developer-key',
|
'developer-key': 'developer-key',
|
||||||
},
|
},
|
||||||
'install-progress': undefined,
|
'install-progress': undefined,
|
||||||
@@ -1835,7 +1835,7 @@ export module Mock {
|
|||||||
icon: 'assets/img/service-icons/bitcoind.png',
|
icon: 'assets/img/service-icons/bitcoind.png',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'marketplace-url': 'marketplace-url.com',
|
'marketplace-url': 'https://marketplace-url.com',
|
||||||
'developer-key': 'developer-key',
|
'developer-key': 'developer-key',
|
||||||
},
|
},
|
||||||
'install-progress': undefined,
|
'install-progress': undefined,
|
||||||
@@ -1895,7 +1895,7 @@ export module Mock {
|
|||||||
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'marketplace-url': 'marketplace-url.com',
|
'marketplace-url': 'https://marketplace-url.com',
|
||||||
'developer-key': 'developer-key',
|
'developer-key': 'developer-key',
|
||||||
},
|
},
|
||||||
'install-progress': undefined,
|
'install-progress': undefined,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Observable, ReplaySubject } from 'rxjs'
|
import { BehaviorSubject, Observable } from 'rxjs'
|
||||||
import { Update } from 'patch-db-client'
|
import { Update } from 'patch-db-client'
|
||||||
import { RR } from './api.types'
|
import { RR } from './api.types'
|
||||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||||
@@ -6,7 +6,7 @@ import { Log } from '@start9labs/shared'
|
|||||||
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
||||||
|
|
||||||
export abstract class ApiService {
|
export abstract class ApiService {
|
||||||
readonly patchStream$ = new ReplaySubject<Update<DataModel>[]>(1)
|
readonly patchStream$ = new BehaviorSubject<Update<DataModel>[]>([])
|
||||||
|
|
||||||
// http
|
// http
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { BehaviorSubject, interval, map, Observable } from 'rxjs'
|
|||||||
import { LocalStorageBootstrap } from '../patch-db/local-storage-bootstrap'
|
import { LocalStorageBootstrap } from '../patch-db/local-storage-bootstrap'
|
||||||
import { mockPatchData } from './mock-patch'
|
import { mockPatchData } from './mock-patch'
|
||||||
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
||||||
|
import { AuthService } from '../auth.service'
|
||||||
|
|
||||||
const PROGRESS: InstallProgress = {
|
const PROGRESS: InstallProgress = {
|
||||||
size: 120,
|
size: 120,
|
||||||
@@ -39,8 +40,21 @@ export class MockApiService extends ApiService {
|
|||||||
private readonly revertTime = 2000
|
private readonly revertTime = 2000
|
||||||
sequence = 0
|
sequence = 0
|
||||||
|
|
||||||
constructor(private readonly bootstrapper: LocalStorageBootstrap) {
|
constructor(
|
||||||
|
private readonly bootstrapper: LocalStorageBootstrap,
|
||||||
|
private readonly auth: AuthService,
|
||||||
|
) {
|
||||||
super()
|
super()
|
||||||
|
this.auth.isVerified$.subscribe(verified => {
|
||||||
|
if (!verified) {
|
||||||
|
this.patchStream$.next([])
|
||||||
|
this.mockWsSource$.next({
|
||||||
|
id: 1,
|
||||||
|
value: mockPatchData,
|
||||||
|
})
|
||||||
|
this.sequence = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStatic(url: string): Promise<string> {
|
async getStatic(url: string): Promise<string> {
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ export const mockPatchData: DataModel = {
|
|||||||
},
|
},
|
||||||
'current-dependencies': {},
|
'current-dependencies': {},
|
||||||
'dependency-info': {},
|
'dependency-info': {},
|
||||||
'marketplace-url': 'marketplace-url.com',
|
'marketplace-url': 'https://marketplace-url.com',
|
||||||
'developer-key': 'developer-key',
|
'developer-key': 'developer-key',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -650,7 +650,7 @@ export const mockPatchData: DataModel = {
|
|||||||
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
icon: 'assets/img/service-icons/btc-rpc-proxy.png',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'marketplace-url': 'marketplace-url.com',
|
'marketplace-url': 'https://marketplace-url.com',
|
||||||
'developer-key': 'developer-key',
|
'developer-key': 'developer-key',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Emver } from '@start9labs/shared'
|
import { Emver } from '@start9labs/shared'
|
||||||
import { BehaviorSubject, combineLatest } from 'rxjs'
|
import { BehaviorSubject, combineLatest } from 'rxjs'
|
||||||
import { distinctUntilChanged, filter, map } from 'rxjs/operators'
|
import { distinctUntilChanged, map } from 'rxjs/operators'
|
||||||
|
|
||||||
import { MarketplaceEOS } from 'src/app/services/api/api.types'
|
import { MarketplaceEOS } 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'
|
||||||
@@ -17,7 +17,6 @@ export class EOSService {
|
|||||||
updateAvailable$ = new BehaviorSubject<boolean>(false)
|
updateAvailable$ = new BehaviorSubject<boolean>(false)
|
||||||
|
|
||||||
readonly updating$ = this.patch.watch$('server-info', 'status-info').pipe(
|
readonly updating$ = this.patch.watch$('server-info', 'status-info').pipe(
|
||||||
filter(Boolean),
|
|
||||||
map(status => !!status['update-progress'] || status.updated),
|
map(status => !!status['update-progress'] || status.updated),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class MarketplaceService extends AbstractMarketplaceService {
|
|||||||
|
|
||||||
private readonly serverInfo$: Observable<ServerInfo> = this.patch
|
private readonly serverInfo$: Observable<ServerInfo> = this.patch
|
||||||
.watch$('server-info')
|
.watch$('server-info')
|
||||||
.pipe(filter(Boolean), take(1), shareReplay())
|
.pipe(take(1), shareReplay())
|
||||||
|
|
||||||
private readonly registryData$: Observable<MarketplaceData> =
|
private readonly registryData$: Observable<MarketplaceData> =
|
||||||
this.uiMarketplaceData$.pipe(
|
this.uiMarketplaceData$.pipe(
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ export interface ServerNameInfo {
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ServerNameService {
|
export class ServerNameService {
|
||||||
private readonly chosenName$ = this.patch.watch$('ui', 'name')
|
private readonly chosenName$ = this.patch.watch$('ui', 'name')
|
||||||
private readonly hostname$ = this.patch
|
private readonly hostname$ = this.patch.watch$('server-info', 'hostname')
|
||||||
.watch$('server-info', 'hostname')
|
|
||||||
.pipe(filter(Boolean))
|
|
||||||
|
|
||||||
readonly name$: Observable<ServerNameInfo> = combineLatest([
|
readonly name$: Observable<ServerNameInfo> = combineLatest([
|
||||||
this.chosenName$,
|
this.chosenName$,
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ export function getPackage(
|
|||||||
export function getAllPackages(
|
export function getAllPackages(
|
||||||
patch: PatchDB<DataModel>,
|
patch: PatchDB<DataModel>,
|
||||||
): Promise<Record<string, PackageDataEntry>> {
|
): Promise<Record<string, PackageDataEntry>> {
|
||||||
return firstValueFrom(patch.watch$('package-data').pipe(filter(Boolean)))
|
return firstValueFrom(patch.watch$('package-data'))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
import { DataModel, ServerInfo } from 'src/app/services/patch-db/data-model'
|
import { DataModel, ServerInfo } from 'src/app/services/patch-db/data-model'
|
||||||
import { filter, firstValueFrom } from 'rxjs'
|
import { firstValueFrom } from 'rxjs'
|
||||||
|
|
||||||
export function getServerInfo(patch: PatchDB<DataModel>): Promise<ServerInfo> {
|
export function getServerInfo(patch: PatchDB<DataModel>): Promise<ServerInfo> {
|
||||||
return firstValueFrom(patch.watch$('server-info').pipe(filter(Boolean)))
|
return firstValueFrom(patch.watch$('server-info'))
|
||||||
}
|
}
|
||||||
|
|||||||
2
patch-db
2
patch-db
Submodule patch-db updated: 20beb61baa...4d987b1921
Reference in New Issue
Block a user