diff --git a/ui/client-manifest.yaml b/ui/client-manifest.yaml index c9b087b52..1ebe81626 100644 --- a/ui/client-manifest.yaml +++ b/ui/client-manifest.yaml @@ -1,6 +1,6 @@ manifest-version: 0 app-id: start9-ambassador -app-version: 0.2.5 +app-version: 0.2.6 uri-rewrites: - =/api -> http://{{start9-ambassador}}:5959/authenticate - /api/ -> http://{{start9-ambassador}}:5959/ diff --git a/ui/package.json b/ui/package.json index 1c88a5088..8b2ed3431 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "embassy-ui", - "version": "0.2.5", + "version": "0.2.6", "description": "GUI for EmbassyOS", "author": "Start9 Labs", "homepage": "https://github.com/Start9Labs/embassy-ui", diff --git a/ui/release.md b/ui/release.md new file mode 100644 index 000000000..78753e5e7 --- /dev/null +++ b/ui/release.md @@ -0,0 +1,2 @@ +- Update app version in package.json +- Update app version in manifest.yaml diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 62f63caf9..49aec556f 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -65,6 +65,7 @@ + diff --git a/ui/src/app/pages/apps-routes/app-config/app-config.page.ts b/ui/src/app/pages/apps-routes/app-config/app-config.page.ts index 2b43fb273..90e800c36 100644 --- a/ui/src/app/pages/apps-routes/app-config/app-config.page.ts +++ b/ui/src/app/pages/apps-routes/app-config/app-config.page.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core' import { NavController, AlertController, ModalController, PopoverController } from '@ionic/angular' import { ActivatedRoute } from '@angular/router' -import { AppStatus } from 'src/app/models/app-model' +import { AppModel, AppStatus } from 'src/app/models/app-model' import { AppInstalledFull } from 'src/app/models/app-types' import { ApiService } from 'src/app/services/api/api.service' -import { pauseFor, isEmptyObject } from 'src/app/util/misc.util' +import { pauseFor, isEmptyObject, modulateTime } from 'src/app/util/misc.util' import { PropertySubject, peekProperties } from 'src/app/util/property-subject.util' import { LoaderService, markAsLoadingDuring$ } from 'src/app/services/loader.service' import { TrackingModalController } from 'src/app/services/tracking-modal-controller.service' @@ -60,6 +60,7 @@ export class AppConfigPage extends Cleanup { private readonly modalController: ModalController, private readonly trackingModalCtrl: TrackingModalController, private readonly popoverController: PopoverController, + private readonly appModel: AppModel, ) { super() } backButtonDefense = false @@ -182,6 +183,7 @@ export class AppConfigPage extends Cleanup { async save () { const app = peekProperties(this.app) + const ogAppStatus = app.status return this.loader.of({ message: `Saving config...`, @@ -208,6 +210,9 @@ export class AppConfigPage extends Cleanup { }) .then(({ skip }) => { if (skip) return + if (ogAppStatus === AppStatus.RUNNING) { + this.appModel.update({ id: this.appId, status: AppStatus.RESTARTING }, modulateTime(new Date(), 3, 'seconds')) + } this.navCtrl.back() }) .catch(e => this.error = { text: e.message }) diff --git a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.html b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.html index a8d317229..99468cdeb 100644 --- a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.html +++ b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.html @@ -81,8 +81,8 @@ Tor Address - -

{{ vars.torAddress | truncateCenter:18:18:true }}

+ +

{{ vars.torAddress }}

