diff options
Diffstat (limited to 'web/src')
-rw-r--r-- | web/src/js/components/ProxyApp.jsx | 43 | ||||
-rw-r--r-- | web/src/js/connection.js | 6 | ||||
-rw-r--r-- | web/src/js/ducks/index.js | 2 | ||||
-rw-r--r-- | web/src/js/ducks/settings.js | 92 | ||||
-rw-r--r-- | web/src/js/store/store.js | 96 | ||||
-rw-r--r-- | web/src/js/store/view.js | 0 |
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 |