diff --git a/src/app/actions/windows-meta/windows-meta.ts b/src/app/actions/windows-meta/windows-meta.ts index fff7bfc760..7ed02a4493 100644 --- a/src/app/actions/windows-meta/windows-meta.ts +++ b/src/app/actions/windows-meta/windows-meta.ts @@ -1,6 +1,8 @@ import { Action } from '@ngrx/store'; export const SET_ACTIVE_WINDOW_ID = 'SET_ACTIVE_WINDOW_ID'; +export const SET_WINDOW_IDS = 'SET_WINDOW_IDS'; +export const REPOSITION_WINDOW = 'REPOSITION_WINDOW'; export class SetActiveWindowIdAction implements Action { readonly type = SET_ACTIVE_WINDOW_ID; @@ -8,4 +10,16 @@ export class SetActiveWindowIdAction implements Action { constructor(public payload: { windowId: string }) {} } -export type Action = SetActiveWindowIdAction; +export class SetWindowIdsAction implements Action { + readonly type = SET_WINDOW_IDS; + + constructor(public payload: { ids: string[]}) {} +} + +export class RepositionWindowAction implements Action { + readonly type = REPOSITION_WINDOW; + + constructor(public payload: { currentPosition: number, newPosition: number }) { } +} + +export type Action = SetActiveWindowIdAction | SetWindowIdsAction | RepositionWindowAction; diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2a77bc4852..1721bba058 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -22,6 +22,7 @@ import { SharedModule } from './shared/shared.module'; import { reducer, metaReducers, reducerToken, reducerProvider } from './reducers'; import { QueryEffects } from './effects/query'; +import { WindowsEffects } from './effects/windows'; import { ComponentModule } from './components'; import { DocViewerModule } from './components/doc-viewer/doc-viewer.module'; @@ -73,7 +74,7 @@ const providers = [ ComponentModule, DocViewerModule, StoreModule.forRoot(reducerToken, { metaReducers }), - EffectsModule.forRoot([ QueryEffects ]), + EffectsModule.forRoot([ QueryEffects, WindowsEffects ]), StoreDevtoolsModule.instrument(), ToastModule.forRoot(), TranslateModule.forRoot({ diff --git a/src/app/components/window-switcher/window-switcher.component.html b/src/app/components/window-switcher/window-switcher.component.html index 15a146c37b..595ce087e9 100644 --- a/src/app/components/window-switcher/window-switcher.component.html +++ b/src/app/components/window-switcher/window-switcher.component.html @@ -1,23 +1,23 @@
+
×
diff --git a/src/app/components/window-switcher/window-switcher.component.ts b/src/app/components/window-switcher/window-switcher.component.ts index a08211c997..3dc1e22125 100644 --- a/src/app/components/window-switcher/window-switcher.component.ts +++ b/src/app/components/window-switcher/window-switcher.component.ts @@ -15,13 +15,15 @@ import config from '../../config'; }) export class WindowSwitcherComponent implements OnInit { - @Input() windows = []; + @Input() windows = {}; + @Input() windowIds = []; @Input() activeWindowId = ''; @Input() isElectron = false; @Output() activeWindowChange = new EventEmitter(); @Output() newWindowChange = new EventEmitter(); @Output() removeWindowChange = new EventEmitter(); @Output() windowNameChange = new EventEmitter(); + @Output() repositionWindowChange = new EventEmitter(); windowNameEditing = null; maxWindowCount = config.max_windows; @@ -42,4 +44,8 @@ export class WindowSwitcherComponent implements OnInit { this.windowNameEditing = null; } + moveWindow(currentPosition, newPosition) { + this.repositionWindowChange.next(({ currentPosition, newPosition })); + } + } diff --git a/src/app/containers/app/app.component.html b/src/app/containers/app/app.component.html index 7a4d8eb36d..965d6c204c 100644 --- a/src/app/containers/app/app.component.html +++ b/src/app/containers/app/app.component.html @@ -17,25 +17,28 @@ -
- - - - - - - -
+ (windowNameChange)="setWindowName($event)" + (repositionWindowChange)="repositionWindow($event)" + > +
+ + + + + + + +
diff --git a/src/app/containers/app/app.component.ts b/src/app/containers/app/app.component.ts index 73475fe4ee..b911f540ae 100644 --- a/src/app/containers/app/app.component.ts +++ b/src/app/containers/app/app.component.ts @@ -36,14 +36,14 @@ export class AppComponent { settings$: Observable; windowIds = []; - windowsArr = []; + windows = {}; activeWindowId = ''; isElectron = isElectron; isReady = false; // determines if the app is fully loaded. Assets, translations, etc. constructor( private windowService: WindowService, - private store: Store, + private store: Store, private translate: TranslateService, private electron: ElectronService ) { @@ -83,18 +83,26 @@ export class AppComponent { }); this.store .subscribe(data => { + this.windows = data.windows; this.windowIds = Object.keys(data.windows); - console.log(data.windows, this.windowIds); - this.windowsArr = this.windowIds.map(id => data.windows[id]); + + // Set the window IDs in the meta state if it does not already exist + if (data.windowsMeta.windowIds) { + this.windowIds = data.windowsMeta.windowIds; + } else { + this.store.dispatch(new windowsMetaActions.SetWindowIdsAction( { ids: this.windowIds })); + } + this.activeWindowId = data.windowsMeta.activeWindowId; + console.log(data.windows, this.windowIds); // If the active window has not been set, default it - if (this.windowsArr.length && (!this.activeWindowId || !data.windows[this.activeWindowId])) { + if (this.windowIds.length && (!this.activeWindowId || !data.windows[this.activeWindowId])) { this.store.dispatch(new windowsMetaActions.SetActiveWindowIdAction({ windowId: this.windowIds[0] })); } }); - if (!this.windowsArr.length) { + if (!this.windowIds.length) { this.windowService.newWindow(); } } @@ -151,6 +159,11 @@ export class AppComponent { this.store.dispatch(new layoutActions.SetWindowNameAction(windowId, windowName)); } + repositionWindow(data) { + const { currentPosition, newPosition } = data; + this.store.dispatch(new windowsMetaActions.RepositionWindowAction({ currentPosition, newPosition })); + } + showSettingsDialog() { this.store.dispatch(new settingsActions.ShowSettingsAction()); } diff --git a/src/app/containers/window/window.component.ts b/src/app/containers/window/window.component.ts index 8e4b231439..27104a7c0d 100644 --- a/src/app/containers/window/window.component.ts +++ b/src/app/containers/window/window.component.ts @@ -43,7 +43,7 @@ export class WindowComponent implements OnInit { responseTime$: Observable; responseStatusText$: Observable; isSubscribed$: Observable; - subscriptionResponses$: Observable>; + subscriptionResponses$: Observable; @Input() windowId: string; diff --git a/src/app/effects/windows.ts b/src/app/effects/windows.ts new file mode 100644 index 0000000000..825c987160 --- /dev/null +++ b/src/app/effects/windows.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { Store, Action } from '@ngrx/store'; +import { Effect, Actions, toPayload } from '@ngrx/effects'; +import { Observable } from 'rxjs/Observable'; + +import * as fromRoot from '../reducers'; + +import * as windowActions from '../actions/windows/windows'; +import * as windowsMetaActions from '../actions/windows-meta/windows-meta'; + +@Injectable() +export class WindowsEffects { + + @Effect() // remove, add, reposition + setWindowIDs$: Observable = this.actions$ + .ofType(windowActions.ADD_WINDOW, windowActions.REMOVE_WINDOW) + .withLatestFrom(this.store, (action: windowActions.Action, state) => { + return { windows: state.windows, action }; + }).switchMap(data => { + const windowIds = Object.keys(data.windows); + return Observable.of(new windowsMetaActions.SetWindowIdsAction({ ids: windowIds })); + }); + + constructor( + private actions$: Actions, + private store: Store + ) {} +} diff --git a/src/app/reducers/windows-meta/windows-meta.ts b/src/app/reducers/windows-meta/windows-meta.ts index 6dce01cebc..bf8842bff0 100644 --- a/src/app/reducers/windows-meta/windows-meta.ts +++ b/src/app/reducers/windows-meta/windows-meta.ts @@ -4,16 +4,31 @@ import * as windowsMeta from '../../actions/windows-meta/windows-meta'; export interface State { activeWindowId: string; + windowIds: Array; } const initialState: State = { - activeWindowId: '' + activeWindowId: '', + windowIds: [] }; export function windowsMetaReducer(state = initialState, action: windowsMeta.Action): State { switch (action.type) { case windowsMeta.SET_ACTIVE_WINDOW_ID: - return Object.assign({}, state, { activeWindowId: action.payload.windowId }); + return { ...state, activeWindowId: action.payload.windowId }; + case windowsMeta.SET_WINDOW_IDS: + return { ...state, windowIds: action.payload.ids }; + case windowsMeta.REPOSITION_WINDOW: + const curPos = action.payload.currentPosition; + const newPos = action.payload.newPosition; + + if (curPos > -1 && curPos < state.windowIds.length && newPos > -1 && newPos < state.windowIds.length) { + const arr = [ ...state.windowIds ]; + arr.splice(newPos, 0, arr.splice(curPos, 1)[0]); + + return { ...state, windowIds: [ ...arr ] }; + } + return state; default: return state; }