refactor(auto-update): Show notification messages with the angular-notifier (#334)

* refactor(log): Refactor logging service

Removed the InjectionToken and changed LogService as default logger.
Finally ElectronLogService implements LogService directly.

* refactor: Optimize imports

* fix(app-update): Add missing rxjs imports

* style: Remove extra line

* refactor(store): Move app.actions.ts to shared module

* feat(notification): Add notification panel

Add angular-notifier to the app and created the ShowNotificationAction
to manage notifications

* style(notification): Fix tslint suggestion

* fix(notification): Add missing rxjs imports

* refactor(app-update): Refactor app-update notification

* fix(auto-update): Add missing rxjs imports
This commit is contained in:
Róbert Kiss
2017-07-05 13:41:45 +02:00
committed by László Monda
parent c9a1e9853c
commit f7212320e6
12 changed files with 53 additions and 22 deletions

View File

@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Rx';
import { AppState, getShowAppUpdateAvailable } from '../store';
import { DoNotUpdateAppAction, UpdateAppAction } from '../store/actions/app-update.action';
import { DoNotUpdateAppAction, UpdateAppAction } from '../shared/store/actions/app-update.action';
@Component({
selector: 'app',

View File

@@ -121,8 +121,8 @@ autoUpdater.on('update-not-available', (ev: any, info: VersionInfo) => {
sendIpcToWindow(IpcEvents.autoUpdater.updateNotAvailable, info);
});
autoUpdater.on('error', (ev: any, err: Error) => {
sendIpcToWindow(IpcEvents.autoUpdater.autoUpdateError, err);
autoUpdater.on('error', (ev: any, err: string) => {
sendIpcToWindow(IpcEvents.autoUpdater.autoUpdateError, err.substr(0, 100));
});
autoUpdater.on('download-progress', (progressObj: ProgressInfo) => {

View File

@@ -4,7 +4,7 @@ import { ipcRenderer } from 'electron';
import { IpcEvents } from '../shared/util';
import { AppState } from '../store';
import { UpdateDownloadedAction } from '../store/actions/app-update.action';
import { UpdateDownloadedAction, UpdateErrorAction } from '../shared/store/actions/app-update.action';
import { CheckForUpdateFailedAction, CheckForUpdateSuccessAction } from '../shared/store/actions/auto-update-settings';
/**
@@ -47,7 +47,7 @@ export class AppUpdateRendererService {
ipcRenderer.on(IpcEvents.autoUpdater.autoUpdateError, (event: string, arg: any) => {
this.writeUpdateState(IpcEvents.autoUpdater.autoUpdateError, arg);
this.dispachStoreAction(new CheckForUpdateFailedAction(arg));
this.dispachStoreAction(new UpdateErrorAction(arg));
});
ipcRenderer.on(IpcEvents.autoUpdater.autoUpdateDownloadProgress, (event: string, arg: any) => {

View File

@@ -1,13 +1,17 @@
import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store';
import { Actions, Effect } from '@ngrx/effects';
import { Actions, Effect, toPayload } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';
import { ActionTypes } from '../actions/app-update.action';
import { ActionTypes } from '../../shared/store/actions/app-update.action';
import { ActionTypes as AutoUpdateActionTypes } from '../../shared/store/actions/auto-update-settings';
import { AppUpdateRendererService } from '../../services/app-update-renderer.service';
import { NotificationType } from '../../shared/models/notification';
import { ShowNotificationAction } from '../../shared/store/actions/app.action';
@Injectable()
export class AppUpdateEffect {
@@ -25,6 +29,16 @@ export class AppUpdateEffect {
this.appUpdateRendererService.checkForUpdate();
});
@Effect() handleError$: Observable<Action> = this.actions$
.ofType(ActionTypes.UPDATE_ERROR)
.map(toPayload)
.map((message: string) => {
return new ShowNotificationAction({
type: NotificationType.Error,
message
});
});
constructor(private actions$: Actions,
private appUpdateRendererService: AppUpdateRendererService) {
}

View File

@@ -1,4 +1,4 @@
import { Actions, ActionTypes } from '../actions/app-update.action';
import { Actions, ActionTypes } from '../../shared/store/actions/app-update.action';
export interface State {
updateAvailable: boolean;
@@ -19,11 +19,13 @@ export function reducer(state = initialState, action: Actions) {
newState.updateAvailable = true;
return newState;
}
case ActionTypes.UPDATE_DOWNLOADED: {
const newState = Object.assign({}, state);
newState.updateDownloaded = true;
return newState;
}
case ActionTypes.DO_NOT_UPDATE_APP: {
const newState = Object.assign({}, state);
newState.doNotUpdateApp = true;

View File

@@ -12,7 +12,6 @@ export class AutoUpdateSettings {
@Input() version: string;
@Input() settings: State;
@Input() checkingForUpdate: boolean;
@Input() message: string;
@Output() toggleCheckForUpdateOnStartUp = new EventEmitter<boolean>();
@Output() toggleUsePreReleaseUpdate = new EventEmitter<boolean>();

View File

@@ -11,7 +11,6 @@
[version]="version"
[settings]="autoUpdateSettings$ | async"
[checkingForUpdate]="checkingForUpdate$ | async"
[message]="autoUpdateMessage$ | async"
(toggleCheckForUpdateOnStartUp)="toogleCheckForUpdateOnStartUp($event)"
(toggleUsePreReleaseUpdate)="toogleUsePreReleaseUpdate($event)"
(checkForUpdate)="checkForUpdate()">

View File

@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { runInElectron } from '../../util/index';
import { AppState, getAutoUpdateMessage, getAutoUpdateSettings, getCheckingForUpdate } from '../../store';
import { AppState, getAutoUpdateSettings, getCheckingForUpdate } from '../../store';
import {
CheckForUpdateNowAction,
ToggleCheckForUpdateOnStartupAction,
@@ -25,12 +25,10 @@ export class SettingsComponent {
version = '1.0.0';
autoUpdateSettings$: Observable<AutoUpdateSettings>;
checkingForUpdate$: Observable<boolean>;
autoUpdateMessage$: Observable<string>;
constructor(private store: Store<AppState>) {
this.autoUpdateSettings$ = store.select(getAutoUpdateSettings);
this.checkingForUpdate$ = store.select(getCheckingForUpdate);
this.autoUpdateMessage$ = store.select(getAutoUpdateMessage);
}
toogleCheckForUpdateOnStartUp(value: boolean) {

View File

@@ -1,5 +1,5 @@
import { Action } from '@ngrx/store';
import { type } from '../../shared/util/';
import { type } from '../../util';
const PREFIX = '[app-update] ';
@@ -9,7 +9,8 @@ export const ActionTypes = {
UPDATE_APP: type(PREFIX + 'update app'),
DO_NOT_UPDATE_APP: type(PREFIX + 'do not update app'),
UPDATE_DOWNLOADED: type(PREFIX + 'update downloaded'),
UPDATING: type(PREFIX + 'updating')
UPDATING: type(PREFIX + 'updating'),
UPDATE_ERROR: type(PREFIX + 'error')
};
export class UpdateAvailableAction implements Action {
@@ -32,9 +33,16 @@ export class UpdatingAction implements Action {
type = ActionTypes.UPDATING;
}
export class UpdateErrorAction implements Action {
type = ActionTypes.UPDATE_ERROR;
constructor(public payload: any) {}
}
export type Actions
= UpdateAvailableAction
| UpdateAppAction
| DoNotUpdateAppAction
| UpdateDownloadedAction
| UpdatingAction;
| UpdatingAction
| UpdateErrorAction;

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { Actions, Effect, toPayload } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { Action, Store } from '@ngrx/store';
@@ -18,6 +18,8 @@ import { DATA_STORAGE_REPOSITORY, DataStorageRepositoryService } from '../../ser
import { AppState, getAutoUpdateSettings } from '../index';
import { initialState } from '../reducers/auto-update-settings';
import { AutoUpdateSettings } from '../../models/auto-update-settings';
import { NotificationType } from '../../models/notification';
import { ShowNotificationAction } from '../actions/app.action';
@Injectable()
export class AutoUpdateSettingsEffects {
@@ -40,6 +42,16 @@ export class AutoUpdateSettingsEffects {
return new SaveAutoUpdateSettingsSuccessAction();
});
@Effect() sendNotification$: Observable<Action> = this.actions$
.ofType(ActionTypes.CHECK_FOR_UPDATE_FAILED, ActionTypes.CHECK_FOR_UPDATE_SUCCESS)
.map(toPayload)
.map((message: string) => {
return new ShowNotificationAction({
type: NotificationType.Info,
message
});
});
constructor(private actions$: Actions,
@Inject(DATA_STORAGE_REPOSITORY) private dataStorageRepository: DataStorageRepositoryService,
private store: Store<AppState>) {

View File

@@ -17,4 +17,3 @@ export const appUpdateState = (state: AppState) => state.autoUpdateSettings;
export const getAutoUpdateSettings = createSelector(appUpdateState, autoUpdate.getUpdateSettings);
export const getCheckingForUpdate = createSelector(appUpdateState, autoUpdate.checkingForUpdate);
export const getAutoUpdateMessage = createSelector(appUpdateState, autoUpdate.getMessage);

View File

@@ -1,10 +1,10 @@
import { Action } from '@ngrx/store';
import { ActionTypes } from '../actions/auto-update-settings';
import { ActionTypes as UpdateActions } from '../actions/app-update.action';
import { AutoUpdateSettings } from '../../models/auto-update-settings';
export interface State extends AutoUpdateSettings {
checkingForUpdate: boolean;
message?: string;
}
export const initialState: State = {
@@ -28,12 +28,13 @@ export function reducer(state = initialState, action: Action): State {
}
case ActionTypes.CHECK_FOR_UPDATE_NOW: {
return Object.assign({}, state, { checkingForUpdate: true, message: null });
return Object.assign({}, state, { checkingForUpdate: true});
}
case UpdateActions.UPDATE_ERROR:
case ActionTypes.CHECK_FOR_UPDATE_SUCCESS:
case ActionTypes.CHECK_FOR_UPDATE_FAILED: {
return Object.assign({}, state, { checkingForUpdate: false, message: action.payload });
return Object.assign({}, state, { checkingForUpdate: false });
}
default:
@@ -47,4 +48,3 @@ export const getUpdateSettings = (state: State) => ({
});
export const checkingForUpdate = (state: State) => state.checkingForUpdate;
export const getMessage = (state: State) => state.message;