mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
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:
@@ -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,
|
||||||
|
|||||||
@@ -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 -->
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()">
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 80px;
|
margin-bottom: 14px;
|
||||||
font-size: 80px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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 }}
|
<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>
|
||||||
<ion-icon name="arrow-forward"></ion-icon>
|
<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>
|
<ion-icon name="arrow-forward"></ion-icon>
|
||||||
|
<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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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$
|
||||||
|
|||||||
Reference in New Issue
Block a user