Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions packages/uhk-agent/src/services/app-update.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,8 @@ export class AppUpdateService extends MainServiceBase {
});

autoUpdater.on('update-available', (info: UpdateInfo) => {
this.logService.misc('[AppUpdateService] update available. Downloading started');
autoUpdater.downloadUpdate()
.then(() => {
this.sendIpcToWindow(IpcEvents.autoUpdater.updateAvailable, info);
})
.catch((error) => {
this.logService.error('[AppUpdateService] Error when reporting update available: ', error);
});
this.logService.misc('[AppUpdateService] update available');
this.sendIpcToWindow(IpcEvents.autoUpdater.updateAvailable, info);
});

autoUpdater.on('update-not-available', (info: UpdateInfo) => {
Expand Down Expand Up @@ -93,13 +87,18 @@ export class AppUpdateService extends MainServiceBase {
return autoUpdater.quitAndInstall(true, true);
});

ipcMain.on(IpcEvents.autoUpdater.downloadUpdate, () => {
this.logService.misc('[AppUpdateService] download update from renderer process');
this.downloadUpdate();
});

ipcMain.on(IpcEvents.app.appStarted, () => {
this.logService.misc('[AppUpdateService] app started');
this.checkForUpdateAtStartup()
.then((checkForUpdate) => {
if (checkForUpdate) {
this.sendAutoUpdateNotification = false;
this.logService.misc('[AppUpdateService] app started. Automatically check for update.');
this.logService.misc('[AppUpdateService] app started. Check for new Agent version on startup.');
this.checkForUpdate();
}
})
Expand Down Expand Up @@ -136,6 +135,13 @@ export class AppUpdateService extends MainServiceBase {
});
}

private downloadUpdate(): void {
autoUpdater.downloadUpdate()
.catch((error) => {
this.logService.error('[AppUpdateService] Error when downloading update: ', error);
});
}

private async checkForUpdateAtStartup() {
const { checkForUpdateOnStartUp = true } = await this.getApplicationSettings();

Expand Down
1 change: 1 addition & 0 deletions packages/uhk-common/src/util/ipcEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class AutoUpdate {
public static readonly autoUpdateDownloaded = 'update-downloaded';
public static readonly autoUpdateDownloadProgress = 'auto-update-download-progress';
public static readonly updateAndRestart = 'update-and-restart';
public static readonly downloadUpdate = 'download-update';
public static readonly checkForUpdate = 'check-for-update';
public static readonly checkForUpdateNotAvailable = 'check-for-update-not-available';
}
Expand Down
1 change: 0 additions & 1 deletion packages/uhk-web/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<div class="main-div" [class.top-notification-panel-visible]="isTopNotificationPanelVisible()">
<app-update-available *ngIf="showUpdateAvailable"
[@topNotificationPanelVisible]
[updateInfo]="updateInfo$ | async"
(updateApp)="updateApp()"
(doNotUpdateApp)="doNotUpdateApp()">
</app-update-available>
Expand Down
4 changes: 0 additions & 4 deletions packages/uhk-web/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
runningInElectron,
saveToKeyboardState,
keypressCapturing,
getUpdateInfo,
firstAttemptOfSaveToKeyboard,
isStatusBufferErrorHidden,
getOutOfSpaceWaringData,
Expand All @@ -33,7 +32,6 @@ import {
import { StartDonglePairingAction } from './store/actions/dongle-pairing.action';
import { AddNewPairedDevicesToHostConnectionsAction } from './store/actions/user-config';
import { ProgressButtonState } from './store/reducers/progress-button-state';
import { UpdateInfo } from './models/update-info';
import {
CloseErrorPanelAction,
ShowErrorPanelAction,
Expand Down Expand Up @@ -113,7 +111,6 @@ export class MainAppComponent implements OnDestroy {
newPairedDevicesState: BleAddingState;
showFirmwareUpgradePanel: boolean;
showUpdateAvailable: boolean;
updateInfo$: Observable<UpdateInfo>;
deviceConfigurationLoaded$: Observable<boolean>;
runningInElectron$: Observable<boolean>;
saveToKeyboardState: ProgressButtonState;
Expand Down Expand Up @@ -188,7 +185,6 @@ export class MainAppComponent implements OnDestroy {
this.showUpdateAvailable = data;
this.cdRef.markForCheck();
});
this.updateInfo$ = store.select(getUpdateInfo);
this.deviceConfigurationLoaded$ = store.select(deviceConfigurationLoaded);
this.runningInElectron$ = store.select(runningInElectron);
this.saveToKeyboardStateSubscription = store.select(saveToKeyboardState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
<label>
<input type="checkbox"
[checked]="state.checkForUpdateOnStartUp"
(change)="emitCheckForUpdateOnStartUp($event.target.checked)"> Automatically check for update on
application start
(change)="emitCheckForUpdateOnStartUp($event.target.checked)"> Check for new Agent version on startup
</label>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
<div class="app-update-available-wrapper" role="alert">
A new Agent version has been <span *ngIf="updateInfo.isPrerelease">pre-</span>released.
A new Agent update is available.

<button type="button"
class="btn btn-link text-underline"
(click)="updateApp.emit()" >Update now!</button>
<a [href]="agentChangelogUrl"
class="btn btn-link text-underline"
externalUrl>Review changelog</a>

<button type="button"
class="btn btn-link float-end"
data-dismiss="alert"
aria-label="Close"
(click)="doNotUpdateApp.emit()">
<span aria-hidden="true">&times;</span>
</button>
<button type="button"
class="btn btn-link text-underline"
(click)="updateApp.emit()">Update</button>

<button type="button"
class="btn btn-link float-end"
data-dismiss="alert"
aria-label="Close"
(click)="doNotUpdateApp.emit()">
<span aria-hidden="true">&times;</span>
</button>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';

import { UpdateInfo } from '../../models/update-info';
import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core';

@Component({
selector: 'app-update-available',
Expand All @@ -10,7 +8,8 @@ import { UpdateInfo } from '../../models/update-info';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UpdateAvailableComponent {
@Input() updateInfo: UpdateInfo;
protected readonly agentChangelogUrl =
'https://github.com/UltimateHackingKeyboard/agent/blob/master/CHANGELOG.md';

@Output() updateApp = new EventEmitter<null>();
@Output() doNotUpdateApp = new EventEmitter<null>();
Expand Down
11 changes: 8 additions & 3 deletions packages/uhk-web/src/app/services/app-update-renderer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Action, Store } from '@ngrx/store';
import { IpcEvents, LogService } from 'uhk-common';
import { UpdateInfo } from '../models/update-info';
import { AppState } from '../store';
import { UpdateDownloadedAction, UpdateErrorAction } from '../store/actions/app-update.action';
import { UpdateAvailableAction, ClearUpdateAvailabilityAction, UpdateDownloadedAction, UpdateErrorAction } from '../store/actions/app-update.action';
import { CheckForUpdateFailedAction, CheckForUpdateSuccessAction } from '../store/actions/auto-update-settings';
import { IpcCommonRenderer } from './ipc-common-renderer';

Expand Down Expand Up @@ -34,18 +34,23 @@ export class AppUpdateRendererService {
this.ipcRenderer.send(IpcEvents.autoUpdater.updateAndRestart);
}

downloadUpdate(): void {
this.ipcRenderer.send(IpcEvents.autoUpdater.downloadUpdate);
}

checkForUpdate(allowPrerelease: boolean): void {
this.ipcRenderer.send(IpcEvents.autoUpdater.checkForUpdate, allowPrerelease);
}

private registerEvents() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.ipcRenderer.on(IpcEvents.autoUpdater.updateAvailable, (event: string, arg: any) => {
this.ipcRenderer.on(IpcEvents.autoUpdater.updateAvailable, (event: string, arg: UpdateInfo) => {
this.logService.misc(IpcEvents.autoUpdater.updateAvailable, arg);
this.dispatchStoreAction(new UpdateAvailableAction(arg));
});

this.ipcRenderer.on(IpcEvents.autoUpdater.updateNotAvailable, () => {
this.logService.misc(IpcEvents.autoUpdater.updateNotAvailable);
this.dispatchStoreAction(new ClearUpdateAvailabilityAction());
this.dispatchStoreAction(new CheckForUpdateSuccessAction('No update available'));
});

Expand Down
20 changes: 18 additions & 2 deletions packages/uhk-web/src/app/store/actions/app-update.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export enum ActionTypes {
DoNotUpdateApp = '[app-update] do not update app',
UpdateDownloaded = '[app-update] update downloaded',
Updating = '[app-update] updating',
UpdateError = '[app-update] error'
UpdateError = '[app-update] error',
ResetUpdateDismiss = '[app-update] reset update dismiss',
ClearUpdateAvailability = '[app-update] clear update availability',
}

export class ForceUpdateAction implements Action {
Expand All @@ -23,6 +25,9 @@ export class InvalidCodesignSignatureAction implements Action {

export class UpdateAvailableAction implements Action {
type = ActionTypes.UpdateAvailable;

constructor(public payload: UpdateInfo) {
}
}

export class UpdateAppAction implements Action {
Expand All @@ -33,6 +38,14 @@ export class DoNotUpdateAppAction implements Action {
type = ActionTypes.DoNotUpdateApp;
}

export class ResetUpdateDismissAction implements Action {
type = ActionTypes.ResetUpdateDismiss;
}

export class ClearUpdateAvailabilityAction implements Action {
type = ActionTypes.ClearUpdateAvailability;
}

export class UpdateDownloadedAction implements Action {
type = ActionTypes.UpdateDownloaded;

Expand All @@ -52,10 +65,13 @@ export class UpdateErrorAction implements Action {
}

export type Actions
= UpdateAvailableAction
= ForceUpdateAction
| UpdateAvailableAction
| InvalidCodesignSignatureAction
| UpdateAppAction
| DoNotUpdateAppAction
| ResetUpdateDismissAction
| ClearUpdateAvailabilityAction
| UpdateDownloadedAction
| UpdatingAction
| UpdateErrorAction;
41 changes: 29 additions & 12 deletions packages/uhk-web/src/app/store/effects/app-update.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { EMPTY } from 'rxjs';
import { first, map, tap, withLatestFrom } from 'rxjs/operators';
import { filter, map, tap, withLatestFrom } from 'rxjs/operators';

import { ERR_UPDATER_INVALID_SIGNATURE, LogService, NotificationType } from 'uhk-common';

import {
ActionTypes,
ClearUpdateAvailabilityAction,
ForceUpdateAction,
InvalidCodesignSignatureAction,
ResetUpdateDismissAction,
UpdateAppAction,
UpdateAvailableAction,
UpdateDownloadedAction,
UpdateErrorAction
} from '../actions/app-update.action';
import { ActionTypes as AutoUpdateActionTypes, CheckForUpdateNowAction } from '../actions/auto-update-settings';
import { ShowNotificationAction } from '../actions/app';
import { AppUpdateRendererService } from '../../services/app-update-renderer.service';
import { AppState, isForceUpdate } from '../index';
import { AppState, isForceUpdate, isUpdateDownloaded, isUpdateRequested } from '../index';

@Injectable()
export class AppUpdateEffect {
appStart$ = createEffect(() => this.actions$
updateApp$ = createEffect(() => this.actions$
.pipe(
ofType(ActionTypes.UpdateApp),
first(),
tap(() => {
this.appUpdateRendererService.sendUpdateAndRestartApp();
withLatestFrom(this.store.select(isUpdateDownloaded)),
tap(([, updateDownloaded]) => {
if (updateDownloaded) {
this.appUpdateRendererService.sendUpdateAndRestartApp();
} else {
this.appUpdateRendererService.downloadUpdate();
}
})
),
{ dispatch: false }
Expand All @@ -35,6 +41,7 @@ export class AppUpdateEffect {
checkForUpdate$ = createEffect(() => this.actions$
.pipe(
ofType<CheckForUpdateNowAction>(AutoUpdateActionTypes.CheckForUpdateNow),
tap(() => this.store.dispatch(new ResetUpdateDismissAction())),
map(action => action.payload),
tap((allowPrerelease: boolean) => {
this.logService.misc('[AppUpdateEffect] call checkForUpdate');
Expand All @@ -55,21 +62,31 @@ export class AppUpdateEffect {
{ dispatch: false }
);

updateAvailable$ = createEffect(() => this.actions$
forceUpdateDownload$ = createEffect(() => this.actions$
.pipe(
ofType<UpdateAvailableAction>(ActionTypes.UpdateAvailable),
withLatestFrom(this.store.select(isForceUpdate)),
map(([, forceUpdate]) => {
tap(([, forceUpdate]) => {
if (forceUpdate) {
return new UpdateAppAction();
this.appUpdateRendererService.downloadUpdate();
}

return EMPTY;
})
),
{ dispatch: false }
);

autoInstallAfterDownload$ = createEffect(() => this.actions$
.pipe(
ofType<UpdateDownloadedAction>(ActionTypes.UpdateDownloaded),
withLatestFrom(
this.store.select(isForceUpdate),
this.store.select(isUpdateRequested)
),
filter(([, forceUpdate, updateRequested]) => forceUpdate || updateRequested),
map(() => new UpdateAppAction())
)
);

handleError$ = createEffect(() => this.actions$
.pipe(
ofType<UpdateErrorAction>(ActionTypes.UpdateError),
Expand Down
2 changes: 2 additions & 0 deletions packages/uhk-web/src/app/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ export const appUpdateState = (state: AppState) => state.appUpdate;
export const getShowAppUpdateAvailable = createSelector(appUpdateState, fromAppUpdate.getShowAppUpdateAvailable);
export const getUpdateInfo = createSelector(appUpdateState, fromAppUpdate.getUpdateInfo);
export const isForceUpdate = createSelector(appUpdateState, fromAppUpdate.isForceUpdate);
export const isUpdateRequested = createSelector(appUpdateState, fromAppUpdate.isUpdateRequested);
export const isUpdateDownloaded = createSelector(appUpdateState, fromAppUpdate.isUpdateDownloaded);

export const appUpdateSettingsState = (state: AppState) => state.autoUpdateSettings;

Expand Down
Loading