mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
alt marketplace feature
re-arrange use url api proxy function matt comments addressed delete cache on marketplace load failure
This commit is contained in:
committed by
Aiden McClelland
parent
691d567d31
commit
2d4ecd3096
@@ -1,5 +1,9 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { MarketplaceData, MarketplaceEOS, MarketplacePkg } from 'src/app/services/api/api.types'
|
||||
import {
|
||||
MarketplaceData,
|
||||
MarketplaceEOS,
|
||||
MarketplacePkg,
|
||||
} from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { Emver } from 'src/app/services/emver.service'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
@@ -12,38 +16,59 @@ export class MarketplaceService {
|
||||
data: MarketplaceData
|
||||
eos: MarketplaceEOS
|
||||
pkgs: MarketplacePkg[] = []
|
||||
releaseNotes: { [id: string]: {
|
||||
[version: string]: string
|
||||
} } = { }
|
||||
releaseNotes: {
|
||||
[id: string]: {
|
||||
[version: string]: string
|
||||
}
|
||||
} = {}
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly emver: Emver,
|
||||
private readonly patch: PatchDbService,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
get eosUpdateAvailable () {
|
||||
return this.emver.compare(this.eos.version, this.patch.data['server-info'].version) === 1
|
||||
get eosUpdateAvailable() {
|
||||
return (
|
||||
this.emver.compare(
|
||||
this.eos.version,
|
||||
this.patch.data['server-info'].version,
|
||||
) === 1
|
||||
)
|
||||
}
|
||||
|
||||
async load (): Promise<void> {
|
||||
const [data, eos, pkgs] = await Promise.all([
|
||||
this.api.getMarketplaceData({ }),
|
||||
this.api.getEos({
|
||||
'eos-version-compat': this.patch.getData()['server-info']['eos-version-compat'],
|
||||
}),
|
||||
this.getPkgs(1, 100),
|
||||
])
|
||||
this.data = data
|
||||
this.eos = eos
|
||||
this.pkgs = pkgs
|
||||
async load(): Promise<void> {
|
||||
try {
|
||||
const [data, eos, pkgs] = await Promise.all([
|
||||
this.api.getMarketplaceData({}),
|
||||
this.api.getEos({
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
}),
|
||||
this.getPkgs(1, 100),
|
||||
])
|
||||
this.data = data
|
||||
this.eos = eos
|
||||
this.pkgs = pkgs
|
||||
} catch (e) {
|
||||
this.data = undefined
|
||||
this.eos = undefined
|
||||
this.pkgs = []
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async getUpdates (localPkgs: { [id: string]: PackageDataEntry }) : Promise<MarketplacePkg[]> {
|
||||
const idAndCurrentVersions = Object.keys(localPkgs).map(key => ({ id: key, version: localPkgs[key].manifest.version }))
|
||||
async getUpdates(localPkgs: {
|
||||
[id: string]: PackageDataEntry
|
||||
}): Promise<MarketplacePkg[]> {
|
||||
const idAndCurrentVersions = Object.keys(localPkgs).map(key => ({
|
||||
id: key,
|
||||
version: localPkgs[key].manifest.version,
|
||||
}))
|
||||
const latestPkgs = await this.api.getMarketplacePkgs({
|
||||
ids: idAndCurrentVersions,
|
||||
'eos-version-compat': this.patch.getData()['server-info']['eos-version-compat'],
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
})
|
||||
|
||||
return latestPkgs.filter(latestPkg => {
|
||||
@@ -53,10 +78,11 @@ export class MarketplaceService {
|
||||
})
|
||||
}
|
||||
|
||||
async getPkg (id: string, version = '*'): Promise<MarketplacePkg> {
|
||||
async getPkg(id: string, version = '*'): Promise<MarketplacePkg> {
|
||||
const pkgs = await this.api.getMarketplacePkgs({
|
||||
ids: [{ id, version }],
|
||||
'eos-version-compat': this.patch.getData()['server-info']['eos-version-compat'],
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
})
|
||||
const pkg = pkgs.find(pkg => pkg.manifest.id == id)
|
||||
|
||||
@@ -67,19 +93,21 @@ export class MarketplaceService {
|
||||
}
|
||||
}
|
||||
|
||||
async getReleaseNotes (id: string): Promise<void> {
|
||||
async getReleaseNotes(id: string): Promise<void> {
|
||||
this.releaseNotes[id] = await this.api.getReleaseNotes({ id })
|
||||
}
|
||||
|
||||
private async getPkgs (page: number, perPage: number) : Promise<MarketplacePkg[]> {
|
||||
private async getPkgs(
|
||||
page: number,
|
||||
perPage: number,
|
||||
): Promise<MarketplacePkg[]> {
|
||||
const pkgs = await this.api.getMarketplacePkgs({
|
||||
page: String(page),
|
||||
'per-page': String(perPage),
|
||||
'eos-version-compat': this.patch.getData()['server-info']['eos-version-compat'],
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
})
|
||||
|
||||
return pkgs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { RouterModule, Routes } from '@angular/router'
|
||||
import { MarketplacesPage } from './marketplaces.page'
|
||||
import { SharingModule } from 'src/app/modules/sharing.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: MarketplacesPage,
|
||||
},
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
SharingModule,
|
||||
],
|
||||
declarations: [MarketplacesPage],
|
||||
})
|
||||
export class MarketplacesPageModule {}
|
||||
@@ -0,0 +1,52 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="embassy"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Marketplace Settings</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item-group>
|
||||
<ion-item-divider>Saved Marketplaces</ion-item-divider>
|
||||
<ion-item button detail="false" (click)="presentModalAdd()">
|
||||
<ion-icon slot="start" name="add" size="large" color="dark"></ion-icon>
|
||||
<ion-label>
|
||||
<ion-text color="dark">
|
||||
<b>Add alternative marketplace</b>
|
||||
</ion-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item
|
||||
[button]="mp.key !== patch.data.ui.marketplace['selected-id']"
|
||||
detail="false"
|
||||
*ngFor="let mp of patch.data.ui.marketplace.options | keyvalue"
|
||||
(click)="presentAction(mp.key)"
|
||||
>
|
||||
<div
|
||||
*ngIf="mp.key !== patch.data.ui.marketplace['selected-id']"
|
||||
slot="start"
|
||||
style="padding-right: 32px"
|
||||
></div>
|
||||
<ion-icon
|
||||
*ngIf="mp.key === patch.data.ui.marketplace['selected-id']"
|
||||
slot="start"
|
||||
size="large"
|
||||
name="checkmark"
|
||||
color="success"
|
||||
></ion-icon>
|
||||
<ion-label>
|
||||
<h2>{{ mp.value.name }}</h2>
|
||||
<p>{{ mp.value.url }}</p>
|
||||
</ion-label>
|
||||
<ion-note
|
||||
*ngIf="mp.key === patch.data.ui.marketplace['selected-id']"
|
||||
slot="end"
|
||||
>
|
||||
<ion-text color="success">Selected</ion-text>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,7 @@
|
||||
.skeleton-parts {
|
||||
ion-button::part(native) {
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 0;
|
||||
};
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
import { Component } from '@angular/core'
|
||||
import {
|
||||
ActionSheetController,
|
||||
LoadingController,
|
||||
ModalController,
|
||||
} from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ActionSheetButton } from '@ionic/core'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
import { PatchDbService } from '../../../services/patch-db/patch-db.service'
|
||||
import { v4 } from 'uuid'
|
||||
import { MarketplaceService } from '../../marketplace-routes/marketplace.service'
|
||||
import {
|
||||
DataModel,
|
||||
UIData,
|
||||
UIMarketplaceData,
|
||||
} from '../../../services/patch-db/data-model'
|
||||
|
||||
@Component({
|
||||
selector: 'marketplaces',
|
||||
templateUrl: 'marketplaces.page.html',
|
||||
styleUrls: ['marketplaces.page.scss'],
|
||||
})
|
||||
export class MarketplacesPage {
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly actionCtrl: ActionSheetController,
|
||||
private readonly marketplaceService: MarketplaceService,
|
||||
public readonly patch: PatchDbService,
|
||||
) {}
|
||||
|
||||
async presentModalAdd() {
|
||||
const marketplaceSpec = getMarketplaceValueSpec()
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: GenericFormPage,
|
||||
componentProps: {
|
||||
title: marketplaceSpec.name,
|
||||
spec: marketplaceSpec.spec,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Save for Later',
|
||||
handler: (value: { url: string }) => {
|
||||
this.save(value.url)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Save and Connect',
|
||||
handler: (value: { url: string }) => {
|
||||
this.saveAndConnect(value.url)
|
||||
},
|
||||
isSubmit: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
cssClass: 'alertlike-modal',
|
||||
})
|
||||
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
async presentAction(id: string) {
|
||||
// no need to view actions if is selected marketplace
|
||||
if (id === this.patch.data.ui.marketplace['selected-id']) return
|
||||
|
||||
const buttons: ActionSheetButton[] = [
|
||||
{
|
||||
text: 'Forget',
|
||||
icon: 'trash',
|
||||
role: 'destructive',
|
||||
handler: () => {
|
||||
this.delete(id)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Connect to marketplace',
|
||||
handler: () => {
|
||||
this.connect(id)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const action = await this.actionCtrl.create({
|
||||
header: id,
|
||||
subHeader: 'Manage marketplaces',
|
||||
mode: 'ios',
|
||||
buttons,
|
||||
})
|
||||
|
||||
await action.present()
|
||||
}
|
||||
|
||||
private async connect(id: string): Promise<void> {
|
||||
const marketplace = JSON.parse(
|
||||
JSON.stringify(this.patch.data.ui.marketplace),
|
||||
)
|
||||
const newMarketplace = marketplace.options[id]
|
||||
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Validating Marketplace...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.api.getMarketplaceData({}, newMarketplace.url)
|
||||
} catch (e) {
|
||||
this.errToast.present({
|
||||
message: `Could not connect to ${newMarketplace.url}`,
|
||||
} as any)
|
||||
loader.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
loader.message = 'Changing Marketplace...'
|
||||
|
||||
try {
|
||||
marketplace['selected-id'] = id
|
||||
await this.api.setDbValue({ pointer: `/marketplace`, value: marketplace })
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
loader.dismiss()
|
||||
}
|
||||
|
||||
loader.message = 'Syncing store...'
|
||||
|
||||
try {
|
||||
await this.marketplaceService.load()
|
||||
} catch (e) {
|
||||
this.errToast.present({
|
||||
message: `Error syncing marketplace data`,
|
||||
} as any)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private async delete(id: string): Promise<void> {
|
||||
const marketplace = JSON.parse(
|
||||
JSON.stringify(this.patch.data.ui.marketplace),
|
||||
)
|
||||
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Deleting...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
delete marketplace.options[id]
|
||||
await this.api.setDbValue({ pointer: `/marketplace`, value: marketplace })
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private async save(url: string): Promise<void> {
|
||||
const marketplace = JSON.parse(
|
||||
JSON.stringify(this.patch.data.ui.marketplace),
|
||||
) as UIMarketplaceData
|
||||
|
||||
// no-op on duplicates
|
||||
const currentUrls = Object.values(marketplace.options).map(
|
||||
u => new URL(u.url).hostname,
|
||||
)
|
||||
if (currentUrls.includes(new URL(url).hostname)) return
|
||||
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Validating Marketplace...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const id = v4()
|
||||
const { name } = await this.api.getMarketplaceData({}, url)
|
||||
marketplace.options[id] = { name, url }
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Could not connect to ${url}` } as any)
|
||||
loader.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
loader.message = 'Saving...'
|
||||
|
||||
try {
|
||||
await this.api.setDbValue({ pointer: `/marketplace`, value: marketplace })
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Error saving marketplace data` } as any)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private async saveAndConnect(url: string): Promise<void> {
|
||||
const marketplace = JSON.parse(
|
||||
JSON.stringify(this.patch.data.ui.marketplace),
|
||||
) as UIMarketplaceData
|
||||
|
||||
// no-op on duplicates
|
||||
const currentUrls = Object.values(marketplace.options).map(
|
||||
u => new URL(u.url).hostname,
|
||||
)
|
||||
if (currentUrls.includes(new URL(url).hostname)) return
|
||||
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Validating Marketplace...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const id = v4()
|
||||
const { name } = await this.api.getMarketplaceData({}, url)
|
||||
marketplace.options[id] = { name, url }
|
||||
marketplace['selected-id'] = id
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Could not connect to ${url}` } as any)
|
||||
loader.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
loader.message = 'Saving...'
|
||||
|
||||
try {
|
||||
await this.api.setDbValue({ pointer: `/marketplace`, value: marketplace })
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Error saving marketplace data` } as any)
|
||||
loader.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
loader.message = 'Syncing store...'
|
||||
|
||||
try {
|
||||
await this.marketplaceService.load()
|
||||
} catch (e) {
|
||||
this.errToast.present({
|
||||
message: `Error syncing marketplace data`,
|
||||
} as any)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMarketplaceValueSpec(): ValueSpecObject {
|
||||
return {
|
||||
type: 'object',
|
||||
name: 'Add Marketplace',
|
||||
'unique-by': null,
|
||||
spec: {
|
||||
url: {
|
||||
type: 'string',
|
||||
name: 'URL',
|
||||
description: 'The fully-qualified URL of the alternative marketplace.',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: `https?:\/\/[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}`,
|
||||
'pattern-description': 'Must be a valid URL',
|
||||
placeholder: 'e.g. https://example.org',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,17 @@ import { Routes, RouterModule } from '@angular/router'
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./server-show/server-show.module').then(m => m.ServerShowPageModule),
|
||||
loadChildren: () =>
|
||||
import('./server-show/server-show.module').then(
|
||||
m => m.ServerShowPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'backup',
|
||||
loadChildren: () => import('./server-backup/server-backup.module').then(m => m.ServerBackupPageModule),
|
||||
loadChildren: () =>
|
||||
import('./server-backup/server-backup.module').then(
|
||||
m => m.ServerBackupPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'lan',
|
||||
@@ -16,35 +22,60 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'logs',
|
||||
loadChildren: () => import('./server-logs/server-logs.module').then(m => m.ServerLogsPageModule),
|
||||
loadChildren: () =>
|
||||
import('./server-logs/server-logs.module').then(
|
||||
m => m.ServerLogsPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'marketplaces',
|
||||
loadChildren: () =>
|
||||
import('./marketplaces/marketplaces.module').then(
|
||||
m => m.MarketplacesPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'metrics',
|
||||
loadChildren: () => import('./server-metrics/server-metrics.module').then(m => m.ServerMetricsPageModule),
|
||||
loadChildren: () =>
|
||||
import('./server-metrics/server-metrics.module').then(
|
||||
m => m.ServerMetricsPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'preferences',
|
||||
loadChildren: () => import('./preferences/preferences.module').then( m => m.PreferencesPageModule),
|
||||
loadChildren: () =>
|
||||
import('./preferences/preferences.module').then(
|
||||
m => m.PreferencesPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'restore',
|
||||
loadChildren: () => import('./restore/restore.component.module').then( m => m.RestorePageModule),
|
||||
loadChildren: () =>
|
||||
import('./restore/restore.component.module').then(
|
||||
m => m.RestorePageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'sessions',
|
||||
loadChildren: () => import('./sessions/sessions.module').then( m => m.SessionsPageModule),
|
||||
loadChildren: () =>
|
||||
import('./sessions/sessions.module').then(m => m.SessionsPageModule),
|
||||
},
|
||||
{
|
||||
path: 'specs',
|
||||
loadChildren: () => import('./server-specs/server-specs.module').then(m => m.ServerSpecsPageModule),
|
||||
loadChildren: () =>
|
||||
import('./server-specs/server-specs.module').then(
|
||||
m => m.ServerSpecsPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'ssh',
|
||||
loadChildren: () => import('./ssh-keys/ssh-keys.module').then( m => m.SSHKeysPageModule),
|
||||
loadChildren: () =>
|
||||
import('./ssh-keys/ssh-keys.module').then(m => m.SSHKeysPageModule),
|
||||
},
|
||||
{
|
||||
path: 'wifi',
|
||||
loadChildren: () => import('./wifi/wifi.module').then(m => m.WifiPageModule),
|
||||
loadChildren: () =>
|
||||
import('./wifi/wifi.module').then(m => m.WifiPageModule),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -52,4 +83,4 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ServerRoutingModule { }
|
||||
export class ServerRoutingModule {}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { AlertController, LoadingController, NavController, IonicSafeString } from '@ionic/angular'
|
||||
import {
|
||||
AlertController,
|
||||
LoadingController,
|
||||
NavController,
|
||||
IonicSafeString,
|
||||
} from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
@@ -16,7 +21,7 @@ import { map } from 'rxjs/operators'
|
||||
export class ServerShowPage {
|
||||
ServerStatus = ServerStatus
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
@@ -24,12 +29,13 @@ export class ServerShowPage {
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly route: ActivatedRoute,
|
||||
public readonly patch: PatchDbService,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
async presentAlertRestart () {
|
||||
async presentAlertRestart() {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Confirm',
|
||||
message: 'Are you sure you want to restart your Embassy? It can take several minutes to come back online.',
|
||||
message:
|
||||
'Are you sure you want to restart your Embassy? It can take several minutes to come back online.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
@@ -47,11 +53,12 @@ export class ServerShowPage {
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
async presentAlertShutdown () {
|
||||
async presentAlertShutdown() {
|
||||
const sts = this.patch.data['server-info'].status
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Warning',
|
||||
message: 'Are you sure you want to power down your Embassy? This can take several minutes, and your Embassy will not come back online automatically. To power on again, You will need to physically unplug your Embassy and plug it back in.',
|
||||
message:
|
||||
'Are you sure you want to power down your Embassy? This can take several minutes, and your Embassy will not come back online automatically. To power on again, You will need to physically unplug your Embassy and plug it back in.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
@@ -69,11 +76,13 @@ export class ServerShowPage {
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
async presentAlertSystemRebuild () {
|
||||
async presentAlertSystemRebuild() {
|
||||
const minutes = Object.keys(this.patch.data['package-data']).length * 2
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'System Rebuild',
|
||||
message: new IonicSafeString(`<ion-text color="warning">Important:</ion-text> This will tear down all service containers and rebuild them from scratch. This may take up to ${minutes} minutes to complete. During this time, you will lose all connectivity to your Embassy.`),
|
||||
message: new IonicSafeString(
|
||||
`<ion-text color="warning">Important:</ion-text> This will tear down all service containers and rebuild them from scratch. This may take up to ${minutes} minutes to complete. During this time, you will lose all connectivity to your Embassy.`,
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
@@ -91,7 +100,7 @@ export class ServerShowPage {
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
private async restart () {
|
||||
private async restart() {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Restarting...',
|
||||
@@ -100,7 +109,7 @@ export class ServerShowPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.restartServer({ })
|
||||
await this.embassyApi.restartServer({})
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -108,7 +117,7 @@ export class ServerShowPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async shutdown () {
|
||||
private async shutdown() {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Shutting down...',
|
||||
@@ -117,7 +126,7 @@ export class ServerShowPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.shutdownServer({ })
|
||||
await this.embassyApi.shutdownServer({})
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -125,7 +134,7 @@ export class ServerShowPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async systemRebuild () {
|
||||
private async systemRebuild() {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Hard Restarting...',
|
||||
@@ -134,7 +143,7 @@ export class ServerShowPage {
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
await this.embassyApi.systemRebuild({ })
|
||||
await this.embassyApi.systemRebuild({})
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -143,12 +152,13 @@ export class ServerShowPage {
|
||||
}
|
||||
|
||||
settings: ServerSettings = {
|
||||
'Backups': [
|
||||
Backups: [
|
||||
{
|
||||
title: 'Create Backup',
|
||||
description: 'Back up your Embassy and all its services',
|
||||
icon: 'save-outline',
|
||||
action: () => this.navCtrl.navigateForward(['backup'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['backup'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -156,17 +166,25 @@ export class ServerShowPage {
|
||||
title: 'Restore From Backup',
|
||||
description: 'Restore one or more services from a prior backup',
|
||||
icon: 'color-wand-outline',
|
||||
action: () => this.navCtrl.navigateForward(['restore'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['restore'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: this.patch.watch$('server-info', 'status').pipe(map(status => [ServerStatus.Updated, ServerStatus.BackingUp].includes(status))),
|
||||
disabled: this.patch
|
||||
.watch$('server-info', 'status')
|
||||
.pipe(
|
||||
map(status =>
|
||||
[ServerStatus.Updated, ServerStatus.BackingUp].includes(status),
|
||||
),
|
||||
),
|
||||
},
|
||||
],
|
||||
'Insights': [
|
||||
Insights: [
|
||||
{
|
||||
title: 'About',
|
||||
description: 'Basic information about your Embassy',
|
||||
icon: 'information-circle-outline',
|
||||
action: () => this.navCtrl.navigateForward(['specs'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['specs'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -174,7 +192,8 @@ export class ServerShowPage {
|
||||
title: 'Monitor',
|
||||
description: 'CPU, disk, memory, and other useful metrics',
|
||||
icon: 'pulse',
|
||||
action: () => this.navCtrl.navigateForward(['metrics'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['metrics'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -182,17 +201,21 @@ export class ServerShowPage {
|
||||
title: 'Logs',
|
||||
description: 'Raw, unfiltered device logs',
|
||||
icon: 'newspaper-outline',
|
||||
action: () => this.navCtrl.navigateForward(['logs'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['logs'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
],
|
||||
'Settings': [
|
||||
Settings: [
|
||||
{
|
||||
title: 'Preferences',
|
||||
description: 'Device name, background tasks',
|
||||
icon: 'options-outline',
|
||||
action: () => this.navCtrl.navigateForward(['preferences'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['preferences'], {
|
||||
relativeTo: this.route,
|
||||
}),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -200,7 +223,8 @@ export class ServerShowPage {
|
||||
title: 'LAN',
|
||||
description: 'Access your Embassy on the Local Area Network',
|
||||
icon: 'home-outline',
|
||||
action: () => this.navCtrl.navigateForward(['lan'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['lan'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -208,16 +232,28 @@ export class ServerShowPage {
|
||||
title: 'SSH',
|
||||
description: 'Access your Embassy from the command line',
|
||||
icon: 'terminal-outline',
|
||||
action: () => this.navCtrl.navigateForward(['ssh'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['ssh'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
|
||||
},
|
||||
{
|
||||
title: 'WiFi',
|
||||
description: 'Add or remove WiFi networks',
|
||||
icon: 'wifi',
|
||||
action: () => this.navCtrl.navigateForward(['wifi'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['wifi'], { relativeTo: this.route }),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
{
|
||||
title: 'Marketplace Settings',
|
||||
description: 'Add or remove marketplaces',
|
||||
icon: 'storefront',
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['marketplaces'], {
|
||||
relativeTo: this.route,
|
||||
}),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
@@ -225,12 +261,15 @@ export class ServerShowPage {
|
||||
title: 'Active Sessions',
|
||||
description: 'View and manage device access',
|
||||
icon: 'desktop-outline',
|
||||
action: () => this.navCtrl.navigateForward(['sessions'], { relativeTo: this.route }),
|
||||
action: () =>
|
||||
this.navCtrl.navigateForward(['sessions'], {
|
||||
relativeTo: this.route,
|
||||
}),
|
||||
detail: true,
|
||||
disabled: of(false),
|
||||
},
|
||||
],
|
||||
'Power': [
|
||||
Power: [
|
||||
{
|
||||
title: 'Restart',
|
||||
description: '',
|
||||
@@ -258,7 +297,7 @@ export class ServerShowPage {
|
||||
],
|
||||
}
|
||||
|
||||
asIsOrder () {
|
||||
asIsOrder() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,19 @@
|
||||
|
||||
<ion-content class="ion-padding-top">
|
||||
<ion-item-group>
|
||||
|
||||
<!-- always -->
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<h2>
|
||||
Adding WiFi credentials to your Embassy allows you to remove the Ethernet cable and move the device anywhere you want. Embassy will automatically connect to available networks.
|
||||
<a href="https://docs.start9.com/user-manual/general/wifi.html" target="_blank" rel="noreferrer">View instructions</a>
|
||||
Adding WiFi credentials to your Embassy allows you to remove the
|
||||
Ethernet cable and move the device anywhere you want. Embassy will
|
||||
automatically connect to available networks.
|
||||
<a
|
||||
href="https://docs.start9.com/user-manual/general/wifi.html"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>View instructions</a
|
||||
>
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
@@ -29,9 +35,16 @@
|
||||
<ion-item-divider>Country</ion-item-divider>
|
||||
|
||||
<!-- not loading -->
|
||||
<ion-item button detail="false" (click)="presentAlertCountry()" [disabled]="loading">
|
||||
<ion-item
|
||||
button
|
||||
detail="false"
|
||||
(click)="presentAlertCountry()"
|
||||
[disabled]="loading"
|
||||
>
|
||||
<ion-icon slot="start" name="earth-outline" size="large"></ion-icon>
|
||||
<ion-label *ngIf="wifi.country">{{ wifi.country }} - {{ this.countries[wifi.country] }}</ion-label>
|
||||
<ion-label *ngIf="wifi.country"
|
||||
>{{ wifi.country }} - {{ this.countries[wifi.country] }}</ion-label
|
||||
>
|
||||
<ion-label *ngIf="!wifi.country">Select Country</ion-label>
|
||||
</ion-item>
|
||||
|
||||
@@ -40,20 +53,26 @@
|
||||
<ion-item-divider>Saved Networks</ion-item-divider>
|
||||
<ion-item *ngFor="let entry of ['', '']" class="skeleton-parts">
|
||||
<ion-button slot="start" fill="clear">
|
||||
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
|
||||
<ion-skeleton-text
|
||||
animated
|
||||
style="width: 30px; height: 30px; border-radius: 0"
|
||||
></ion-skeleton-text>
|
||||
</ion-button>
|
||||
<ion-label>
|
||||
<ion-skeleton-text animated style="width: 18%;"></ion-skeleton-text>
|
||||
<ion-skeleton-text animated style="width: 18%"></ion-skeleton-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item-divider>Available Networks</ion-item-divider>
|
||||
<ion-item *ngFor="let entry of ['', '']" class="skeleton-parts">
|
||||
<ion-button slot="start" fill="clear">
|
||||
<ion-skeleton-text animated style="width: 30px; height: 30px; border-radius: 0;"></ion-skeleton-text>
|
||||
<ion-skeleton-text
|
||||
animated
|
||||
style="width: 30px; height: 30px; border-radius: 0"
|
||||
></ion-skeleton-text>
|
||||
</ion-button>
|
||||
<ion-label>
|
||||
<ion-skeleton-text animated style="width: 18%;"></ion-skeleton-text>
|
||||
<ion-skeleton-text animated style="width: 18%"></ion-skeleton-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
@@ -61,29 +80,88 @@
|
||||
<!-- not loading -->
|
||||
<ng-container *ngIf="!loading && wifi.country">
|
||||
<ion-item-divider>Saved Networks</ion-item-divider>
|
||||
<ion-item button detail="false" *ngFor="let ssid of wifi.ssids | keyvalue" (click)="presentAction(ssid.key)">
|
||||
<div *ngIf="ssid.key !== wifi.connected" slot="start" style="padding-right: 32px;"></div>
|
||||
<ion-icon *ngIf="ssid.key === wifi.connected" slot="start" size="large" name="checkmark" color="success"></ion-icon>
|
||||
<ion-item
|
||||
button
|
||||
detail="false"
|
||||
*ngFor="let ssid of wifi.ssids | keyvalue"
|
||||
(click)="presentAction(ssid.key)"
|
||||
>
|
||||
<div
|
||||
*ngIf="ssid.key !== wifi.connected"
|
||||
slot="start"
|
||||
style="padding-right: 32px"
|
||||
></div>
|
||||
<ion-icon
|
||||
*ngIf="ssid.key === wifi.connected"
|
||||
slot="start"
|
||||
size="large"
|
||||
name="checkmark"
|
||||
color="success"
|
||||
></ion-icon>
|
||||
<ion-label>{{ ssid.key }}</ion-label>
|
||||
<img *ngIf="ssid.value > 0 && ssid.value < 5" slot="end" src="assets/img/icons/wifi-1.png" style="max-width: 32px;" />
|
||||
<img *ngIf="ssid.value >= 5 && ssid.value < 50" slot="end" src="assets/img/icons/wifi-1.png" style="max-width: 32px;" />
|
||||
<img *ngIf="ssid.value >= 50 && ssid.value < 90" slot="end" src="assets/img/icons/wifi-2.png" style="max-width: 32px;" />
|
||||
<img *ngIf="ssid.value >= 90" slot="end" src="assets/img/icons/wifi-3.png" style="max-width: 32px;" />
|
||||
<img
|
||||
*ngIf="ssid.value > 0 && ssid.value < 5"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-1.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="ssid.value >= 5 && ssid.value < 50"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-1.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="ssid.value >= 50 && ssid.value < 90"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-2.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="ssid.value >= 90"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-3.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
</ion-item>
|
||||
|
||||
|
||||
<ion-item-divider>Available Networks</ion-item-divider>
|
||||
<ion-item button detail="false" *ngFor="let avWifi of wifi['available-wifi']" (click)="presentModalAdd(avWifi.ssid, !!avWifi.security.length)">
|
||||
<ion-icon slot="start" name="add" size="large"></ion-icon>
|
||||
<ion-item
|
||||
button
|
||||
detail="false"
|
||||
*ngFor="let avWifi of wifi['available-wifi']"
|
||||
(click)="presentModalAdd(avWifi.ssid, !!avWifi.security.length)"
|
||||
>
|
||||
<ion-label>{{ avWifi.ssid }}</ion-label>
|
||||
<img *ngIf="avWifi.strength < 5" slot="end" src="assets/img/icons/wifi-1.png" style="max-width: 32px;" />
|
||||
<img *ngIf="avWifi.strength >= 5 && avWifi.strength < 50" slot="end" src="assets/img/icons/wifi-1.png" style="max-width: 32px;" />
|
||||
<img *ngIf="avWifi.strength >= 50 && avWifi.strength < 90" slot="end" src="assets/img/icons/wifi-2.png" style="max-width: 32px;" />
|
||||
<img *ngIf="avWifi.strength >= 90" slot="end" src="assets/img/icons/wifi-3.png" style="max-width: 32px;" />
|
||||
<img
|
||||
*ngIf="avWifi.strength < 5"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-1.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="avWifi.strength >= 5 && avWifi.strength < 50"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-1.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="avWifi.strength >= 50 && avWifi.strength < 90"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-2.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
<img
|
||||
*ngIf="avWifi.strength >= 90"
|
||||
slot="end"
|
||||
src="assets/img/icons/wifi-3.png"
|
||||
style="max-width: 32px"
|
||||
/>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalAdd()">
|
||||
<ion-icon slot="start" name="add" size="large"></ion-icon>
|
||||
<ion-label>Other</ion-label>
|
||||
<ion-label>Join other network</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-item-group>
|
||||
</ion-content>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ActionSheetController, AlertController, LoadingController, ModalController, ToastController } from '@ionic/angular'
|
||||
import {
|
||||
ActionSheetController,
|
||||
AlertController,
|
||||
LoadingController,
|
||||
ModalController,
|
||||
ToastController,
|
||||
} from '@ionic/angular'
|
||||
import { AlertInput } from '@ionic/core'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ActionSheetButton } from '@ionic/core'
|
||||
@@ -17,10 +23,12 @@ import { ConfigService } from 'src/app/services/config.service'
|
||||
})
|
||||
export class WifiPage {
|
||||
loading = true
|
||||
wifi: RR.GetWifiRes = { } as any
|
||||
countries = require('../../../util/countries.json') as { [key: string]: string }
|
||||
wifi: RR.GetWifiRes = {} as any
|
||||
countries = require('../../../util/countries.json') as {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
private readonly api: ApiService,
|
||||
private readonly toastCtrl: ToastController,
|
||||
private readonly alertCtrl: AlertController,
|
||||
@@ -29,9 +37,9 @@ export class WifiPage {
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly actionCtrl: ActionSheetController,
|
||||
private readonly config: ConfigService,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
async ngOnInit () {
|
||||
async ngOnInit() {
|
||||
try {
|
||||
await this.getWifi()
|
||||
} catch (e) {
|
||||
@@ -41,24 +49,24 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
async getWifi (timeout?: number): Promise<void> {
|
||||
this.wifi = await this.api.getWifi({ }, timeout)
|
||||
async getWifi(timeout?: number): Promise<void> {
|
||||
this.wifi = await this.api.getWifi({}, timeout)
|
||||
if (!this.wifi.country) {
|
||||
await this.presentAlertCountry()
|
||||
}
|
||||
}
|
||||
|
||||
async presentAlertCountry (): Promise<void> {
|
||||
async presentAlertCountry(): Promise<void> {
|
||||
if (!this.config.isLan) {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Cannot Complete Action',
|
||||
message: 'You must be connected to your Emassy via LAN to change the country.',
|
||||
message:
|
||||
'You must be connected to your Emassy via LAN to change the country.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'OK',
|
||||
role: 'cancel',
|
||||
},
|
||||
|
||||
],
|
||||
cssClass: 'wide-alert enter-click',
|
||||
})
|
||||
@@ -66,19 +74,22 @@ export class WifiPage {
|
||||
return
|
||||
}
|
||||
|
||||
const inputs: AlertInput[] = Object.entries(this.countries).map(([country, fullName]) => {
|
||||
return {
|
||||
name: fullName,
|
||||
type: 'radio',
|
||||
label: `${country} - ${fullName}`,
|
||||
value: country,
|
||||
checked: country === this.wifi.country,
|
||||
}
|
||||
})
|
||||
const inputs: AlertInput[] = Object.entries(this.countries).map(
|
||||
([country, fullName]) => {
|
||||
return {
|
||||
name: fullName,
|
||||
type: 'radio',
|
||||
label: `${country} - ${fullName}`,
|
||||
value: country,
|
||||
checked: country === this.wifi.country,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Select Country',
|
||||
message: 'Warning: Changing the country will delete all saved networks from the Embassy.',
|
||||
subHeader:
|
||||
'Warning: Changing the country will delete all saved networks from the Embassy.',
|
||||
inputs,
|
||||
buttons: [
|
||||
{
|
||||
@@ -92,12 +103,12 @@ export class WifiPage {
|
||||
},
|
||||
},
|
||||
],
|
||||
cssClass: 'wide-alert enter-click',
|
||||
cssClass: 'wide-alert enter-click select-warning',
|
||||
})
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
async presentModalAdd (ssid?: string, needsPW: boolean = true) {
|
||||
async presentModalAdd(ssid?: string, needsPW: boolean = true) {
|
||||
const wifiSpec = getWifiValueSpec(ssid, needsPW)
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: GenericFormPage,
|
||||
@@ -107,13 +118,13 @@ export class WifiPage {
|
||||
buttons: [
|
||||
{
|
||||
text: 'Save for Later',
|
||||
handler: async (value: { ssid: string, password: string }) => {
|
||||
handler: async (value: { ssid: string; password: string }) => {
|
||||
await this.save(value.ssid, value.password)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Save and Connect',
|
||||
handler: async (value: { ssid: string, password: string }) => {
|
||||
handler: async (value: { ssid: string; password: string }) => {
|
||||
await this.saveAndConnect(value.ssid, value.password)
|
||||
},
|
||||
isSubmit: true,
|
||||
@@ -125,7 +136,7 @@ export class WifiPage {
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
async presentAction (ssid: string) {
|
||||
async presentAction(ssid: string) {
|
||||
const buttons: ActionSheetButton[] = [
|
||||
{
|
||||
text: 'Forget',
|
||||
@@ -138,15 +149,13 @@ export class WifiPage {
|
||||
]
|
||||
|
||||
if (ssid !== this.wifi.connected) {
|
||||
buttons.unshift(
|
||||
{
|
||||
text: 'Connect',
|
||||
icon: 'wifi',
|
||||
handler: () => {
|
||||
this.connect(ssid)
|
||||
},
|
||||
buttons.unshift({
|
||||
text: 'Connect',
|
||||
icon: 'wifi',
|
||||
handler: () => {
|
||||
this.connect(ssid)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const action = await this.actionCtrl.create({
|
||||
@@ -159,7 +168,7 @@ export class WifiPage {
|
||||
await action.present()
|
||||
}
|
||||
|
||||
private async setCountry (country: string): Promise<void> {
|
||||
private async setCountry(country: string): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
cssClass: 'loader',
|
||||
@@ -177,7 +186,10 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async confirmWifi (ssid: string, deleteOnFailure = false): Promise<void> {
|
||||
private async confirmWifi(
|
||||
ssid: string,
|
||||
deleteOnFailure = false,
|
||||
): Promise<void> {
|
||||
const timeout = 4000
|
||||
const maxAttempts = 5
|
||||
let attempts = 0
|
||||
@@ -210,10 +222,11 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async presentAlertSuccess (ssid: string): Promise<void> {
|
||||
private async presentAlertSuccess(ssid: string): Promise<void> {
|
||||
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.',
|
||||
message:
|
||||
'Note. It may take several minutes to an hour for your Embassy to reconnect over Tor.',
|
||||
buttons: [
|
||||
{
|
||||
text: 'Ok',
|
||||
@@ -226,7 +239,7 @@ export class WifiPage {
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
private async presentToastFail (): Promise<void> {
|
||||
private async presentToastFail(): Promise<void> {
|
||||
const toast = await this.toastCtrl.create({
|
||||
header: 'Failed to connect:',
|
||||
message: `Check credentials and try again`,
|
||||
@@ -247,7 +260,7 @@ export class WifiPage {
|
||||
await toast.present()
|
||||
}
|
||||
|
||||
private async connect (ssid: string): Promise<void> {
|
||||
private async connect(ssid: string): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Connecting. This could take a while...',
|
||||
@@ -265,7 +278,7 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async delete (ssid: string): Promise<void> {
|
||||
private async delete(ssid: string): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Deleting...',
|
||||
@@ -284,7 +297,7 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async save (ssid: string, password: string): Promise<void> {
|
||||
private async save(ssid: string, password: string): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Saving...',
|
||||
@@ -307,7 +320,7 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
private async saveAndConnect (ssid: string, password: string): Promise<void> {
|
||||
private async saveAndConnect(ssid: string, password: string): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Connecting. This could take a while...',
|
||||
@@ -324,7 +337,6 @@ export class WifiPage {
|
||||
})
|
||||
|
||||
await this.confirmWifi(ssid, true)
|
||||
|
||||
} catch (e) {
|
||||
this.errToast.present(e)
|
||||
} finally {
|
||||
@@ -333,11 +345,15 @@ export class WifiPage {
|
||||
}
|
||||
}
|
||||
|
||||
function getWifiValueSpec (ssid?: string, needsPW: boolean = true): ValueSpecObject {
|
||||
function getWifiValueSpec(
|
||||
ssid?: string,
|
||||
needsPW: boolean = true,
|
||||
): ValueSpecObject {
|
||||
return {
|
||||
type: 'object',
|
||||
name: 'WiFi Credentials',
|
||||
description: 'Enter the network SSID and password. You can connect now or save the network for later.',
|
||||
description:
|
||||
'Enter the network SSID and password. You can connect now or save the network for later.',
|
||||
'unique-by': null,
|
||||
spec: {
|
||||
ssid: {
|
||||
@@ -358,4 +374,3 @@ function getWifiValueSpec (ssid?: string, needsPW: boolean = true): ValueSpecObj
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import { Dump, Revision } from 'patch-db-client'
|
||||
import { PackagePropertiesVersioned } from 'src/app/util/properties.util'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { DataModel, DependencyError, Manifest, URL } from 'src/app/services/patch-db/data-model'
|
||||
import {
|
||||
DataModel,
|
||||
DependencyError,
|
||||
Manifest,
|
||||
URL,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export module RR {
|
||||
|
||||
// DB
|
||||
|
||||
export type GetRevisionsRes = Revision[] | Dump<DataModel>
|
||||
|
||||
export type GetDumpRes = Dump<DataModel>
|
||||
|
||||
export type SetDBValueReq = WithExpire<{ pointer: string, value: any }> // db.put.ui
|
||||
export type SetDBValueReq = WithExpire<{ pointer: string; value: any }> // db.put.ui
|
||||
export type SetDBValueRes = WithRevision<null>
|
||||
|
||||
// auth
|
||||
|
||||
export type LoginReq = { password: string, metadata: SessionMetadata } // auth.login - unauthed
|
||||
export type LoginReq = { password: string; metadata: SessionMetadata } // auth.login - unauthed
|
||||
export type loginRes = null
|
||||
|
||||
export type LogoutReq = { } // auth.logout
|
||||
export type LogoutReq = {} // auth.logout
|
||||
export type LogoutRes = null
|
||||
|
||||
// server
|
||||
@@ -27,27 +31,31 @@ export module RR {
|
||||
export type SetShareStatsReq = WithExpire<{ value: boolean }> // server.config.share-stats
|
||||
export type SetShareStatsRes = WithRevision<null>
|
||||
|
||||
export type GetServerLogsReq = { cursor?: string, before_flag?: boolean, limit?: number }
|
||||
export type GetServerLogsReq = {
|
||||
cursor?: string
|
||||
before_flag?: boolean
|
||||
limit?: number
|
||||
}
|
||||
export type GetServerLogsRes = LogsRes
|
||||
|
||||
export type GetServerMetricsReq = { } // server.metrics
|
||||
export type GetServerMetricsReq = {} // server.metrics
|
||||
export type GetServerMetricsRes = Metrics
|
||||
|
||||
export type UpdateServerReq = WithExpire<{ }> // server.update
|
||||
export type UpdateServerReq = WithExpire<{}> // server.update
|
||||
export type UpdateServerRes = WithRevision<'updating' | 'no-updates'>
|
||||
|
||||
export type RestartServerReq = { } // server.restart
|
||||
export type RestartServerReq = {} // server.restart
|
||||
export type RestartServerRes = null
|
||||
|
||||
export type ShutdownServerReq = { } // server.shutdown
|
||||
export type ShutdownServerReq = {} // server.shutdown
|
||||
export type ShutdownServerRes = null
|
||||
|
||||
export type SystemRebuildReq = { } // server.rebuild
|
||||
export type SystemRebuildReq = {} // server.rebuild
|
||||
export type SystemRebuildRes = null
|
||||
|
||||
// sessions
|
||||
|
||||
export type GetSessionsReq = { } // sessions.list
|
||||
export type GetSessionsReq = {} // sessions.list
|
||||
export type GetSessionsRes = {
|
||||
current: string
|
||||
sessions: { [hash: string]: Session }
|
||||
@@ -71,7 +79,10 @@ export module RR {
|
||||
|
||||
// notification
|
||||
|
||||
export type GetNotificationsReq = WithExpire<{ before?: number, limit?: number }> // notification.list
|
||||
export type GetNotificationsReq = WithExpire<{
|
||||
before?: number
|
||||
limit?: number
|
||||
}> // notification.list
|
||||
export type GetNotificationsRes = WithRevision<ServerNotification<number>[]>
|
||||
|
||||
export type DeleteNotificationReq = { id: number } // notification.delete
|
||||
@@ -85,18 +96,19 @@ export module RR {
|
||||
export type SetWifiCountryReq = { country: string }
|
||||
export type SetWifiCountryRes = null
|
||||
|
||||
export type GetWifiReq = { }
|
||||
export type GetWifiReq = {}
|
||||
export type GetWifiRes = {
|
||||
ssids: {
|
||||
[ssid: string]: number
|
||||
},
|
||||
connected?: string,
|
||||
country: string,
|
||||
ethernet: boolean,
|
||||
[ssid: string]: number
|
||||
}
|
||||
connected?: string
|
||||
country: string
|
||||
ethernet: boolean
|
||||
'available-wifi': AvailableWifi[]
|
||||
}
|
||||
}
|
||||
|
||||
export type AddWifiReq = { // wifi.add
|
||||
export type AddWifiReq = {
|
||||
// wifi.add
|
||||
ssid: string
|
||||
password: string
|
||||
priority: number
|
||||
@@ -112,7 +124,7 @@ export module RR {
|
||||
|
||||
// ssh
|
||||
|
||||
export type GetSSHKeysReq = { } // ssh.list
|
||||
export type GetSSHKeysReq = {} // ssh.list
|
||||
export type GetSSHKeysRes = SSHKey[]
|
||||
|
||||
export type AddSSHKeyReq = { key: string } // ssh.add
|
||||
@@ -123,10 +135,11 @@ export module RR {
|
||||
|
||||
// backup
|
||||
|
||||
export type GetBackupTargetsReq = { } // backup.target.list
|
||||
export type GetBackupTargetsReq = {} // backup.target.list
|
||||
export type GetBackupTargetsRes = { [id: string]: BackupTarget }
|
||||
|
||||
export type AddBackupTargetReq = { // backup.target.cifs.add
|
||||
export type AddBackupTargetReq = {
|
||||
// backup.target.cifs.add
|
||||
hostname: string
|
||||
path: string
|
||||
username: string
|
||||
@@ -140,10 +153,11 @@ export module RR {
|
||||
export type RemoveBackupTargetReq = { id: string } // backup.target.cifs.remove
|
||||
export type RemoveBackupTargetRes = null
|
||||
|
||||
export type GetBackupInfoReq = { 'target-id': string, password: string } // backup.target.info
|
||||
export type GetBackupInfoReq = { 'target-id': string; password: string } // backup.target.info
|
||||
export type GetBackupInfoRes = BackupInfo
|
||||
|
||||
export type CreateBackupReq = WithExpire<{ // backup.create
|
||||
export type CreateBackupReq = WithExpire<{
|
||||
// backup.create
|
||||
'target-id': string
|
||||
'old-password': string | null
|
||||
password: string
|
||||
@@ -153,40 +167,58 @@ export module RR {
|
||||
// package
|
||||
|
||||
export type GetPackagePropertiesReq = { id: string } // package.properties
|
||||
export type GetPackagePropertiesRes<T extends number> = PackagePropertiesVersioned<T>
|
||||
export type GetPackagePropertiesRes<T extends number> =
|
||||
PackagePropertiesVersioned<T>
|
||||
|
||||
export type LogsRes = { entries: Log[], 'start-cursor'?: string, 'end-cursor'?: string }
|
||||
export type LogsRes = {
|
||||
entries: Log[]
|
||||
'start-cursor'?: string
|
||||
'end-cursor'?: string
|
||||
}
|
||||
|
||||
export type GetPackageLogsReq = { id: string, cursor?: string, before_flag?: boolean, limit?: number } // package.logs
|
||||
export type GetPackageLogsReq = {
|
||||
id: string
|
||||
cursor?: string
|
||||
before_flag?: boolean
|
||||
limit?: number
|
||||
} // package.logs
|
||||
export type GetPackageLogsRes = LogsRes
|
||||
|
||||
export type GetPackageMetricsReq = { id: string } // package.metrics
|
||||
export type GetPackageMetricsRes = Metric
|
||||
|
||||
export type InstallPackageReq = WithExpire<{ id: string, 'version-spec'?: string }> // package.install
|
||||
export type InstallPackageReq = WithExpire<{
|
||||
id: string
|
||||
'version-spec'?: string
|
||||
}> // package.install
|
||||
export type InstallPackageRes = WithRevision<null>
|
||||
|
||||
export type DryUpdatePackageReq = { id: string, version: string } // package.update.dry
|
||||
export type DryUpdatePackageReq = { id: string; version: string } // package.update.dry
|
||||
export type DryUpdatePackageRes = Breakages
|
||||
|
||||
export type GetPackageConfigReq = { id: string } // package.config.get
|
||||
export type GetPackageConfigRes = { spec: ConfigSpec, config: object }
|
||||
export type GetPackageConfigRes = { spec: ConfigSpec; config: object }
|
||||
|
||||
export type DrySetPackageConfigReq = { id: string, config: object } // package.config.set.dry
|
||||
export type DrySetPackageConfigReq = { id: string; config: object } // package.config.set.dry
|
||||
export type DrySetPackageConfigRes = Breakages
|
||||
|
||||
export type SetPackageConfigReq = WithExpire<DrySetPackageConfigReq> // package.config.set
|
||||
export type SetPackageConfigRes = WithRevision<null>
|
||||
|
||||
export type RestorePackagesReq = WithExpire<{ // package.backup.restore
|
||||
export type RestorePackagesReq = WithExpire<{
|
||||
// package.backup.restore
|
||||
ids: string[]
|
||||
'target-id': string
|
||||
'old-password': string | null,
|
||||
'old-password': string | null
|
||||
password: string
|
||||
}>
|
||||
export type RestorePackagesRes = WithRevision<null>
|
||||
|
||||
export type ExecutePackageActionReq = { id: string, 'action-id': string, input?: object } // package.action
|
||||
export type ExecutePackageActionReq = {
|
||||
id: string
|
||||
'action-id': string
|
||||
input?: object
|
||||
} // package.action
|
||||
export type ExecutePackageActionRes = ActionResponse
|
||||
|
||||
export type StartPackageReq = WithExpire<{ id: string }> // package.start
|
||||
@@ -207,7 +239,10 @@ export module RR {
|
||||
export type DeleteRecoveredPackageReq = { id: string } // package.delete-recovered
|
||||
export type DeleteRecoveredPackageRes = WithRevision<null>
|
||||
|
||||
export type DryConfigureDependencyReq = { 'dependency-id': string, 'dependent-id': string } // package.dependency.configure.dry
|
||||
export type DryConfigureDependencyReq = {
|
||||
'dependency-id': string
|
||||
'dependent-id': string
|
||||
} // package.dependency.configure.dry
|
||||
export type DryConfigureDependencyRes = {
|
||||
'old-config': object
|
||||
'new-config': object
|
||||
@@ -216,7 +251,7 @@ export module RR {
|
||||
|
||||
// marketplace
|
||||
|
||||
export type GetMarketplaceDataReq = { }
|
||||
export type GetMarketplaceDataReq = { url?: string }
|
||||
export type GetMarketplaceDataRes = MarketplaceData
|
||||
|
||||
export type GetMarketplaceEOSReq = {
|
||||
@@ -225,13 +260,14 @@ export module RR {
|
||||
export type GetMarketplaceEOSRes = MarketplaceEOS
|
||||
|
||||
export type GetMarketplacePackagesReq = {
|
||||
ids?: { id: string, version: string }[]
|
||||
ids?: { id: string; version: string }[]
|
||||
'eos-version-compat': string
|
||||
// iff !ids
|
||||
category?: string
|
||||
query?: string
|
||||
page?: string
|
||||
'per-page'?: string
|
||||
url?: string
|
||||
}
|
||||
export type GetMarketplacePackagesRes = MarketplacePkg[]
|
||||
|
||||
@@ -240,14 +276,14 @@ export module RR {
|
||||
|
||||
export type GetLatestVersionReq = { ids: string[] }
|
||||
export type GetLatestVersionRes = { [id: string]: string }
|
||||
|
||||
}
|
||||
|
||||
export type WithExpire<T> = { 'expire-id'?: string } & T
|
||||
export type WithRevision<T> = { response: T, revision?: Revision }
|
||||
export type WithRevision<T> = { response: T; revision?: Revision }
|
||||
|
||||
export interface MarketplaceData {
|
||||
categories: string[]
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface MarketplaceEOS {
|
||||
@@ -268,7 +304,7 @@ export interface MarketplacePkg {
|
||||
title: string
|
||||
icon: URL
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export interface Breakages {
|
||||
@@ -318,7 +354,22 @@ export interface SessionMetadata {
|
||||
platforms: PlatformType[]
|
||||
}
|
||||
|
||||
export type PlatformType = 'cli' | 'ios' | 'ipad' | 'iphone' | 'android' | 'phablet' | 'tablet' | 'cordova' | 'capacitor' | 'electron' | 'pwa' | 'mobile' | 'mobileweb' | 'desktop' | 'hybrid'
|
||||
export type PlatformType =
|
||||
| 'cli'
|
||||
| 'ios'
|
||||
| 'ipad'
|
||||
| 'iphone'
|
||||
| 'android'
|
||||
| 'phablet'
|
||||
| 'tablet'
|
||||
| 'cordova'
|
||||
| 'capacitor'
|
||||
| 'electron'
|
||||
| 'pwa'
|
||||
| 'mobile'
|
||||
| 'mobileweb'
|
||||
| 'desktop'
|
||||
| 'hybrid'
|
||||
|
||||
export type BackupTarget = DiskBackupTarget | CifsBackupTarget
|
||||
|
||||
@@ -387,8 +438,8 @@ export interface EmbassyOsDiskInfo {
|
||||
}
|
||||
|
||||
export interface BackupInfo {
|
||||
version: string,
|
||||
timestamp: string,
|
||||
version: string
|
||||
timestamp: string
|
||||
'package-backups': {
|
||||
[id: string]: PackageBackupInfo
|
||||
}
|
||||
@@ -432,9 +483,11 @@ export enum NotificationLevel {
|
||||
Error = 'error',
|
||||
}
|
||||
|
||||
export type NotificationData<T> = T extends 0 ? null :
|
||||
T extends 1 ? BackupReport :
|
||||
any
|
||||
export type NotificationData<T> = T extends 0
|
||||
? null
|
||||
: T extends 1
|
||||
? BackupReport
|
||||
: any
|
||||
|
||||
export interface BackupReport {
|
||||
server: {
|
||||
@@ -451,5 +504,5 @@ export interface BackupReport {
|
||||
export interface AvailableWifi {
|
||||
ssid: string
|
||||
strength: number
|
||||
security: string []
|
||||
}
|
||||
security: string[]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { Subject, Observable } from 'rxjs'
|
||||
import { Http, Update, Operation, Revision, Source, Store, RPCResponse } from 'patch-db-client'
|
||||
import {
|
||||
Http,
|
||||
Update,
|
||||
Operation,
|
||||
Revision,
|
||||
Source,
|
||||
Store,
|
||||
RPCResponse,
|
||||
} from 'patch-db-client'
|
||||
import { RR } from './api.types'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { RequestError } from '../http.service'
|
||||
@@ -10,53 +18,63 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
||||
|
||||
/** PatchDb Source interface. Post/Patch requests provide a source of patches to the db. */
|
||||
// sequenceStream '_' is not used by the live api, but is overridden by the mock
|
||||
watch$ (_?: Store<DataModel>): Observable<RPCResponse<Update<DataModel>>> {
|
||||
return this.sync$.asObservable().pipe(map( result => ({ result,
|
||||
jsonrpc: '2.0'})))
|
||||
watch$(_?: Store<DataModel>): Observable<RPCResponse<Update<DataModel>>> {
|
||||
return this.sync$
|
||||
.asObservable()
|
||||
.pipe(map(result => ({ result, jsonrpc: '2.0' })))
|
||||
}
|
||||
|
||||
// for getting static files: ex icons, instructions, licenses
|
||||
abstract getStatic (url: string): Promise<string>
|
||||
abstract getStatic(url: string): Promise<string>
|
||||
|
||||
// db
|
||||
|
||||
abstract getRevisions (since: number): Promise<RR.GetRevisionsRes>
|
||||
abstract getRevisions(since: number): Promise<RR.GetRevisionsRes>
|
||||
|
||||
abstract getDump (): Promise<RR.GetDumpRes>
|
||||
abstract getDump(): Promise<RR.GetDumpRes>
|
||||
|
||||
protected abstract setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes>
|
||||
setDbValue = (params: RR.SetDBValueReq) => this.syncResponse(
|
||||
() => this.setDbValueRaw(params),
|
||||
)()
|
||||
protected abstract setDbValueRaw(
|
||||
params: RR.SetDBValueReq,
|
||||
): Promise<RR.SetDBValueRes>
|
||||
setDbValue = (params: RR.SetDBValueReq) =>
|
||||
this.syncResponse(() => this.setDbValueRaw(params))()
|
||||
|
||||
// auth
|
||||
|
||||
abstract login (params: RR.LoginReq): Promise<RR.loginRes>
|
||||
abstract login(params: RR.LoginReq): Promise<RR.loginRes>
|
||||
|
||||
abstract logout (params: RR.LogoutReq): Promise<RR.LogoutRes>
|
||||
abstract logout(params: RR.LogoutReq): Promise<RR.LogoutRes>
|
||||
|
||||
abstract getSessions (params: RR.GetSessionsReq): Promise<RR.GetSessionsRes>
|
||||
abstract getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes>
|
||||
|
||||
abstract killSessions (params: RR.KillSessionsReq): Promise<RR.KillSessionsRes>
|
||||
abstract killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes>
|
||||
|
||||
// server
|
||||
|
||||
protected abstract setShareStatsRaw (params: RR.SetShareStatsReq): Promise<RR.SetShareStatsRes>
|
||||
setShareStats = (params: RR.SetShareStatsReq) => this.syncResponse(
|
||||
() => this.setShareStatsRaw(params),
|
||||
)()
|
||||
protected abstract setShareStatsRaw(
|
||||
params: RR.SetShareStatsReq,
|
||||
): Promise<RR.SetShareStatsRes>
|
||||
setShareStats = (params: RR.SetShareStatsReq) =>
|
||||
this.syncResponse(() => this.setShareStatsRaw(params))()
|
||||
|
||||
abstract getServerLogs (params: RR.GetServerLogsReq): Promise<RR.GetServerLogsRes>
|
||||
abstract getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes>
|
||||
|
||||
abstract getServerMetrics (params: RR.GetServerMetricsReq): Promise<RR.GetServerMetricsRes>
|
||||
abstract getServerMetrics(
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetServerMetricsRes>
|
||||
|
||||
abstract getPkgMetrics (params: RR.GetPackageMetricsReq): Promise<RR.GetPackageMetricsRes>
|
||||
abstract getPkgMetrics(
|
||||
params: RR.GetPackageMetricsReq,
|
||||
): Promise<RR.GetPackageMetricsRes>
|
||||
|
||||
protected abstract updateServerRaw (params: RR.UpdateServerReq): Promise<RR.UpdateServerRes>
|
||||
updateServer = (params: RR.UpdateServerReq) => this.syncResponse(
|
||||
() => this.updateServerWrapper(params),
|
||||
)()
|
||||
async updateServerWrapper (params: RR.UpdateServerReq) {
|
||||
protected abstract updateServerRaw(
|
||||
params: RR.UpdateServerReq,
|
||||
): Promise<RR.UpdateServerRes>
|
||||
updateServer = (params: RR.UpdateServerReq) =>
|
||||
this.syncResponse(() => this.updateServerWrapper(params))()
|
||||
async updateServerWrapper(params: RR.UpdateServerReq) {
|
||||
const res = await this.updateServerRaw(params)
|
||||
if (res.response === 'no-updates') {
|
||||
throw new Error('Could ont find a newer version of EmbassyOS')
|
||||
@@ -64,23 +82,40 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
||||
return res
|
||||
}
|
||||
|
||||
abstract restartServer (params: RR.UpdateServerReq): Promise<RR.RestartServerRes>
|
||||
abstract restartServer(
|
||||
params: RR.UpdateServerReq,
|
||||
): Promise<RR.RestartServerRes>
|
||||
|
||||
abstract shutdownServer (params: RR.ShutdownServerReq): Promise<RR.ShutdownServerRes>
|
||||
abstract shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes>
|
||||
|
||||
abstract systemRebuild (params: RR.SystemRebuildReq): Promise<RR.SystemRebuildRes>
|
||||
abstract systemRebuild(
|
||||
params: RR.SystemRebuildReq,
|
||||
): Promise<RR.SystemRebuildRes>
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
abstract getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes>
|
||||
abstract getEos(
|
||||
params: RR.GetMarketplaceEOSReq,
|
||||
): Promise<RR.GetMarketplaceEOSRes>
|
||||
|
||||
abstract getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes>
|
||||
abstract getMarketplaceData(
|
||||
params: RR.GetMarketplaceDataReq,
|
||||
url?: string,
|
||||
): Promise<RR.GetMarketplaceDataRes>
|
||||
|
||||
abstract getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes>
|
||||
abstract getMarketplacePkgs(
|
||||
params: RR.GetMarketplacePackagesReq,
|
||||
): Promise<RR.GetMarketplacePackagesRes>
|
||||
|
||||
abstract getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes>
|
||||
abstract getReleaseNotes(
|
||||
params: RR.GetReleaseNotesReq,
|
||||
): Promise<RR.GetReleaseNotesRes>
|
||||
|
||||
abstract getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes>
|
||||
abstract getLatestVersion(
|
||||
params: RR.GetLatestVersionReq,
|
||||
): Promise<RR.GetLatestVersionRes>
|
||||
|
||||
// protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes>
|
||||
// setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse(
|
||||
@@ -92,112 +127,162 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
||||
|
||||
// notification
|
||||
|
||||
abstract getNotificationsRaw (params: RR.GetNotificationsReq): Promise<RR.GetNotificationsRes>
|
||||
getNotifications = (params: RR.GetNotificationsReq) => this.syncResponse<RR.GetNotificationsRes['response'], any>(
|
||||
() => this.getNotificationsRaw(params),
|
||||
)()
|
||||
abstract getNotificationsRaw(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes>
|
||||
getNotifications = (params: RR.GetNotificationsReq) =>
|
||||
this.syncResponse<RR.GetNotificationsRes['response'], any>(() =>
|
||||
this.getNotificationsRaw(params),
|
||||
)()
|
||||
|
||||
abstract deleteNotification (params: RR.DeleteNotificationReq): Promise<RR.DeleteNotificationRes>
|
||||
abstract deleteNotification(
|
||||
params: RR.DeleteNotificationReq,
|
||||
): Promise<RR.DeleteNotificationRes>
|
||||
|
||||
abstract deleteAllNotifications (params: RR.DeleteAllNotificationsReq): Promise<RR.DeleteAllNotificationsRes>
|
||||
abstract deleteAllNotifications(
|
||||
params: RR.DeleteAllNotificationsReq,
|
||||
): Promise<RR.DeleteAllNotificationsRes>
|
||||
|
||||
// wifi
|
||||
|
||||
abstract getWifi (params: RR.GetWifiReq, timeout: number): Promise<RR.GetWifiRes>
|
||||
abstract getWifi(
|
||||
params: RR.GetWifiReq,
|
||||
timeout: number,
|
||||
): Promise<RR.GetWifiRes>
|
||||
|
||||
abstract setWifiCountry (params: RR.SetWifiCountryReq): Promise<RR.SetWifiCountryRes>
|
||||
abstract setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes>
|
||||
|
||||
abstract addWifi (params: RR.AddWifiReq): Promise<RR.AddWifiRes>
|
||||
abstract addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes>
|
||||
|
||||
abstract connectWifi (params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes>
|
||||
abstract connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes>
|
||||
|
||||
abstract deleteWifi (params: RR.DeleteWifiReq): Promise<RR.ConnectWifiRes>
|
||||
abstract deleteWifi(params: RR.DeleteWifiReq): Promise<RR.ConnectWifiRes>
|
||||
|
||||
// ssh
|
||||
|
||||
abstract getSshKeys (params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes>
|
||||
abstract getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes>
|
||||
|
||||
abstract addSshKey (params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes>
|
||||
abstract addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes>
|
||||
|
||||
abstract deleteSshKey (params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes>
|
||||
abstract deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes>
|
||||
|
||||
// backup
|
||||
|
||||
abstract getBackupTargets (params: RR.GetBackupTargetsReq): Promise<RR.GetBackupTargetsRes>
|
||||
abstract getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes>
|
||||
|
||||
abstract addBackupTarget (params: RR.AddBackupTargetReq): Promise<RR.AddBackupTargetRes>
|
||||
abstract addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes>
|
||||
|
||||
abstract updateBackupTarget (params: RR.UpdateBackupTargetReq): Promise<RR.UpdateBackupTargetRes>
|
||||
abstract updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes>
|
||||
|
||||
abstract removeBackupTarget (params: RR.RemoveBackupTargetReq): Promise<RR.RemoveBackupTargetRes>
|
||||
abstract removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes>
|
||||
|
||||
abstract getBackupInfo (params: RR.GetBackupInfoReq): Promise<RR.GetBackupInfoRes>
|
||||
abstract getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes>
|
||||
|
||||
protected abstract createBackupRaw (params: RR.CreateBackupReq): Promise<RR.CreateBackupRes>
|
||||
createBackup = (params: RR.CreateBackupReq) => this.syncResponse(
|
||||
() => this.createBackupRaw(params),
|
||||
)()
|
||||
protected abstract createBackupRaw(
|
||||
params: RR.CreateBackupReq,
|
||||
): Promise<RR.CreateBackupRes>
|
||||
createBackup = (params: RR.CreateBackupReq) =>
|
||||
this.syncResponse(() => this.createBackupRaw(params))()
|
||||
|
||||
// package
|
||||
|
||||
abstract getPackageProperties (params: RR.GetPackagePropertiesReq): Promise<RR.GetPackagePropertiesRes<2>['data']>
|
||||
abstract getPackageProperties(
|
||||
params: RR.GetPackagePropertiesReq,
|
||||
): Promise<RR.GetPackagePropertiesRes<2>['data']>
|
||||
|
||||
abstract getPackageLogs (params: RR.GetPackageLogsReq): Promise<RR.GetPackageLogsRes>
|
||||
abstract getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes>
|
||||
|
||||
protected abstract installPackageRaw (params: RR.InstallPackageReq): Promise<RR.InstallPackageRes>
|
||||
installPackage = (params: RR.InstallPackageReq) => this.syncResponse(
|
||||
() => this.installPackageRaw(params),
|
||||
)()
|
||||
protected abstract installPackageRaw(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes>
|
||||
installPackage = (params: RR.InstallPackageReq) =>
|
||||
this.syncResponse(() => this.installPackageRaw(params))()
|
||||
|
||||
abstract dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise<RR.DryUpdatePackageRes>
|
||||
abstract dryUpdatePackage(
|
||||
params: RR.DryUpdatePackageReq,
|
||||
): Promise<RR.DryUpdatePackageRes>
|
||||
|
||||
abstract getPackageConfig (params: RR.GetPackageConfigReq): Promise<RR.GetPackageConfigRes>
|
||||
abstract getPackageConfig(
|
||||
params: RR.GetPackageConfigReq,
|
||||
): Promise<RR.GetPackageConfigRes>
|
||||
|
||||
abstract drySetPackageConfig (params: RR.DrySetPackageConfigReq): Promise<RR.DrySetPackageConfigRes>
|
||||
abstract drySetPackageConfig(
|
||||
params: RR.DrySetPackageConfigReq,
|
||||
): Promise<RR.DrySetPackageConfigRes>
|
||||
|
||||
protected abstract setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise<RR.SetPackageConfigRes>
|
||||
setPackageConfig = (params: RR.SetPackageConfigReq) => this.syncResponse(
|
||||
() => this.setPackageConfigRaw(params),
|
||||
)()
|
||||
protected abstract setPackageConfigRaw(
|
||||
params: RR.SetPackageConfigReq,
|
||||
): Promise<RR.SetPackageConfigRes>
|
||||
setPackageConfig = (params: RR.SetPackageConfigReq) =>
|
||||
this.syncResponse(() => this.setPackageConfigRaw(params))()
|
||||
|
||||
protected abstract restorePackagesRaw (params: RR.RestorePackagesReq): Promise<RR.RestorePackagesRes>
|
||||
restorePackages = (params: RR.RestorePackagesReq) => this.syncResponse(
|
||||
() => this.restorePackagesRaw(params),
|
||||
)()
|
||||
protected abstract restorePackagesRaw(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes>
|
||||
restorePackages = (params: RR.RestorePackagesReq) =>
|
||||
this.syncResponse(() => this.restorePackagesRaw(params))()
|
||||
|
||||
abstract executePackageAction (params: RR.ExecutePackageActionReq): Promise<RR.ExecutePackageActionRes>
|
||||
abstract executePackageAction(
|
||||
params: RR.ExecutePackageActionReq,
|
||||
): Promise<RR.ExecutePackageActionRes>
|
||||
|
||||
protected abstract startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes>
|
||||
startPackage = (params: RR.StartPackageReq) => this.syncResponse(
|
||||
() => this.startPackageRaw(params),
|
||||
)()
|
||||
protected abstract startPackageRaw(
|
||||
params: RR.StartPackageReq,
|
||||
): Promise<RR.StartPackageRes>
|
||||
startPackage = (params: RR.StartPackageReq) =>
|
||||
this.syncResponse(() => this.startPackageRaw(params))()
|
||||
|
||||
abstract dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes>
|
||||
abstract dryStopPackage(
|
||||
params: RR.DryStopPackageReq,
|
||||
): Promise<RR.DryStopPackageRes>
|
||||
|
||||
protected abstract stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes>
|
||||
stopPackage = (params: RR.StopPackageReq) => this.syncResponse(
|
||||
() => this.stopPackageRaw(params),
|
||||
)()
|
||||
protected abstract stopPackageRaw(
|
||||
params: RR.StopPackageReq,
|
||||
): Promise<RR.StopPackageRes>
|
||||
stopPackage = (params: RR.StopPackageReq) =>
|
||||
this.syncResponse(() => this.stopPackageRaw(params))()
|
||||
|
||||
abstract dryUninstallPackage (params: RR.DryUninstallPackageReq): Promise<RR.DryUninstallPackageRes>
|
||||
abstract dryUninstallPackage(
|
||||
params: RR.DryUninstallPackageReq,
|
||||
): Promise<RR.DryUninstallPackageRes>
|
||||
|
||||
protected abstract uninstallPackageRaw (params: RR.UninstallPackageReq): Promise<RR.UninstallPackageRes>
|
||||
uninstallPackage = (params: RR.UninstallPackageReq) => this.syncResponse(
|
||||
() => this.uninstallPackageRaw(params),
|
||||
)()
|
||||
protected abstract uninstallPackageRaw(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes>
|
||||
uninstallPackage = (params: RR.UninstallPackageReq) =>
|
||||
this.syncResponse(() => this.uninstallPackageRaw(params))()
|
||||
|
||||
abstract dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise<RR.DryConfigureDependencyRes>
|
||||
|
||||
protected abstract deleteRecoveredPackageRaw (params: RR.UninstallPackageReq): Promise<RR.UninstallPackageRes>
|
||||
deleteRecoveredPackage = (params: RR.UninstallPackageReq) => this.syncResponse(
|
||||
() => this.deleteRecoveredPackageRaw(params),
|
||||
)()
|
||||
abstract dryConfigureDependency(
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes>
|
||||
|
||||
protected abstract deleteRecoveredPackageRaw(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes>
|
||||
deleteRecoveredPackage = (params: RR.UninstallPackageReq) =>
|
||||
this.syncResponse(() => this.deleteRecoveredPackageRaw(params))()
|
||||
|
||||
// Helper allowing quick decoration to sync the response patch and return the response contents.
|
||||
// Pass in a tempUpdate function which returns a UpdateTemp corresponding to a temporary
|
||||
// state change you'd like to enact prior to request and expired when request terminates.
|
||||
private syncResponse<T, F extends (...args: any[]) => Promise<{ response: T, revision?: Revision }>> (f: F, temp?: Operation): (...args: Parameters<F>) => Promise<T> {
|
||||
private syncResponse<
|
||||
T,
|
||||
F extends (...args: any[]) => Promise<{ response: T; revision?: Revision }>,
|
||||
>(f: F, temp?: Operation): (...args: Parameters<F>) => Promise<T> {
|
||||
return (...a) => {
|
||||
// let expireId = undefined
|
||||
// if (temp) {
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { HttpService, Method } from '../http.service'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import { RR } from './api.types'
|
||||
import { parsePropertiesPermissive } from 'src/app/util/properties.util'
|
||||
import { PatchDbService } from '../patch-db/patch-db.service'
|
||||
|
||||
@Injectable()
|
||||
export class LiveApiService extends ApiService {
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
private readonly http: HttpService,
|
||||
private readonly patch: PatchDbService,
|
||||
) {
|
||||
super();
|
||||
(window as any).rpcClient = this
|
||||
}
|
||||
super()
|
||||
;(window as any).rpcClient = this
|
||||
}
|
||||
|
||||
async getStatic (url: string): Promise<string> {
|
||||
async getStatic(url: string): Promise<string> {
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url,
|
||||
@@ -24,69 +25,101 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// db
|
||||
|
||||
async getRevisions (since: number): Promise<RR.GetRevisionsRes> {
|
||||
async getRevisions(since: number): Promise<RR.GetRevisionsRes> {
|
||||
return this.http.rpcRequest({ method: 'db.revisions', params: { since } })
|
||||
}
|
||||
|
||||
async getDump (): Promise<RR.GetDumpRes> {
|
||||
async getDump(): Promise<RR.GetDumpRes> {
|
||||
return this.http.rpcRequest({ method: 'db.dump' })
|
||||
}
|
||||
|
||||
async setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
async setDbValueRaw(params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
return this.http.rpcRequest({ method: 'db.put.ui', params })
|
||||
}
|
||||
|
||||
// auth
|
||||
|
||||
async login (params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
async login(params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
return this.http.rpcRequest({ method: 'auth.login', params })
|
||||
}
|
||||
|
||||
async logout (params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
async logout(params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
return this.http.rpcRequest({ method: 'auth.logout', params })
|
||||
}
|
||||
|
||||
async getSessions (params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
async getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
return this.http.rpcRequest({ method: 'auth.session.list', params })
|
||||
}
|
||||
|
||||
async killSessions (params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
async killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
return this.http.rpcRequest({ method: 'auth.session.kill', params })
|
||||
}
|
||||
|
||||
// server
|
||||
|
||||
async setShareStatsRaw (params: RR.SetShareStatsReq): Promise<RR.SetShareStatsRes> {
|
||||
return this.http.rpcRequest( { method: 'server.config.share-stats', params })
|
||||
async setShareStatsRaw(
|
||||
params: RR.SetShareStatsReq,
|
||||
): Promise<RR.SetShareStatsRes> {
|
||||
return this.http.rpcRequest({ method: 'server.config.share-stats', params })
|
||||
}
|
||||
|
||||
async getServerLogs (params: RR.GetServerLogsReq): Promise<RR.GetServerLogsRes> {
|
||||
return this.http.rpcRequest( { method: 'server.logs', params })
|
||||
async getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
return this.http.rpcRequest({ method: 'server.logs', params })
|
||||
}
|
||||
|
||||
async getServerMetrics (params: RR.GetServerMetricsReq): Promise<RR.GetServerMetricsRes> {
|
||||
async getServerMetrics(
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetServerMetricsRes> {
|
||||
return this.http.rpcRequest({ method: 'server.metrics', params })
|
||||
}
|
||||
|
||||
async updateServerRaw (params: RR.UpdateServerReq): Promise<RR.UpdateServerRes> {
|
||||
async updateServerRaw(
|
||||
params: RR.UpdateServerReq,
|
||||
): Promise<RR.UpdateServerRes> {
|
||||
return this.http.rpcRequest({ method: 'server.update', params })
|
||||
}
|
||||
|
||||
async restartServer (params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
async restartServer(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
return this.http.rpcRequest({ method: 'server.restart', params })
|
||||
}
|
||||
|
||||
async shutdownServer (params: RR.ShutdownServerReq): Promise<RR.ShutdownServerRes> {
|
||||
async shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes> {
|
||||
return this.http.rpcRequest({ method: 'server.shutdown', params })
|
||||
}
|
||||
|
||||
async systemRebuild (params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
|
||||
async systemRebuild(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
return this.http.rpcRequest({ method: 'server.rebuild', params })
|
||||
}
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
|
||||
private async marketplaceProxy<T>(
|
||||
path: string,
|
||||
params: {},
|
||||
url?: string,
|
||||
): Promise<T> {
|
||||
if (!url) {
|
||||
const id = this.patch.data.ui.marketplace['selected-id']
|
||||
url = this.patch.data.ui.marketplace.options[id].url
|
||||
}
|
||||
const fullURL = `${url}${path}?${new URLSearchParams(params).toString()}`
|
||||
return this.http.rpcRequest({
|
||||
method: 'marketplace.get',
|
||||
params: { url: fullURL },
|
||||
})
|
||||
}
|
||||
|
||||
async getEos(
|
||||
params: RR.GetMarketplaceEOSReq,
|
||||
): Promise<RR.GetMarketplaceEOSRes> {
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url: '/marketplace/eos/latest',
|
||||
@@ -94,27 +127,26 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes> {
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url: '/marketplace/package/data',
|
||||
params,
|
||||
})
|
||||
async getMarketplaceData(
|
||||
params: RR.GetMarketplaceDataReq,
|
||||
url?: string,
|
||||
): Promise<RR.GetMarketplaceDataRes> {
|
||||
return this.marketplaceProxy('/marketplace/package/data', params, url)
|
||||
}
|
||||
|
||||
async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> {
|
||||
async getMarketplacePkgs(
|
||||
params: RR.GetMarketplacePackagesReq,
|
||||
): Promise<RR.GetMarketplacePackagesRes> {
|
||||
if (params.query) params.category = undefined
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url: '/marketplace/package/index',
|
||||
params: {
|
||||
...params,
|
||||
ids: JSON.stringify(params.ids),
|
||||
},
|
||||
return this.marketplaceProxy('/marketplace/package/index', {
|
||||
...params,
|
||||
ids: JSON.stringify(params.ids),
|
||||
})
|
||||
}
|
||||
|
||||
async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> {
|
||||
async getReleaseNotes(
|
||||
params: RR.GetReleaseNotesReq,
|
||||
): Promise<RR.GetReleaseNotesRes> {
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url: '/marketplace/package/release-notes',
|
||||
@@ -122,7 +154,9 @@ export class LiveApiService extends ApiService {
|
||||
})
|
||||
}
|
||||
|
||||
async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> {
|
||||
async getLatestVersion(
|
||||
params: RR.GetLatestVersionReq,
|
||||
): Promise<RR.GetLatestVersionRes> {
|
||||
return this.http.httpRequest({
|
||||
method: Method.GET,
|
||||
url: '/marketplace/latest-version',
|
||||
@@ -141,149 +175,211 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// notification
|
||||
|
||||
async getNotificationsRaw (params: RR.GetNotificationsReq): Promise<RR.GetNotificationsRes> {
|
||||
async getNotificationsRaw(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes> {
|
||||
return this.http.rpcRequest({ method: 'notification.list', params })
|
||||
}
|
||||
|
||||
async deleteNotification (params: RR.DeleteNotificationReq): Promise<RR.DeleteNotificationRes> {
|
||||
async deleteNotification(
|
||||
params: RR.DeleteNotificationReq,
|
||||
): Promise<RR.DeleteNotificationRes> {
|
||||
return this.http.rpcRequest({ method: 'notification.delete', params })
|
||||
}
|
||||
|
||||
async deleteAllNotifications (params: RR.DeleteAllNotificationsReq): Promise<RR.DeleteAllNotificationsRes> {
|
||||
return this.http.rpcRequest({ method: 'notification.delete-before', params })
|
||||
async deleteAllNotifications(
|
||||
params: RR.DeleteAllNotificationsReq,
|
||||
): Promise<RR.DeleteAllNotificationsRes> {
|
||||
return this.http.rpcRequest({
|
||||
method: 'notification.delete-before',
|
||||
params,
|
||||
})
|
||||
}
|
||||
|
||||
// wifi
|
||||
|
||||
async getWifi (params: RR.GetWifiReq, timeout?: number): Promise<RR.GetWifiRes> {
|
||||
async getWifi(
|
||||
params: RR.GetWifiReq,
|
||||
timeout?: number,
|
||||
): Promise<RR.GetWifiRes> {
|
||||
return this.http.rpcRequest({ method: 'wifi.get', params, timeout })
|
||||
}
|
||||
|
||||
async setWifiCountry (params: RR.SetWifiCountryReq): Promise<RR.SetWifiCountryRes> {
|
||||
async setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes> {
|
||||
return this.http.rpcRequest({ method: 'wifi.country.set', params })
|
||||
}
|
||||
|
||||
async addWifi (params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
async addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
return this.http.rpcRequest({ method: 'wifi.add', params })
|
||||
}
|
||||
|
||||
async connectWifi (params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
async connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
return this.http.rpcRequest({ method: 'wifi.connect', params })
|
||||
}
|
||||
|
||||
async deleteWifi (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
async deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
return this.http.rpcRequest({ method: 'wifi.delete', params })
|
||||
}
|
||||
|
||||
// ssh
|
||||
|
||||
async getSshKeys (params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
async getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
return this.http.rpcRequest({ method: 'ssh.list', params })
|
||||
}
|
||||
|
||||
async addSshKey (params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
async addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
return this.http.rpcRequest({ method: 'ssh.add', params })
|
||||
}
|
||||
|
||||
async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
return this.http.rpcRequest({ method: 'ssh.delete', params })
|
||||
}
|
||||
|
||||
// backup
|
||||
|
||||
async getBackupTargets (params: RR.GetBackupTargetsReq): Promise<RR.GetBackupTargetsRes> {
|
||||
async getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes> {
|
||||
return this.http.rpcRequest({ method: 'backup.target.list', params })
|
||||
}
|
||||
|
||||
async addBackupTarget (params: RR.AddBackupTargetReq): Promise<RR.AddBackupTargetRes> {
|
||||
async addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes> {
|
||||
params.path = params.path.replace('/\\/g', '/')
|
||||
return this.http.rpcRequest({ method: 'backup.target.cifs.add', params })
|
||||
}
|
||||
|
||||
async updateBackupTarget (params: RR.UpdateBackupTargetReq): Promise<RR.UpdateBackupTargetRes> {
|
||||
async updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes> {
|
||||
return this.http.rpcRequest({ method: 'backup.target.cifs.update', params })
|
||||
}
|
||||
|
||||
async removeBackupTarget (params: RR.RemoveBackupTargetReq): Promise<RR.RemoveBackupTargetRes> {
|
||||
async removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes> {
|
||||
return this.http.rpcRequest({ method: 'backup.target.cifs.remove', params })
|
||||
}
|
||||
|
||||
async getBackupInfo (params: RR.GetBackupInfoReq): Promise<RR.GetBackupInfoRes> {
|
||||
async getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes> {
|
||||
return this.http.rpcRequest({ method: 'backup.target.info', params })
|
||||
}
|
||||
|
||||
async createBackupRaw (params: RR.CreateBackupReq): Promise <RR.CreateBackupRes> {
|
||||
async createBackupRaw(
|
||||
params: RR.CreateBackupReq,
|
||||
): Promise<RR.CreateBackupRes> {
|
||||
return this.http.rpcRequest({ method: 'backup.create', params })
|
||||
}
|
||||
|
||||
// package
|
||||
|
||||
async getPackageProperties (params: RR.GetPackagePropertiesReq): Promise<RR.GetPackagePropertiesRes < 2 > ['data'] > {
|
||||
return this.http.rpcRequest({ method: 'package.properties', params })
|
||||
async getPackageProperties(
|
||||
params: RR.GetPackagePropertiesReq,
|
||||
): Promise<RR.GetPackagePropertiesRes<2>['data']> {
|
||||
return this.http
|
||||
.rpcRequest({ method: 'package.properties', params })
|
||||
.then(parsePropertiesPermissive)
|
||||
}
|
||||
|
||||
async getPackageLogs (params: RR.GetPackageLogsReq): Promise<RR.GetPackageLogsRes> {
|
||||
return this.http.rpcRequest( { method: 'package.logs', params })
|
||||
async getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes> {
|
||||
return this.http.rpcRequest({ method: 'package.logs', params })
|
||||
}
|
||||
|
||||
async getPkgMetrics (params: RR.GetPackageMetricsReq): Promise<RR.GetPackageMetricsRes> {
|
||||
async getPkgMetrics(
|
||||
params: RR.GetPackageMetricsReq,
|
||||
): Promise<RR.GetPackageMetricsRes> {
|
||||
return this.http.rpcRequest({ method: 'package.metrics', params })
|
||||
}
|
||||
|
||||
async installPackageRaw (params: RR.InstallPackageReq): Promise<RR.InstallPackageRes> {
|
||||
async installPackageRaw(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.install', params })
|
||||
}
|
||||
|
||||
async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise<RR.DryUpdatePackageRes> {
|
||||
async dryUpdatePackage(
|
||||
params: RR.DryUpdatePackageReq,
|
||||
): Promise<RR.DryUpdatePackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.update.dry', params })
|
||||
}
|
||||
|
||||
async getPackageConfig (params: RR.GetPackageConfigReq): Promise<RR.GetPackageConfigRes> {
|
||||
async getPackageConfig(
|
||||
params: RR.GetPackageConfigReq,
|
||||
): Promise<RR.GetPackageConfigRes> {
|
||||
return this.http.rpcRequest({ method: 'package.config.get', params })
|
||||
}
|
||||
|
||||
async drySetPackageConfig (params: RR.DrySetPackageConfigReq): Promise<RR.DrySetPackageConfigRes> {
|
||||
async drySetPackageConfig(
|
||||
params: RR.DrySetPackageConfigReq,
|
||||
): Promise<RR.DrySetPackageConfigRes> {
|
||||
return this.http.rpcRequest({ method: 'package.config.set.dry', params })
|
||||
}
|
||||
|
||||
async setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise<RR.SetPackageConfigRes> {
|
||||
async setPackageConfigRaw(
|
||||
params: RR.SetPackageConfigReq,
|
||||
): Promise<RR.SetPackageConfigRes> {
|
||||
return this.http.rpcRequest({ method: 'package.config.set', params })
|
||||
}
|
||||
|
||||
async restorePackagesRaw (params: RR.RestorePackagesReq): Promise<RR.RestorePackagesRes> {
|
||||
async restorePackagesRaw(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes> {
|
||||
return this.http.rpcRequest({ method: 'package.backup.restore', params })
|
||||
}
|
||||
|
||||
async executePackageAction (params: RR.ExecutePackageActionReq): Promise<RR.ExecutePackageActionRes> {
|
||||
async executePackageAction(
|
||||
params: RR.ExecutePackageActionReq,
|
||||
): Promise<RR.ExecutePackageActionRes> {
|
||||
return this.http.rpcRequest({ method: 'package.action', params })
|
||||
}
|
||||
|
||||
async startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
|
||||
async startPackageRaw(
|
||||
params: RR.StartPackageReq,
|
||||
): Promise<RR.StartPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.start', params })
|
||||
}
|
||||
|
||||
async dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes> {
|
||||
async dryStopPackage(
|
||||
params: RR.DryStopPackageReq,
|
||||
): Promise<RR.DryStopPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.stop.dry', params })
|
||||
}
|
||||
|
||||
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.stop', params })
|
||||
}
|
||||
|
||||
async dryUninstallPackage (params: RR.DryUninstallPackageReq): Promise<RR.DryUninstallPackageRes> {
|
||||
async dryUninstallPackage(
|
||||
params: RR.DryUninstallPackageReq,
|
||||
): Promise<RR.DryUninstallPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.uninstall.dry', params })
|
||||
}
|
||||
|
||||
async deleteRecoveredPackageRaw (params: RR.DeleteRecoveredPackageReq): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
async deleteRecoveredPackageRaw(
|
||||
params: RR.DeleteRecoveredPackageReq,
|
||||
): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.delete-recovered', params })
|
||||
}
|
||||
|
||||
async uninstallPackageRaw (params: RR.UninstallPackageReq): Promise<RR.UninstallPackageRes> {
|
||||
async uninstallPackageRaw(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
return this.http.rpcRequest({ method: 'package.uninstall', params })
|
||||
}
|
||||
|
||||
async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise<RR.DryConfigureDependencyRes> {
|
||||
return this.http.rpcRequest({ method: 'package.dependency.configure.dry', params })
|
||||
async dryConfigureDependency(
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes> {
|
||||
return this.http.rpcRequest({
|
||||
method: 'package.dependency.configure.dry',
|
||||
params,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,22 +25,22 @@ export class MockApiService extends ApiService {
|
||||
private readonly revertTime = 4000
|
||||
sequence: number
|
||||
|
||||
constructor(private readonly bootstrapper: LocalStorageBootstrap) {
|
||||
constructor (private readonly bootstrapper: LocalStorageBootstrap) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getStatic(url: string): Promise<string> {
|
||||
async getStatic (url: string): Promise<string> {
|
||||
await pauseFor(2000)
|
||||
return markdown
|
||||
}
|
||||
|
||||
// db
|
||||
|
||||
async getRevisions(since: number): Promise<RR.GetRevisionsRes> {
|
||||
async getRevisions (since: number): Promise<RR.GetRevisionsRes> {
|
||||
return this.getDump()
|
||||
}
|
||||
|
||||
async getDump(): Promise<RR.GetDumpRes> {
|
||||
async getDump (): Promise<RR.GetDumpRes> {
|
||||
const cache = await this.bootstrapper.init()
|
||||
return {
|
||||
id: cache.sequence,
|
||||
@@ -49,7 +49,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async setDbValueRaw(params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
async setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -63,7 +63,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// auth
|
||||
|
||||
async login(params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
async login (params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -73,24 +73,24 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async logout(params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
async logout (params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
async getSessions (params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Sessions
|
||||
}
|
||||
|
||||
async killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
async killSessions (params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// server
|
||||
|
||||
async setShareStatsRaw(
|
||||
async setShareStatsRaw (
|
||||
params: RR.SetShareStatsReq,
|
||||
): Promise<RR.SetShareStatsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -105,7 +105,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async getServerLogs(
|
||||
async getServerLogs (
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -127,21 +127,21 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getServerMetrics(
|
||||
async getServerMetrics (
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetServerMetricsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.getServerMetrics()
|
||||
}
|
||||
|
||||
async getPkgMetrics(
|
||||
async getPkgMetrics (
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetPackageMetricsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.getAppMetrics()
|
||||
}
|
||||
|
||||
async updateServerRaw(
|
||||
async updateServerRaw (
|
||||
params: RR.UpdateServerReq,
|
||||
): Promise<RR.UpdateServerRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -165,21 +165,21 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch, 'updating')
|
||||
}
|
||||
|
||||
async restartServer(
|
||||
async restartServer (
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async shutdownServer(
|
||||
async shutdownServer (
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async systemRebuild(
|
||||
async systemRebuild (
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -188,18 +188,20 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async getEos(
|
||||
async getEos (
|
||||
params: RR.GetMarketplaceEOSReq,
|
||||
): Promise<RR.GetMarketplaceEOSRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.MarketplaceEos
|
||||
}
|
||||
|
||||
async getMarketplaceData(
|
||||
async getMarketplaceData (
|
||||
params: RR.GetMarketplaceDataReq,
|
||||
url?: string,
|
||||
): Promise<RR.GetMarketplaceDataRes> {
|
||||
await pauseFor(2000)
|
||||
return {
|
||||
name: 'Dark9',
|
||||
categories: [
|
||||
'featured',
|
||||
'bitcoin',
|
||||
@@ -212,21 +214,21 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getMarketplacePkgs(
|
||||
async getMarketplacePkgs (
|
||||
params: RR.GetMarketplacePackagesReq,
|
||||
): Promise<RR.GetMarketplacePackagesRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.MarketplacePkgsList
|
||||
}
|
||||
|
||||
async getReleaseNotes(
|
||||
async getReleaseNotes (
|
||||
params: RR.GetReleaseNotesReq,
|
||||
): Promise<RR.GetReleaseNotesRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.ReleaseNotes
|
||||
}
|
||||
|
||||
async getLatestVersion(
|
||||
async getLatestVersion (
|
||||
params: RR.GetLatestVersionReq,
|
||||
): Promise<RR.GetLatestVersionRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -244,7 +246,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// notification
|
||||
|
||||
async getNotificationsRaw(
|
||||
async getNotificationsRaw (
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -259,14 +261,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch, Mock.Notifications)
|
||||
}
|
||||
|
||||
async deleteNotification(
|
||||
async deleteNotification (
|
||||
params: RR.DeleteNotificationReq,
|
||||
): Promise<RR.DeleteNotificationRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteAllNotifications(
|
||||
async deleteAllNotifications (
|
||||
params: RR.DeleteAllNotificationsReq,
|
||||
): Promise<RR.DeleteAllNotificationsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -275,60 +277,60 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// wifi
|
||||
|
||||
async getWifi(params: RR.GetWifiReq): Promise<RR.GetWifiRes> {
|
||||
async getWifi (params: RR.GetWifiReq): Promise<RR.GetWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Wifi
|
||||
}
|
||||
|
||||
async setWifiCountry(
|
||||
async setWifiCountry (
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
async addWifi (params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
async connectWifi (params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
async deleteWifi (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// ssh
|
||||
|
||||
async getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
async getSshKeys (params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKeys
|
||||
}
|
||||
|
||||
async addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
async addSshKey (params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKey
|
||||
}
|
||||
|
||||
async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// backup
|
||||
|
||||
async getBackupTargets(
|
||||
async getBackupTargets (
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupTargets
|
||||
}
|
||||
|
||||
async addBackupTarget(
|
||||
async addBackupTarget (
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -345,7 +347,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateBackupTarget(
|
||||
async updateBackupTarget (
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -360,21 +362,21 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async removeBackupTarget(
|
||||
async removeBackupTarget (
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getBackupInfo(
|
||||
async getBackupInfo (
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupInfo
|
||||
}
|
||||
|
||||
async createBackupRaw(
|
||||
async createBackupRaw (
|
||||
params: RR.CreateBackupReq,
|
||||
): Promise<RR.CreateBackupRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -425,14 +427,14 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// package
|
||||
|
||||
async getPackageProperties(
|
||||
async getPackageProperties (
|
||||
params: RR.GetPackagePropertiesReq,
|
||||
): Promise<RR.GetPackagePropertiesRes<2>['data']> {
|
||||
await pauseFor(2000)
|
||||
return parsePropertiesPermissive(Mock.PackageProperties)
|
||||
}
|
||||
|
||||
async getPackageLogs(
|
||||
async getPackageLogs (
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -454,7 +456,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async installPackageRaw(
|
||||
async installPackageRaw (
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -489,14 +491,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryUpdatePackage(
|
||||
async dryUpdatePackage (
|
||||
params: RR.DryUpdatePackageReq,
|
||||
): Promise<RR.DryUpdatePackageRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async getPackageConfig(
|
||||
async getPackageConfig (
|
||||
params: RR.GetPackageConfigReq,
|
||||
): Promise<RR.GetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -506,14 +508,14 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async drySetPackageConfig(
|
||||
async drySetPackageConfig (
|
||||
params: RR.DrySetPackageConfigReq,
|
||||
): Promise<RR.DrySetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async setPackageConfigRaw(
|
||||
async setPackageConfigRaw (
|
||||
params: RR.SetPackageConfigReq,
|
||||
): Promise<RR.SetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -527,7 +529,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async restorePackagesRaw(
|
||||
async restorePackagesRaw (
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -563,14 +565,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async executePackageAction(
|
||||
async executePackageAction (
|
||||
params: RR.ExecutePackageActionReq,
|
||||
): Promise<RR.ExecutePackageActionRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.ActionResponse
|
||||
}
|
||||
|
||||
async startPackageRaw(
|
||||
async startPackageRaw (
|
||||
params: RR.StartPackageReq,
|
||||
): Promise<RR.StartPackageRes> {
|
||||
const path = `/package-data/${params.id}/installed/status/main`
|
||||
@@ -649,7 +651,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(originalPatch)
|
||||
}
|
||||
|
||||
async dryStopPackage(
|
||||
async dryStopPackage (
|
||||
params: RR.DryStopPackageReq,
|
||||
): Promise<RR.DryStopPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -663,7 +665,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
await pauseFor(2000)
|
||||
const path = `/package-data/${params.id}/installed/status/main`
|
||||
|
||||
@@ -694,14 +696,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryUninstallPackage(
|
||||
async dryUninstallPackage (
|
||||
params: RR.DryUninstallPackageReq,
|
||||
): Promise<RR.DryUninstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async uninstallPackageRaw(
|
||||
async uninstallPackageRaw (
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -727,7 +729,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async deleteRecoveredPackageRaw(
|
||||
async deleteRecoveredPackageRaw (
|
||||
params: RR.DeleteRecoveredPackageReq,
|
||||
): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -740,7 +742,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryConfigureDependency(
|
||||
async dryConfigureDependency (
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -751,7 +753,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
private async updateProgress(
|
||||
private async updateProgress (
|
||||
id: string,
|
||||
initialProgress: InstallProgress,
|
||||
): Promise<void> {
|
||||
@@ -797,7 +799,7 @@ export class MockApiService extends ApiService {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
private async updateOSProgress(size: number) {
|
||||
private async updateOSProgress (size: number) {
|
||||
let downloaded = 0
|
||||
while (downloaded < size) {
|
||||
await pauseFor(250)
|
||||
@@ -847,7 +849,7 @@ export class MockApiService extends ApiService {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
private async updateMock(patch: Operation[]): Promise<void> {
|
||||
private async updateMock (patch: Operation[]): Promise<void> {
|
||||
if (!this.sequence) {
|
||||
const { sequence } = await this.bootstrapper.init()
|
||||
this.sequence = sequence
|
||||
@@ -860,7 +862,7 @@ export class MockApiService extends ApiService {
|
||||
this.mockPatch$.next(revision)
|
||||
}
|
||||
|
||||
private async withRevision<T>(
|
||||
private async withRevision<T> (
|
||||
patch: Operation[],
|
||||
response: T = null,
|
||||
): Promise<WithRevision<T>> {
|
||||
|
||||
@@ -16,6 +16,15 @@ export const mockPatchData: DataModel = {
|
||||
'pkg-order': [],
|
||||
'ack-welcome': '1.0.0',
|
||||
'ack-share-stats': false,
|
||||
marketplace: {
|
||||
'selected-id': 'asdfasdf',
|
||||
options: {
|
||||
asdfasdf: {
|
||||
name: 'Start9',
|
||||
url: 'start9marketplace.com',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'server-info': {
|
||||
id: 'embassy-abcdefgh',
|
||||
|
||||
@@ -13,6 +13,17 @@ export interface UIData {
|
||||
'pkg-order': string[]
|
||||
'ack-welcome': string // EOS version
|
||||
'ack-share-stats': boolean
|
||||
marketplace: UIMarketplaceData
|
||||
}
|
||||
|
||||
export interface UIMarketplaceData {
|
||||
'selected-id': string
|
||||
options: {
|
||||
[id: string]: {
|
||||
url: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { AlertController, IonicSafeString, ModalController, NavController } from '@ionic/angular'
|
||||
import {
|
||||
AlertController,
|
||||
IonicSafeString,
|
||||
ModalController,
|
||||
NavController,
|
||||
} from '@ionic/angular'
|
||||
import { wizardModal } from '../components/install-wizard/install-wizard.component'
|
||||
import { WizardBaker } from '../components/install-wizard/prebaked-wizards'
|
||||
import { OSWelcomePage } from '../modals/os-welcome/os-welcome.page'
|
||||
@@ -15,6 +20,7 @@ import { isEmptyObject } from '../util/misc.util'
|
||||
import { ApiService } from './api/embassy-api.service'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ServerConfigService } from './server-config.service'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -22,7 +28,7 @@ import { ServerConfigService } from './server-config.service'
|
||||
export class StartupAlertsService {
|
||||
private checks: Check<any>[]
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly config: ConfigService,
|
||||
@@ -52,69 +58,74 @@ export class StartupAlertsService {
|
||||
check: () => this.osUpdateCheck(),
|
||||
display: pkg => this.displayOsUpdateCheck(pkg),
|
||||
}
|
||||
const pkgsUpdate: Check<boolean> = {
|
||||
name: 'pkgsUpdate',
|
||||
shouldRun: () => this.shouldRunAppsCheck(),
|
||||
check: () => this.appsCheck(),
|
||||
display: () => this.displayAppsCheck(),
|
||||
}
|
||||
this.checks = [osWelcome, shareStats, osUpdate, pkgsUpdate]
|
||||
this.checks = [osWelcome, shareStats, osUpdate]
|
||||
}
|
||||
|
||||
// This takes our three checks and filters down to those that should run.
|
||||
// Then, the reduce fires, quickly iterating through yielding a promise (previousDisplay) to the next element
|
||||
// Each promise fires more or less concurrently, so each c.check(server) is run concurrently
|
||||
// Then, since we await previousDisplay before c.display(res), each promise executing gets hung awaiting the display of the previous run
|
||||
runChecks (): Subscription {
|
||||
return this.patch.watch$()
|
||||
.pipe(
|
||||
filter(data => !isEmptyObject(data)),
|
||||
take(1),
|
||||
)
|
||||
.subscribe(async () => {
|
||||
await this.checks
|
||||
.filter(c => !this.config.skipStartupAlerts && c.shouldRun())
|
||||
// returning true in the below block means to continue to next modal
|
||||
// returning false means to skip all subsequent modals
|
||||
.reduce(async (previousDisplay, c) => {
|
||||
let checkRes: any
|
||||
try {
|
||||
checkRes = await c.check()
|
||||
} catch (e) {
|
||||
console.error(`Exception in ${c.name} check:`, e)
|
||||
return true
|
||||
runChecks(): Subscription {
|
||||
return this.patch
|
||||
.watch$()
|
||||
.pipe(
|
||||
filter(data => !isEmptyObject(data)),
|
||||
take(1),
|
||||
)
|
||||
.subscribe(async data => {
|
||||
if (!data.ui.marketplace) {
|
||||
const uuid = v4()
|
||||
const value = {
|
||||
'selected-id': uuid,
|
||||
options: {
|
||||
[uuid]: {
|
||||
url: 'marketplaceurl.com',
|
||||
name: 'Start9',
|
||||
},
|
||||
},
|
||||
}
|
||||
await this.api.setDbValue({ pointer: 'marketplace', value })
|
||||
}
|
||||
await this.checks
|
||||
.filter(c => !this.config.skipStartupAlerts && c.shouldRun())
|
||||
// returning true in the below block means to continue to next modal
|
||||
// returning false means to skip all subsequent modals
|
||||
.reduce(async (previousDisplay, c) => {
|
||||
let checkRes: any
|
||||
try {
|
||||
checkRes = await c.check()
|
||||
} catch (e) {
|
||||
console.error(`Exception in ${c.name} check:`, e)
|
||||
return true
|
||||
}
|
||||
|
||||
const displayRes = await previousDisplay
|
||||
const displayRes = await previousDisplay
|
||||
|
||||
if (!checkRes) return true
|
||||
if (displayRes) return c.display(checkRes)
|
||||
}, Promise.resolve(true))
|
||||
})
|
||||
if (!checkRes) return true
|
||||
if (displayRes) return c.display(checkRes)
|
||||
}, Promise.resolve(true))
|
||||
})
|
||||
}
|
||||
|
||||
// ** should run **
|
||||
|
||||
private shouldRunOsWelcome (): boolean {
|
||||
private shouldRunOsWelcome(): boolean {
|
||||
return this.patch.getData().ui['ack-welcome'] !== this.config.version
|
||||
}
|
||||
private shouldRunShareStats (): boolean {
|
||||
private shouldRunShareStats(): boolean {
|
||||
return !this.patch.getData().ui['ack-share-stats']
|
||||
}
|
||||
|
||||
private shouldRunOsUpdateCheck (): boolean {
|
||||
return this.patch.getData().ui['auto-check-updates']
|
||||
}
|
||||
|
||||
private shouldRunAppsCheck (): boolean {
|
||||
private shouldRunOsUpdateCheck(): boolean {
|
||||
return this.patch.getData().ui['auto-check-updates']
|
||||
}
|
||||
|
||||
// ** check **
|
||||
|
||||
private async osUpdateCheck (): Promise<RR.GetMarketplaceEOSRes | undefined> {
|
||||
private async osUpdateCheck(): Promise<RR.GetMarketplaceEOSRes | undefined> {
|
||||
const res = await this.api.getEos({
|
||||
'eos-version-compat': this.patch.getData()['server-info']['eos-version-compat'],
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
})
|
||||
|
||||
if (this.emver.compare(this.config.version, res.version) === -1) {
|
||||
@@ -124,14 +135,9 @@ export class StartupAlertsService {
|
||||
}
|
||||
}
|
||||
|
||||
private async appsCheck (): Promise<boolean> {
|
||||
const updates = await this.marketplaceService.getUpdates(this.patch.getData()['package-data'])
|
||||
return !!updates.length
|
||||
}
|
||||
|
||||
// ** display **
|
||||
|
||||
private async displayOsWelcome (): Promise<boolean> {
|
||||
private async displayOsWelcome(): Promise<boolean> {
|
||||
return new Promise(async resolve => {
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: OSWelcomePage,
|
||||
@@ -141,27 +147,37 @@ export class StartupAlertsService {
|
||||
},
|
||||
})
|
||||
modal.onWillDismiss().then(() => {
|
||||
this.api.setDbValue({ pointer: '/ack-welcome', value: this.config.version })
|
||||
.catch()
|
||||
this.api
|
||||
.setDbValue({ pointer: '/ack-welcome', value: this.config.version })
|
||||
.catch()
|
||||
return resolve(true)
|
||||
})
|
||||
await modal.present()
|
||||
})
|
||||
}
|
||||
|
||||
private async displayShareStats (): Promise<boolean> {
|
||||
private async displayShareStats(): Promise<boolean> {
|
||||
return new Promise(async resolve => {
|
||||
const alert = await this.serverConfig.presentAlert('share-stats', this.patch.getData()['server-info']['share-stats'])
|
||||
const alert = await this.serverConfig.presentAlert(
|
||||
'share-stats',
|
||||
this.patch.getData()['server-info']['share-stats'],
|
||||
)
|
||||
|
||||
alert.onDidDismiss().then(() => {
|
||||
this.api.setDbValue({ pointer: '/ack-share-stats', value: this.config.version })
|
||||
this.api
|
||||
.setDbValue({
|
||||
pointer: '/ack-share-stats',
|
||||
value: this.config.version,
|
||||
})
|
||||
.catch()
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private async displayOsUpdateCheck (eos: RR.GetMarketplaceEOSRes): Promise<boolean> {
|
||||
private async displayOsUpdateCheck(
|
||||
eos: RR.GetMarketplaceEOSRes,
|
||||
): Promise<boolean> {
|
||||
const { update } = await this.presentAlertNewOS(eos.version)
|
||||
if (update) {
|
||||
const { cancelled } = await wizardModal(
|
||||
@@ -178,46 +194,19 @@ export class StartupAlertsService {
|
||||
return true
|
||||
}
|
||||
|
||||
private async displayAppsCheck (): Promise<boolean> {
|
||||
return new Promise(async resolve => {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Updates Available!',
|
||||
message: new IonicSafeString(
|
||||
`<div style="display: flex; flex-direction: column; justify-content: space-around; min-height: 100px">
|
||||
<div>New service updates are available in the Marketplace.</div>
|
||||
<div style="font-size:x-small">You can disable these checks in your Embassy Config</div>
|
||||
</div>
|
||||
`,
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel',
|
||||
handler: () => resolve(true),
|
||||
},
|
||||
{
|
||||
text: 'View in Marketplace',
|
||||
handler: () => {
|
||||
this.navCtrl.navigateForward('/marketplace').then(() => resolve(false))
|
||||
},
|
||||
cssClass: 'enter-click',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await alert.present()
|
||||
})
|
||||
}
|
||||
|
||||
// more
|
||||
|
||||
private async presentAlertNewOS (versionLatest: string): Promise<{ cancel?: true, update?: true }> {
|
||||
private async presentAlertNewOS(
|
||||
versionLatest: string,
|
||||
): Promise<{ cancel?: true; update?: true }> {
|
||||
return new Promise(async resolve => {
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'New EmbassyOS Version!',
|
||||
message: new IonicSafeString(
|
||||
`<div style="display: flex; flex-direction: column; justify-content: space-around; min-height: 100px">
|
||||
<div>Update EmbassyOS to version ${displayEmver(versionLatest)}?</div>
|
||||
<div>Update EmbassyOS to version ${displayEmver(
|
||||
versionLatest,
|
||||
)}?</div>
|
||||
<div style="font-size:x-small">You can disable these checks in your Embassy Config</div>
|
||||
</div>
|
||||
`,
|
||||
@@ -250,4 +239,4 @@ type Check<T> = {
|
||||
display: (a: T) => Promise<boolean>
|
||||
// for logging purposes
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user