refactor: use rxjs pipe syntax (#900)

The `let` operator was not migrated because earlier two reducer needed be refactored
- user-configuration reducer
- present reducer

This commit is prerequisite of the angular upgrade.
This commit is contained in:
Róbert Kiss
2019-01-20 23:23:01 +01:00
committed by László Monda
parent e18a98d8bb
commit bb31c2cefa
27 changed files with 683 additions and 599 deletions

View File

@@ -14,18 +14,13 @@ import {
UpdateFirmwareData UpdateFirmwareData
} from 'uhk-common'; } from 'uhk-common';
import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb'; import { snooze, UhkHidDevice, UhkOperations } from 'uhk-usb';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { interval } from 'rxjs/observable/interval';
import { fromPromise } from 'rxjs/observable/fromPromise';
import { distinctUntilChanged, startWith, switchMap, tap } from 'rxjs/operators';
import { emptyDir } from 'fs-extra'; import { emptyDir } from 'fs-extra';
import * as path from 'path'; import * as path from 'path';
import 'rxjs/add/observable/interval';
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/distinctUntilChanged';
import { TmpFirmware } from '../models/tmp-firmware'; import { TmpFirmware } from '../models/tmp-firmware';
import { QueueManager } from './queue-manager'; import { QueueManager } from './queue-manager';
import { import {
@@ -254,14 +249,16 @@ export class DeviceService {
return; return;
} }
this.pollTimer$ = Observable.interval(1000) this.pollTimer$ = interval(1000)
.startWith(0) .pipe(
.switchMap(() => Observable.fromPromise(this.device.getDeviceConnectionStateAsync())) startWith(0),
.distinctUntilChanged<DeviceConnectionState>(isEqual) switchMap(() => fromPromise(this.device.getDeviceConnectionStateAsync())),
.do((state: DeviceConnectionState) => { distinctUntilChanged<DeviceConnectionState>(isEqual),
this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state); tap((state: DeviceConnectionState) => {
this.logService.info('[DeviceService] Device connection state changed to:', state); this.win.webContents.send(IpcEvents.device.deviceConnectionStateChanged, state);
}) this.logService.info('[DeviceService] Device connection state changed to:', state);
})
)
.subscribe(); .subscribe();
} }

View File

