Better Updates Tab and updates count (#2151)

* wip

* should be working now

* delete unused function

* delete 2 more unused functions

* update fixture to include beta registry

* address comments

* wait for connection to get local packages
This commit is contained in:
Matt Hill
2023-02-06 10:55:51 -07:00
committed by Aiden McClelland
parent 62f78e4312
commit 4d3df867da
7 changed files with 82 additions and 75 deletions

View File

@@ -45,10 +45,6 @@ export function isValidHttpUrl(url: string): boolean {
} }
} }
export function getUrlHostname(url: string): string {
return new URL(url).hostname
}
export function toUrl(text: string | null | undefined): string { export function toUrl(text: string | null | undefined): string {
try { try {
const url = new URL(text as string) const url = new URL(text as string)

View File

@@ -1,13 +1,13 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core' import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'
import { EOSService } from '../../services/eos.service' import { EOSService } from '../../services/eos.service'
import { PatchDB } from 'patch-db-client' import { PatchDB } from 'patch-db-client'
import { combineLatest, map, Observable, of, startWith } from 'rxjs' import { combineLatest, filter, first, map, Observable, switchMap } from 'rxjs'
import { AbstractMarketplaceService } from '@start9labs/marketplace' import { AbstractMarketplaceService } from '@start9labs/marketplace'
import { MarketplaceService } from 'src/app/services/marketplace.service' import { MarketplaceService } from 'src/app/services/marketplace.service'
import { DataModel } from 'src/app/services/patch-db/data-model' import { DataModel } from 'src/app/services/patch-db/data-model'
import { SplitPaneTracker } from 'src/app/services/split-pane.service' import { SplitPaneTracker } from 'src/app/services/split-pane.service'
import { Emver } from '@start9labs/shared' import { Emver } from '@start9labs/shared'
import { marketplaceSame, versionLower } from '../../pages/updates/updates.page' import { ConnectionService } from 'src/app/services/connection.service'
@Component({ @Component({
selector: 'app-menu', selector: 'app-menu',
@@ -53,23 +53,31 @@ export class MenuComponent {
readonly showEOSUpdate$ = this.eosService.showUpdate$ readonly showEOSUpdate$ = this.eosService.showUpdate$
private readonly local$ = this.connectionService.connected$.pipe(
filter(Boolean),
switchMap(() => this.patch.watch$('package-data')),
first(),
)
readonly updateCount$: Observable<number> = combineLatest([ readonly updateCount$: Observable<number> = combineLatest([
this.marketplaceService.getMarketplace$(), this.marketplaceService.getMarketplace$(true),
this.patch.watch$('package-data'), this.local$,
]).pipe( ]).pipe(
map(([marketplace, local]) => map(([marketplace, local]) =>
Object.entries(marketplace).reduce( Object.entries(marketplace).reduce((list, [_, store]) => {
(length, [url, store]) => store?.packages.forEach(({ manifest: { id, version } }) => {
length + if (
(store?.packages.filter( this.emver.compare(
({ manifest }) => version,
marketplaceSame(manifest, local, url) && local[id]?.installed?.manifest.version || '',
versionLower(manifest, local, this.emver), ) === 1
).length || 0), )
0, list.add(id)
), })
return list
}, new Set<string>()),
), ),
startWith(0), map(list => list.size),
) )
readonly sidebarOpen$ = this.splitPane.sidebarOpen$ readonly sidebarOpen$ = this.splitPane.sidebarOpen$
@@ -81,5 +89,6 @@ export class MenuComponent {
private readonly marketplaceService: MarketplaceService, private readonly marketplaceService: MarketplaceService,
private readonly splitPane: SplitPaneTracker, private readonly splitPane: SplitPaneTracker,
private readonly emver: Emver, private readonly emver: Emver,
private readonly connectionService: ConnectionService,
) {} ) {}
} }

View File

@@ -3,7 +3,7 @@ import { ActivatedRoute } from '@angular/router'
import { ModalController } from '@ionic/angular' import { ModalController } from '@ionic/angular'
import { AbstractMarketplaceService } from '@start9labs/marketplace' import { AbstractMarketplaceService } from '@start9labs/marketplace'
import { PatchDB } from 'patch-db-client' import { PatchDB } from 'patch-db-client'
import { filter, map } from 'rxjs' import { map } from 'rxjs'
import { MarketplaceSettingsPage } from 'src/app/modals/marketplace-settings/marketplace-settings.page' import { MarketplaceSettingsPage } from 'src/app/modals/marketplace-settings/marketplace-settings.page'
import { ConfigService } from 'src/app/services/config.service' import { ConfigService } from 'src/app/services/config.service'
import { MarketplaceService } from 'src/app/services/marketplace.service' import { MarketplaceService } from 'src/app/services/marketplace.service'
@@ -85,9 +85,6 @@ export class MarketplaceListPage {
const modal = await this.modalCtrl.create({ const modal = await this.modalCtrl.create({
component: MarketplaceSettingsPage, component: MarketplaceSettingsPage,
}) })
modal.onDidDismiss().then(res => {
console.log(res)
})
await modal.present() await modal.present()
} }

View File

@@ -26,7 +26,7 @@
*ngIf="data.marketplace[host.url]?.packages as packages else loading" *ngIf="data.marketplace[host.url]?.packages as packages else loading"
> >
<ng-container <ng-container
*ngIf="packages | filterUpdates : data.localPkgs : host.url as updates" *ngIf="packages | filterUpdates : data.localPkgs as updates"
> >
<div *ngFor="let pkg of updates" class="item-container"> <div *ngFor="let pkg of updates" class="item-container">
<ion-item lines="none"> <ion-item lines="none">

View File

@@ -14,9 +14,9 @@ import {
MarketplacePkg, MarketplacePkg,
StoreIdentity, StoreIdentity,
} from '@start9labs/marketplace' } from '@start9labs/marketplace'
import { Emver, isEmptyObject, sameUrl } from '@start9labs/shared' import { Emver, isEmptyObject } from '@start9labs/shared'
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { combineLatest, map, Observable } from 'rxjs' import { combineLatest, Observable } from 'rxjs'
import { import {
AlertController, AlertController,
LoadingController, LoadingController,
@@ -25,8 +25,6 @@ import {
import { hasCurrentDeps } from 'src/app/util/has-deps' import { hasCurrentDeps } from 'src/app/util/has-deps'
import { getAllPackages } from 'src/app/util/get-package-data' import { getAllPackages } from 'src/app/util/get-package-data'
import { Breakages } from 'src/app/services/api/api.types' import { Breakages } from 'src/app/services/api/api.types'
import { ClientStorageService } from 'src/app/services/client-storage.service'
import { ConfigService } from 'src/app/services/config.service'
interface UpdatesData { interface UpdatesData {
hosts: StoreIdentity[] hosts: StoreIdentity[]
@@ -41,20 +39,8 @@ interface UpdatesData {
styleUrls: ['updates.page.scss'], styleUrls: ['updates.page.scss'],
}) })
export class UpdatesPage { export class UpdatesPage {
readonly hosts$ = combineLatest([
this.clientStorageService.showDevTools$,
this.marketplaceService.getKnownHosts$(),
]).pipe(
map(([devMode, knownHosts]) => {
if (devMode) return knownHosts
return knownHosts.filter(
({ url }) => !url.includes('alpha') && !url.includes('beta'),
)
}),
)
readonly data$: Observable<UpdatesData> = combineLatest({ readonly data$: Observable<UpdatesData> = combineLatest({
hosts: this.hosts$, hosts: this.marketplaceService.getKnownHosts$(true),
marketplace: this.marketplaceService.getMarketplace$(), marketplace: this.marketplaceService.getMarketplace$(),
localPkgs: this.patch.watch$('package-data'), localPkgs: this.patch.watch$('package-data'),
errors: this.marketplaceService.getRequestErrors$(), errors: this.marketplaceService.getRequestErrors$(),
@@ -70,8 +56,6 @@ export class UpdatesPage {
private readonly navCtrl: NavController, private readonly navCtrl: NavController,
private readonly loadingCtrl: LoadingController, private readonly loadingCtrl: LoadingController,
private readonly alertCtrl: AlertController, private readonly alertCtrl: AlertController,
private readonly clientStorageService: ClientStorageService,
private readonly config: ConfigService,
) {} ) {}
viewInMarketplace(pkg: PackageDataEntry) { viewInMarketplace(pkg: PackageDataEntry) {
@@ -191,33 +175,18 @@ export class FilterUpdatesPipe implements PipeTransform {
transform( transform(
pkgs: MarketplacePkg[], pkgs: MarketplacePkg[],
local: Record<string, PackageDataEntry> = {}, local: Record<string, PackageDataEntry | undefined>,
url: string,
): MarketplacePkg[] { ): MarketplacePkg[] {
return pkgs.filter( return pkgs.filter(({ manifest }) => {
({ manifest }) => const localPkg = local[manifest.id]
marketplaceSame(manifest, local, url) &&
versionLower(manifest, local, this.emver), return (
) localPkg?.state === PackageState.Updating ||
this.emver.compare(
manifest.version,
localPkg?.installed?.manifest.version || '',
) === 1
)
})
} }
} }
export function marketplaceSame(
{ id }: MarketplaceManifest,
local: Record<string, PackageDataEntry>,
url: string,
): boolean {
const localUrl = local[id]?.installed?.['marketplace-url']
return sameUrl(localUrl, url)
}
export function versionLower(
{ version, id }: MarketplaceManifest,
local: Record<string, PackageDataEntry>,
emver: Emver,
): boolean {
return (
local[id].state === PackageState.Updating ||
emver.compare(version, local[id].installed?.manifest.version || '') === 1
)
}

View File

@@ -20,7 +20,7 @@ export const mockPatchData: DataModel = {
name: 'Start9 Registry', name: 'Start9 Registry',
}, },
'https://community-registry.start9.com/': {}, 'https://community-registry.start9.com/': {},
'https://dark9-marketplace.com/': { 'https://beta-registry.start9.com/': {
name: 'Dark9', name: 'Dark9',
}, },
}, },

View File

@@ -34,6 +34,7 @@ import {
} from 'rxjs/operators' } from 'rxjs/operators'
import { ConfigService } from './config.service' import { ConfigService } from './config.service'
import { sameUrl } from '@start9labs/shared' import { sameUrl } from '@start9labs/shared'
import { ClientStorageService } from './client-storage.service'
@Injectable() @Injectable()
export class MarketplaceService implements AbstractMarketplaceService { export class MarketplaceService implements AbstractMarketplaceService {
@@ -55,6 +56,20 @@ export class MarketplaceService implements AbstractMarketplaceService {
}), }),
) )
private readonly filteredKnownHosts$: Observable<StoreIdentity[]> =
combineLatest([
this.clientStorageService.showDevTools$,
this.knownHosts$,
]).pipe(
map(([devMode, knownHosts]) =>
devMode
? knownHosts
: knownHosts.filter(
({ url }) => !url.includes('alpha') && !url.includes('beta'),
),
),
)
private readonly selectedHost$: Observable<StoreIdentity> = this.patch private readonly selectedHost$: Observable<StoreIdentity> = this.patch
.watch$('ui', 'marketplace') .watch$('ui', 'marketplace')
.pipe( .pipe(
@@ -93,6 +108,24 @@ export class MarketplaceService implements AbstractMarketplaceService {
shareReplay(1), shareReplay(1),
) )
private readonly filteredMarketplace$ = combineLatest([
this.clientStorageService.showDevTools$,
this.marketplace$,
]).pipe(
map(([devMode, marketplace]) =>
Object.entries(marketplace).reduce(
(filtered, [url, store]) =>
!devMode && (url.includes('alpha') || url.includes('beta'))
? filtered
: {
[url]: store,
...filtered,
},
{} as Marketplace,
),
),
)
private readonly selectedStore$: Observable<StoreData> = private readonly selectedStore$: Observable<StoreData> =
this.selectedHost$.pipe( this.selectedHost$.pipe(
switchMap(({ url }) => switchMap(({ url }) =>
@@ -110,18 +143,21 @@ export class MarketplaceService implements AbstractMarketplaceService {
private readonly api: ApiService, private readonly api: ApiService,
private readonly patch: PatchDB<DataModel>, private readonly patch: PatchDB<DataModel>,
private readonly config: ConfigService, private readonly config: ConfigService,
private readonly clientStorageService: ClientStorageService,
) {} ) {}
getKnownHosts$(): Observable<StoreIdentity[]> { getKnownHosts$(filtered = false): Observable<StoreIdentity[]> {
return this.knownHosts$ // option to filter out hosts containing 'alpha' or 'beta' substrings in registryURL
return filtered ? this.filteredKnownHosts$ : this.knownHosts$
} }
getSelectedHost$(): Observable<StoreIdentity> { getSelectedHost$(): Observable<StoreIdentity> {
return this.selectedHost$ return this.selectedHost$
} }
getMarketplace$(): Observable<Marketplace> { getMarketplace$(filtered = false): Observable<Marketplace> {
return this.marketplace$ // option to filter out hosts containing 'alpha' or 'beta' substrings in registryURL
return filtered ? this.filteredMarketplace$ : this.marketplace$
} }
getSelectedStore$(): Observable<StoreData> { getSelectedStore$(): Observable<StoreData> {