UI multiple bug fixes (#2072)

* fixes #2071 #2068

* closes #2070

* closes #2046

* fixes #2074

* closes #2045

* closes #2077. Use LAN address instead of IP when opening https
This commit is contained in:
Matt Hill
2022-12-19 13:42:05 -07:00
committed by GitHub
parent 16270cbd1a
commit 6300fc5364
16 changed files with 135 additions and 103 deletions

View File

@@ -34,7 +34,7 @@ export class SuccessPage {
fadeFactor = 0.07 fadeFactor = 0.07
columns: any[] = [] columns: any[] = []
maxStackHeight: any maxStackHeight: any
disableLogin = true disableLogin = this.stateService.setupType === 'fresh'
constructor( constructor(
@Inject(DOCUMENT) private readonly document: Document, @Inject(DOCUMENT) private readonly document: Document,

View File

@@ -134,15 +134,15 @@
<ion-label> <ion-label>
<b> <b>
{{ spec.name }} {{ spec.name }}
<ion-text *ngIf="entry.value.dirty" color="warning">
(Edited)</ion-text
>
<ion-text <ion-text
*ngIf="original?.[entry.key] === undefined" *ngIf="original?.[entry.key] === undefined"
color="success" color="success"
> >
(New)</ion-text (New)</ion-text
> >
<ion-text *ngIf="entry.value.dirty" color="warning">
(Edited)</ion-text
>
</b> </b>
</ion-label> </ion-label>
<!-- boolean --> <!-- boolean -->

View File

@@ -1,4 +1,9 @@
<img *ngIf="url | getIcon as icon; else noIcon" [src]="icon" alt="" /> <img
*ngIf="url | getIcon as icon; else noIcon"
[style.max-width]="size || '100%'"
[src]="icon"
alt=""
/>
<ng-template #noIcon> <ng-template #noIcon>
<ion-icon name="storefront-outline"></ion-icon> <ion-icon name="storefront-outline" [style.font-size]="size"></ion-icon>
</ng-template> </ng-template>

View File

@@ -16,6 +16,7 @@ import { sameUrl } from '@start9labs/shared'
}) })
export class StoreIconComponent { export class StoreIconComponent {
@Input() url: string = '' @Input() url: string = ''
@Input() size?: string
} }
@Pipe({ @Pipe({

View File

@@ -50,11 +50,7 @@
[button]="!a.selected" [button]="!a.selected"
(click)="a.selected ? '' : presentAction(a, true)" (click)="a.selected ? '' : presentAction(a, true)"
> >
<store-icon <store-icon slot="start" [url]="a.url" size="36px"></store-icon>
slot="start"
[url]="a.url"
style="font-size: 36px"
></store-icon>
<ion-label> <ion-label>
<h2>{{ a.name }}</h2> <h2>{{ a.name }}</h2>
<p>{{ a.url }}</p> <p>{{ a.url }}</p>

View File

@@ -15,6 +15,7 @@ import { ActivatedRoute } from '@angular/router'
import { getPkgId } from '@start9labs/shared' import { getPkgId } from '@start9labs/shared'
import { DOCUMENT } from '@angular/common' import { DOCUMENT } from '@angular/common'
import { ConfigService } from 'src/app/services/config.service' import { ConfigService } from 'src/app/services/config.service'
import { getServerInfo } from 'src/app/util/get-server-info'
const STATES = [ const STATES = [
PackageState.Installing, PackageState.Installing,
@@ -63,7 +64,8 @@ export class AppShowPage {
return STATES.includes(state) return STATES.includes(state)
} }
launchHttps() { async launchHttps() {
window.open(this.document.location.href.replace('http', 'https')) const { 'lan-address': lanAddress } = await getServerInfo(this.patch)
window.open(lanAddress)
} }
} }

View File

@@ -23,7 +23,11 @@
<ion-row> <ion-row>
<ion-col size="12"> <ion-col size="12">
<div class="heading"> <div class="heading">
<store-icon class="icon" [url]="details.url"></store-icon> <store-icon
class="icon"
size="80px"
[url]="details.url"
></store-icon>
<h1 class="montserrat">{{ details.name }}</h1> <h1 class="montserrat">{{ details.name }}</h1>
</div> </div>
<ion-button fill="clear" (click)="presentModalMarketplaceSettings()"> <ion-button fill="clear" (click)="presentModalMarketplaceSettings()">

View File

@@ -8,8 +8,7 @@
.icon { .icon {
display: inline-block; display: inline-block;
max-width: 80px; margin-bottom: 14px;
font-size: 80px;
} }
.divider { .divider {

View File

@@ -56,10 +56,13 @@
" "
> >
<ion-icon <ion-icon
style="font-size: 84px; color: #595959" style="font-size: 84px; color: #767676"
name="mail-outline" name="mail-outline"
></ion-icon> ></ion-icon>
<h4 style="color: #595959; margin-top: 0px">Inbox Empty</h4> <h4 style="color: #767676; margin-top: 0px; font-weight: 600">
Important system alerts and notifications from your Embassy will
display here
</h4>
</div> </div>
</ion-item-group> </ion-item-group>

View File

@@ -24,6 +24,7 @@ import {
} from 'src/app/modals/generic-input/generic-input.component' } from 'src/app/modals/generic-input/generic-input.component'
import { ConfigService } from 'src/app/services/config.service' import { ConfigService } from 'src/app/services/config.service'
import { DOCUMENT } from '@angular/common' import { DOCUMENT } from '@angular/common'
import { getServerInfo } from 'src/app/util/get-server-info'
@Component({ @Component({
selector: 'server-show', selector: 'server-show',
@@ -208,8 +209,9 @@ export class ServerShowPage {
await alert.present() await alert.present()
} }
launchHttps() { async launchHttps() {
window.open(this.document.location.href.replace('http', 'https')) const { 'lan-address': lanAddress } = await getServerInfo(this.patch)
window.open(lanAddress)
} }
addClick(title: string) { addClick(title: string) {

View File

@@ -4,7 +4,12 @@ import { IonicModule } from '@ionic/angular'
import { RouterModule, Routes } from '@angular/router' import { RouterModule, Routes } from '@angular/router'
import { FilterUpdatesPipe, UpdatesPage } from './updates.page' import { FilterUpdatesPipe, UpdatesPage } from './updates.page'
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 { MarkdownPipeModule, SharedPipesModule } from '@start9labs/shared' import {
EmverDisplayPipe,
EmverPipesModule,
MarkdownPipeModule,
SharedPipesModule,
} from '@start9labs/shared'
import { SkeletonListComponentModule } from 'src/app/components/skeleton-list/skeleton-list.component.module' import { SkeletonListComponentModule } from 'src/app/components/skeleton-list/skeleton-list.component.module'
import { RoundProgressModule } from 'angular-svg-round-progressbar' import { RoundProgressModule } from 'angular-svg-round-progressbar'
import { InstallProgressPipeModule } from 'src/app/pipes/install-progress/install-progress.module' import { InstallProgressPipeModule } from 'src/app/pipes/install-progress/install-progress.module'
@@ -29,6 +34,7 @@ const routes: Routes = [
RoundProgressModule, RoundProgressModule,
InstallProgressPipeModule, InstallProgressPipeModule,
StoreIconComponentModule, StoreIconComponentModule,
EmverPipesModule,
], ],
declarations: [UpdatesPage, FilterUpdatesPipe], declarations: [UpdatesPage, FilterUpdatesPipe],
}) })

View File

@@ -10,10 +10,10 @@
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<ion-item-group *ngIf="data$ | async as data"> <ion-item-group *ngIf="data$ | async as data">
<ng-container *ngFor="let host of data.hosts"> <ng-container *ngFor="let host of data.hosts">
<ion-item-divider> <ion-item-divider class="header">
{{ host.name }} &nbsp; <div class="inline">
<div style="max-width: 16px"> <h1>{{ host.name }}</h1>
<store-icon [url]="host.url"></store-icon> <store-icon [url]="host.url" size="24px"></store-icon>
</div> </div>
</ion-item-divider> </ion-item-divider>
@@ -28,62 +28,73 @@
<ng-container <ng-container
*ngIf="packages | filterUpdates : data.localPkgs : host.url as updates" *ngIf="packages | filterUpdates : data.localPkgs : host.url as updates"
> >
<ion-item *ngFor="let pkg of updates"> <div *ngFor="let pkg of updates" class="item-container">
<ng-container *ngIf="data.localPkgs[pkg.manifest.id] as local"> <ion-item lines="none">
<ion-avatar <ng-container *ngIf="data.localPkgs[pkg.manifest.id] as local">
class="service-avatar" <ion-thumbnail
(click)="viewInMarketplace(local)" slot="start"
>
<img [src]="'data:image/png;base64,' + pkg.icon | trustUrl" />
</ion-avatar>
<ion-label>
<h1
(click)="viewInMarketplace(local)"
style="cursor: pointer" style="cursor: pointer"
(click)="viewInMarketplace(local)"
> >
{{ pkg.manifest.title }} <img
</h1> [src]="'data:image/png;base64,' + pkg.icon | trustUrl"
<h2 class="inline"> />
<span>{{ local.manifest.version }}</span> </ion-thumbnail>
&nbsp;<ion-icon name="arrow-forward"></ion-icon>&nbsp; <ion-label>
<ion-text color="success"> <h1
{{ pkg.manifest.version }} (click)="viewInMarketplace(local)"
</ion-text> style="cursor: pointer"
</h2> >
<p [innerHTML]="pkg.manifest['release-notes'] | markdown"></p> {{ pkg.manifest.title }}
<p *ngIf="errors[pkg.manifest.id] as error"> </h1>
<ion-text color="danger">{{ error }}</ion-text> <h2 class="inline">
</p> <span>{{ local.manifest.version | displayEmver }}</span>
</ion-label> &nbsp;<ion-icon name="arrow-forward"></ion-icon>&nbsp;
<ion-text color="success">
{{ pkg.manifest.version | displayEmver }}
</ion-text>
</h2>
<p
*ngIf="marketplaceService.updateErrors[pkg.manifest.id] as error"
>
<ion-text color="danger">{{ error }}</ion-text>
</p>
</ion-label>
<div slot="end"> <div slot="end" style="margin-left: 8px">
<round-progress <round-progress
*ngIf="local.state === PackageState.Installing else notInstalling" *ngIf="local.state === PackageState.Updating else notUpdating"
[current]="local['install-progress'] | installProgress" [current]="local['install-progress'] | installProgress"
[max]="100" [max]="100"
[radius]="24" [radius]="24"
[stroke]="4" [stroke]="4"
[rounded]="true" [rounded]="true"
color="var(--ion-color-primary)" color="var(--ion-color-primary)"
></round-progress> ></round-progress>
<ng-template #notInstalling> <ng-template #notUpdating>
<ion-spinner <ion-spinner
*ngIf="queued[pkg.manifest.id] else updateBtn" *ngIf="marketplaceService.updateQueue[pkg.manifest.id] else updateBtn"
color="dark" color="dark"
></ion-spinner> ></ion-spinner>
<ng-template #updateBtn> <ng-template #updateBtn>
<ion-button <ion-button
(click)="tryUpdate(pkg.manifest, host.url, local)" (click)="tryUpdate(pkg.manifest, host.url, local)"
[color]="errors[pkg.manifest.id] ? 'danger' : 'dark'" [color]="marketplaceService.updateErrors[pkg.manifest.id] ? 'danger' : 'dark'"
strong strong
> >
{{ errors[pkg.manifest.id] ? 'Retry' : 'Update' }} {{ marketplaceService.updateErrors[pkg.manifest.id] ?
</ion-button> 'Retry' : 'Update' }}
</ion-button>
</ng-template>
</ng-template> </ng-template>
</ng-template> </div>
</div> </ng-container>
</ng-container> </ion-item>
</ion-item> <div class="notes">
<h5><b>What's New</b></h5>
<p [innerHTML]="pkg.manifest['release-notes'] | markdown"></p>
</div>
</div>
<ion-item *ngIf="!updates.length"> <ion-item *ngIf="!updates.length">
<p>All services are up to date!</p> <p>All services are up to date!</p>

View File

@@ -1,13 +1,16 @@
.service-avatar { .item-container {
position: absolute; padding-bottom: 24px;
top: 6px; border-bottom: 1px solid #373737;
cursor: pointer;
} }
ion-label { .notes {
margin-left: 64px; margin-left: 20px;
} }
.name:only-child { .header {
display: none; margin-bottom: 20px;
h1 {
font-weight: bold;
margin: 0 12px 0 0;
}
} }

View File

@@ -17,7 +17,6 @@ import {
import { Emver, isEmptyObject, sameUrl } from '@start9labs/shared' import { Emver, isEmptyObject, sameUrl } from '@start9labs/shared'
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { combineLatest, Observable } from 'rxjs' import { combineLatest, Observable } from 'rxjs'
import { PrimaryRendering } from '../../services/pkg-status-rendering.service'
import { import {
AlertController, AlertController,
LoadingController, LoadingController,
@@ -40,9 +39,6 @@ interface UpdatesData {
styleUrls: ['updates.page.scss'], styleUrls: ['updates.page.scss'],
}) })
export class UpdatesPage { export class UpdatesPage {
queued: Record<string, boolean> = {}
errors: Record<string, string> = {}
readonly data$: Observable<UpdatesData> = combineLatest({ readonly data$: Observable<UpdatesData> = combineLatest({
hosts: this.marketplaceService.getKnownHosts$(), hosts: this.marketplaceService.getKnownHosts$(),
marketplace: this.marketplaceService.getMarketplace$(), marketplace: this.marketplaceService.getMarketplace$(),
@@ -51,11 +47,10 @@ export class UpdatesPage {
}) })
readonly PackageState = PackageState readonly PackageState = PackageState
readonly rendering = PrimaryRendering[PackageState.Installing]
constructor( constructor(
@Inject(AbstractMarketplaceService) @Inject(AbstractMarketplaceService)
private readonly marketplaceService: MarketplaceService, readonly marketplaceService: MarketplaceService,
private readonly api: ApiService, private readonly api: ApiService,
private readonly patch: PatchDB<DataModel>, private readonly patch: PatchDB<DataModel>,
private readonly navCtrl: NavController, private readonly navCtrl: NavController,
@@ -79,8 +74,8 @@ export class UpdatesPage {
): Promise<void> { ): Promise<void> {
const { id, version } = manifest const { id, version } = manifest
delete this.errors[id] delete this.marketplaceService.updateErrors[id]
this.queued[id] = true this.marketplaceService.updateQueue[id] = true
if (hasCurrentDeps(local)) { if (hasCurrentDeps(local)) {
this.dryUpdate(manifest, url) this.dryUpdate(manifest, url)
@@ -114,12 +109,12 @@ export class UpdatesPage {
if (proceed) { if (proceed) {
this.update(id, version, url) this.update(id, version, url)
} else { } else {
delete this.queued[id] delete this.marketplaceService.updateQueue[id]
} }
} }
} catch (e: any) { } catch (e: any) {
delete this.queued[id] delete this.marketplaceService.updateQueue[id]
this.errors[id] = e.message this.marketplaceService.updateErrors[id] = e.message
} }
} }
@@ -162,11 +157,13 @@ export class UpdatesPage {
}) })
} }
private update(id: string, version: string, url: string) { private async update(id: string, version: string, url: string) {
this.marketplaceService.installPackage(id, version, url).catch(e => { try {
delete this.queued[id] await this.marketplaceService.installPackage(id, version, url)
this.errors[id] = e.message } catch (e: any) {
}) delete this.marketplaceService.updateQueue[id]
this.marketplaceService.updateErrors[id] = e.message
}
} }
} }
@@ -204,7 +201,7 @@ export function versionLower(
emver: Emver, emver: Emver,
): boolean { ): boolean {
return ( return (
local[id].state === PackageState.Installing || local[id].state === PackageState.Updating ||
emver.compare(version, local[id].installed?.manifest.version || '') === 1 emver.compare(version, local[id].installed?.manifest.version || '') === 1
) )
} }

View File

@@ -587,7 +587,8 @@ export class MockApiService extends ApiService {
path: `/package-data/${params.id}`, path: `/package-data/${params.id}`,
value: { value: {
...Mock.LocalPkgs[params.id], ...Mock.LocalPkgs[params.id],
state: PackageState.Installing, // state: PackageState.Installing,
state: PackageState.Updating,
'install-progress': { ...PROGRESS }, 'install-progress': { ...PROGRESS },
}, },
}, },

View File

@@ -156,6 +156,8 @@ export class MarketplaceService implements AbstractMarketplaceService {
} }
// UI only // UI only
readonly updateErrors: Record<string, string> = {}
readonly updateQueue: Record<string, boolean> = {}
getRequestErrors$(): Observable<string[]> { getRequestErrors$(): Observable<string[]> {
return this.requestErrors$ return this.requestErrors$