@@ -4,8 +4,6 @@ import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import 'rxjs/add/operator/last';
import { DoNotUpdateAppAction, UpdateAppAction } from './store/actions/app-update.action'; import { DoNotUpdateAppAction, UpdateAppAction } from './store/actions/app-update.action';
import { EnableUsbStackTestAction } from './store/actions/device'; import { EnableUsbStackTestAction } from './store/actions/device';
import { import {

View File

@@ -2,7 +2,7 @@ import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/pluck'; import { pluck } from 'rxjs/operators';
@Component({ @Component({
selector: 'add-on', selector: 'add-on',
@@ -18,6 +18,8 @@ export class AddOnComponent {
constructor(route: ActivatedRoute) { constructor(route: ActivatedRoute) {
this.name$ = route this.name$ = route
.params .params
.pluck<{}, string>('name'); .pipe(
pluck<{}, string>('name')
);
} }
} }

View File

@@ -4,8 +4,7 @@ import { Keymap } from 'uhk-common';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/combineLatest'; import { combineLatest, publishReplay, refCount } from 'rxjs/operators';
import 'rxjs/add/operator/publishReplay';
import { AppState } from '../../../store'; import { AppState } from '../../../store';
import { KeymapActions } from '../../../store/actions'; import { KeymapActions } from '../../../store/actions';
@@ -29,11 +28,13 @@ export class KeymapAddComponent {
this.filterExpression$ = new BehaviorSubject(''); this.filterExpression$ = new BehaviorSubject('');
this.presets$ = this.presetsAll$ this.presets$ = this.presetsAll$
.combineLatest(this.filterExpression$, (keymaps: Keymap[], filterExpression: string) => { .pipe(
return keymaps.filter((keymap: Keymap) => keymap.name.toLocaleLowerCase().includes(filterExpression)); combineLatest(this.filterExpression$, (keymaps: Keymap[], filterExpression: string) => {
}) return keymaps.filter((keymap: Keymap) => keymap.name.toLocaleLowerCase().includes(filterExpression));
.publishReplay(1) }),
.refCount(); publishReplay(1),
refCount()
);
} }
filterKeyboards(filterExpression: string) { filterKeyboards(filterExpression: string) {

View File

@@ -3,15 +3,14 @@ import { CanActivate, Router } from '@angular/router';
import { Keymap } from 'uhk-common'; import { Keymap } from 'uhk-common';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { switchMap, tap } from 'rxjs/operators';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/let'; import 'rxjs/add/operator/let';
import 'rxjs/add/operator/switchMap';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '../../../store/index'; import { AppState } from '../../../store';
import { getKeymaps } from '../../../store/reducers/user-configuration'; import { getKeymaps } from '../../../store/reducers/user-configuration';
@Injectable() @Injectable()
@@ -22,12 +21,14 @@ export class KeymapEditGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store return this.store
.let(getKeymaps()) .let(getKeymaps())
.do((keymaps: Keymap[]) => { .pipe(
const defaultKeymap = keymaps.find(keymap => keymap.isDefault); tap((keymaps: Keymap[]) => {
if (defaultKeymap) { const defaultKeymap = keymaps.find(keymap => keymap.isDefault);
this.router.navigate(['/keymap', defaultKeymap.abbreviation]); if (defaultKeymap) {
} this.router.navigate(['/keymap', defaultKeymap.abbreviation]);
}) }
.switchMap(() => Observable.of(false)); }),
switchMap(() => of(false))
);
} }
} }

View File

@@ -4,13 +4,8 @@ import { Store } from '@ngrx/store';
import { Keymap } from 'uhk-common'; import { Keymap } from 'uhk-common';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/first'; import { combineLatest, first, map, pluck, publishReplay, refCount, switchMap } from 'rxjs/operators';
import 'rxjs/add/operator/let'; import 'rxjs/add/operator/let';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/publishReplay';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/pluck';
import 'rxjs/add/operator/combineLatest';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
@@ -42,13 +37,17 @@ export class KeymapEditComponent {
route: ActivatedRoute) { route: ActivatedRoute) {
this.keymap$ = route this.keymap$ = route
.params .params
.pluck<{}, string>('abbr') .pipe(
.switchMap((abbr: string) => store.let(getKeymap(abbr))) pluck<{}, string>('abbr'),
.publishReplay(1) switchMap((abbr: string) => store.let(getKeymap(abbr))),
.refCount(); publishReplay(1),
refCount()
);
this.deletable$ = store.let(getKeymaps()) this.deletable$ = store.let(getKeymaps())
.map((keymaps: Keymap[]) => keymaps.length > 1); .pipe(
map((keymaps: Keymap[]) => keymaps.length > 1)
);
this.keyboardLayout$ = store.select(getKeyboardLayout); this.keyboardLayout$ = store.select(getKeyboardLayout);
this.allowLayerDoubleTap$ = store.select(layerDoubleTapSupported); this.allowLayerDoubleTap$ = store.select(layerDoubleTapSupported);
@@ -56,17 +55,21 @@ export class KeymapEditComponent {
downloadKeymap() { downloadKeymap() {
const exportableJSON$: Observable<string> = this.keymap$ const exportableJSON$: Observable<string> = this.keymap$
.switchMap(keymap => this.toExportableJSON(keymap)) .pipe(
.map(exportableJSON => JSON.stringify(exportableJSON)); switchMap(keymap => this.toExportableJSON(keymap)),
map(exportableJSON => JSON.stringify(exportableJSON))
);
this.keymap$ this.keymap$
.combineLatest(exportableJSON$) .pipe(
.first() combineLatest(exportableJSON$),
first()
)
.subscribe(latest => { .subscribe(latest => {
const keymap = latest[0]; const keymap = latest[0];
const exportableJSON = latest[1]; const exportableJSON = latest[1];
const fileName = keymap.name + '_keymap.json'; const fileName = keymap.name + '_keymap.json';
saveAs(new Blob([exportableJSON], {type: 'application/json'}), fileName); saveAs(new Blob([exportableJSON], { type: 'application/json' }), fileName);
}); });
} }
@@ -82,18 +85,20 @@ export class KeymapEditComponent {
private toExportableJSON(keymap: Keymap): Observable<any> { private toExportableJSON(keymap: Keymap): Observable<any> {
return this.store return this.store
.let(getUserConfiguration()) .let(getUserConfiguration())
.first() .pipe(
.map(userConfiguration => { first(),
return { map(userConfiguration => {
site: 'https://ultimatehackingkeyboard.com', return {
description: 'Ultimate Hacking Keyboard keymap', site: 'https://ultimatehackingkeyboard.com',
keyboardModel: 'UHK60', description: 'Ultimate Hacking Keyboard keymap',
userConfigMajorVersion: userConfiguration.userConfigMajorVersion, keyboardModel: 'UHK60',
userConfigMinorVersion: userConfiguration.userConfigMinorVersion, userConfigMajorVersion: userConfiguration.userConfigMajorVersion,
userConfigPatchVersion: userConfiguration.userConfigPatchVersion, userConfigMinorVersion: userConfiguration.userConfigMinorVersion,
objectType: 'keymap', userConfigPatchVersion: userConfiguration.userConfigPatchVersion,
objectValue: keymap.toJsonObject() objectType: 'keymap',
}; objectValue: keymap.toJsonObject()
}); };
})
);
} }
} }

View File

@@ -5,7 +5,7 @@ import { Macro, MacroAction } from 'uhk-common';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/pluck'; import { pluck, switchMap } from 'rxjs/operators';
import { MacroActions } from '../../../store/actions'; import { MacroActions } from '../../../store/actions';
import { AppState, macroPlaybackSupported } from '../../../store'; import { AppState, macroPlaybackSupported } from '../../../store';
@@ -26,14 +26,17 @@ export class MacroEditComponent implements OnDestroy {
macroPlaybackSupported$: Observable<boolean>; macroPlaybackSupported$: Observable<boolean>;
private subscription: Subscription; private subscription: Subscription;
constructor(private store: Store<AppState>, public route: ActivatedRoute) { constructor(private store: Store<AppState>, public route: ActivatedRoute) {
this.subscription = route this.subscription = route
.params .params
.pluck<{}, string>('id') .pipe(
.switchMap((id: string) => { pluck<{}, string>('id'),
this.macroId = +id; switchMap((id: string) => {
return store.let(getMacro(this.macroId)); this.macroId = +id;
}) return store.let(getMacro(this.macroId));
})
)
.subscribe((macro: Macro) => { .subscribe((macro: Macro) => {
this.macro = macro; this.macro = macro;
}); });

View File

@@ -3,9 +3,8 @@ import { CanActivate, Router } from '@angular/router';
import { Macro } from 'uhk-common'; import { Macro } from 'uhk-common';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import 'rxjs/add/operator/let'; import 'rxjs/add/operator/let';
import 'rxjs/add/operator/map';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@@ -20,12 +19,14 @@ export class MacroNotFoundGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store return this.store
.let(getMacros()) .let(getMacros())
.map((macros: Macro[]) => { .pipe(
const hasMacros = macros.length > 0; map((macros: Macro[]) => {
if (hasMacros) { const hasMacros = macros.length > 0;
this.router.navigate(['/macro', macros[0].id]); if (hasMacros) {
} this.router.navigate(['/macro', macros[0].id]);
return !hasMacros; }
}); return !hasMacros;
})
);
} }
} }

View File

@@ -16,8 +16,7 @@ import { animate, keyframes, state, style, transition, trigger } from '@angular/
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/combineLatest'; import { combineLatest, map } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import { import {
KeyAction, KeyAction,
@@ -155,9 +154,10 @@ export class PopoverComponent implements OnChanges {
private cdRef: ChangeDetectorRef) { private cdRef: ChangeDetectorRef) {
this.animationState = 'closed'; this.animationState = 'closed';
this.keymaps$ = store.let(getKeymaps()) this.keymaps$ = store.let(getKeymaps())
.combineLatest(this.currentKeymap$) .pipe(
.map(([keymaps, currentKeymap]: [Keymap[], Keymap]) => combineLatest(this.currentKeymap$),
keymaps.filter((keymap: Keymap) => currentKeymap.abbreviation !== keymap.abbreviation) map(([keymaps, currentKeymap]: [Keymap[], Keymap]) =>
keymaps.filter((keymap: Keymap) => currentKeymap.abbreviation !== keymap.abbreviation))
); );
this.macroPlaybackSupported$ = store.select(macroPlaybackSupported); this.macroPlaybackSupported$ = store.select(macroPlaybackSupported);
} }

View File

@@ -12,9 +12,6 @@ import { animate, state, style, transition, trigger } from '@angular/animations'
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/let';
import { AppState, getSideMenuPageState } from '../../store'; import { AppState, getSideMenuPageState } from '../../store';
import { MacroActions } from '../../store/actions'; import { MacroActions } from '../../store/actions';

View File

@@ -3,8 +3,7 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NouisliderComponent } from 'ng2-nouislider'; import { NouisliderComponent } from 'ng2-nouislider';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer'; import { Observer } from 'rxjs/Observer';
import 'rxjs/add/operator/debounceTime'; import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import 'rxjs/add/operator/distinctUntilChanged';
export interface SliderPips { export interface SliderPips {
mode: string; mode: string;
@@ -80,9 +79,10 @@ export class SliderWrapperComponent implements AfterViewInit, ControlValueAccess
if (!this.changeObserver$) { if (!this.changeObserver$) {
Observable.create(observer => { Observable.create(observer => {
this.changeObserver$ = observer; this.changeObserver$ = observer;
}).debounceTime(this.changeDebounceTime) }).pipe(
.distinctUntilChanged() debounceTime(this.changeDebounceTime),
.subscribe(this.propagateChange); distinctUntilChanged()
).subscribe(this.propagateChange);
return; // No change event on first change as the value is just being set return; // No change event on first change as the value is just being set
} }

View File

@@ -14,8 +14,8 @@ import {
} from '@angular/core'; } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of'; import { of } from 'rxjs/observable/of';
import 'rxjs/add/operator/map'; import { map } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { import {
@@ -319,40 +319,44 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
const playMacroAction: PlayMacroAction = keyAction; const playMacroAction: PlayMacroAction = keyAction;
return this.store return this.store
.select(appState => appState.userConfiguration.macros) .select(appState => appState.userConfiguration.macros)
.map(macroState => macroState.find(macro => { .pipe(
return macro.id === playMacroAction.macroId; map(macroState => macroState.find(macro => {
}).name) return macro.id === playMacroAction.macroId;
.map(macroName => { }).name),
const content: NameValuePair[] = [ map(macroName => {
{ const content: NameValuePair[] = [
name: 'Action type', {
value: 'Play macro' name: 'Action type',
}, value: 'Play macro'
{ },
name: 'Macro name', {
value: macroName name: 'Macro name',
} value: macroName
]; }
return content; ];
}); return content;
})
);
} else if (keyAction instanceof SwitchKeymapAction) { } else if (keyAction instanceof SwitchKeymapAction) {
const switchKeymapAction: SwitchKeymapAction = keyAction; const switchKeymapAction: SwitchKeymapAction = keyAction;
return this.store return this.store
.select(appState => appState.userConfiguration.keymaps) .select(appState => appState.userConfiguration.keymaps)
.map(keymaps => keymaps.find(keymap => keymap.abbreviation === switchKeymapAction.keymapAbbreviation).name) .pipe(
.map(keymapName => { map(keymaps => keymaps.find(keymap => keymap.abbreviation === switchKeymapAction.keymapAbbreviation).name),
const content: NameValuePair[] = [ map(keymapName => {
{ const content: NameValuePair[] = [
name: 'Action type', {
value: 'Switch keymap' name: 'Action type',
}, value: 'Switch keymap'
{ },
name: 'Keymap', {
value: keymapName name: 'Keymap',
} value: keymapName
]; }
return content; ];
}); return content;
})
);
} else if (keyAction instanceof SwitchLayerAction) { } else if (keyAction instanceof SwitchLayerAction) {
const switchLayerAction: SwitchLayerAction = keyAction; const switchLayerAction: SwitchLayerAction = keyAction;
const content: NameValuePair[] = const content: NameValuePair[] =
@@ -370,9 +374,9 @@ export class SvgKeyboardWrapComponent implements OnInit, OnChanges {
value: switchLayerAction.switchLayerMode === SwitchLayerMode.toggle ? 'On' : 'Off' value: switchLayerAction.switchLayerMode === SwitchLayerMode.toggle ? 'On' : 'Off'
} }
]; ];
return Observable.of(content); return of(content);
} }
return Observable.of([]); return of([]);
} }
} }

View File

