aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/js')
-rw-r--r--web/src/js/components/ProxyApp.jsx43
-rw-r--r--web/src/js/connection.js6
-rw-r--r--web/src/js/ducks/index.js2
-rw-r--r--web/src/js/ducks/settings.js92
-rw-r--r--web/src/js/store/store.js96
-rw-r--r--web/src/js/store/view.js0
6 files changed, 111 insertions, 128 deletions
diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx
index c458639d..8129b0f0 100644
--- a/web/src/js/components/ProxyApp.jsx
+++ b/web/src/js/components/ProxyApp.jsx
@@ -3,10 +3,10 @@ import ReactDOM from 'react-dom'
import _ from 'lodash'
import { connect } from 'react-redux'
+import { fetch as fetchSettings } from '../ducks/settings'
import Header from './Header'
import EventLog from './EventLog'
import Footer from './Footer'
-import { SettingsStore } from '../store/store.js'
import { Key } from '../utils.js'
class ProxyAppMain extends Component {
@@ -22,17 +22,9 @@ class ProxyAppMain extends Component {
constructor(props, context) {
super(props, context)
- this.settingsStore = new SettingsStore()
-
- // Default Settings before fetch
- _.extend(this.settingsStore.dict, {})
-
- this.state = { settings: this.settingsStore.dict }
-
this.focus = this.focus.bind(this)
this.onKeyDown = this.onKeyDown.bind(this)
this.updateLocation = this.updateLocation.bind(this)
- this.onSettingsChange = this.onSettingsChange.bind(this)
}
/**
@@ -58,30 +50,16 @@ class ProxyAppMain extends Component {
return _.clone(this.props.location.query)
}
+ componentWillMount() {
+ this.props.fetchSettings();
+ }
+
/**
- * @todo remove settings store
* @todo connect websocket here
* @todo listen to window's key events
*/
componentDidMount() {
this.focus()
- this.settingsStore.addListener('recalculate', this.onSettingsChange)
- }
-
- /**
- * @todo remove settings store
- * @todo disconnect websocket here
- * @todo stop listening to window's key events
- */
- componentWillUnmount() {
- this.settingsStore.removeListener('recalculate', this.onSettingsChange)
- }
-
- /**
- * @todo move to actions
- */
- onSettingsChange() {
- this.setState({ settings: this.settingsStore.dict })
}
/**
@@ -139,8 +117,7 @@ class ProxyAppMain extends Component {
}
render() {
- const { showEventLog, location, children } = this.props
- const { settings } = this.state
+ const { showEventLog, location, children, settings } = this.props
const query = this.getQuery()
return (
<div id="container" tabIndex="0" onKeyDown={this.onKeyDown}>
@@ -160,6 +137,10 @@ class ProxyAppMain extends Component {
export default connect(
state => ({
- showEventLog: state.eventLog.visible
- })
+ showEventLog: state.eventLog.visible,
+ settings: state.settings.settings,
+ }),
+ {
+ fetchSettings,
+ }
)(ProxyAppMain)
diff --git a/web/src/js/connection.js b/web/src/js/connection.js
index 5961909e..a2582288 100644
--- a/web/src/js/connection.js
+++ b/web/src/js/connection.js
@@ -3,6 +3,7 @@ import {AppDispatcher} from "./dispatcher.js";
import * as webSocketActions from "./ducks/websocket"
import * as eventLogActions from "./ducks/eventLog"
import * as flowActions from "./ducks/flows"
+import * as settingsActions from './ducks/settings'
export default function Connection(url, dispatch) {
if (url[0] === "/") {
@@ -12,6 +13,7 @@ export default function Connection(url, dispatch) {
var ws = new WebSocket(url);
ws.onopen = function () {
dispatch(webSocketActions.connected())
+ dispatch(settingsActions.fetch())
dispatch(flowActions.fetchFlows())
// workaround to make sure that our state is already available.
.then(() => {
@@ -28,6 +30,8 @@ export default function Connection(url, dispatch) {
return dispatch(eventLogActions.updateLogEntries(message))
case flowActions.UPDATE_FLOWS:
return dispatch(flowActions.updateFlows(message))
+ case settingsActions.WS_MSG_TYPE:
+ return dispatch(settingsActions.handleWsMsg(message))
default:
console.warn("unknown message", message)
}
@@ -42,4 +46,4 @@ export default function Connection(url, dispatch) {
dispatch(webSocketActions.disconnected());
};
return ws;
-} \ No newline at end of file
+}
diff --git a/web/src/js/ducks/index.js b/web/src/js/ducks/index.js
index fee4d792..ffde1a64 100644
--- a/web/src/js/ducks/index.js
+++ b/web/src/js/ducks/index.js
@@ -2,12 +2,14 @@ import {combineReducers} from 'redux'
import eventLog from './eventLog'
import websocket from './websocket'
import flows from './flows'
+import settings from './settings'
import ui from './ui'
const rootReducer = combineReducers({
eventLog,
websocket,
flows,
+ settings,
ui
})
diff --git a/web/src/js/ducks/settings.js b/web/src/js/ducks/settings.js
new file mode 100644
index 00000000..37ff04de
--- /dev/null
+++ b/web/src/js/ducks/settings.js
@@ -0,0 +1,92 @@
+import { StoreCmds } from '../actions'
+import { addLogEntry } from './eventLog'
+
+export const WS_MSG_TYPE = 'settings'
+export const WS_MSG_CMD_RESET = 'reset'
+export const WS_MSG_CMD_UPDATE = 'update'
+
+export const BEGIN_FETCH = 'SETTINGS_BEGIN_FETCH'
+export const FETCHED = 'SETTINGS_FETCHED'
+export const RESET = 'SETTINGS_RESET'
+export const FETCH_ERROR = 'SETTINGS_FETCH_ERROR'
+export const RECV_WS_MSG = 'SETTINGS_RECV_WS_MSG'
+
+const defaultState = { settings: {}, pendings: null, req: null }
+
+export default function reduce(state = defaultState, action) {
+ switch (action.type) {
+
+ case BEGIN_FETCH:
+ return { ...state, pendings: [], req: action.req }
+
+ case FETCHED:
+ const pendings = state.pendings || []
+ return { ...state, pendings: null, settings: pendings.reduce(reduceData, action.data) }
+
+ case RESET:
+ return { ...state, pendings: null, settings: action.data || {} }
+
+ case RECV_WS_MSG:
+ if (state.pendings) {
+ return { ...state, pendings: state.pendings.concat(action) }
+ }
+ return { ...state, settings: reduceData(state.settings, action) }
+
+ default:
+ return state
+ }
+}
+
+function reduceData(data, action) {
+ switch (action.cmd) {
+
+ case WS_MSG_CMD_RESET:
+ return action.data || {}
+
+ case WS_MSG_CMD_UPDATE:
+ return _.merge({}, data, action.data)
+
+ default:
+ return data
+ }
+}
+
+export function fetch() {
+ return dispatch => {
+ const req = $.getJSON('/settings')
+ .done(msg => dispatch(handleFetchResponse(msg.data)))
+ .fail(error => dispatch(handleFetchError(error)));
+
+ dispatch({ type: BEGIN_FETCH, req })
+
+ return req
+ }
+}
+
+export function handleWsMsg(msg) {
+ return (dispatch, getState) => {
+ if (msg.cmd !== StoreCmds.RESET) {
+ return dispatch({ type: RECV_WS_MSG, cmd: msg.cmd, data: msg.data })
+ }
+ const req = getState().settings.req
+ if (req) {
+ req.abort()
+ }
+ dispatch(reset(msg.data))
+ }
+}
+
+export function handleFetchResponse(data) {
+ return { type: FETCHED, data }
+}
+
+export function reset(data) {
+ return { type: RESET, data }
+}
+
+export function handleFetchError(error) {
+ return (dispatch, getState) => {
+ dispatch(addLogEntry(error.stack || error.message || error))
+ dispatch({ type: FETCH_ERROR, error })
+ }
+}
diff --git a/web/src/js/store/store.js b/web/src/js/store/store.js
deleted file mode 100644
index f3e2074f..00000000
--- a/web/src/js/store/store.js
+++ /dev/null
@@ -1,96 +0,0 @@
-
-import _ from "lodash";
-import $ from "jquery";
-import {EventEmitter} from 'events';
-import {ActionTypes, StoreCmds} from "../actions.js";
-import {AppDispatcher} from "../dispatcher.js";
-
-
-function DictStore() {
- EventEmitter.call(this);
- this.reset();
-}
-_.extend(DictStore.prototype, EventEmitter.prototype, {
- update: function (dict) {
- _.merge(this.dict, dict);
- this.emit("recalculate");
- },
- reset: function (dict) {
- this.dict = dict || {};
- this.emit("recalculate");
- }
-});
-
-function LiveStoreMixin(type) {
- this.type = type;
-
- this._updates_before_fetch = undefined;
- this._fetchxhr = false;
-
- this.handle = this.handle.bind(this);
- AppDispatcher.register(this.handle);
-
- // Avoid double-fetch on startup.
- if (!(window.ws && window.ws.readyState === WebSocket.CONNECTING)) {
- this.fetch();
- }
-}
-_.extend(LiveStoreMixin.prototype, {
- handle: function (event) {
- if (event.type === ActionTypes.CONNECTION_OPEN) {
- return this.fetch();
- }
- if (event.type === this.type) {
- if (event.cmd === StoreCmds.RESET) {
- this.fetch(event.data);
- } else if (this._updates_before_fetch) {
- console.log("defer update", event);
- this._updates_before_fetch.push(event);
- } else {
- this[event.cmd](event.data);
- }
- }
- },
- close: function () {
- AppDispatcher.unregister(this.handle);
- },
- fetch: function (data) {
- console.log("fetch " + this.type);
- if (this._fetchxhr) {
- this._fetchxhr.abort();
- }
- this._updates_before_fetch = []; // (JS: empty array is true)
- if (data) {
- this.handle_fetch(data);
- } else {
- this._fetchxhr = $.getJSON("/" + this.type)
- .done(function (message) {
- this.handle_fetch(message.data);
- }.bind(this))
- .fail(function () {
- console.error("Could not fetch " + this.type)
- }.bind(this));
- }
- },
- handle_fetch: function (data) {
- this._fetchxhr = false;
- console.log(this.type + " fetched.", this._updates_before_fetch);
- this.reset(data);
- var updates = this._updates_before_fetch;
- this._updates_before_fetch = false;
- for (var i = 0; i < updates.length; i++) {
- this.handle(updates[i]);
- }
- },
-});
-
-function LiveDictStore(type) {
- DictStore.call(this);
- LiveStoreMixin.call(this, type);
-}
-_.extend(LiveDictStore.prototype, DictStore.prototype, LiveStoreMixin.prototype);
-
-
-export function SettingsStore() {
- return new LiveDictStore(ActionTypes.SETTINGS_STORE);
-} \ No newline at end of file
diff --git a/web/src/js/store/view.js b/web/src/js/store/view.js
deleted file mode 100644
index e69de29b..00000000
--- a/web/src/js/store/view.js
+++ /dev/null