diff --git a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts index 596447f53..1d906bc5a 100644 --- a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts +++ b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts @@ -17,6 +17,7 @@ import { catchError, concatMap, filter, switchMap, tap } from 'rxjs/operators' import { Cleanup } from 'src/app/util/cleanup' import { InformationPopoverComponent } from 'src/app/components/information-popover/information-popover.component' import { Emver } from 'src/app/services/emver.service' +import { displayEmver } from 'src/app/pipes/emver.pipe' @Component({ selector: 'app-installed-show', @@ -115,7 +116,7 @@ export class AppInstalledShowPage extends Cleanup { const alert = await this.alertCtrl.create({ backdropDismiss: false, header: 'Update Available', - message: `New version ${versionLatest} found for ${app.title}.`, + message: `New version ${displayEmver(versionLatest)} found for ${app.title}.`, buttons: [ { text: 'Cancel', diff --git a/ui/src/app/pipes/truncate.pipe.ts b/ui/src/app/pipes/truncate.pipe.ts index 9a76a428f..19c9560d2 100644 --- a/ui/src/app/pipes/truncate.pipe.ts +++ b/ui/src/app/pipes/truncate.pipe.ts @@ -20,13 +20,3 @@ export class TruncateEndPipe implements PipeTransform { return val.slice(0, length) + '...' } } - - -// 4 and 4 - -// 12345678 => 12345678 -// 123456789 => 123456789 -// 1234567890 => 1234567890 -// 12345678901 => 12345678901 -// 1234...9012 => 1234...9012 -// 1234...0123 => 1234...0123 \ No newline at end of file diff --git a/ui/src/app/services/api/api.service.ts b/ui/src/app/services/api/api.service.ts index c0df7176e..7678b3ba6 100644 --- a/ui/src/app/services/api/api.service.ts +++ b/ui/src/app/services/api/api.service.ts @@ -47,7 +47,7 @@ export abstract class ApiService { abstract restoreAppBackup (appId: string, logicalname: string, password?: string): Promise abstract stopAppBackup (appId: string): Promise abstract patchAppConfig (app: AppInstalledPreview, config: object, dryRun?: boolean): Promise<{ breakages: DependentBreakage[] }> - abstract postConfigureDependency(dependencyId: string, dependentId: string, dryRun?: boolean): Promise<{config: object, breakages: DependentBreakage[] }> + abstract postConfigureDependency (dependencyId: string, dependentId: string, dryRun?: boolean): Promise< {config: object, breakages: DependentBreakage[] }> abstract patchServerConfig (attr: string, value: any): Promise abstract wipeAppData (app: AppInstalledPreview): Promise abstract addSSHKey (sshKey: string): Promise diff --git a/ui/src/app/services/api/live-api.service.ts b/ui/src/app/services/api/live-api.service.ts index f1887a1f9..eeec15c75 100644 --- a/ui/src/app/services/api/live-api.service.ts +++ b/ui/src/app/services/api/live-api.service.ts @@ -9,6 +9,7 @@ import { HttpErrorResponse } from '@angular/common/http' import { isUnauthorized } from 'src/app/util/web.util' import { Replace } from 'src/app/util/types.util' import { AppMetrics, parseMetricsPermissive } from 'src/app/util/metrics.util' +import { modulateTime } from 'src/app/util/misc.util' @Injectable() export class LiveApiService extends ApiService { @@ -122,23 +123,23 @@ export class LiveApiService extends ApiService { } async uninstallApp (appId: string, dryRun: boolean = false): Promise<{ breakages: DependentBreakage[] }> { - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/uninstall${dryRunParam(dryRun, true)}`, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/uninstall${dryRunParam(dryRun, true)}`, readTimeout: 60000 }) } async startApp (appId: string): Promise { - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/start`, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/start`, readTimeout: 60000 }) .then(() => this.appModel.update({ id: appId, status: AppStatus.RUNNING })) .then(() => ({ })) } async stopApp (appId: string, dryRun: boolean = false): Promise<{ breakages: DependentBreakage[] }> { - const res = await this.authRequest<{ breakages: DependentBreakage[] }>({ method: Method.POST, url: `/apps/${appId}/stop${dryRunParam(dryRun, true)}`, readTimeout: 30000 }) - if (!dryRun) this.appModel.update({ id: appId, status: AppStatus.STOPPING }) + const res = await this.authRequest<{ breakages: DependentBreakage[] }>({ method: Method.POST, url: `/apps/${appId}/stop${dryRunParam(dryRun, true)}`, readTimeout: 60000 }) + if (!dryRun) this.appModel.update({ id: appId, status: AppStatus.STOPPING }, modulateTime(new Date(), 5, 'seconds')) return res } async restartApp (appId: string): Promise { - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/restart`, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/restart`, readTimeout: 60000 }) .then(() => ({ } as any)) } @@ -147,13 +148,13 @@ export class LiveApiService extends ApiService { password: password || undefined, logicalname, } - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup`, data, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup`, data, readTimeout: 60000 }) .then(() => this.appModel.update({ id: appId, status: AppStatus.CREATING_BACKUP })) .then(() => ({ })) } async stopAppBackup (appId: string): Promise { - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup/stop`, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup/stop`, readTimeout: 60000 }) .then(() => this.appModel.update({ id: appId, status: AppStatus.STOPPED })) .then(() => ({ })) } @@ -163,7 +164,7 @@ export class LiveApiService extends ApiService { password: password || undefined, logicalname, } - return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup/restore`, data, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${appId}/backup/restore`, data, readTimeout: 60000 }) .then(() => this.appModel.update({ id: appId, status: AppStatus.RESTORING_BACKUP })) .then(() => ({ })) } @@ -172,24 +173,24 @@ export class LiveApiService extends ApiService { const data: ReqRes.PatchAppConfigReq = { config, } - return this.authRequest({ method: Method.PATCH, url: `/apps/${app.id}/config${dryRunParam(dryRun, true)}`, data, readTimeout: 30000 }) + return this.authRequest({ method: Method.PATCH, url: `/apps/${app.id}/config${dryRunParam(dryRun, true)}`, data, readTimeout: 60000 }) } async postConfigureDependency (dependencyId: string, dependentId: string, dryRun?: boolean): Promise<{ config: object, breakages: DependentBreakage[] }> { - return this.authRequest({ method: Method.POST, url: `/apps/${dependencyId}/autoconfig/${dependentId}${dryRunParam(dryRun, true)}`, readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: `/apps/${dependencyId}/autoconfig/${dependentId}${dryRunParam(dryRun, true)}`, readTimeout: 60000 }) } async patchServerConfig (attr: string, value: any): Promise { const data: ReqRes.PatchServerConfigReq = { value, } - return this.authRequest({ method: Method.PATCH, url: `/${attr}`, data, readTimeout: 30000 }) + return this.authRequest({ method: Method.PATCH, url: `/${attr}`, data, readTimeout: 60000 }) .then(() => this.serverModel.update({ [attr]: value })) .then(() => ({ })) } async wipeAppData (app: AppInstalledPreview): Promise { - return this.authRequest({ method: Method.POST, url: `/apps/${app.id}/wipe`, readTimeout: 30000 }).then((res) => { + return this.authRequest({ method: Method.POST, url: `/apps/${app.id}/wipe`, readTimeout: 60000 }).then((res) => { this.appModel.update({ id: app.id, status: AppStatus.NEEDS_CONFIG }) return res }) @@ -230,11 +231,11 @@ export class LiveApiService extends ApiService { } async restartServer (): Promise { - return this.authRequest({ method: Method.POST, url: '/restart', readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: '/restart', readTimeout: 60000 }) } async shutdownServer (): Promise { - return this.authRequest({ method: Method.POST, url: '/shutdown', readTimeout: 30000 }) + return this.authRequest({ method: Method.POST, url: '/shutdown', readTimeout: 60000 }) } private async authRequest (opts: HttpOptions, overrides: Partial<{ version: string }> = { }): Promise {