mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +00:00
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:
committed by
Aiden McClelland
parent
62f78e4312
commit
4d3df867da
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
Reference in New Issue
Block a user