@@ -3,8 +3,7 @@ import { Store } from '@ngrx/store';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do'; import { tap } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import { AppState, bootloaderActive } from '../store'; import { AppState, bootloaderActive } from '../store';
@@ -15,10 +14,12 @@ export class UhkDeviceBootloaderNotActiveGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(bootloaderActive) return this.store.select(bootloaderActive)
.do(active => { .pipe(
if (!active) { tap(active => {
this.router.navigate(['/']); if (!active) {
} this.router.navigate(['/']);
}); }
})
);
} }
} }

View File

@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do'; import { map, tap } from 'rxjs/operators';
import { AppState, deviceConnected } from '../store/index'; import { AppState, deviceConnected } from '../store/index';
@@ -14,11 +14,13 @@ export class UhkDeviceConnectedGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(deviceConnected) return this.store.select(deviceConnected)
.do(connected => { .pipe(
if (connected) { tap(connected => {
this.router.navigate(['/']); if (connected) {
} this.router.navigate(['/']);
}) }
.map(connected => !connected); }),
map(connected => !connected)
);
} }
} }

View File

@@ -2,10 +2,9 @@ import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do'; import { tap } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import { AppState, deviceConnected } from '../store/index'; import { AppState, deviceConnected } from '../store';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@Injectable() @Injectable()
@@ -15,10 +14,12 @@ export class UhkDeviceDisconnectedGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(deviceConnected) return this.store.select(deviceConnected)
.do(connected => { .pipe(
if (!connected) { tap(connected => {
this.router.navigate(['/detection']); if (!connected) {
} this.router.navigate(['/detection']);
}); }
})
);
} }
} }

View File

@@ -2,9 +2,7 @@ import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { map, tap } from 'rxjs/operators';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import { AppState, hasDevicePermission } from '../store/index'; import { AppState, hasDevicePermission } from '../store/index';
@@ -15,11 +13,13 @@ export class UhkDeviceInitializedGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(hasDevicePermission) return this.store.select(hasDevicePermission)
.do(hasPermission => { .pipe(
if (hasPermission) { tap(hasPermission => {
this.router.navigate(['/detection']); if (hasPermission) {
} this.router.navigate(['/detection']);
}) }
.map(hasPermission => !hasPermission); }),
map(hasPermission => !hasPermission)
);
} }
} }

View File

@@ -3,8 +3,7 @@ import { Store } from '@ngrx/store';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do'; import { map, tap } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import { AppState, deviceConfigurationLoaded } from '../store'; import { AppState, deviceConfigurationLoaded } from '../store';
@@ -15,11 +14,13 @@ export class UhkDeviceLoadedGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(deviceConfigurationLoaded) return this.store.select(deviceConfigurationLoaded)
.do(loaded => { .pipe(
if (loaded) { tap(loaded => {
this.router.navigate(['/']); if (loaded) {
} this.router.navigate(['/']);
}) }
.map(loaded => !loaded); }),
map(loaded => !loaded)
);
} }
} }

View File

@@ -3,7 +3,7 @@ import { Store } from '@ngrx/store';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do'; import { tap } from 'rxjs/operators';
import { AppState, deviceConfigurationLoaded } from '../store'; import { AppState, deviceConfigurationLoaded } from '../store';
@@ -14,10 +14,12 @@ export class UhkDeviceLoadingGuard implements CanActivate {
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(deviceConfigurationLoaded) return this.store.select(deviceConfigurationLoaded)
.do(loaded => { .pipe(
if (!loaded) { tap(loaded => {
this.router.navigate(['/loading']); if (!loaded) {
} this.router.navigate(['/loading']);
}); }
})
);
} }
} }

View File

@@ -2,23 +2,24 @@ import { CanActivate, Router } from '@angular/router';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { tap } from 'rxjs/operators';
import 'rxjs/add/operator/do'; import { AppState, hasDevicePermission } from '../store';
import 'rxjs/add/operator/map';
import { AppState, hasDevicePermission } from '../store/index';
@Injectable() @Injectable()
export class UhkDeviceUninitializedGuard implements CanActivate { export class UhkDeviceUninitializedGuard implements CanActivate {
constructor(private store: Store<AppState>, private router: Router) { } constructor(private store: Store<AppState>, private router: Router) {
}
canActivate(): Observable<boolean> { canActivate(): Observable<boolean> {
return this.store.select(hasDevicePermission) return this.store.select(hasDevicePermission)
.do(hasPermission => { .pipe(
if (!hasPermission) { tap(hasPermission => {
this.router.navigate(['/privilege']); if (!hasPermission) {
} this.router.navigate(['/privilege']);
}); }
})
);
} }
} }

View File

