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
columns: any[] = []
maxStackHeight: any
disableLogin = true
disableLogin = this.stateService.setupType === 'fresh'
constructor(
@Inject(DOCUMENT) private readonly document: Document,

View File

@@ -134,15 +134,15 @@
<ion-label>
<b>
{{ spec.name }}
<ion-text *ngIf="entry.value.dirty" color="warning">
(Edited)</ion-text
>
<ion-text
*ngIf="original?.[entry.key] === undefined"
color="success"
>
(New)</ion-text
>
<ion-text *ngIf="entry.value.dirty" color="warning">
(Edited)</ion-text
>
</b>
</ion-label>
<!-- 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>
<ion-icon name="storefront-outline"></ion-icon>
<ion-icon name="storefront-outline" [style.font-size]="size"></ion-icon>
</ng-template>

View File

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

View File

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

View File

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

View File

@@ -23,7 +23,11 @@
<ion-row>
<ion-col size="12">
<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>
</div>
<ion-button fill="clear" (click)="presentModalMarketplaceSettings()">

View File

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

View File

@@ -56,10 +56,13 @@
"
>
<ion-icon
style="font-size: 84px; color: #595959"
style="font-size: 84px; color: #767676"
name="mail-outline"
></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>
</ion-item-group>

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,16 @@
.service-avatar {
position: absolute;
top: 6px;
cursor: pointer;
.item-container {
padding-bottom: 24px;
border-bottom: 1px solid #373737;
}
ion-label {
margin-left: 64px;
.notes {
margin-left: 20px;
}
.name:only-child {
display: none;
.header {
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 { Pipe, PipeTransform } from '@angular/core'
import { combineLatest, Observable } from 'rxjs'
import { PrimaryRendering } from '../../services/pkg-status-rendering.service'
import {
AlertController,
LoadingController,
@@ -40,9 +39,6 @@ interface UpdatesData {
styleUrls: ['updates.page.scss'],
})
export class UpdatesPage {
queued: Record<string, boolean> = {}
errors: Record<string, string> = {}
readonly data$: Observable<UpdatesData> = combineLatest({
hosts: this.marketplaceService.getKnownHosts$(),
marketplace: this.marketplaceService.getMarketplace$(),
@@ -51,11 +47,10 @@ export class UpdatesPage {
})
readonly PackageState = PackageState
readonly rendering = PrimaryRendering[PackageState.Installing]
constructor(
@Inject(AbstractMarketplaceService)
private readonly marketplaceService: MarketplaceService,
readonly marketplaceService: MarketplaceService,
private readonly api: ApiService,
private readonly patch: PatchDB<DataModel>,
private readonly navCtrl: NavController,
@@ -79,8 +74,8 @@ export class UpdatesPage {
): Promise<void> {
const { id, version } = manifest
delete this.errors[id]
this.queued[id] = true
delete this.marketplaceService.updateErrors[id]
this.marketplaceService.updateQueue[id] = true
if (hasCurrentDeps(local)) {
this.dryUpdate(manifest, url)
@@ -114,12 +109,12 @@ export class UpdatesPage {
if (proceed) {
this.update(id, version, url)
} else {
delete this.queued[id]
delete this.marketplaceService.updateQueue[id]
}
}
} catch (e: any) {
delete this.queued[id]
this.errors[id] = e.message
delete this.marketplaceService.updateQueue[id]
this.marketplaceService.updateErrors[id] = e.message
}
}
@@ -162,11 +157,13 @@ export class UpdatesPage {
})
}
private update(id: string, version: string, url: string) {
this.marketplaceService.installPackage(id, version, url).catch(e => {
delete this.queued[id]
this.errors[id] = e.message
})
private async update(id: string, version: string, url: string) {
try {
await this.marketplaceService.installPackage(id, version, url)
} catch (e: any) {
delete this.marketplaceService.updateQueue[id]
this.marketplaceService.updateErrors[id] = e.message
}
}
}
@@ -204,7 +201,7 @@ export function versionLower(
emver: Emver,
): boolean {
return (
local[id].state === PackageState.Installing ||
local[id].state === PackageState.Updating ||
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}`,
value: {
...Mock.LocalPkgs[params.id],
state: PackageState.Installing,
// state: PackageState.Installing,
state: PackageState.Updating,
'install-progress': { ...PROGRESS },
},
},

View File

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