From d6fcd7e06d24ce75a17b82290ce54a802bc5e868 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Fri, 3 Jun 2016 17:11:23 -0700 Subject: web: implement redux store fetching --- web/src/js/app.js | 9 ++- web/src/js/components/eventlog.js | 1 - web/src/js/connection.js | 15 +++-- web/src/js/ducks/eventLog.js | 29 +++++---- web/src/js/ducks/list.js | 21 ------- web/src/js/ducks/utils/list.js | 121 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 38 deletions(-) delete mode 100644 web/src/js/ducks/list.js create mode 100644 web/src/js/ducks/utils/list.js (limited to 'web/src/js') diff --git a/web/src/js/app.js b/web/src/js/app.js index fc99f1d2..b49de002 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -2,7 +2,9 @@ import React from "react" import {render} from 'react-dom' import {applyMiddleware, createStore} from 'redux' import {Provider} from 'react-redux' -import createLogger from 'redux-logger'; +import createLogger from 'redux-logger' +import thunkMiddleware from 'redux-thunk' + import Connection from "./connection" import {App} from "./components/proxyapp.js" @@ -11,7 +13,10 @@ import {addLogEntry} from "./ducks/eventLog"; // logger must be last const logger = createLogger(); -const store = createStore(rootReducer, applyMiddleware(logger)); +const store = createStore( + rootReducer, + applyMiddleware(thunkMiddleware, logger) +); window.onerror = function (msg) { store.dispatch(addLogEntry(msg)); diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 95889a66..6ada58ff 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -64,7 +64,6 @@ class EventLogContents extends React.Component { } setHeight(id, node) { - console.log("setHeight", id, node); if (node && !this.heights[id]) { const height = node.offsetHeight; if (this.heights[id] !== height) { diff --git a/web/src/js/connection.js b/web/src/js/connection.js index 75c2cf25..090dbb29 100644 --- a/web/src/js/connection.js +++ b/web/src/js/connection.js @@ -1,6 +1,7 @@ import {ConnectionActions, EventLogActions} from "./actions.js"; import {AppDispatcher} from "./dispatcher.js"; -import * as websocketActions from "./ducks/websocket" +import * as webSocketActions from "./ducks/websocket" +import * as eventLogActions from "./ducks/eventLog" export default function Connection(url, dispatch) { if (url[0] === "/") { @@ -9,14 +10,20 @@ export default function Connection(url, dispatch) { var ws = new WebSocket(url); ws.onopen = function () { - dispatch(websocketActions.connected()); - ConnectionActions.open(); + dispatch(webSocketActions.connected()) + dispatch(eventLogActions.fetchLogEntries()) + ConnectionActions.open() //TODO: fetch stuff! }; ws.onmessage = function (m) { var message = JSON.parse(m.data); AppDispatcher.dispatchServerAction(message); - dispatch(message); + switch (message.type) { + case eventLogActions.UPDATE_LOG: + return dispatch(eventLogActions.updateLogEntries(message)) + default: + console.warn("unknown message", message) + } }; ws.onerror = function () { ConnectionActions.error(); diff --git a/web/src/js/ducks/eventLog.js b/web/src/js/ducks/eventLog.js index 2040711c..081a2276 100644 --- a/web/src/js/ducks/eventLog.js +++ b/web/src/js/ducks/eventLog.js @@ -1,8 +1,17 @@ -import getList, {ADD} from "./list" +import makeList, {ADD} from "./utils/list" + const TOGGLE_FILTER = 'TOGGLE_EVENTLOG_FILTER' const TOGGLE_VISIBILITY = 'TOGGLE_EVENTLOG_VISIBILITY' -const UPDATE_LIST = "UPDATE_EVENTLOG" +export const UPDATE_LOG = "UPDATE_EVENTLOG" + +const { + reduceList, + addToList, + updateList, + fetchList, +} = makeList(UPDATE_LOG, "/events"); +export {updateList as updateLogEntries, fetchList as fetchLogEntries} const defaultState = { visible: false, @@ -11,7 +20,7 @@ const defaultState = { "info": true, "web": true }, - events: getList(), + events: reduceList(), filteredEvents: [], } @@ -32,8 +41,8 @@ export default function reducer(state = defaultState, action) { ...state, visible: !state.visible } - case UPDATE_LIST: - const events = getList(state.events, action) + case UPDATE_LOG: + const events = reduceList(state.events, action) return { ...state, events, @@ -53,9 +62,9 @@ export function toggleEventLogVisibility() { } let id = 0; export function addLogEntry(message, level = "web") { - return { - type: UPDATE_LIST, - cmd: ADD, - data: {message, level, id: `log-${id++}`} - } + return addToList({ + message, + level, + id: `log-${id++}` + }) } \ No newline at end of file diff --git a/web/src/js/ducks/list.js b/web/src/js/ducks/list.js deleted file mode 100644 index 0b3771e2..00000000 --- a/web/src/js/ducks/list.js +++ /dev/null @@ -1,21 +0,0 @@ -export const ADD = 'add' - -const defaultState = { - list: [], - //isFetching: false, - //updateBeforeFetch: [], - indexOf: {}, - //views: {} -}; - -export default function getList(state = defaultState, action = {}) { - switch (action.cmd) { - case ADD: - return { - list: [...state.list, action.data], - indexOf: {...state.indexOf, [action.data.id]: state.list.length}, - } - default: - return state - } -} \ No newline at end of file diff --git a/web/src/js/ducks/utils/list.js b/web/src/js/ducks/utils/list.js new file mode 100644 index 00000000..37b2ae3a --- /dev/null +++ b/web/src/js/ducks/utils/list.js @@ -0,0 +1,121 @@ +import {fetchApi} from "../../utils"; + +const ADD = "ADD" +const REQUEST_LIST = "REQUEST_LIST" +const RECEIVE_LIST = "RECEIVE_LIST" + + +const defaultState = { + list: [], + isFetching: false, + actionsDuringFetch: [], + byId: {}, + indexOf: {}, +}; + +export default function makeList(actionType, fetchURL) { + function reduceList(state = defaultState, action = {}) { + + if (action.type !== actionType) { + return state + } + + // Handle cases where we finished fetching or are still fetching. + if (action.cmd === RECEIVE_LIST) { + let s = { + isFetching: false, + actionsDuringFetch: [], + list: action.list, + byId: {}, + indexOf: {} + } + for (let i = 0; i < action.list.length; i++) { + let item = action.list[i] + s.byId[item.id] = item + s.indexOf[item.id] = i + } + for (action of state.actionsDuringFetch) { + s = reduceList(s, action) + } + return s + } else if (state.isFetching) { + return { + ...state, + actionsDuringFetch: [...state.actionsDuringFetch, action] + } + } + + switch (action.cmd) { + case ADD: + return { + list: [...state.list, action.item], + byId: {...state.byId, [action.item.id]: action.item}, + indexOf: {...state.indexOf, [action.item.id]: state.list.length}, + } + + case REQUEST_LIST: + return { + ...defaultState, + isFetching: true + } + + default: + console.debug("unknown action", action.type) + return state + } + } + + function addToList(item) { + return { + type: actionType, + cmd: ADD, + item + } + } + + + function updateList(action) { + /* This action creater takes all WebSocket events */ + return dispatch => { + switch (action.cmd) { + case "add": + return dispatch(addToList(action.data)) + case "reset": + return dispatch(fetchList()) + default: + console.error("unknown list update", action) + } + } + } + + function requestList() { + return { + type: actionType, + cmd: REQUEST_LIST, + } + } + + function receiveList(list) { + return { + type: actionType, + cmd: RECEIVE_LIST, + list + } + } + + function fetchList() { + return dispatch => { + + dispatch(requestList()) + + fetchApi(fetchURL).then(response => { + return response.json().then(json => { + dispatch(receiveList(json.data)) + }) + }) + } + } + + + return {reduceList, addToList, updateList, fetchList} +} \ No newline at end of file -- cgit v1.2.3