remove share-stats, cosmetic improvements

This commit is contained in:
Matt Hill
2022-02-09 11:55:12 -07:00
committed by Keagan McClelland
parent 5326de9b84
commit 20acd8efea
17 changed files with 125 additions and 276 deletions

View File

@@ -15,9 +15,10 @@
"build:setup-wizard": "ng run setup-wizard:build",
"build:ui": "ng run ui:build && tsc projects/ui/postprocess.ts && node projects/ui/postprocess.js && git log | head -n1 > dist/ui/git-hash.txt",
"build:all": "npm run build:deps && npm run build:diagnostic-ui && npm run build:setup-wizard && npm run build:ui",
"start:diagnostic-ui": "ionic serve --project diagnostic-ui",
"start:setup-wizard": "ionic serve --project setup-wizard",
"start:ui": "ionic serve --project ui"
"start:diagnostic-ui": "npm run copy-git-hash && ionic serve --project diagnostic-ui",
"start:setup-wizard": "npm run copy-git-hash && ionic serve --project setup-wizard",
"start:ui": "npm run copy-git-hash && ionic serve --project ui",
"copy-git-hash": "./update-git-hash.sh"
},
"dependencies": {
"@angular/animations": "^13.2.0",

View File

@@ -49,7 +49,7 @@
<ion-icon
*ngIf="eosService.updateAvailable$ | async"
color="success"
name="repeat"
name="rocket-outline"
></ion-icon>
</ng-container>
<ion-badge
@@ -162,7 +162,7 @@
<ion-icon name="reload"></ion-icon>
<ion-icon name="remove"></ion-icon>
<ion-icon name="remove-circle-outline"></ion-icon>
<ion-icon name="repeat"></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="storefront-outline"></ion-icon>

View File

@@ -13,6 +13,7 @@ import {
AlertController,
IonicSafeString,
LoadingController,
ModalController,
ToastController,
} from '@ionic/angular'
import { Emver } from './services/emver.service'
@@ -24,7 +25,6 @@ import {
ConnectionFailure,
ConnectionService,
} from './services/connection.service'
import { StartupAlertsService } from './services/startup-alerts.service'
import { ConfigService } from './services/config.service'
import { debounce, isEmptyObject } from './util/misc.util'
import { ErrorToastService } from './services/error-toast.service'
@@ -32,6 +32,7 @@ import { Subscription } from 'rxjs'
import { LocalStorageService } from './services/local-storage.service'
import { EOSService } from './services/eos.service'
import { MarketplaceService } from './pages/marketplace-routes/marketplace.service'
import { OSWelcomePage } from './modals/os-welcome/os-welcome.page'
@Component({
selector: 'app-root',
@@ -95,7 +96,7 @@ export class AppComponent {
private readonly loadingCtrl: LoadingController,
private readonly emver: Emver,
private readonly connectionService: ConnectionService,
private readonly startupAlertsService: StartupAlertsService,
private readonly modalCtrl: ModalController,
private readonly marketplaceService: MarketplaceService,
private readonly toastCtrl: ToastController,
private readonly errToast: ErrorToastService,
@@ -146,6 +147,8 @@ export class AppComponent {
.subscribe(data => {
// check for updates to EOS
this.checkForEosUpdate(data.ui)
// show eos welcome message
this.showEosWelcome(data.ui['ack-welcome'])
this.subscriptions = this.subscriptions.concat([
// watch status to present toast for updated state
@@ -158,8 +161,6 @@ export class AppComponent {
this.watchNotifications(),
// watch marketplace URL for changes
this.marketplaceService.init(),
// run startup alerts
this.startupAlertsService.runChecks(),
])
})
// UNVERIFIED
@@ -214,9 +215,27 @@ export class AppComponent {
await alert.present()
}
private async checkForEosUpdate (ui: UIData): Promise<void> {
private checkForEosUpdate(ui: UIData): void {
if (ui['auto-check-updates']) {
await this.eosService.getEOS()
this.eosService.getEOS()
}
}
private async showEosWelcome(ackVersion: string): Promise<void> {
if (!this.config.skipStartupAlerts && ackVersion !== this.config.version) {
const modal = await this.modalCtrl.create({
component: OSWelcomePage,
presentingElement: await this.modalCtrl.getTop(),
componentProps: {
version: this.config.version,
},
})
modal.onWillDismiss().then(() => {
this.embassyApi
.setDbValue({ pointer: '/ack-welcome', value: this.config.version })
.catch()
})
modal.present()
}
}

View File

@@ -15,16 +15,6 @@
<ion-note slot="end">{{ patch.data.ui.name || defaultName }}</ion-note>
</ion-item>
<ion-item
button
(click)="serverConfig.presentAlert('share-stats', server['share-stats'])"
>
<ion-label>Auto Report Bugs</ion-label>
<ion-note slot="end"
>{{ server['share-stats'] ? 'Enabled' : 'Disabled' }}</ion-note
>
</ion-item>
<ion-item-divider>Marketplace</ion-item-divider>
<ion-item
button

View File

@@ -28,9 +28,9 @@ export class PreferencesPage {
private readonly loadingCtrl: LoadingController,
private readonly modalCtrl: ModalController,
private readonly api: ApiService,
public readonly serverConfig: ServerConfigService,
private readonly toastCtrl: ToastController,
private readonly localStorageService: LocalStorageService,
public readonly serverConfig: ServerConfigService,
public readonly patch: PatchDbService,
) {}

View File

@@ -59,19 +59,21 @@
</span>
</ng-container>
</p>
<!-- "Software Update" button only -->
<p *ngIf="button.title === 'Software Update'">
<ng-container
*ngIf="eosService.updateAvailable$ | async; else check"
>
<ion-text class="inline" color="success">
<ion-icon name="repeat"></ion-icon>
<ion-icon name="rocket-outline"></ion-icon>
Update Available
</ion-text>
</ng-container>
<ng-template #check>
<i>Check for updates</i>
<ion-text class="inline" color="dark">
<ion-icon name="refresh"></ion-icon>
Check for updates
</ion-text>
</ng-template>
</p>
</ion-label>

View File

@@ -204,7 +204,10 @@ export class ServerShowPage {
await loader.present()
try {
await this.eosService.getEOS()
const updateAvailable = await this.eosService.getEOS()
if (updateAvailable) {
this.updateEos()
}
} catch (e) {
this.errToast.present(e)
} finally {

View File

@@ -28,9 +28,6 @@ export module RR {
// server
export type SetShareStatsReq = WithExpire<{ value: boolean }> // server.config.share-stats
export type SetShareStatsRes = WithRevision<null>
export type GetServerLogsReq = {
cursor?: string
before_flag?: boolean

View File

@@ -51,12 +51,6 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
// server
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>

View File

@@ -57,12 +57,6 @@ export class LiveApiService extends ApiService {
// server
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> {

View File

@@ -90,21 +90,6 @@ export class MockApiService extends ApiService {
// server
async setShareStatsRaw (
params: RR.SetShareStatsReq,
): Promise<RR.SetShareStatsRes> {
await pauseFor(2000)
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/share-stats',
value: params.value,
},
]
return this.withRevision(patch)
}
async getServerLogs(
params: RR.GetServerLogsReq,
): Promise<RR.GetServerLogsRes> {

View File

@@ -15,7 +15,6 @@ export const mockPatchData: DataModel = {
'auto-check-updates': true,
'pkg-order': [],
'ack-welcome': '1.0.0',
'ack-share-stats': false,
marketplace: undefined,
},
'server-info': {
@@ -25,9 +24,6 @@ export const mockPatchData: DataModel = {
status: ServerStatus.Running,
'lan-address': 'https://embassy-abcdefgh.local',
'tor-address': 'http://myveryownspecialtoraddress.onion',
'eos-marketplace': 'https://beta-registry-0-3.start9labs.com',
'package-marketplace': null,
'share-stats': false,
'unread-notification-count': 4,
'password-hash':
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',

View File

@@ -18,7 +18,7 @@ export class EOSService {
private readonly patch: PatchDbService,
) {}
async getEOS(): Promise<void> {
async getEOS(): Promise<boolean> {
this.eos = await this.api.getEos({
'eos-version-compat':
this.patch.getData()['server-info']['eos-version-compat'],
@@ -29,5 +29,6 @@ export class EOSService {
this.patch.data['server-info'].version,
) === 1
this.updateAvailable$.next(updateAvailable)
return updateAvailable
}
}

View File

@@ -12,7 +12,6 @@ export interface UIData {
'auto-check-updates': boolean
'pkg-order': string[]
'ack-welcome': string // EOS version
'ack-share-stats': boolean
marketplace: UIMarketplaceData
}
@@ -33,9 +32,6 @@ export interface ServerInfo {
'lan-address': URL
'tor-address': URL
status: ServerStatus
'eos-marketplace': URL
'package-marketplace': URL | null // uses EOS marketplace if null
'share-stats': boolean
'unread-notification-count': number
'update-progress'?: {
size: number

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'
import { AlertInput, AlertButton, IonicSafeString } from '@ionic/core'
import { AlertInput, AlertButton } from '@ionic/core'
import { ApiService } from './api/embassy-api.service'
import { ConfigSpec } from '../pkg-config/config-types'
import { AlertController, LoadingController } from '@ionic/angular'
@@ -104,9 +104,6 @@ export class ServerConfigService {
value: enabled,
})
},
'share-stats': async (enabled: boolean) => {
return this.embassyApi.setShareStats({ value: enabled })
},
}
}
@@ -115,15 +112,7 @@ export const serverConfig: ConfigSpec = {
type: 'boolean',
name: 'Auto Check for Updates',
description:
'If enabled, EmbassyOS will automatically check for updates of itself and any installed services. Updating will still require your approval and action. Updates will never be performed automatically.',
'If enabled, EmbassyOS will automatically check for updates of itself. Updating will still require your approval and action. Updates will never be performed automatically.',
default: true,
},
'share-stats': {
type: 'boolean',
name: 'Report Bugs',
description: new IonicSafeString(
`If enabled, generic error codes will be anonymously transmitted over Tor to the Start9 team. This helps us identify and fix bugs quickly. <a href="https://docs.start9.com/user-manual/general/user-preferences/report-bugs.html" target="_blank" rel="noreferrer">Read more</a> `,
) as any,
default: false,
},
}

View File

@@ -1,125 +0,0 @@
import { Injectable } from '@angular/core'
import { ModalController } from '@ionic/angular'
import { WizardBaker } from '../components/install-wizard/prebaked-wizards'
import { OSWelcomePage } from '../modals/os-welcome/os-welcome.page'
import { ConfigService } from './config.service'
import { PatchDbService } from './patch-db/patch-db.service'
import { filter, take } from 'rxjs/operators'
import { isEmptyObject } from '../util/misc.util'
import { ApiService } from './api/embassy-api.service'
import { Subscription } from 'rxjs'
import { ServerConfigService } from './server-config.service'
@Injectable({
providedIn: 'root',
})
export class StartupAlertsService {
private checks: Check<any>[]
constructor(
private readonly config: ConfigService,
private readonly modalCtrl: ModalController,
private readonly api: ApiService,
private readonly wizardBaker: WizardBaker,
private readonly patch: PatchDbService,
private readonly serverConfig: ServerConfigService,
) {
const osWelcome: Check<boolean> = {
name: 'osWelcome',
shouldRun: () => this.shouldRunOsWelcome(),
display: () => this.displayOsWelcome(),
}
const shareStats: Check<boolean> = {
name: 'shareStats',
shouldRun: () => this.shouldRunShareStats(),
display: () => this.displayShareStats(),
}
this.checks = [osWelcome, shareStats]
}
// 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) => {
const displayRes = await previousDisplay
if (displayRes) return c.display()
}, Promise.resolve(true))
})
}
// ** should run **
private shouldRunOsWelcome(): boolean {
return this.patch.getData().ui['ack-welcome'] !== this.config.version
}
private shouldRunShareStats(): boolean {
return !this.patch.getData().ui['ack-share-stats']
}
private shouldRunOsUpdateCheck(): boolean {
return this.patch.getData().ui['auto-check-updates']
}
// ** display **
private async displayOsWelcome(): Promise<boolean> {
return new Promise(async resolve => {
const modal = await this.modalCtrl.create({
component: OSWelcomePage,
presentingElement: await this.modalCtrl.getTop(),
componentProps: {
version: this.config.version,
},
})
modal.onWillDismiss().then(() => {
this.api
.setDbValue({ pointer: '/ack-welcome', value: this.config.version })
.catch()
return resolve(true)
})
await modal.present()
})
}
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'],
)
alert.onDidDismiss().then(() => {
this.api
.setDbValue({
pointer: '/ack-share-stats',
value: this.config.version,
})
.catch()
return resolve(true)
})
})
}
}
type Check<T> = {
// validates whether a check should run based on server properties
shouldRun: () => boolean
// display an alert based on the result of the check.
// return false if subsequent modals should not be displayed
display: () => Promise<boolean>
// for logging purposes
name: string
}

7
frontend/update-git-hash.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
cd "$(dirname "$0")"
TMP_FILE=$(mktemp)
jq ".gitHash = \"$(git rev-parse HEAD)\"" config.json > $TMP_FILE && mv $TMP_FILE config.json