feat(marketplace): extract common components (#1338)

* feat(marketplace): extract common components

* chore: fix service provide

* feat(markdown): allow Observable content

* chore: remove unnecessary module import

* minor styling for marketplacee list

* only show loading for marketplace show if version change

* chore: get rid of unnecessary server request

* chore: fix version switching

Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
Alex Inkin
2022-03-21 22:50:06 +03:00
committed by GitHub
parent 8b286431e6
commit 7ea3aefdd5
111 changed files with 1064 additions and 803 deletions

View File

@@ -1,4 +1,4 @@
import { PackageState } from '@start9labs/shared'
import { PackageState } from 'src/app/types/package-state'
import { ConfigSpec } from 'src/app/pkg-config/config-types'
import {
DependencyErrorType,

View File

@@ -1,3 +1,4 @@
import { AbstractApiService } from '@start9labs/shared'
import { Subject, Observable } from 'rxjs'
import {
Http,
@@ -13,7 +14,10 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
import { RequestError } from '../http.service'
import { map } from 'rxjs/operators'
export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
export abstract class ApiService
extends AbstractApiService
implements Source<DataModel>, Http<DataModel>
{
protected readonly sync$ = new Subject<Update<DataModel>>()
/** PatchDb Source interface. Post/Patch requests provide a source of patches to the db. */
@@ -24,9 +28,6 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
.pipe(map(result => ({ result, jsonrpc: '2.0' })))
}
// for getting static files: ex icons, instructions, licenses
abstract getStatic(url: string): Promise<string>
// db
abstract getRevisions(since: number): Promise<RR.GetRevisionsRes>

View File

@@ -1,8 +1,9 @@
import { Injectable } from '@angular/core'
import { InstallProgress, pauseFor } from '@start9labs/shared'
import { pauseFor } from '@start9labs/shared'
import { ApiService } from './embassy-api.service'
import { PatchOp, Update, Operation, RemoveOperation } from 'patch-db-client'
import { PackageState } from '@start9labs/shared'
import { PackageState } from 'src/app/types/package-state'
import { InstallProgress } from 'src/app/types/install-progress'
import {
DataModel,
DependencyErrorType,
@@ -192,6 +193,8 @@ export class MockApiService extends ApiService {
return Mock.MarketplacePkgsList
} else if (path.startsWith('/package/v0/release-notes')) {
return Mock.ReleaseNotes
} else if (path.includes('instructions') || path.includes('license')) {
return markdown
}
}

View File

@@ -1,4 +1,4 @@
import { PackageState } from '@start9labs/shared'
import { PackageState } from 'src/app/types/package-state'
import {
DataModel,
DependencyErrorType,

View File

@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core'
import { WorkspaceConfig, PackageState } from '@start9labs/shared'
import { WorkspaceConfig } from '@start9labs/shared'
import { PackageState } from 'src/app/types/package-state'
import {
InterfaceDef,
PackageDataEntry,

View File

@@ -15,9 +15,9 @@ import { ServerInfo } from 'src/app/services/patch-db/data-model'
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
import {
catchError,
finalize,
map,
shareReplay,
startWith,
switchMap,
tap,
} from 'rxjs/operators'
@@ -56,11 +56,11 @@ export class MarketplaceService extends AbstractMarketplaceService {
constructor(
private readonly api: ApiService,
private readonly emver: Emver,
private readonly patch: PatchDbService,
private readonly config: ConfigService,
private readonly loadingCtrl: LoadingController,
private readonly errToast: ErrorToastService,
private readonly emver: Emver,
) {
super()
}
@@ -79,12 +79,17 @@ export class MarketplaceService extends AbstractMarketplaceService {
getPackage(id: string, version: string): Observable<MarketplacePkg> {
const params = { ids: [{ id, version }] }
return this.init$.pipe(
const fallback$ = this.init$.pipe(
switchMap(({ url }) => from(this.getMarketplacePkgs(params, url))),
map(pkgs => pkgs.find(pkg => pkg.manifest.id == id)),
map(pkgs => this.findPackage(pkgs, id, version)),
startWith(null),
)
return this.getPackages().pipe(
map(pkgs => this.findPackage(pkgs, id, version)),
switchMap(pkg => (pkg ? of(pkg) : fallback$)),
tap(pkg => {
if (!pkg) {
if (pkg === undefined) {
throw new Error(`No results for ${id}${version ? ' ' + version : ''}`)
}
}),
@@ -103,26 +108,6 @@ export class MarketplaceService extends AbstractMarketplaceService {
)
}
// async install(id: string, version?: string): Promise<void> {
// const loader = await this.loadingCtrl.create({
// spinner: 'lines',
// message: 'Beginning Installation',
// cssClass: 'loader',
// })
// loader.present()
//
// try {
// await this.installPackage({
// id,
// 'version-spec': version ? `=${version}` : undefined,
// })
// } catch (e) {
// this.errToast.present(e)
// } finally {
// loader.dismiss()
// }
// }
install(id: string, version?: string): Observable<unknown> {
return defer(() =>
from(
@@ -161,6 +146,20 @@ export class MarketplaceService extends AbstractMarketplaceService {
)
}
getPackageMarkdown(type: string, pkgId: string): Observable<string> {
return this.getMarketplace().pipe(
switchMap(({ url }) =>
from(
this.api.marketplaceProxy<string>(
`/package/v0/${type}/${pkgId}`,
{},
url,
),
),
),
)
}
async getMarketplaceData(
params: RR.GetMarketplaceDataReq,
url: string,
@@ -217,4 +216,18 @@ export class MarketplaceService extends AbstractMarketplaceService {
})
}
}
private findPackage(
pkgs: readonly MarketplacePkg[],
id: string,
version: string,
): MarketplacePkg | undefined {
return pkgs.find(pkg => {
const versionIsSame =
version === '*' ||
this.emver.compare(pkg.manifest.version, version) === 0
return pkg.manifest.id === id && versionIsSame
})
}
}

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { ModalController } from '@ionic/angular'
import { DependentInfo } from '@start9labs/shared'
import { DependentInfo } from 'src/app/types/dependent-info'
import { AppConfigPage } from 'src/app/modals/app-config/app-config.page'
@Injectable({

View File

@@ -1,7 +1,9 @@
import { ConfigSpec } from 'src/app/pkg-config/config-types'
import { InstallProgress, PackageState, Url } from '@start9labs/shared'
import { Url } from '@start9labs/shared'
import { MarketplaceManifest } from '@start9labs/marketplace'
import { BasicInfo } from 'src/app/pages/developer-routes/developer-menu/form-info'
import { PackageState } from 'src/app/types/package-state'
import { InstallProgress } from 'src/app/types/install-progress'
export interface DataModel {
'server-info': ServerInfo
@@ -111,7 +113,7 @@ export interface CurrentDependencyInfo {
'health-checks': string[] // array of health check IDs
}
export interface Manifest extends MarketplaceManifest {
export interface Manifest extends MarketplaceManifest<DependencyConfig> {
main: ActionImpl
'health-checks': Record<
string,
@@ -125,7 +127,11 @@ export interface Manifest extends MarketplaceManifest {
migrations: Migrations
actions: Record<string, Action>
permissions: any // @TODO 0.3.1
dependencies: DependencyInfo
}
export interface DependencyConfig {
check: ActionImpl
'auto-configure': ActionImpl
}
export interface ActionImpl {
@@ -352,28 +358,3 @@ export interface DependencyErrorHealthChecksFailed {
export interface DependencyErrorTransitive {
type: DependencyErrorType.Transitive
}
export interface DependencyInfo {
[id: string]: DependencyEntry
}
export interface DependencyEntry {
version: string
requirement:
| {
type: 'opt-in'
how: string
}
| {
type: 'opt-out'
how: string
}
| {
type: 'required'
}
description: string | null
config: {
check: ActionImpl
'auto-configure': ActionImpl
}
}

View File

@@ -1,4 +1,5 @@
import { isEmptyObject, PackageState } from '@start9labs/shared'
import { isEmptyObject } from '@start9labs/shared'
import { PackageState } from 'src/app/types/package-state'
import {
PackageDataEntry,
PackageMainStatus,