mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
better eager loading and better error messaging for backup flow (#1368)
* better eager loading and better error messaging for backup flow * add arch qp to marketplace proxy requests * better styling for eos release notes
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"mocks": {
|
||||
"maskAs": "tor",
|
||||
"skipStartupAlerts": true
|
||||
}
|
||||
},
|
||||
"targetArch": "aarch64"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
New in {{ pkg.manifest.version | displayEmver }}
|
||||
<ion-button routerLink="notes" class="all-notes" fill="clear" color="dark">
|
||||
All Release Notes
|
||||
<ion-icon slot="end" name="arrow-forward-outline"></ion-icon>
|
||||
<ion-icon slot="end" name="arrow-forward"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item-divider>
|
||||
<ion-item lines="none" color="transparent">
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<h2>Other Versions</h2>
|
||||
<p>Click to view other versions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item button detail="false" (click)="presentModalMd('license')">
|
||||
<ion-label>
|
||||
<h2>License</h2>
|
||||
<p>{{ pkg.manifest.license }}</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
<ion-item
|
||||
button
|
||||
@@ -27,7 +27,7 @@
|
||||
<h2>Instructions</h2>
|
||||
<p>Click to view instructions</p>
|
||||
</ion-label>
|
||||
<ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
|
||||
<ion-icon slot="end" name="chevron-forward"></ion-icon>
|
||||
</ion-item>
|
||||
</ion-item-group>
|
||||
</ion-col>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export type WorkspaceConfig = {
|
||||
targetArch: 'aarch64' | 'x86_64'
|
||||
gitHash: string
|
||||
useMocks: boolean
|
||||
// each key corresponds to a project and values adjust settings for that project, eg: ui, setup-wizard, diagnostic-ui
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
<ion-icon name="alert-circle-outline"></ion-icon>
|
||||
<ion-icon name="aperture-outline"></ion-icon>
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
<ion-icon name="arrow-forward"></ion-icon>
|
||||
<ion-icon name="arrow-up"></ion-icon>
|
||||
<ion-icon name="briefcase-outline"></ion-icon>
|
||||
<ion-icon name="bookmark-outline"></ion-icon>
|
||||
@@ -165,7 +166,9 @@
|
||||
<ion-icon name="medkit-outline"></ion-icon>
|
||||
<ion-icon name="newspaper-outline"></ion-icon>
|
||||
<ion-icon name="notifications-outline"></ion-icon>
|
||||
<ion-icon name="open-outline"></ion-icon>
|
||||
<ion-icon name="options-outline"></ion-icon>
|
||||
<ion-icon name="pencil"></ion-icon>
|
||||
<ion-icon name="phone-portrait-outline"></ion-icon>
|
||||
<ion-icon name="play-circle-outline"></ion-icon>
|
||||
<ion-icon name="power"></ion-icon>
|
||||
@@ -177,12 +180,15 @@
|
||||
<ion-icon name="remove"></ion-icon>
|
||||
<ion-icon name="remove-circle-outline"></ion-icon>
|
||||
<ion-icon name="remove-outline"></ion-icon>
|
||||
<ion-icon name="reorder-three"></ion-icon>
|
||||
<ion-icon name="rocket-outline"></ion-icon>
|
||||
<ion-icon name="save-outline"></ion-icon>
|
||||
<ion-icon name="shield-checkmark-outline"></ion-icon>
|
||||
<ion-icon name="stop-outline"></ion-icon>
|
||||
<ion-icon name="storefront-outline"></ion-icon>
|
||||
<ion-icon name="swap-vertical"></ion-icon>
|
||||
<ion-icon name="terminal-outline"></ion-icon>
|
||||
<ion-icon name="trash"></ion-icon>
|
||||
<ion-icon name="trash-outline"></ion-icon>
|
||||
<ion-icon name="warning-outline"></ion-icon>
|
||||
<ion-icon name="wifi"></ion-icon>
|
||||
@@ -190,6 +196,7 @@
|
||||
<!-- Ionic components -->
|
||||
<ion-action-sheet></ion-action-sheet>
|
||||
<ion-alert></ion-alert>
|
||||
<ion-back-button></ion-back-button>
|
||||
<ion-badge></ion-badge>
|
||||
<ion-button></ion-button>
|
||||
<ion-buttons></ion-buttons>
|
||||
@@ -220,7 +227,9 @@
|
||||
<ion-modal></ion-modal>
|
||||
<ion-note></ion-note>
|
||||
<ion-radio></ion-radio>
|
||||
<ion-reorder></ion-reorder>
|
||||
<ion-row></ion-row>
|
||||
<ion-searchbar></ion-searchbar>
|
||||
<ion-segment></ion-segment>
|
||||
<ion-segment-button></ion-segment-button>
|
||||
<ion-select></ion-select>
|
||||
@@ -234,6 +243,21 @@
|
||||
<ion-toggle></ion-toggle>
|
||||
<ion-toolbar></ion-toolbar>
|
||||
<ion-menu-button></ion-menu-button>
|
||||
|
||||
<!-- fonts -->
|
||||
<p style="font-family: Montserrat">a</p>
|
||||
<p style="font-family: Montserrat; font-weight: bold">a</p>
|
||||
<p style="font-family: Montserrat; font-weight: 100">a</p>
|
||||
<p style="font-family: Open Sans">a</p>
|
||||
<p style="font-family: Open Sans; font-weight: bold">a</p>
|
||||
<p style="font-family: Open Sans; font-weight: 100">a</p>
|
||||
|
||||
<!-- images -->
|
||||
<img src="assets/img/logo.png" />
|
||||
<img src="assets/img/icons/snek.png" />
|
||||
<img src="assets/img/icons/wifi-1.png" />
|
||||
<img src="assets/img/icons/wifi-2.png" />
|
||||
<img src="assets/img/icons/wifi-3.png" />
|
||||
</section>
|
||||
</ion-content>
|
||||
<ion-footer
|
||||
|
||||
@@ -56,6 +56,7 @@ export class BackupService {
|
||||
}
|
||||
|
||||
hasValidBackup(target: BackupTarget): boolean {
|
||||
return this.emver.compare(target['embassy-os']?.version, '0.3.0') !== -1
|
||||
const backup = target['embassy-os']
|
||||
return !!backup && this.emver.compare(backup.version, '0.3.0') !== -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
ion-input {
|
||||
font-weight: 500;
|
||||
font-weight: bold;
|
||||
--placeholder-font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
min-height: 40vh
|
||||
}
|
||||
|
||||
.notes-content {
|
||||
text-align: left;
|
||||
margin: 32px;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: xx-large;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
<div class="slide-content">
|
||||
<div style="margin-top: 25px;">
|
||||
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
||||
<ion-label [color]="params.titleColor">
|
||||
<div class="notes-content">
|
||||
<h1>{{ params.title }}</h1>
|
||||
<h2>{{ params.headline }}</h2>
|
||||
</ion-label>
|
||||
</div>
|
||||
<div *ngFor="let note of params.notes | keyvalue : asIsOrder">
|
||||
<h2>{{ note.key }}</h2>
|
||||
<div class="long-message" [innerHTML]="note.value | markdown"></div>
|
||||
<br />
|
||||
<div *ngFor="let v of params.versions; let i = index">
|
||||
<h4>
|
||||
<b>
|
||||
{{ v.version }}
|
||||
<span *ngIf="i === 0"> (Current Version)</span>
|
||||
</b>
|
||||
</h4>
|
||||
<hr style="height: 0; border-width: 1px" />
|
||||
<div [innerHTML]="v.notes | markdown"></div>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,17 +8,17 @@ import { BehaviorSubject, Subject } from 'rxjs'
|
||||
})
|
||||
export class NotesComponent {
|
||||
@Input() params: {
|
||||
notes: { [version: string]: string }
|
||||
versions: { version: string; notes: string }[]
|
||||
title: string
|
||||
titleColor: string
|
||||
headline: string
|
||||
}
|
||||
|
||||
load () { }
|
||||
load() {}
|
||||
loading$ = new BehaviorSubject(false)
|
||||
cancel$ = new Subject<void>()
|
||||
|
||||
asIsOrder () {
|
||||
asIsOrder() {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,16 @@ export class WizardBaker {
|
||||
}): InstallWizardComponent['params'] {
|
||||
const { version, releaseNotes, headline } = values
|
||||
|
||||
const versions = Object.keys(releaseNotes)
|
||||
.sort()
|
||||
.reverse()
|
||||
.map(version => {
|
||||
return {
|
||||
version,
|
||||
notes: releaseNotes[version],
|
||||
}
|
||||
})
|
||||
|
||||
const action = 'update'
|
||||
const title = 'EmbassyOS'
|
||||
const toolbar: TopbarParams = { action, title, version }
|
||||
@@ -112,7 +122,7 @@ export class WizardBaker {
|
||||
slide: {
|
||||
selector: 'notes',
|
||||
params: {
|
||||
notes: releaseNotes,
|
||||
versions,
|
||||
title: 'Release Notes',
|
||||
titleColor: 'dark',
|
||||
headline,
|
||||
|
||||
@@ -99,7 +99,7 @@ function loading(
|
||||
return pipe(
|
||||
// Show notification on error
|
||||
catchError(e => from(errToast.present(e))),
|
||||
// Map any result to false to stop loading inidicator
|
||||
// Map any result to false to stop loading indicator
|
||||
mapTo(false),
|
||||
// Start operation with true
|
||||
startWith(true),
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ModalController, NavController } from '@ionic/angular'
|
||||
import {
|
||||
LoadingController,
|
||||
ModalController,
|
||||
NavController,
|
||||
} from '@ionic/angular'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import {
|
||||
GenericInputComponent,
|
||||
@@ -12,7 +16,6 @@ import {
|
||||
DiskBackupTarget,
|
||||
} from 'src/app/services/api/api.types'
|
||||
import { AppRecoverSelectPage } from 'src/app/modals/app-recover-select/app-recover-select.page'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import * as argon2 from '@start9labs/argon2'
|
||||
|
||||
@Component({
|
||||
@@ -25,21 +28,24 @@ export class RestorePage {
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly embassyApi: ApiService,
|
||||
private readonly patch: PatchDbService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
) {}
|
||||
|
||||
async presentModalPassword(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
): Promise<void> {
|
||||
const options: GenericInputOptions = {
|
||||
title: 'Master Password Required',
|
||||
title: 'Password Required',
|
||||
message:
|
||||
'Enter your master password. On the next screen, you will select the individual services you want to restore.',
|
||||
'Enter the master password that was used to encrypt this backup. On the next screen, you will select the individual services you want to restore.',
|
||||
label: 'Master Password',
|
||||
placeholder: 'Enter master password',
|
||||
useMask: true,
|
||||
buttonText: 'Next',
|
||||
submitFn: (password: string) => this.decryptDrive(target, password),
|
||||
submitFn: async (password: string) => {
|
||||
argon2.verify(target.entry['embassy-os']['password-hash'], password)
|
||||
await this.restoreFromBackup(target, password)
|
||||
},
|
||||
}
|
||||
|
||||
const modal = await this.modalCtrl.create({
|
||||
@@ -52,57 +58,27 @@ export class RestorePage {
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
private async decryptDrive(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
const passwordHash = this.patch.getData()['server-info']['password-hash']
|
||||
argon2.verify(passwordHash, password)
|
||||
|
||||
try {
|
||||
argon2.verify(target.entry['embassy-os']['password-hash'], password)
|
||||
await this.restoreFromBackup(target, password)
|
||||
} catch (e) {
|
||||
setTimeout(() => this.presentModalOldPassword(target, password), 500)
|
||||
}
|
||||
}
|
||||
|
||||
private async presentModalOldPassword(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
const options: GenericInputOptions = {
|
||||
title: 'Original Password Needed',
|
||||
message:
|
||||
'This backup was created with a different password. Enter the ORIGINAL password that was used to encrypt this backup.',
|
||||
label: 'Original Password',
|
||||
placeholder: 'Enter original password',
|
||||
useMask: true,
|
||||
buttonText: 'Restore From Backup',
|
||||
submitFn: (oldPassword: string) =>
|
||||
this.restoreFromBackup(target, password, oldPassword),
|
||||
}
|
||||
|
||||
const m = await this.modalCtrl.create({
|
||||
component: GenericInputComponent,
|
||||
componentProps: { options },
|
||||
presentingElement: await this.modalCtrl.getTop(),
|
||||
cssClass: 'alertlike-modal',
|
||||
})
|
||||
|
||||
await m.present()
|
||||
}
|
||||
|
||||
private async restoreFromBackup(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
oldPassword?: string,
|
||||
): Promise<void> {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Decrypting drive...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const backupInfo = await this.embassyApi.getBackupInfo({
|
||||
'target-id': target.id,
|
||||
password,
|
||||
})
|
||||
this.presentModalSelect(target.id, backupInfo, password, oldPassword)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private async presentModalSelect(
|
||||
|
||||
@@ -86,7 +86,29 @@ export class ServerBackupPage {
|
||||
placeholder: 'Enter master password',
|
||||
useMask: true,
|
||||
buttonText: 'Create Backup',
|
||||
submitFn: (password: string) => this.test(target, password),
|
||||
submitFn: async (password: string) => {
|
||||
// confirm password matches current master password
|
||||
const passwordHash =
|
||||
this.patch.getData()['server-info']['password-hash']
|
||||
argon2.verify(passwordHash, password)
|
||||
|
||||
// first time backup
|
||||
if (!target.hasValidBackup) {
|
||||
await this.createBackup(target.id, password)
|
||||
// existing backup
|
||||
} else {
|
||||
try {
|
||||
argon2.verify(target.entry['embassy-os']['password-hash'], password)
|
||||
} catch {
|
||||
setTimeout(
|
||||
() => this.presentModalOldPassword(target, password),
|
||||
500,
|
||||
)
|
||||
return
|
||||
}
|
||||
await this.createBackup(target.id, password)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const m = await this.modalCtrl.create({
|
||||
@@ -98,33 +120,6 @@ export class ServerBackupPage {
|
||||
await m.present()
|
||||
}
|
||||
|
||||
private async test(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
oldPassword?: string,
|
||||
): Promise<void> {
|
||||
const passwordHash = this.patch.getData()['server-info']['password-hash']
|
||||
argon2.verify(passwordHash, password)
|
||||
|
||||
if (!target.hasValidBackup) {
|
||||
await this.createBackup(target.id, password)
|
||||
} else {
|
||||
try {
|
||||
argon2.verify(
|
||||
target.entry['embassy-os']['password-hash'],
|
||||
oldPassword || password,
|
||||
)
|
||||
await this.createBackup(target.id, password)
|
||||
} catch (e) {
|
||||
if (oldPassword) {
|
||||
throw e
|
||||
} else {
|
||||
setTimeout(() => this.presentModalOldPassword(target, password), 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async presentModalOldPassword(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
@@ -137,8 +132,10 @@ export class ServerBackupPage {
|
||||
placeholder: 'Enter original password',
|
||||
useMask: true,
|
||||
buttonText: 'Create Backup',
|
||||
submitFn: (oldPassword: string) =>
|
||||
this.test(target, password, oldPassword),
|
||||
submitFn: async (oldPassword: string) => {
|
||||
argon2.verify(target.entry['embassy-os']['password-hash'], oldPassword)
|
||||
await this.createBackup(target.id, password, oldPassword)
|
||||
},
|
||||
}
|
||||
|
||||
const m = await this.modalCtrl.create({
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { PackageState } from 'src/app/types/package-state'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import {
|
||||
DependencyErrorType,
|
||||
DockerIoFormat,
|
||||
@@ -1034,7 +1033,8 @@ export module Mock {
|
||||
version: '0.3.0',
|
||||
full: true,
|
||||
'password-hash':
|
||||
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNK',
|
||||
// password is asdfasdf
|
||||
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
|
||||
'wrapped-key': '',
|
||||
},
|
||||
},
|
||||
@@ -1056,21 +1056,23 @@ export module Mock {
|
||||
mountable: true,
|
||||
'embassy-os': null,
|
||||
},
|
||||
// 'powjefhjbnwhdva': {
|
||||
// type: 'disk',
|
||||
// logicalname: 'sdba1',
|
||||
// label: 'Another Drive',
|
||||
// capacity: 2000000000000,
|
||||
// used: 100000000000,
|
||||
// model: null,
|
||||
// vendor: 'SSK',
|
||||
// 'embassy-os': {
|
||||
// version: '0.3.0',
|
||||
// full: true,
|
||||
// 'password-hash': '$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
|
||||
// 'wrapped-key': '',
|
||||
// },
|
||||
// },
|
||||
powjefhjbnwhdva: {
|
||||
type: 'disk',
|
||||
logicalname: 'sdba1',
|
||||
label: 'Another Drive',
|
||||
capacity: 2000000000000,
|
||||
used: 100000000000,
|
||||
model: null,
|
||||
vendor: 'SSK',
|
||||
'embassy-os': {
|
||||
version: '0.3.0',
|
||||
full: true,
|
||||
// password is asdfasdf
|
||||
'password-hash':
|
||||
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
|
||||
'wrapped-key': '',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const BackupInfo: RR.GetBackupInfoRes = {
|
||||
|
||||
@@ -245,7 +245,7 @@ export module RR {
|
||||
export type GetMarketplaceDataRes = MarketplaceData
|
||||
|
||||
export type GetMarketplaceEOSReq = {
|
||||
'eos-version-compat': string
|
||||
'eos-version': string
|
||||
}
|
||||
export type GetMarketplaceEOSRes = MarketplaceEOS
|
||||
|
||||
|
||||
@@ -105,8 +105,9 @@ export class LiveApiService extends ApiService {
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async marketplaceProxy<T>(path: string, params: {}, url: string): Promise<T> {
|
||||
const fullURL = `${url}${path}?${new URLSearchParams(params).toString()}`
|
||||
async marketplaceProxy<T>(path: string, qp: {}, url: string): Promise<T> {
|
||||
Object.assign(qp, { arch: this.config.targetArch })
|
||||
const fullURL = `${url}${path}?${new URLSearchParams(qp).toString()}`
|
||||
return this.http.rpcRequest({
|
||||
method: 'marketplace.get',
|
||||
params: { url: fullURL },
|
||||
|
||||
@@ -374,7 +374,7 @@ export class MockApiService extends ApiService {
|
||||
params: RR.CreateBackupReq,
|
||||
): Promise<RR.CreateBackupRes> {
|
||||
await pauseFor(2000)
|
||||
const path = '/server-info/status'
|
||||
const path = '/server-info/status-info/backing-up'
|
||||
const ids = ['bitcoind', 'lnd']
|
||||
|
||||
setTimeout(async () => {
|
||||
@@ -402,7 +402,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path,
|
||||
value: ServerStatus.Running,
|
||||
value: false,
|
||||
},
|
||||
]
|
||||
this.updateMock(lastPatch)
|
||||
@@ -412,7 +412,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path,
|
||||
value: ServerStatus.BackingUp,
|
||||
value: true,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -788,6 +788,10 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/package-data/${id}/install-progress`,
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
path: `/recovered-packages/${id}`,
|
||||
},
|
||||
]
|
||||
this.updateMock(patch2)
|
||||
}, 1000)
|
||||
|
||||
@@ -25,10 +25,15 @@ export const mockPatchData: DataModel = {
|
||||
'lan-address': 'https://embassy-abcdefgh.local',
|
||||
'tor-address': 'http://myveryownspecialtoraddress.onion',
|
||||
'unread-notification-count': 4,
|
||||
// password is asdfasdf
|
||||
'password-hash':
|
||||
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
|
||||
'eos-version-compat': '>=0.3.0 <=0.3.0.1',
|
||||
'status-info': null,
|
||||
'status-info': {
|
||||
'backing-up': false,
|
||||
updated: false,
|
||||
'update-progress': null,
|
||||
},
|
||||
},
|
||||
'recovered-packages': {
|
||||
'btc-rpc-proxy': {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
const {
|
||||
targetArch,
|
||||
gitHash,
|
||||
useMocks,
|
||||
ui: { patchDb, api, mocks, marketplace },
|
||||
@@ -19,15 +20,13 @@ const {
|
||||
export class ConfigService {
|
||||
origin = removePort(removeProtocol(window.origin))
|
||||
version = require('../../../../../package.json').version
|
||||
|
||||
useMocks = useMocks
|
||||
mocks = mocks
|
||||
|
||||
targetArch = targetArch
|
||||
gitHash = gitHash
|
||||
patchDb = patchDb
|
||||
api = api
|
||||
marketplace = marketplace
|
||||
|
||||
skipStartupAlerts = useMocks && mocks.skipStartupAlerts
|
||||
isConsulate = window['platform'] === 'ios'
|
||||
supportsWebSockets = !!window.WebSocket || this.isConsulate
|
||||
|
||||
@@ -19,9 +19,9 @@ export class EOSService {
|
||||
) {}
|
||||
|
||||
async getEOS(): Promise<boolean> {
|
||||
const version = this.patch.getData()['server-info'].version
|
||||
this.eos = await this.api.getEos({
|
||||
'eos-version-compat':
|
||||
this.patch.getData()['server-info']['eos-version-compat'],
|
||||
'eos-version': version,
|
||||
})
|
||||
const updateAvailable =
|
||||
this.emver.compare(
|
||||
|
||||
@@ -33,13 +33,6 @@
|
||||
src: url('/assets/fonts/Open_Sans/OpenSans-Bold.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('/assets/fonts/Open_Sans/OpenSans-SemiBold.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
@@ -81,7 +74,7 @@ $subheader-height: 48px;
|
||||
.input-label {
|
||||
margin-bottom: 6px;
|
||||
font-size: medium;
|
||||
font-weight: 500;
|
||||
font-weight: bold;
|
||||
* {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
Reference in New Issue
Block a user