mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Update Marketplace (#2742)
* update abstract marketplace for usage accuracy andrename store to registry * use new abstract functions * fix(marketplace): get rid of `AbstractMarketplaceService` * bump shared marketplace lib * update marketplace to use query params for registry url; comment out updates page - will be refactored * cleanup * cleanup duplicate * cleanup unused imports * rework setting registry url when loading marketplace * cleanup marketplace service * fix background --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> Co-authored-by: waterplea <alexander@inkin.ru> Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com>
This commit is contained in:
@@ -1,113 +1,108 @@
|
||||
<header>
|
||||
<ng-container *tuiLet="store$ | async as store">
|
||||
<div class="title">
|
||||
<store-icon
|
||||
[class.tui-skeleton]="!store"
|
||||
[class.tui-skeleton_rounded]="!store"
|
||||
size="60px"
|
||||
[url]="store?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
/>
|
||||
<h1 [class.tui-skeleton]="!store">
|
||||
{{ store?.info?.name || 'Loading store...' }}
|
||||
</h1>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=desktop]"></ng-content>
|
||||
</div>
|
||||
<!-- mobile nav -->
|
||||
<div class="nav-mobile">
|
||||
<div class="nav-mobile-bar">
|
||||
<!-- mobile search -->
|
||||
<marketplace-search
|
||||
[(query)]="query"
|
||||
(queryChange)="onQueryChange($event)"
|
||||
/>
|
||||
<button
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="link"
|
||||
(click)="toggleMenu(true)"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
[style.--tui-padding]="'1.2rem'"
|
||||
>
|
||||
<store-icon
|
||||
size="42px"
|
||||
[style.height]="'42px'"
|
||||
[style.border-radius]="'100%'"
|
||||
[url]="store?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
[class.tui-skeleton]="!store"
|
||||
[class.tui-skeleton_rounded]="!store"
|
||||
/>
|
||||
<nav
|
||||
*tuiSidebar="open; direction: 'right'; autoWidth: true"
|
||||
class="nav-mobile-sidebar divide-bar"
|
||||
>
|
||||
<div class="nav-mobile-sidebar-top">
|
||||
<h1 [class.tui-skeleton]="!store">
|
||||
{{ store?.info?.name }}
|
||||
</h1>
|
||||
<button
|
||||
[style.--tui-padding]="0"
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="icon"
|
||||
iconStart="@tui.x"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
(click)="toggleMenu(false)"
|
||||
></button>
|
||||
</div>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=mobile]"></ng-content>
|
||||
<div class="nav-mobile-sidebar-bottom divide-bar">
|
||||
<marketplace-categories
|
||||
[categories]="store?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event); toggleMenu(false)"
|
||||
/>
|
||||
<div>
|
||||
<!-- link to store for brochure -->
|
||||
<ng-content select="[slot=store-mobile]" />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://docs.start9.com/0.3.5.x/developer-docs/"
|
||||
>
|
||||
<span>Package a service</span>
|
||||
<tui-icon tuiAppearance="icon" icon="@tui.external-link" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- desktop nav -->
|
||||
<nav class="nav-desktop">
|
||||
<!-- desktop search -->
|
||||
<div class="title">
|
||||
<store-icon
|
||||
[class.tui-skeleton]="!registry"
|
||||
[class.tui-skeleton_rounded]="!registry"
|
||||
size="60px"
|
||||
[url]="registry?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
/>
|
||||
<h1 [class.tui-skeleton]="!registry">
|
||||
{{ registry?.info?.name || 'Unnamed Registry' }}
|
||||
</h1>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=desktop]"></ng-content>
|
||||
</div>
|
||||
<!-- mobile nav -->
|
||||
<div class="nav-mobile">
|
||||
<div class="nav-mobile-bar">
|
||||
<!-- mobile search -->
|
||||
<marketplace-search
|
||||
[query]="query"
|
||||
[(query)]="query"
|
||||
(queryChange)="onQueryChange($event)"
|
||||
/>
|
||||
<div class="nav-desktop-container">
|
||||
<marketplace-categories
|
||||
[categories]="store?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event)"
|
||||
<button
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="link"
|
||||
(click)="toggleMenu(true)"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
[style.--tui-padding]="'1.2rem'"
|
||||
>
|
||||
<store-icon
|
||||
size="42px"
|
||||
[style.height]="'42px'"
|
||||
[style.border-radius]="'100%'"
|
||||
[url]="registry?.url || ''"
|
||||
[marketplace]="iconConfig"
|
||||
[class.tui-skeleton]="!registry"
|
||||
[class.tui-skeleton_rounded]="!registry"
|
||||
/>
|
||||
<div>
|
||||
<!-- link to store for brochure -->
|
||||
<ng-content select="[slot=store]" />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://docs.start9.com/0.3.5.x/developer-docs/"
|
||||
>
|
||||
<span>Package a service</span>
|
||||
<tui-icon tuiAppearance="icon" icon="@tui.external-link" />
|
||||
</a>
|
||||
</div>
|
||||
<nav
|
||||
*tuiSidebar="open; direction: 'right'; autoWidth: true"
|
||||
class="nav-mobile-sidebar divide-bar"
|
||||
>
|
||||
<div class="nav-mobile-sidebar-top">
|
||||
<h1 [class.tui-skeleton]="!registry">
|
||||
{{ registry?.info?.name }}
|
||||
</h1>
|
||||
<button
|
||||
[style.--tui-padding]="0"
|
||||
tuiButton
|
||||
type="button"
|
||||
appearance="icon"
|
||||
iconStart="@tui.x"
|
||||
(tuiActiveZoneChange)="toggleMenu($event)"
|
||||
(click)="toggleMenu(false)"
|
||||
></button>
|
||||
</div>
|
||||
<!-- change registry modal -->
|
||||
<ng-content select="[slot=mobile]"></ng-content>
|
||||
<div class="nav-mobile-sidebar-bottom divide-bar">
|
||||
<marketplace-categories
|
||||
[categories]="registry?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event); toggleMenu(false)"
|
||||
/>
|
||||
<div>
|
||||
<!-- link to store for brochure -->
|
||||
<ng-content select="[slot=store-mobile]" />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://docs.start9.com/0.3.5.x/developer-docs/"
|
||||
>
|
||||
<span>Package a service</span>
|
||||
<tui-icon tuiAppearance="icon" icon="@tui.external-link" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- desktop nav -->
|
||||
<nav class="nav-desktop">
|
||||
<!-- desktop search -->
|
||||
<marketplace-search [query]="query" (queryChange)="onQueryChange($event)" />
|
||||
<div class="nav-desktop-container">
|
||||
<marketplace-categories
|
||||
[categories]="registry?.info?.categories"
|
||||
[category]="query ? '' : category"
|
||||
(categoryChange)="onCategoryChange($event)"
|
||||
/>
|
||||
<div>
|
||||
<!-- link to store for brochure -->
|
||||
<ng-content select="[slot=store]" />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://docs.start9.com/0.3.5.x/developer-docs/"
|
||||
>
|
||||
<span>Package a service</span>
|
||||
<tui-icon tuiAppearance="icon" icon="@tui.external-link" />
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</ng-container>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -5,11 +5,10 @@ import {
|
||||
Input,
|
||||
OnDestroy,
|
||||
} from '@angular/core'
|
||||
import { combineLatest, map, Subject, takeUntil } from 'rxjs'
|
||||
import { StoreIdentity } from '../../types'
|
||||
import { AbstractMarketplaceService } from '../../services/marketplace.service'
|
||||
import { AbstractCategoryService } from '../../services/category.service'
|
||||
import { MarketplaceConfig } from '@start9labs/shared'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import { AbstractCategoryService } from '../../services/category.service'
|
||||
import { StoreDataWithUrl } from '../../types'
|
||||
|
||||
@Component({
|
||||
selector: 'menu',
|
||||
@@ -21,19 +20,11 @@ export class MenuComponent implements OnDestroy {
|
||||
@Input({ required: true })
|
||||
iconConfig!: MarketplaceConfig
|
||||
|
||||
@Input({ required: true })
|
||||
registry!: StoreDataWithUrl | null
|
||||
|
||||
private destroy$ = new Subject<void>()
|
||||
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||
private readonly categoryService = inject(AbstractCategoryService)
|
||||
readonly store$ = this.marketplaceService.getSelectedStoreWithCategories$()
|
||||
readonly alt$ = combineLatest([
|
||||
this.marketplaceService.getKnownHosts$(),
|
||||
this.marketplaceService.getSelectedHost$(),
|
||||
]).pipe(
|
||||
map(([stores, selected]) =>
|
||||
stores.filter(({ url }) => url != selected.url),
|
||||
),
|
||||
)
|
||||
private hosts?: StoreIdentity[]
|
||||
category = ''
|
||||
query = ''
|
||||
open = false
|
||||
@@ -52,13 +43,6 @@ export class MenuComponent implements OnDestroy {
|
||||
.subscribe(val => {
|
||||
this.category = val
|
||||
})
|
||||
|
||||
this.marketplaceService
|
||||
.getKnownHosts$()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(hosts => {
|
||||
this.hosts = hosts
|
||||
})
|
||||
}
|
||||
|
||||
onCategoryChange(category: string): void {
|
||||
@@ -66,7 +50,6 @@ export class MenuComponent implements OnDestroy {
|
||||
this.query = ''
|
||||
this.categoryService.resetQuery()
|
||||
this.categoryService.changeCategory(category)
|
||||
this.categoryService.handleNavigation()
|
||||
}
|
||||
|
||||
onQueryChange(query: string): void {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||
import { MarketplacePkg } from '../../src/types'
|
||||
import { Exver, MarkdownPipeModule } from '@start9labs/shared'
|
||||
import { TuiButton, TuiDialogContext, TuiLoader } from '@taiga-ui/core'
|
||||
import { TuiAccordion } from '@taiga-ui/kit'
|
||||
@@ -8,26 +7,21 @@ import {
|
||||
POLYMORPHEUS_CONTEXT,
|
||||
PolymorpheusComponent,
|
||||
} from '@taiga-ui/polymorpheus'
|
||||
import { map } from 'rxjs'
|
||||
import { AbstractMarketplaceService } from '../services/marketplace.service'
|
||||
import { MarketplacePkg } from '../../src/types'
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
template: `
|
||||
@if (notes$ | async; as notes) {
|
||||
<tui-accordion>
|
||||
@for (note of notes | keyvalue: asIsOrder; track $index) {
|
||||
<tui-accordion-item>
|
||||
{{ note.key }}
|
||||
<ng-template tuiAccordionItemContent>
|
||||
<div [innerHTML]="note.value | markdown"></div>
|
||||
</ng-template>
|
||||
</tui-accordion-item>
|
||||
}
|
||||
</tui-accordion>
|
||||
} @else {
|
||||
<tui-loader textContent="Loading Release Notes" />
|
||||
}
|
||||
<tui-accordion>
|
||||
@for (note of notes | keyvalue: asIsOrder; track $index) {
|
||||
<tui-accordion-item>
|
||||
{{ note.key }}
|
||||
<ng-template tuiAccordionItemContent>
|
||||
<div [innerHTML]="note.value | markdown"></div>
|
||||
</ng-template>
|
||||
</tui-accordion-item>
|
||||
}
|
||||
</tui-accordion>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
@@ -43,26 +37,20 @@ export class ReleaseNotesComponent {
|
||||
private readonly pkg =
|
||||
inject<TuiDialogContext<void, MarketplacePkg>>(POLYMORPHEUS_CONTEXT).data
|
||||
|
||||
readonly notes$ = inject(AbstractMarketplaceService)
|
||||
.getSelectedStore$()
|
||||
.pipe(
|
||||
map(s => {
|
||||
return Object.entries(this.pkg.otherVersions)
|
||||
.filter(
|
||||
([v, _]) =>
|
||||
this.exver.getFlavor(v) === this.pkg.flavor &&
|
||||
this.exver.compareExver(this.pkg.version, v) === 1,
|
||||
)
|
||||
.reduce(
|
||||
(obj, [version, info]) => ({
|
||||
...obj,
|
||||
[version]: info.releaseNotes,
|
||||
}),
|
||||
{
|
||||
[`${this.pkg.version} (current)`]: this.pkg.releaseNotes,
|
||||
},
|
||||
)
|
||||
readonly notes = Object.entries(this.pkg.otherVersions)
|
||||
.filter(
|
||||
([v, _]) =>
|
||||
this.exver.getFlavor(v) === this.pkg.flavor &&
|
||||
this.exver.compareExver(this.pkg.version, v) === 1,
|
||||
)
|
||||
.reduce(
|
||||
(obj, [version, info]) => ({
|
||||
...obj,
|
||||
[version]: info.releaseNotes,
|
||||
}),
|
||||
{
|
||||
[`${this.pkg.version} (current)`]: this.pkg.releaseNotes,
|
||||
},
|
||||
)
|
||||
|
||||
asIsOrder(a: any, b: any) {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</ng-template>
|
||||
<!-- license -->
|
||||
<marketplace-additional-item
|
||||
(click)="presentModalMd('License')"
|
||||
(click)="static.emit('License')"
|
||||
[data]="pkg.license"
|
||||
label="License"
|
||||
icon="@tui.chevron-right"
|
||||
@@ -36,7 +36,7 @@
|
||||
/>
|
||||
<!-- instructions -->
|
||||
<marketplace-additional-item
|
||||
(click)="presentModalMd('Instructions')"
|
||||
(click)="static.emit('Instructions')"
|
||||
data="Click to view instructions"
|
||||
label="Instructions"
|
||||
icon="@tui.chevron-right"
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
inject,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { CopyService } from '@start9labs/shared'
|
||||
import { TuiDialogService } from '@taiga-ui/core'
|
||||
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { CopyService, MarkdownComponent } from '@start9labs/shared'
|
||||
import { MarketplacePkg } from '../../../types'
|
||||
import { AbstractMarketplaceService } from '../../../services/marketplace.service'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplace-additional',
|
||||
@@ -21,7 +20,8 @@ export class AdditionalComponent {
|
||||
@Input({ required: true })
|
||||
pkg!: MarketplacePkg
|
||||
|
||||
private readonly marketplaceService = inject(AbstractMarketplaceService)
|
||||
@Output()
|
||||
readonly static = new EventEmitter<string>()
|
||||
|
||||
constructor(
|
||||
readonly copyService: CopyService,
|
||||
@@ -30,19 +30,4 @@ export class AdditionalComponent {
|
||||
) {}
|
||||
|
||||
readonly url = this.route.snapshot.queryParamMap.get('url') || undefined
|
||||
|
||||
presentModalMd(label: string) {
|
||||
this.dialogs
|
||||
.open(new PolymorpheusComponent(MarkdownComponent), {
|
||||
label,
|
||||
size: 'l',
|
||||
data: {
|
||||
content: this.marketplaceService.fetchStatic$(
|
||||
this.pkg,
|
||||
label === 'License' ? 'LICENSE.md' : 'instructions.md',
|
||||
),
|
||||
},
|
||||
})
|
||||
.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { MarketplacePkg } from '../../../types'
|
||||
tuiCell
|
||||
[routerLink]="[]"
|
||||
[queryParams]="{ id: pkg.id, flavor: pkg.flavor }"
|
||||
queryParamsHandling="merge"
|
||||
>
|
||||
<tui-avatar [src]="pkg.icon | trustUrl" />
|
||||
<span tuiTitle>
|
||||
|
||||
@@ -29,7 +29,6 @@ export * from './components/menu/menu.component.module'
|
||||
export * from './components/menu/menu.component'
|
||||
export * from './components/registry.component'
|
||||
|
||||
export * from './services/marketplace.service'
|
||||
export * from './services/category.service'
|
||||
|
||||
export * from './types'
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Observable } from 'rxjs'
|
||||
import { Marketplace, MarketplacePkg, StoreData, StoreIdentity } from '../types'
|
||||
|
||||
export abstract class AbstractMarketplaceService {
|
||||
abstract getKnownHosts$(): Observable<StoreIdentity[]>
|
||||
|
||||
abstract getSelectedHost$(): Observable<StoreIdentity>
|
||||
|
||||
abstract getMarketplace$(): Observable<Marketplace>
|
||||
|
||||
abstract getSelectedStore$(): Observable<StoreData>
|
||||
|
||||
abstract getSelectedStoreWithCategories$(): Observable<
|
||||
StoreIdentity & StoreData
|
||||
>
|
||||
|
||||
abstract getPackage$(
|
||||
id: string,
|
||||
version: string | null,
|
||||
flavor: string | null,
|
||||
url?: string,
|
||||
): Observable<MarketplacePkg>
|
||||
|
||||
abstract fetchStatic$(
|
||||
pkg: MarketplacePkg,
|
||||
type: 'LICENSE.md' | 'instructions.md',
|
||||
): Observable<string>
|
||||
}
|
||||
@@ -37,3 +37,5 @@ export type MarketplacePkg = T.PackageVersionInfo &
|
||||
version: string
|
||||
flavor: string | null
|
||||
}
|
||||
|
||||
export type StoreDataWithUrl = StoreData & { url: string }
|
||||
|
||||
Reference in New Issue
Block a user