react to enter key for alerts and modals. Styling and logic

This commit is contained in:
Matt Hill
2021-08-24 16:55:53 -06:00
committed by Aiden McClelland
parent 5c2f724e0c
commit 37a6df0815
24 changed files with 195 additions and 229 deletions

View File

@@ -80,6 +80,7 @@ export class AppActionsPage {
handler: () => {
this.executeAction(pkg.manifest.id, action.key)
},
cssClass: 'enter-click',
},
],
})
@@ -104,7 +105,7 @@ export class AppActionsPage {
header: 'Forbidden',
message: error || `Action "${action.value.name}" can only be executed when service is ${statusesStr}`,
buttons: ['OK'],
cssClass: 'alert-error-message',
cssClass: 'alert-error-message enter-click',
})
await alert.present()
}
@@ -159,7 +160,13 @@ export class AppActionsPage {
const successAlert = await this.alertCtrl.create({
header: 'Execution Complete',
message: res.message.split('\n').join('</br ></br />'),
buttons: ['OK'],
buttons: [
{
text: 'Ok',
role: 'cancel',
cssClass: 'enter-click',
},
],
})
setTimeout(() => successAlert.present(), 400)

View File

@@ -6,7 +6,7 @@
<ion-title>Properties</ion-title>
<ion-buttons slot="end">
<ion-button (click)="refresh()">
<ion-icon slot="start" name="refresh-outline"></ion-icon>
<ion-icon slot="start" name="refresh"></ion-icon>
Refresh
</ion-button>
</ion-buttons>

View File

@@ -130,7 +130,6 @@ export class AppShowPage {
const alert = await this.alertCtrl.create({
header: 'Not Accepting Donations',
message: `The developers of ${this.pkg.manifest.title} have not provided a donation URL. Please contact them directly if you insist on giving them money.`,
buttons: ['OK'],
})
await alert.present()
}
@@ -215,6 +214,7 @@ export class AppShowPage {
handler: () => {
this.start()
},
cssClass: 'enter-click',
},
],
})

View File

@@ -140,18 +140,6 @@
<ion-row>
<ion-col sizeSm="12" sizeMd="6">
<ion-item-group>
<ion-item detail="false">
<ion-label>
<h2>Service ID</h2>
<p>{{ pkg.manifest.id }}</p>
</ion-label>
</ion-item>
<ion-item detail="false">
<ion-label>
<h2>Categories</h2>
<p>{{ pkg.categories.join(', ') }}</p>
</ion-label>
</ion-item>
<ion-item button detail="false" (click)="presentAlertVersions()">
<ion-label>
<h2>Other Versions</h2>
@@ -198,20 +186,6 @@
</ion-label>
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-item>
<ion-item [href]="pkg.manifest['marketing-site']" target="_blank" detail="false">
<ion-label>
<h2>Marketing Site</h2>
<p>{{ pkg.manifest['marketing-site'] }}</p>
</ion-label>
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-item>
<ion-item *ngIf="pkg.manifest['donation-url'] as donationUrl" [href]="donationUrl" target="_blank" detail="false">
<ion-label>
<h2>Donation Site</h2>
<p>{{ donationUrl }}</p>
</ion-label>
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-item>
</ion-item-group>
</ion-col>
</ion-row>

View File

