mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
global click protections, install wizard fixes, better login, better marketplace search, fix mocks
This commit is contained in:
committed by
Aiden McClelland
parent
14a0dbe66e
commit
7b9ce88a16
@@ -8,41 +8,48 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content style="position: relative">
|
||||
<div *ngIf="pkgs | empty; else list" class="ion-text-center ion-padding">
|
||||
<div style="display: flex; flex-direction: column; justify-content: center; height: 40vh">
|
||||
<h2>Welcome to <ion-text color="danger" style="font-family: 'Montserrat';">Embassy</ion-text></h2>
|
||||
<p class="ion-text-wrap">Get started by installing your first service.</p>
|
||||
|
||||
<!-- loading -->
|
||||
<text-spinner *ngIf="loading" text="Connecting to Embassy"></text-spinner>
|
||||
|
||||
<!-- not loading -->
|
||||
<div *ngIf="!loading">
|
||||
<div *ngIf="pkgs | empty; else list" class="ion-text-center ion-padding">
|
||||
<div style="display: flex; flex-direction: column; justify-content: center; height: 40vh">
|
||||
<h2>Welcome to <ion-text color="danger" style="font-family: 'Montserrat';">Embassy</ion-text></h2>
|
||||
<p class="ion-text-wrap">Get started by installing your first service.</p>
|
||||
</div>
|
||||
<ion-button color="dark" [routerLink]="['/marketplace']" style="width: 50%;">
|
||||
<ion-icon slot="start" name="storefront-outline"></ion-icon>
|
||||
Marketplace
|
||||
</ion-button>
|
||||
</div>
|
||||
<ion-button color="dark" [routerLink]="['/marketplace']" style="width: 50%;">
|
||||
<ion-icon slot="start" name="storefront-outline"></ion-icon>
|
||||
Marketplace
|
||||
</ion-button>
|
||||
</div>
|
||||
|
||||
<ng-template #list>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="4" sizeSm="3" sizeLg="3" sizeXl="2">
|
||||
<ion-card class="installed-card" [routerLink]="['/services', pkg.value.entry.manifest.id]">
|
||||
<div class="launch-container" *ngIf="pkg.value.entry.manifest.interfaces | hasUi">
|
||||
<div class="launch-button-triangle" (click)="launchUi(pkg.value.entry, $event)" [class.launch-disabled]="!(pkg.value.entry.state | isLaunchable : pkg.value.entry.installed?.status.main.status : pkg.value.entry.manifest.interfaces)">
|
||||
<ion-icon name="open-outline"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img style="position: absolute" class="main-img" [src]="pkg.value.entry['static-files'].icon" alt="icon" />
|
||||
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
||||
<img *ngIf="connectionFailure" class="bulb-off" src="assets/img/off-bulb.png" />
|
||||
<img *ngIf="!connectionFailure" [class]="pkg.value.bulb.class" [src]="pkg.value.bulb.img" />
|
||||
|
||||
<ion-card-header>
|
||||
<status *ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state" [disconnected]="connectionFailure" [rendering]="pkg.value.statusRendering" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
<p *ngIf="[PackageState.Installing, PackageState.Updating] | includes : pkg.value.entry.state" class="main-status"><ion-text color="primary">{{ pkg.value.entry.state | titlecase }}...{{ (pkg.value.entry['install-progress'] | installState).totalProgress }}%</ion-text></p>
|
||||
<ion-card-title>{{ pkg.value.entry.manifest.title }}</ion-card-title>
|
||||
</ion-card-header>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-template>
|
||||
<ng-template #list>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="4" sizeSm="3" sizeLg="3" sizeXl="2">
|
||||
<ion-card class="installed-card" [routerLink]="['/services', pkg.value.entry.manifest.id]">
|
||||
<div class="launch-container" *ngIf="pkg.value.entry.manifest.interfaces | hasUi">
|
||||
<div class="launch-button-triangle" (click)="launchUi(pkg.value.entry, $event)" [class.launch-disabled]="!(pkg.value.entry.state | isLaunchable : pkg.value.entry.installed?.status.main.status : pkg.value.entry.manifest.interfaces)">
|
||||
<ion-icon name="open-outline"></ion-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img style="position: absolute" class="main-img" [src]="pkg.value.entry['static-files'].icon" alt="icon" />
|
||||
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
||||
<img *ngIf="connectionFailure" class="bulb-off" src="assets/img/off-bulb.png" />
|
||||
<img *ngIf="!connectionFailure" [class]="pkg.value.bulb.class" [src]="pkg.value.bulb.img" />
|
||||
|
||||
<ion-card-header>
|
||||
<status *ngIf="[PackageState.Installed, PackageState.Removing] | includes : pkg.value.entry.state" [disconnected]="connectionFailure" [rendering]="pkg.value.statusRendering" size="calc(8px + .4vw)" weight="bold"></status>
|
||||
<p *ngIf="[PackageState.Installing, PackageState.Updating] | includes : pkg.value.entry.state" class="main-status"><ion-text color="primary">{{ pkg.value.entry.state | titlecase }}...{{ (pkg.value.entry['install-progress'] | installState).totalProgress }}%</ion-text></p>
|
||||
<ion-card-title>{{ pkg.value.entry.manifest.title }}</ion-card-title>
|
||||
</ion-card-header>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ng-template>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||
import { filter } from 'rxjs/operators'
|
||||
import { delay, filter } from 'rxjs/operators'
|
||||
|
||||
@Component({
|
||||
selector: 'app-list',
|
||||
@@ -25,6 +25,7 @@ export class AppListPage {
|
||||
sub: Subscription | null
|
||||
}} = { }
|
||||
PackageState = PackageState
|
||||
loading = true
|
||||
|
||||
constructor (
|
||||
private readonly config: ConfigService,
|
||||
@@ -41,6 +42,8 @@ export class AppListPage {
|
||||
}),
|
||||
)
|
||||
.subscribe(pkgs => {
|
||||
this.loading = false
|
||||
|
||||
const ids = Object.keys(pkgs)
|
||||
|
||||
Object.keys(this.pkgs).forEach(id => {
|
||||
|
||||
@@ -84,33 +84,31 @@ export class AppShowPage {
|
||||
|
||||
async stop (): Promise<void> {
|
||||
const { id, title, version } = this.pkg.manifest
|
||||
const loader = await this.loadingCtrl.create({
|
||||
message: `Stopping...`,
|
||||
spinner: 'lines',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const breakages = await this.embassyApi.dryStopPackage({ id })
|
||||
if (isEmptyObject(this.pkg.installed['current-dependents'])) {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
message: `Stopping...`,
|
||||
spinner: 'lines',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
if (!isEmptyObject(breakages)) {
|
||||
const { cancelled } = await wizardModal(
|
||||
this.modalCtrl,
|
||||
this.wizardBaker.stop({
|
||||
id,
|
||||
title,
|
||||
version,
|
||||
breakages,
|
||||
}),
|
||||
)
|
||||
if (cancelled) return
|
||||
try {
|
||||
await this.embassyApi.stopPackage({ id })
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
await this.embassyApi.stopPackage({ id })
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
} else {
|
||||
wizardModal(
|
||||
this.modalCtrl,
|
||||
this.wizardBaker.stop({
|
||||
id,
|
||||
title,
|
||||
version,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Component } from '@angular/core'
|
||||
import { LoadingController } from '@ionic/angular'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { AuthService } from 'src/app/services/auth.service'
|
||||
import { PatchConnection, PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
|
||||
@Component({
|
||||
selector: 'login',
|
||||
@@ -19,13 +18,8 @@ export class LoginPage {
|
||||
constructor (
|
||||
private readonly authService: AuthService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
private readonly patch: PatchDbService,
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
if (this.loader) {
|
||||
this.loader.dismiss()
|
||||
@@ -52,16 +46,10 @@ export class LoginPage {
|
||||
|
||||
try {
|
||||
await this.authService.login(this.password)
|
||||
this.loader.message = 'Loading Embassy Data'
|
||||
this.password = ''
|
||||
this.patchConnectionSub = this.patch.watchPatchConnection$().subscribe(status => {
|
||||
if (status === PatchConnection.Disconnected) {
|
||||
this.error = 'Connection failed'
|
||||
this.loader.dismiss()
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
this.error = e.message
|
||||
} finally {
|
||||
this.loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MarketplaceListPage } from './marketplace-list.page'
|
||||
import { SharingModule } from '../../../modules/sharing.module'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { StatusComponentModule } from 'src/app/components/status/status.component.module'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -18,6 +19,7 @@ const routes: Routes = [
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
FormsModule,
|
||||
RouterModule.forChild(routes),
|
||||
StatusComponentModule,
|
||||
SharingModule,
|
||||
|
||||
@@ -9,7 +9,14 @@
|
||||
<ion-content class="ion-padding">
|
||||
<h1 style="font-family: 'Montserrat'; font-weight: 100px; margin: 32px 0;" class="ion-text-center">Embassy Marketplace</h1>
|
||||
|
||||
<ion-searchbar color="dark" (ionChange)="search($event)" debounce="400" style="padding-bottom: 32px;"></ion-searchbar>
|
||||
<ion-toolbar style="padding-bottom: 32px; max-width: 600px;" color="transparent">
|
||||
<ion-searchbar color="dark" (keyup.enter)="search()" debounce="300" [(ngModel)]="query"></ion-searchbar>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button color="primary" fill="solid" (click)="search()">
|
||||
<ion-icon slot="icon-only" name="search-outline"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
|
||||
<!-- page loading -->
|
||||
<ng-container *ngIf="pageLoading; else pageLoaded">
|
||||
|
||||
@@ -88,10 +88,11 @@ export class MarketplaceListPage {
|
||||
e.target.complete()
|
||||
}
|
||||
|
||||
async search (e?: any): Promise<void> {
|
||||
this.query = e.target.value || undefined
|
||||
this.page = 1
|
||||
async search (): Promise<void> {
|
||||
if (!this.query) return
|
||||
this.pkgsLoading = true
|
||||
this.category = undefined
|
||||
this.page = 1
|
||||
await this.getPkgs()
|
||||
}
|
||||
|
||||
@@ -134,9 +135,9 @@ export class MarketplaceListPage {
|
||||
}
|
||||
|
||||
async switchCategory (category: string): Promise<void> {
|
||||
this.pkgs = []
|
||||
this.category = category
|
||||
this.pkgsLoading = true
|
||||
this.category = category
|
||||
this.query = undefined
|
||||
this.page = 1
|
||||
await this.getPkgs()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user