@@ -2,10 +2,7 @@ import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store'; import { Action } from '@ngrx/store';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { first, map, tap } from 'rxjs/operators';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';
import { LogService, NotificationType } from 'uhk-common'; import { LogService, NotificationType } from 'uhk-common';
@@ -19,27 +16,33 @@ export class AppUpdateEffect {
@Effect({ dispatch: false }) @Effect({ dispatch: false })
appStart$: Observable<Action> = this.actions$ appStart$: Observable<Action> = this.actions$
.ofType(ActionTypes.UPDATE_APP) .ofType(ActionTypes.UPDATE_APP)
.first() .pipe(
.do(() => { first(),
this.appUpdateRendererService.sendUpdateAndRestartApp(); tap(() => {
}); this.appUpdateRendererService.sendUpdateAndRestartApp();
})
);
@Effect({ dispatch: false }) checkForUpdate$: Observable<Action> = this.actions$ @Effect({ dispatch: false }) checkForUpdate$: Observable<Action> = this.actions$
.ofType(AutoUpdateActionTypes.CHECK_FOR_UPDATE_NOW) .ofType(AutoUpdateActionTypes.CHECK_FOR_UPDATE_NOW)
.do(() => { .pipe(
this.logService.debug('[AppUpdateEffect] call checkForUpdate'); tap(() => {
this.appUpdateRendererService.checkForUpdate(); this.logService.debug('[AppUpdateEffect] call checkForUpdate');
}); this.appUpdateRendererService.checkForUpdate();
})
);
@Effect() handleError$: Observable<Action> = this.actions$ @Effect() handleError$: Observable<Action> = this.actions$
.ofType<UpdateErrorAction>(ActionTypes.UPDATE_ERROR) .ofType<UpdateErrorAction>(ActionTypes.UPDATE_ERROR)
.map(action => action.payload) .pipe(
.map((message: string) => { map(action => action.payload),
return new ShowNotificationAction({ map((message: string) => {
type: NotificationType.Error, return new ShowNotificationAction({
message type: NotificationType.Error,
}); message
}); });
})
);
constructor(private actions$: Actions, constructor(private actions$: Actions,
private appUpdateRendererService: AppUpdateRendererService, private appUpdateRendererService: AppUpdateRendererService,

View File

@@ -2,14 +2,9 @@ import { Injectable } from '@angular/core';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { map, startWith, tap, withLatestFrom } from 'rxjs/operators';
import { NotifierService } from 'angular-notifier'; import { NotifierService } from 'angular-notifier';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch';
import { AppStartInfo, LogService, Notification, NotificationType } from 'uhk-common'; import { AppStartInfo, LogService, Notification, NotificationType } from 'uhk-common';
import { import {
ActionTypes, ActionTypes,
@@ -32,13 +27,15 @@ export class ApplicationEffects {
@Effect() @Effect()
appStart$: Observable<Action> = this.actions$ appStart$: Observable<Action> = this.actions$
.ofType(ActionTypes.APP_BOOTSRAPPED) .ofType(ActionTypes.APP_BOOTSRAPPED)
.startWith(new AppStartedAction()) .pipe(
.do(() => { startWith(new AppStartedAction()),
this.logService.info('Renderer appStart effect start'); tap(() => {
this.appUpdateRendererService.sendAppStarted(); this.logService.info('Renderer appStart effect start');
this.appRendererService.getAppStartInfo(); this.appUpdateRendererService.sendAppStarted();
this.logService.info('Renderer appStart effect end'); this.appRendererService.getAppStartInfo();
}); this.logService.info('Renderer appStart effect end');
})
);
@Effect({dispatch: false}) @Effect({dispatch: false})
appStartInfo$: Observable<Action> = this.actions$ appStartInfo$: Observable<Action> = this.actions$
@@ -50,13 +47,15 @@ export class ApplicationEffects {
@Effect({dispatch: false}) @Effect({dispatch: false})
showNotification$: Observable<Action> = this.actions$ showNotification$: Observable<Action> = this.actions$
.ofType<ShowNotificationAction>(ActionTypes.APP_SHOW_NOTIFICATION) .ofType<ShowNotificationAction>(ActionTypes.APP_SHOW_NOTIFICATION)
.map(action => action.payload) .pipe(
.do((notification: Notification) => { map(action => action.payload),
if (notification.type === NotificationType.Undoable) { tap((notification: Notification) => {
return; if (notification.type === NotificationType.Undoable) {
} return;
this.notifierService.notify(notification.type, notification.message); }
}); this.notifierService.notify(notification.type, notification.message);
})
);
@Effect() @Effect()
processStartInfo$: Observable<Action> = this.actions$ processStartInfo$: Observable<Action> = this.actions$
@@ -77,16 +76,18 @@ export class ApplicationEffects {
@Effect({dispatch: false}) openUrlInNewWindow$ = this.actions$ @Effect({dispatch: false}) openUrlInNewWindow$ = this.actions$
.ofType<OpenUrlInNewWindowAction>(ActionTypes.OPEN_URL_IN_NEW_WINDOW) .ofType<OpenUrlInNewWindowAction>(ActionTypes.OPEN_URL_IN_NEW_WINDOW)
.withLatestFrom(this.store.select(runningInElectron)) .pipe(
.do(([action, inElectron]) => { withLatestFrom(this.store.select(runningInElectron)),
const url = action.payload; tap(([action, inElectron]) => {
const url = action.payload;
if (inElectron) { if (inElectron) {
this.appRendererService.openUrl(url); this.appRendererService.openUrl(url);
} else { } else {
window.open(url, '_blank'); window.open(url, '_blank');
} }
}); })
);
constructor(private actions$: Actions, constructor(private actions$: Actions,
private notifierService: NotifierService, private notifierService: NotifierService,

View File

@@ -2,11 +2,7 @@ import { Injectable } from '@angular/core';
import { Actions, Effect, toPayload } from '@ngrx/effects'; import { Actions, Effect, toPayload } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { map, startWith, switchMap, withLatestFrom } from 'rxjs/operators';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/operator/map';
import { NotificationType } from 'uhk-common'; import { NotificationType } from 'uhk-common';
@@ -27,32 +23,38 @@ import { ShowNotificationAction } from '../actions/app';
export class AutoUpdateSettingsEffects { export class AutoUpdateSettingsEffects {
@Effect() loadUserConfig$: Observable<Action> = this.actions$ @Effect() loadUserConfig$: Observable<Action> = this.actions$
.ofType(ActionTypes.LOAD_AUTO_UPDATE_SETTINGS) .ofType(ActionTypes.LOAD_AUTO_UPDATE_SETTINGS)
.startWith(new LoadAutoUpdateSettingsAction()) .pipe(
.switchMap(() => { startWith(new LoadAutoUpdateSettingsAction()),
let settings: AutoUpdateSettings = this.dataStorageRepository.getAutoUpdateSettings(); switchMap(() => {
if (!settings) { let settings: AutoUpdateSettings = this.dataStorageRepository.getAutoUpdateSettings();
settings = initialState; if (!settings) {
} settings = initialState;
return Observable.of(new LoadAutoUpdateSettingsSuccessAction(settings)); }
}); return Observable.of(new LoadAutoUpdateSettingsSuccessAction(settings));
})
);
@Effect() saveAutoUpdateConfig$: Observable<Action> = this.actions$ @Effect() saveAutoUpdateConfig$: Observable<Action> = this.actions$
.ofType(ActionTypes.TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP, ActionTypes.TOGGLE_PRE_RELEASE_FLAG) .ofType(ActionTypes.TOGGLE_CHECK_FOR_UPDATE_ON_STARTUP, ActionTypes.TOGGLE_PRE_RELEASE_FLAG)
.withLatestFrom(this.store.select(getAutoUpdateSettings)) .pipe(
.map(([action, config]) => { withLatestFrom(this.store.select(getAutoUpdateSettings)),
this.dataStorageRepository.saveAutoUpdateSettings(config); map(([action, config]) => {
return new SaveAutoUpdateSettingsSuccessAction(); this.dataStorageRepository.saveAutoUpdateSettings(config);
}); return new SaveAutoUpdateSettingsSuccessAction();
})
);
@Effect() sendNotification$: Observable<Action> = this.actions$ @Effect() sendNotification$: Observable<Action> = this.actions$
.ofType(ActionTypes.CHECK_FOR_UPDATE_FAILED, ActionTypes.CHECK_FOR_UPDATE_SUCCESS) .ofType(ActionTypes.CHECK_FOR_UPDATE_FAILED, ActionTypes.CHECK_FOR_UPDATE_SUCCESS)
.map(toPayload) .pipe(
.map((message: string) => { map(toPayload),
return new ShowNotificationAction({ map((message: string) => {
type: NotificationType.Info, return new ShowNotificationAction({
message type: NotificationType.Info,
}); message
}); });
})
);
constructor(private actions$: Actions, constructor(private actions$: Actions,
private dataStorageRepository: DataStorageRepositoryService, private dataStorageRepository: DataStorageRepositoryService,

View File

@@ -3,15 +3,10 @@ import { Router } from '@angular/router';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import 'rxjs/add/observable/of'; import { empty } from 'rxjs/observable/empty';
import 'rxjs/add/observable/empty'; import { timer } from 'rxjs/observable/timer';
import 'rxjs/add/observable/timer'; import { map, mergeMap, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/operator/switchMap';
import { import {
FirmwareUpgradeIpcResponse, FirmwareUpgradeIpcResponse,
@@ -58,195 +53,228 @@ export class DeviceEffects {
@Effect() @Effect()
deviceConnectionStateChange$: Observable<Action> = this.actions$ deviceConnectionStateChange$: Observable<Action> = this.actions$
.ofType<ConnectionStateChangedAction>(ActionTypes.CONNECTION_STATE_CHANGED) .ofType<ConnectionStateChangedAction>(ActionTypes.CONNECTION_STATE_CHANGED)
.withLatestFrom(this.store.select(getRouterState), this.store.select(deviceConnected)) .pipe(
.do(([action, route]) => { withLatestFrom(this.store.select(getRouterState), this.store.select(deviceConnected)),
const state = action.payload; tap(([action, route]) => {
const state = action.payload;
if (route.state && route.state.url.startsWith('/device/firmware')) { if (route.state && route.state.url.startsWith('/device/firmware')) {
return; return;
} }
if (!state.hasPermission) { if (!state.hasPermission) {
return this.router.navigate(['/privilege']); return this.router.navigate(['/privilege']);
} }
if (state.bootloaderActive) { if (state.bootloaderActive) {
return this.router.navigate(['/recovery-device']); return this.router.navigate(['/recovery-device']);
} }
if (!state.zeroInterfaceAvailable) { if (!state.zeroInterfaceAvailable) {
return this.router.navigate(['/privilege']); return this.router.navigate(['/privilege']);
} }
if (state.connected && state.zeroInterfaceAvailable) { if (state.connected && state.zeroInterfaceAvailable) {
return this.router.navigate(['/']); return this.router.navigate(['/']);
} }
return this.router.navigate(['/detection']); return this.router.navigate(['/detection']);
}) }),
.switchMap(([action, route, connected]) => { switchMap(([action, route, connected]) => {
const payload = action.payload; const payload = action.payload;
if (connected && payload.hasPermission && payload.zeroInterfaceAvailable) { if (connected && payload.hasPermission && payload.zeroInterfaceAvailable) {
return Observable.of(new LoadConfigFromDeviceAction()); return Observable.of(new LoadConfigFromDeviceAction());
} }
return Observable.empty(); return empty();
}); })
);
@Effect({dispatch: false}) @Effect({ dispatch: false })
setPrivilegeOnLinux$: Observable<Action> = this.actions$ setPrivilegeOnLinux$: Observable<Action> = this.actions$
.ofType(ActionTypes.SET_PRIVILEGE_ON_LINUX) .ofType(ActionTypes.SET_PRIVILEGE_ON_LINUX)
.do(() => { .pipe(
this.deviceRendererService.setPrivilegeOnLinux(); tap(() => {
}); this.deviceRendererService.setPrivilegeOnLinux();
})
);
@Effect() @Effect()
setPrivilegeOnLinuxReply$: Observable<Action> = this.actions$ setPrivilegeOnLinuxReply$: Observable<Action> = this.actions$
.ofType<SetPrivilegeOnLinuxReplyAction>(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY) .ofType<SetPrivilegeOnLinuxReplyAction>(ActionTypes.SET_PRIVILEGE_ON_LINUX_REPLY)
.map(action => action.payload) .pipe(
.switchMap((response: any): any => { map(action => action.payload),
if (response.success) { switchMap((response: any): any => {
this.appRendererService.getAppStartInfo(); if (response.success) {
return Observable.empty(); this.appRendererService.getAppStartInfo();
} return empty();
}
return Observable.of(new SetupPermissionErrorAction(response.error)); return of(new SetupPermissionErrorAction(response.error));
}); })
);
@Effect({dispatch: false}) @Effect({ dispatch: false })
saveConfiguration$: Observable<Action> = this.actions$ saveConfiguration$: Observable<Action> = this.actions$
.ofType(ActionTypes.SAVE_CONFIGURATION) .ofType(ActionTypes.SAVE_CONFIGURATION)
.withLatestFrom(this.store) .pipe(
.do(([action, state]) => { withLatestFrom(this.store),
setTimeout(() => this.sendUserConfigToKeyboard(state.userConfiguration, state.app.hardwareConfig), 100); tap(([action, state]) => {
}) setTimeout(() => this.sendUserConfigToKeyboard(state.userConfiguration, state.app.hardwareConfig), 100);
.switchMap(() => Observable.empty()); }),
switchMap(() => empty())
);
@Effect() @Effect()
saveConfigurationReply$: Observable<Action> = this.actions$ saveConfigurationReply$: Observable<Action> = this.actions$
.ofType<SaveConfigurationReplyAction>(ActionTypes.SAVE_CONFIGURATION_REPLY) .ofType<SaveConfigurationReplyAction>(ActionTypes.SAVE_CONFIGURATION_REPLY)
.map(action => action.payload) .pipe(
.mergeMap((response: IpcResponse) => { map(action => action.payload),
if (response.success) { mergeMap((response: IpcResponse) => {
return [ if (response.success) {
new SaveToKeyboardSuccessAction() return [
]; new SaveToKeyboardSuccessAction()
} ];
}
return [ return [
new ShowNotificationAction({ new ShowNotificationAction({
type: NotificationType.Error, type: NotificationType.Error,
message: response.error.message message: response.error.message
}), }),
new SaveToKeyboardSuccessFailed() new SaveToKeyboardSuccessFailed()
]; ];
}); })
);
@Effect() @Effect()
autoHideSaveToKeyboardButton$: Observable<Action> = this.actions$ autoHideSaveToKeyboardButton$: Observable<Action> = this.actions$
.ofType(ActionTypes.SAVE_TO_KEYBOARD_SUCCESS) .ofType(ActionTypes.SAVE_TO_KEYBOARD_SUCCESS)
.withLatestFrom(this.store) .pipe(
.switchMap(([action, state]) => Observable.timer(1000) withLatestFrom(this.store),
.mergeMap(() => { switchMap(([action, state]) => timer(1000)
const actions = [new HideSaveToKeyboardButton()]; .mergeMap(() => {
const actions = [new HideSaveToKeyboardButton()];
if (state.device.hasBackupUserConfiguration) { if (state.device.hasBackupUserConfiguration) {
actions.push(new RestoreUserConfigurationFromBackupSuccessAction()); actions.push(new RestoreUserConfigurationFromBackupSuccessAction());
this.router.navigate(['/']); this.router.navigate(['/']);
} }
return actions; return actions;
}) })
)
); );
@Effect() @Effect()
resetMouseSpeedSettings$: Observable<Action> = this.actions$ resetMouseSpeedSettings$: Observable<Action> = this.actions$
.ofType(ActionTypes.RESET_MOUSE_SPEED_SETTINGS) .ofType(ActionTypes.RESET_MOUSE_SPEED_SETTINGS)
.switchMap(() => { .pipe(
const config = this.defaultUserConfigurationService.getDefault(); switchMap(() => {
const mouseSpeedDefaultSettings = {}; const config = this.defaultUserConfigurationService.getDefault();
const mouseSpeedProps = [ const mouseSpeedDefaultSettings = {};
'mouseMoveInitialSpeed', const mouseSpeedProps = [
'mouseMoveAcceleration', 'mouseMoveInitialSpeed',
'mouseMoveDeceleratedSpeed', 'mouseMoveAcceleration',
'mouseMoveBaseSpeed', 'mouseMoveDeceleratedSpeed',
'mouseMoveAcceleratedSpeed', 'mouseMoveBaseSpeed',
'mouseScrollInitialSpeed', 'mouseMoveAcceleratedSpeed',
'mouseScrollAcceleration', 'mouseScrollInitialSpeed',
'mouseScrollDeceleratedSpeed', 'mouseScrollAcceleration',
'mouseScrollBaseSpeed', 'mouseScrollDeceleratedSpeed',
'mouseScrollAcceleratedSpeed' 'mouseScrollBaseSpeed',
]; 'mouseScrollAcceleratedSpeed'
mouseSpeedProps.forEach(prop => { ];
mouseSpeedDefaultSettings[prop] = config[prop]; mouseSpeedProps.forEach(prop => {
}); mouseSpeedDefaultSettings[prop] = config[prop];
return Observable.of(new LoadResetUserConfigurationAction(<UserConfiguration>mouseSpeedDefaultSettings)); });
}); return of(new LoadResetUserConfigurationAction(<UserConfiguration>mouseSpeedDefaultSettings));
})
);
@Effect() resetUserConfiguration$: Observable<Action> = this.actions$ @Effect() resetUserConfiguration$: Observable<Action> = this.actions$
.ofType(ActionTypes.RESET_USER_CONFIGURATION) .ofType(ActionTypes.RESET_USER_CONFIGURATION)
.switchMap(() => { .pipe(
const config = this.defaultUserConfigurationService.getDefault(); switchMap(() => {
return Observable.of(new LoadResetUserConfigurationAction(config)); const config = this.defaultUserConfigurationService.getDefault();
}); return of(new LoadResetUserConfigurationAction(config));
})
);
@Effect() saveResetUserConfigurationToDevice$ = this.actions$ @Effect() saveResetUserConfigurationToDevice$ = this.actions$
.ofType<ApplyUserConfigurationFromFileAction .ofType<ApplyUserConfigurationFromFileAction
| LoadResetUserConfigurationAction>( | LoadResetUserConfigurationAction>(
UserConfigActions.LOAD_RESET_USER_CONFIGURATION, UserConfigActions.LOAD_RESET_USER_CONFIGURATION,
UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE) UserConfigActions.APPLY_USER_CONFIGURATION_FROM_FILE)
.map(action => action.payload) .pipe(
.switchMap((config: UserConfiguration) => { map(action => action.payload),
this.dataStorageRepository.saveConfig(config); switchMap((config: UserConfiguration) => {
this.dataStorageRepository.saveConfig(config);
return Observable.of(new SaveConfigurationAction()); return of(new SaveConfigurationAction());
}); })
);
@Effect({dispatch: false}) updateFirmware$ = this.actions$ @Effect({ dispatch: false }) updateFirmware$ = this.actions$
.ofType<UpdateFirmwareAction>(ActionTypes.UPDATE_FIRMWARE) .ofType<UpdateFirmwareAction>(ActionTypes.UPDATE_FIRMWARE)
.do(() => this.deviceRendererService.updateFirmware({ .pipe(
versionInformation: getVersions() tap(() => this.deviceRendererService.updateFirmware({
})); versionInformation: getVersions()
}))
);
@Effect({dispatch: false}) updateFirmwareWith$ = this.actions$ @Effect({ dispatch: false }) updateFirmwareWith$ = this.actions$
.ofType<UpdateFirmwareWithAction>(ActionTypes.UPDATE_FIRMWARE_WITH) .ofType<UpdateFirmwareWithAction>(ActionTypes.UPDATE_FIRMWARE_WITH)
.map(action => action.payload) .pipe(
.do(data => this.deviceRendererService.updateFirmware({ map(action => action.payload),
versionInformation: getVersions(), tap(data => this.deviceRendererService.updateFirmware({
firmware: data versionInformation: getVersions(),
})); firmware: data
}))
);
@Effect() updateFirmwareReply$ = this.actions$ @Effect() updateFirmwareReply$ = this.actions$
.ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY) .ofType<UpdateFirmwareReplyAction>(ActionTypes.UPDATE_FIRMWARE_REPLY)
.map(action => action.payload) .pipe(
.switchMap((response: FirmwareUpgradeIpcResponse) map(action => action.payload),
: Observable<UpdateFirmwareSuccessAction | UpdateFirmwareFailedAction> => { switchMap((response: FirmwareUpgradeIpcResponse)
if (response.success) { : Observable<UpdateFirmwareSuccessAction | UpdateFirmwareFailedAction> => {
return Observable.of(new UpdateFirmwareSuccessAction(response.modules));
}
return Observable.of(new UpdateFirmwareFailedAction({ if (response.success) {
error: response.error, return Observable.of(new UpdateFirmwareSuccessAction(response.modules));
modules: response.modules }
}));
}); return of(new UpdateFirmwareFailedAction({
error: response.error,
modules: response.modules
}));
})
);
@Effect() restoreUserConfiguration$ = this.actions$ @Effect() restoreUserConfiguration$ = this.actions$
.ofType<ResetUserConfigurationAction>(ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP) .ofType<ResetUserConfigurationAction>(ActionTypes.RESTORE_CONFIGURATION_FROM_BACKUP)
.map(() => new SaveConfigurationAction()); .pipe(
map(() => new SaveConfigurationAction())
);
@Effect({dispatch: false}) recoveryDevice$ = this.actions$ @Effect({ dispatch: false }) recoveryDevice$ = this.actions$
.ofType<RecoveryDeviceAction>(ActionTypes.RECOVERY_DEVICE) .ofType<RecoveryDeviceAction>(ActionTypes.RECOVERY_DEVICE)
.do(() => this.deviceRendererService.recoveryDevice()); .pipe(
tap(() => this.deviceRendererService.recoveryDevice())
);
@Effect({dispatch: false}) enableUsbStackTest$ = this.actions$ @Effect({ dispatch: false }) enableUsbStackTest$ = this.actions$
.ofType<EnableUsbStackTestAction>(ActionTypes.ENABLE_USB_STACK_TEST) .ofType<EnableUsbStackTestAction>(ActionTypes.ENABLE_USB_STACK_TEST)
.do(() => this.deviceRendererService.enableUsbStackTest()); .pipe(
tap(() => this.deviceRendererService.enableUsbStackTest())
);
@Effect({dispatch: false}) startConnectionPoller$ = this.actions$ @Effect({ dispatch: false }) startConnectionPoller$ = this.actions$
.ofType(ActionTypes.START_CONNECTION_POLLER) .ofType(ActionTypes.START_CONNECTION_POLLER)
.do(() => this.deviceRendererService.startConnectionPoller()); .pipe(
tap(() => this.deviceRendererService.startConnectionPoller())
);
constructor(private actions$: Actions, constructor(private actions$: Actions,
private router: Router, private router: Router,

View File

@@ -4,14 +4,8 @@ import { Router } from '@angular/router';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import 'rxjs/add/operator/do'; import { map, pairwise, startWith, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/pairwise';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/observable/of';
import { Keymap } from 'uhk-common'; import { Keymap } from 'uhk-common';
import { findNewItem } from '../../util'; import { findNewItem } from '../../util';
@@ -24,47 +18,60 @@ export class KeymapEffects {
@Effect() loadKeymaps$: Observable<Action> = this.actions$ @Effect() loadKeymaps$: Observable<Action> = this.actions$
.ofType(KeymapActions.LOAD_KEYMAPS) .ofType(KeymapActions.LOAD_KEYMAPS)
.startWith(KeymapActions.loadKeymaps()) .pipe(
.switchMap(() => { startWith(KeymapActions.loadKeymaps()),
const presetsRequireContext = (<any>require).context('../../../res/presets', false, /.json$/); switchMap(() => {
const uhkPresets = presetsRequireContext.keys().map(presetsRequireContext) // load the presets into an array const presetsRequireContext = (<any>require).context('../../../res/presets', false, /.json$/);
.map((keymap: any) => new Keymap().fromJsonObject(keymap)); const uhkPresets = presetsRequireContext.keys().map(presetsRequireContext) // load the presets into an array
.map((keymap: any) => new Keymap().fromJsonObject(keymap));
return Observable.of(KeymapActions.loadKeymapsSuccess(uhkPresets)); return of(KeymapActions.loadKeymapsSuccess(uhkPresets));
}); })
);
@Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$ @Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$
.ofType(KeymapActions.ADD, KeymapActions.DUPLICATE) .ofType(KeymapActions.ADD, KeymapActions.DUPLICATE)
.withLatestFrom(this.store.let(getKeymaps()).pairwise(), (action, latest) => latest) .pipe(
.do(([prevKeymaps, newKeymaps]) => { withLatestFrom(this.store.let(getKeymaps())
const newKeymap = findNewItem(prevKeymaps, newKeymaps); .pipe(
this.router.navigate(['/keymap', newKeymap.abbreviation]); pairwise()
}); )
),
map(([action, latest]) => latest),
tap(([prevKeymaps, newKeymaps]) => {
const newKeymap = findNewItem(prevKeymaps, newKeymaps);
this.router.navigate(['/keymap', newKeymap.abbreviation]);
})
);
@Effect({ dispatch: false }) remove$: any = this.actions$ @Effect({ dispatch: false }) remove$: any = this.actions$
.ofType(KeymapActions.REMOVE) .ofType(KeymapActions.REMOVE)
.withLatestFrom(this.store) .pipe(
.map(latest => latest[1].userConfiguration.keymaps) withLatestFrom(this.store),
.do(keymaps => { map(latest => latest[1].userConfiguration.keymaps),
if (keymaps.length === 0) { tap(keymaps => {
this.router.navigate(['/keymap/add']); if (keymaps.length === 0) {
} else { this.router.navigate(['/keymap/add']);
const favourite: Keymap = keymaps.find(keymap => keymap.isDefault); } else {
this.router.navigate(['/keymap', favourite.abbreviation]); const favourite: Keymap = keymaps.find(keymap => keymap.isDefault);
} this.router.navigate(['/keymap', favourite.abbreviation]);
}); }
})
);
@Effect({ dispatch: false }) editAbbr$: any = this.actions$ @Effect({ dispatch: false }) editAbbr$: any = this.actions$
.ofType(KeymapActions.EDIT_ABBR) .ofType(KeymapActions.EDIT_ABBR)
.withLatestFrom(this.store) .pipe(
.do(([action, store]: [KeymapActions.EditKeymapAbbreviationAction, AppState]) => { withLatestFrom(this.store),
for (const keymap of store.userConfiguration.keymaps) { tap(([action, store]: [KeymapActions.EditKeymapAbbreviationAction, AppState]) => {
if (keymap.name === action.payload.name && keymap.abbreviation === action.payload.newAbbr) { for (const keymap of store.userConfiguration.keymaps) {
this.router.navigate(['/keymap', action.payload.newAbbr]); if (keymap.name === action.payload.name && keymap.abbreviation === action.payload.newAbbr) {
return; this.router.navigate(['/keymap', action.payload.newAbbr]);
return;
}
} }
} })
}); );
constructor(private actions$: Actions, private router: Router, private store: Store<AppState>) { } constructor(private actions$: Actions, private router: Router, private store: Store<AppState>) { }
} }

View File

@@ -3,14 +3,10 @@ import { Router } from '@angular/router';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Store, Action } from '@ngrx/store'; import { Store, Action } from '@ngrx/store';
import { map, pairwise, tap, withLatestFrom } from 'rxjs/operators';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/pairwise';
import 'rxjs/add/operator/withLatestFrom';
import { Macro } from 'uhk-common'; import { Macro } from 'uhk-common';
import { KeymapActions, MacroActions } from '../actions'; import { KeymapActions, MacroAction, MacroActions } from '../actions';
import { AppState } from '../index'; import { AppState } from '../index';
import { getMacros } from '../reducers/user-configuration'; import { getMacros } from '../reducers/user-configuration';
import { findNewItem } from '../../util'; import { findNewItem } from '../../util';
@@ -19,29 +15,42 @@ import { findNewItem } from '../../util';
export class MacroEffects { export class MacroEffects {
@Effect({ dispatch: false }) remove$: any = this.actions$ @Effect({ dispatch: false }) remove$: any = this.actions$
.ofType(MacroActions.REMOVE) .ofType<MacroAction>(MacroActions.REMOVE)
.do<any>(action => this.store.dispatch(KeymapActions.checkMacro(action.payload))) .pipe(
.withLatestFrom(this.store) tap(action => this.store.dispatch(KeymapActions.checkMacro(action.payload))),
.map(([action, state]) => state.userConfiguration.macros) withLatestFrom(this.store),
.do(macros => { map(([action, state]) => state.userConfiguration.macros),
if (macros.length === 0) { tap(macros => {
this.router.navigate(['/macro']); if (macros.length === 0) {
} else { return this.router.navigate(['/macro']);
this.router.navigate(['/macro', macros[0].id]); }
}
}); return this.router.navigate(['/macro', macros[0].id]);
}
)
);
@Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$ @Effect({ dispatch: false }) addOrDuplicate$: any = this.actions$
.ofType(MacroActions.ADD, MacroActions.DUPLICATE) .ofType<MacroAction>(MacroActions.ADD, MacroActions.DUPLICATE)
.withLatestFrom(this.store.let(getMacros()).pairwise(), (action, latest) => ([action, latest[0], latest[1]])) .pipe(
.do(([action, prevMacros, newMacros]: [Action, Macro[], Macro[]]) => { withLatestFrom(this.store.let(getMacros())
const newMacro = findNewItem(prevMacros, newMacros); .pipe(
const commands = ['/macro', newMacro.id]; pairwise()
if (action.type === MacroActions.ADD) { )
commands.push('new'); ),
} map(([action, latest]) => ([action, latest[0], latest[1]])),
this.router.navigate(commands); tap(([action, prevMacros, newMacros]: [Action, Macro[], Macro[]]) => {
}); const newMacro = findNewItem(prevMacros, newMacros);
const commands = ['/macro', newMacro.id];
if (action.type === MacroActions.ADD) {
commands.push('new');
}
this.router.navigate(commands);
})
);
constructor(private actions$: Actions, private router: Router, private store: Store<AppState>) { } constructor(private actions$: Actions,
private router: Router,
private store: Store<AppState>) {
}
} }

View File

@@ -3,17 +3,11 @@ import { Router } from '@angular/router';
import { Actions, Effect } from '@ngrx/effects'; import { Actions, Effect } from '@ngrx/effects';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { defer } from 'rxjs/observable/defer'; import { defer } from 'rxjs/observable/defer';
import { of } from 'rxjs/observable/of';
import { map, mergeMap, tap, withLatestFrom } from 'rxjs/operators';
import { Action, Store } from '@ngrx/store'; import { Action, Store } from '@ngrx/store';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/empty';
import { import {
getHardwareConfigFromDeviceResponse, getHardwareConfigFromDeviceResponse,
getUserConfigFromDeviceResponse, getUserConfigFromDeviceResponse,
@@ -57,7 +51,7 @@ import { UploadFileData } from '../../models/upload-file-data';
export class UserConfigEffects { export class UserConfigEffects {
@Effect() loadUserConfig$: Observable<Action> = defer(() => { @Effect() loadUserConfig$: Observable<Action> = defer(() => {
return Observable.of(new LoadUserConfigSuccessAction(this.getUserConfiguration())); return of(new LoadUserConfigSuccessAction(this.getUserConfiguration()));
}); });
@Effect() saveUserConfig$: Observable<Action> = (this.actions$ @Effect() saveUserConfig$: Observable<Action> = (this.actions$
@@ -66,160 +60,175 @@ export class UserConfigEffects {
KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY, KeymapActions.EDIT_DESCRIPTION, KeymapActions.SET_DEFAULT, KeymapActions.REMOVE, KeymapActions.SAVE_KEY, KeymapActions.EDIT_DESCRIPTION,
MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION, MacroActions.ADD, MacroActions.DUPLICATE, MacroActions.EDIT_NAME, MacroActions.REMOVE, MacroActions.ADD_ACTION,
MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION, MacroActions.SAVE_ACTION, MacroActions.DELETE_ACTION, MacroActions.REORDER_ACTION,
ActionTypes.RENAME_USER_CONFIGURATION, ActionTypes.SET_USER_CONFIGURATION_VALUE) as ActionTypes.RENAME_USER_CONFIGURATION, ActionTypes.SET_USER_CONFIGURATION_VALUE
Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>) ) as Observable<KeymapAction | MacroAction | RenameUserConfigurationAction>)
.withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration)) .pipe(
.mergeMap(([action, config, prevUserConfiguration]) => { withLatestFrom(this.store.select(getUserConfiguration), this.store.select(getPrevUserConfiguration)),
config.recalculateConfigurationLength(); mergeMap(([action, config, prevUserConfiguration]) => {
this.dataStorageRepository.saveConfig(config); config.recalculateConfigurationLength();
this.dataStorageRepository.saveConfig(config);
if (action.type === KeymapActions.REMOVE || action.type === MacroActions.REMOVE) { if (action.type === KeymapActions.REMOVE || action.type === MacroActions.REMOVE) {
const text = action.type === KeymapActions.REMOVE ? 'Keymap' : 'Macro'; const text = action.type === KeymapActions.REMOVE ? 'Keymap' : 'Macro';
const pathPrefix = action.type === KeymapActions.REMOVE ? 'keymap' : 'macro'; const pathPrefix = action.type === KeymapActions.REMOVE ? 'keymap' : 'macro';
const payload: UndoUserConfigData = { const payload: UndoUserConfigData = {
path: `/${pathPrefix}/${action.payload}`, path: `/${pathPrefix}/${action.payload}`,
config: prevUserConfiguration.toJsonObject() config: prevUserConfiguration.toJsonObject()
}; };
return [
new SaveUserConfigSuccessAction(config),
new ShowNotificationAction({
type: NotificationType.Undoable,
message: `${text} has been deleted`,
extra: {
payload,
type: KeymapActions.UNDO_LAST_ACTION
}
}),
new ShowSaveToKeyboardButtonAction()
];
}
return [ return [
new SaveUserConfigSuccessAction(config), new SaveUserConfigSuccessAction(config),
new ShowNotificationAction({ new DismissUndoNotificationAction(),
type: NotificationType.Undoable,
message: `${text} has been deleted`,
extra: {
payload,
type: KeymapActions.UNDO_LAST_ACTION
}
}),
new ShowSaveToKeyboardButtonAction() new ShowSaveToKeyboardButtonAction()
]; ];
} })
);
return [
new SaveUserConfigSuccessAction(config),
new DismissUndoNotificationAction(),
new ShowSaveToKeyboardButtonAction()
];
});
@Effect() undoUserConfig$: Observable<Action> = this.actions$ @Effect() undoUserConfig$: Observable<Action> = this.actions$
.ofType<UndoLastAction>(KeymapActions.UNDO_LAST_ACTION) .ofType<UndoLastAction>(KeymapActions.UNDO_LAST_ACTION)
.map(action => action.payload) .pipe(
.mergeMap((payload: UndoUserConfigData) => { map(action => action.payload),
const config = new UserConfiguration().fromJsonObject(payload.config); mergeMap((payload: UndoUserConfigData) => {
this.dataStorageRepository.saveConfig(config); const config = new UserConfiguration().fromJsonObject(payload.config);
this.router.navigate([payload.path]); this.dataStorageRepository.saveConfig(config);
return [new LoadUserConfigSuccessAction(config)]; this.router.navigate([payload.path]);
});
@Effect({dispatch: false}) loadConfigFromDevice$ = this.actions$ return [new LoadUserConfigSuccessAction(config)];
})
);
@Effect({ dispatch: false }) loadConfigFromDevice$ = this.actions$
.ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE) .ofType(ActionTypes.LOAD_CONFIG_FROM_DEVICE)
.do(() => this.deviceRendererService.loadConfigurationFromKeyboard()); .pipe(
tap(() => this.deviceRendererService.loadConfigurationFromKeyboard())
);
@Effect() loadConfigFromDeviceReply$ = this.actions$ @Effect() loadConfigFromDeviceReply$ = this.actions$
.ofType<LoadConfigFromDeviceReplyAction>(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY) .ofType<LoadConfigFromDeviceReplyAction>(ActionTypes.LOAD_CONFIG_FROM_DEVICE_REPLY)
.withLatestFrom(this.store.select(getRouterState)) .pipe(
.mergeMap(([action, route]): any => { withLatestFrom(this.store.select(getRouterState)),
const data: ConfigurationReply = action.payload; mergeMap(([action, route]): any => {
const data: ConfigurationReply = action.payload;
if (!data.success) { if (!data.success) {
return [new ShowNotificationAction({ return [new ShowNotificationAction({
type: NotificationType.Error, type: NotificationType.Error,
message: data.error message: data.error
})]; })];
}
const result = [];
let newPageDestination: Array<string>;
try {
const userConfig = getUserConfigFromDeviceResponse(data.userConfiguration);
result.push(new LoadUserConfigSuccessAction(userConfig));
if (route.state && !route.state.url.startsWith('/device/firmware')) {
newPageDestination = ['/'];
} }
} catch (err) { const result = [];
this.logService.error('Eeprom user-config parse error:', err); let newPageDestination: Array<string>;
const userConfig = new UserConfiguration().fromJsonObject(data.backupConfiguration);
result.push(new HasBackupUserConfigurationAction(!!data.backupConfiguration)); try {
result.push(new LoadUserConfigSuccessAction(userConfig)); const userConfig = getUserConfigFromDeviceResponse(data.userConfiguration);
result.push(new LoadUserConfigSuccessAction(userConfig));
newPageDestination = ['/device/restore-user-configuration']; if (route.state && !route.state.url.startsWith('/device/firmware')) {
} newPageDestination = ['/'];
}
try { } catch (err) {
const hardwareConfig = getHardwareConfigFromDeviceResponse(data.hardwareConfiguration); this.logService.error('Eeprom user-config parse error:', err);
result.push(new LoadHardwareConfigurationSuccessAction(hardwareConfig)); const userConfig = new UserConfiguration().fromJsonObject(data.backupConfiguration);
} catch (err) {
this.logService.error('Eeprom hardware-config parse error:', err);
result.push(
new ShowNotificationAction({
type: NotificationType.Error,
message: err
}));
}
result.push(new HardwareModulesLoadedAction(data.modules)); result.push(new HasBackupUserConfigurationAction(!!data.backupConfiguration));
result.push(new LoadUserConfigSuccessAction(userConfig));
if (newPageDestination) { newPageDestination = ['/device/restore-user-configuration'];
this.router.navigate(newPageDestination); }
}
return result; try {
}); const hardwareConfig = getHardwareConfigFromDeviceResponse(data.hardwareConfiguration);
result.push(new LoadHardwareConfigurationSuccessAction(hardwareConfig));
} catch (err) {
this.logService.error('Eeprom hardware-config parse error:', err);
result.push(
new ShowNotificationAction({
type: NotificationType.Error,
message: err
}));
}
@Effect({dispatch: false}) saveUserConfigInJsonFile$ = this.actions$ result.push(new HardwareModulesLoadedAction(data.modules));
if (newPageDestination) {
this.router.navigate(newPageDestination);
}
return result;
})
);
@Effect({ dispatch: false }) saveUserConfigInJsonFile$ = this.actions$
.ofType(ActionTypes.SAVE_USER_CONFIG_IN_JSON_FILE) .ofType(ActionTypes.SAVE_USER_CONFIG_IN_JSON_FILE)
.withLatestFrom(this.store.select(getUserConfiguration)) .pipe(
.do(([action, userConfiguration]) => { withLatestFrom(this.store.select(getUserConfiguration)),
const asString = JSON.stringify(userConfiguration.toJsonObject(), null, 2); tap(([action, userConfiguration]) => {
const asBlob = new Blob([asString], {type: 'text/plain'}); const asString = JSON.stringify(userConfiguration.toJsonObject(), null, 2);
saveAs(asBlob, 'UserConfiguration.json'); const asBlob = new Blob([asString], { type: 'text/plain' });
}); saveAs(asBlob, 'UserConfiguration.json');
})
);
@Effect({dispatch: false}) saveUserConfigInBinFile$ = this.actions$ @Effect({ dispatch: false }) saveUserConfigInBinFile$ = this.actions$
.ofType(ActionTypes.SAVE_USER_CONFIG_IN_BIN_FILE) .ofType(ActionTypes.SAVE_USER_CONFIG_IN_BIN_FILE)
.withLatestFrom(this.store.select(getUserConfiguration)) .pipe(
.do(([action, userConfiguration]) => { withLatestFrom(this.store.select(getUserConfiguration)),
const uhkBuffer = new UhkBuffer(); tap(([action, userConfiguration]) => {
userConfiguration.toBinary(uhkBuffer); const uhkBuffer = new UhkBuffer();
const blob = new Blob([uhkBuffer.getBufferContent()]); userConfiguration.toBinary(uhkBuffer);
saveAs(blob, 'UserConfiguration.bin'); const blob = new Blob([uhkBuffer.getBufferContent()]);
}); saveAs(blob, 'UserConfiguration.bin');
})
);
@Effect() loadUserConfigurationFromFile$ = this.actions$ @Effect() loadUserConfigurationFromFile$ = this.actions$
.ofType<LoadUserConfigurationFromFileAction>(ActionTypes.LOAD_USER_CONFIGURATION_FROM_FILE) .ofType<LoadUserConfigurationFromFileAction>(ActionTypes.LOAD_USER_CONFIGURATION_FROM_FILE)
.map(action => action.payload) .pipe(
.map((info: UploadFileData) => { map(action => action.payload),
try { map((info: UploadFileData) => {
const userConfig = new UserConfiguration(); try {
const userConfig = new UserConfiguration();
if (info.filename.endsWith('.bin')) { if (info.filename.endsWith('.bin')) {
userConfig.fromBinary(UhkBuffer.fromArray(info.data)); userConfig.fromBinary(UhkBuffer.fromArray(info.data));
} else { } else {
const buffer = new Buffer(info.data); const buffer = new Buffer(info.data);
const json = buffer.toString(); const json = buffer.toString();
userConfig.fromJsonObject(JSON.parse(json)); userConfig.fromJsonObject(JSON.parse(json));
}
if (userConfig.userConfigMajorVersion) {
return new ApplyUserConfigurationFromFileAction(userConfig);
}
return new ShowNotificationAction({
type: NotificationType.Error,
message: 'Invalid configuration specified.'
});
} catch (err) {
return new ShowNotificationAction({
type: NotificationType.Error,
message: 'Invalid configuration specified.'
});
} }
})
if (userConfig.userConfigMajorVersion) { );
return new ApplyUserConfigurationFromFileAction(userConfig);
}
return new ShowNotificationAction({
type: NotificationType.Error,
message: 'Invalid configuration specified.'
});
} catch (err) {
return new ShowNotificationAction({
type: NotificationType.Error,
message: 'Invalid configuration specified.'
});
}
});
constructor(private actions$: Actions, constructor(private actions$: Actions,
private dataStorageRepository: DataStorageRepositoryService, private dataStorageRepository: DataStorageRepositoryService,

View File

@@ -1,8 +1,8 @@
import { Action } from '@ngrx/store'; import { Action } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of'; import { of } from 'rxjs/observable/of';
import 'rxjs/add/operator/map'; import { map } from 'rxjs/operators';
import { import {
KeyAction, KeyAction,
@@ -360,29 +360,37 @@ export function getKeymap(abbr: string) {
} }
return (state$: Observable<AppState>) => getKeymaps()(state$) return (state$: Observable<AppState>) => getKeymaps()(state$)
.map((keymaps: Keymap[]) => .pipe(
keymaps.find((keymap: Keymap) => keymap.abbreviation === abbr) map((keymaps: Keymap[]) =>
keymaps.find((keymap: Keymap) => keymap.abbreviation === abbr)
)
); );
} }
export function getDefaultKeymap() { export function getDefaultKeymap() {
return (state$: Observable<AppState>) => getKeymaps()(state$) return (state$: Observable<AppState>) => getKeymaps()(state$)
.map((keymaps: Keymap[]) => .pipe(
keymaps.find((keymap: Keymap) => keymap.isDefault) map((keymaps: Keymap[]) =>
keymaps.find((keymap: Keymap) => keymap.isDefault)
)
); );
} }
export function getMacros(): (state$: Observable<AppState>) => Observable<Macro[]> { export function getMacros(): (state$: Observable<AppState>) => Observable<Macro[]> {
return (state$: Observable<AppState>) => state$ return (state$: Observable<AppState>) => state$
.map(state => state.userConfiguration.macros); .pipe(
map(state => state.userConfiguration.macros)
);
} }
export function getMacro(id: number) { export function getMacro(id: number) {
if (isNaN(id)) { if (isNaN(id)) {
return () => Observable.of<Macro>(undefined); return () => of<Macro>(undefined);
} else { } else {
return (state$: Observable<AppState>) => getMacros()(state$) return (state$: Observable<AppState>) => getMacros()(state$)
.map((macros: Macro[]) => macros.find((macro: Macro) => macro.id === id)); .pipe(
map((macros: Macro[]) => macros.find((macro: Macro) => macro.id === id))
);
} }
} }