@@ -81,7 +81,6 @@ export class MarketplaceShowPage {
async presentAlertVersions () {
const alert = await this.alertCtrl.create({
header: 'Versions',
backdropDismiss: false,
inputs: this.marketplaceService.pkgs[this.pkgId].versions.sort((a, b) => -1 * this.emver.compare(a, b)).map(v => {
return {
name: v, // for CSS
@@ -100,6 +99,7 @@ export class MarketplaceShowPage {
handler: (version: string) => {
this.getPkg(version)
},
cssClass: 'enter-click',
},
],
})

View File

@@ -32,7 +32,6 @@ export class SessionsPage {
async presentAlertKill (id: string) {
const alert = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Caution',
message: `Are you sure you want to kill this session?`,
buttons: [
@@ -45,6 +44,7 @@ export class SessionsPage {
handler: () => {
this.kill(id)
},
cssClass: 'enter-click',
},
],
})

View File

@@ -22,7 +22,7 @@
<ion-item-divider>Saved Keys</ion-item-divider>
<ion-item button detail="false" (click)="serverConfig.presentModalInput('ssh')">
<ion-item button detail="false" (click)="presentModalAdd()">
<ion-icon slot="start" name="add" size="large"></ion-icon>
<ion-label>Add new key</ion-label>
</ion-item>

View File

@@ -1,10 +1,9 @@
import { Component } from '@angular/core'
import { ServerConfigService } from 'src/app/services/server-config.service'
import { AlertController, LoadingController } from '@ionic/angular'
import { SSHService } from './ssh.service'
import { Subscription } from 'rxjs'
import { AlertController, LoadingController, ModalController } from '@ionic/angular'
import { SSHKeys } from 'src/app/services/api/api.types'
import { ErrorToastService } from 'src/app/services/error-toast.service'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { BackupConfirmationComponent } from 'src/app/modals/backup-confirmation/backup-confirmation.component'
@Component({
selector: 'ssh-keys',
@@ -14,37 +13,66 @@ import { ErrorToastService } from 'src/app/services/error-toast.service'
export class SSHKeysPage {
loading = true
sshKeys: SSHKeys
subs: Subscription[] = []
readonly docsUrl = 'https://docs.start9.com/user-manual/general/developer-options/ssh-setup.html'
constructor (
private readonly loadingCtrl: LoadingController,
private readonly modalCtrl: ModalController,
private readonly errToast: ErrorToastService,
private readonly alertCtrl: AlertController,
private readonly sshService: SSHService,
public readonly serverConfig: ServerConfigService,
private readonly embassyApi: ApiService,
) { }
async ngOnInit () {
this.subs = [
this.sshService.watch$()
.subscribe(keys => {
this.sshKeys = keys
}),
]
await this.sshService.getKeys()
this.loading = false
await this.getKeys()
}
ngOnDestroy () {
this.subs.forEach(sub => sub.unsubscribe())
async getKeys (): Promise<void> {
try {
this.sshKeys = await this.embassyApi.getSshKeys({ })
} catch (e) {
this.errToast.present(e)
} finally {
this.loading = false
}
}
async presentModalAdd () {
const { name, description } = sshSpec
const modal = await this.modalCtrl.create({
component: BackupConfirmationComponent,
componentProps: {
title: name,
message: description,
label: name,
submitFn: this.add,
},
cssClass: 'alertlike-modal',
})
await modal.present()
}
async add (pubkey: string): Promise<void> {
const loader = await this.loadingCtrl.create({
spinner: 'lines',
message: 'Saving...',
cssClass: 'loader',
})
await loader.present()
try {
const key = await this.embassyApi.addSshKey({ pubkey })
this.sshKeys = { ...this.sshKeys, ...key }
} catch (e) {
this.errToast.present(e)
} finally {
loader.dismiss()
}
}
async presentAlertDelete (hash: string) {
const alert = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Caution',
message: `Are you sure you want to delete this key?`,
buttons: [
@@ -57,6 +85,7 @@ export class SSHKeysPage {
handler: () => {
this.delete(hash)
},
cssClass: 'enter-click',
},
],
})
@@ -72,7 +101,8 @@ export class SSHKeysPage {
await loader.present()
try {
await this.sshService.delete(hash)
await this.embassyApi.deleteSshKey({ hash })
delete this.sshKeys[hash]
} catch (e) {
this.errToast.present(e)
} finally {
@@ -84,3 +114,15 @@ export class SSHKeysPage {
return 0
}
}
const sshSpec = {
type: 'string',
name: 'SSH Key',
description: 'Enter the SSH public key of you would like to authorize for root access to your Embassy.',
nullable: false,
// @TODO regex for SSH Key
// pattern: '',
'pattern-description': 'Must be a valid SSH key',
masked: false,
copyable: false,
}

View File

@@ -17,27 +17,5 @@ export class SSHService {
return this.keys$.asObservable()
}
async getKeys (): Promise<void> {
const keys = await this.embassyApi.getSshKeys({ })
this.keys$.next(keys)
}
async add (pubkey: string): Promise<void> {
const key = await this.embassyApi.addSshKey({ pubkey })
const keys = this.keys$.getValue()
this.keys$.next({ ...keys, ...key })
}
async delete (hash: string): Promise<void> {
await this.embassyApi.deleteSshKey({ hash })
const keys = this.keys$.getValue()
const filtered = Object.keys(keys)
.filter(h => h !== hash)
.reduce((res, h) => {
res[h] = keys[h]
return res
}, { })
this.keys$.next(filtered)
}
}

View File

@@ -27,7 +27,6 @@ export class ServerShowPage {
async presentAlertRestart () {
const alert = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Confirm',
message: `Are you sure you want to restart your Embassy?`,
buttons: [
@@ -40,15 +39,15 @@ export class ServerShowPage {
handler: () => {
this.restart()
},
cssClass: 'enter-click',
},
]},
)
],
})
await alert.present()
}
async presentAlertShutdown () {
const alert = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Confirm',
message: `Are you sure you want to shut down your Embassy? To turn it back on, you will need to physically unplug the device and plug it back in.`,
buttons: [
@@ -61,6 +60,7 @@ export class ServerShowPage {
handler: () => {
this.shutdown()
},
cssClass: 'enter-click',
},
],
})

View File

@@ -33,7 +33,7 @@ export class WifiPage {
try {
await this.getWifi()
} catch (e) {
this.errToast.present(e.message)
this.errToast.present(e)
} finally {
this.loading = false
}
@@ -72,7 +72,7 @@ export class WifiPage {
},
},
],
cssClass: 'wide-alert',
cssClass: 'wide-alert enter-click',
})
await alert.present()
}
@@ -206,7 +206,13 @@ export class WifiPage {
const alert = await this.alertCtrl.create({
header: `Connected to "${ssid}"`,
message: 'Note. It may take several minutes to an hour for your Embassy to reconnect over Tor.',
buttons: ['OK'],
buttons: [
{
text: 'Ok',
role: 'cancel',
cssClass: 'enter-click',
},
],
})
await alert.present()