aboutsummaryrefslogtreecommitdiffstats
path: root/web/src
diff options
context:
space:
mode:
authorJason <jason.daurus@gmail.com>2016-06-23 23:20:41 +0800
committerJason <jason.daurus@gmail.com>2016-06-23 23:20:41 +0800
commit5adb7a54fd689f69d5734d64fea0d3de43f4ce6d (patch)
tree4c733db43737e1b6d02fe81a14e1a1ce08ecf06b /web/src
parent397554b7c7ceddb54755605dc5df29731bb37214 (diff)
downloadmitmproxy-5adb7a54fd689f69d5734d64fea0d3de43f4ce6d.tar.gz
mitmproxy-5adb7a54fd689f69d5734d64fea0d3de43f4ce6d.tar.bz2
mitmproxy-5adb7a54fd689f69d5734d64fea0d3de43f4ce6d.zip
[web] separate views and list
Diffstat (limited to 'web/src')
-rw-r--r--web/src/js/ducks/eventLog.js5
-rw-r--r--web/src/js/ducks/flows.js112
-rw-r--r--web/src/js/ducks/utils/list.js129
-rwxr-xr-xweb/src/js/ducks/utils/view.js139
-rwxr-xr-xweb/src/js/ducks/views.js35
-rwxr-xr-xweb/src/js/ducks/views/main.js166
6 files changed, 413 insertions, 173 deletions
diff --git a/web/src/js/ducks/eventLog.js b/web/src/js/ducks/eventLog.js
index 4eba8b54..61b5882f 100644
--- a/web/src/js/ducks/eventLog.js
+++ b/web/src/js/ducks/eventLog.js
@@ -16,7 +16,8 @@ const defaultState = {
logId: 0,
visible: false,
filters: { debug: false, info: true, web: true },
- list: reduceList(undefined, { type: Symbol('EVENTLOG_INIT_LIST') })
+ list: reduceList(undefined, { type: Symbol('EVENTLOG_INIT_LIST') }),
+ view: reduceView(undefined, viewActions.init([]))
}
export default function reduce(state = defaultState, action) {
@@ -30,7 +31,7 @@ export default function reduce(state = defaultState, action) {
return {
...state,
filters,
- list: reduceList(state.list, listActions.updateFilter(e => filters[e.level]))
+ view: reduceView(state.list, listActions.updateFilter(e => filters[e.level], state.list))
}
case ADD:
diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js
index 5825efa1..4111c8bc 100644
--- a/web/src/js/ducks/flows.js
+++ b/web/src/js/ducks/flows.js
@@ -1,124 +1,66 @@
-import { fetchApi as fetch } from '../utils'
-import { CMD_RESET as WS_CMD_RESET } from './websocket'
import reduceList, * as listActions from './utils/list'
+import reduceViews, * as viewsActions from './views'
-export const WS_MSG_TYPE ='UPDATE_FLOWS'
+export const WS_MSG_TYPE = 'UPDATE_FLOWS'
-export const UPDATE_FILTER = 'FLOWS_UPDATE_FLOW_FILTER'
-export const UPDATE_HIGHLIGHT = 'FLOWS_UPDATE_FLOW_HIGHLIGHT'
-export const UPDATE_SORT = 'FLOWS_UPDATE_FLOW_SORT'
-export const WS_MSG = 'FLOWS_WS_MSG'
-export const SELECT_FLOW = 'FLOWS_SELECT_FLOW'
-export const REQUEST_ACTION = 'FLOWS_REQUEST_ACTION'
+export const ADD = 'FLOWS_ADD'
+export const UPDATE = 'FLOWS_UPDATE'
+export const REMOVE = 'FLOWS_REMOVE'
export const REQUEST = 'FLOWS_REQUEST'
export const RECEIVE = 'FLOWS_RECEIVE'
+export const WS_MSG = 'FLOWS_WS_MSG'
+export const REQUEST_ACTION = 'FLOWS_REQUEST_ACTION'
export const FETCH_ERROR = 'FLOWS_FETCH_ERROR'
const defaultState = {
- selected: [],
- sorter: {},
- filter: null,
- highlight: null,
- list: reduceList(undefined, { type: Symbol('FLOWS_INIT_LIST') }),
+ list: null,
+ views: null,
}
export default function reduce(state = defaultState, action) {
switch (action.type) {
- case UPDATE_FILTER:
+ case ADD:
return {
...state,
- filter: action.filter,
- list: reduceList(state.list, listActions.updateFilter(makeFilterFun(action.filter))),
+ list: reduceList(state.list, listActions.add(action.item)),
+ views: reduceViews(state.views, viewsActions.add(action.item)),
}
- case UPDATE_HIGHLIGHT:
+ case UPDATE:
return {
...state,
- highlight: action.highlight,
+ list: reduceList(state.list, listActions.update(action.item.id, action.item)),
+ views: reduceViews(state.views, viewsActions.update(action.item.id, action.item)),
}
- case UPDATE_SORTER:
+ case REMOVE:
return {
...state,
- sorter: { column: action.column, desc: action.desc },
- list: reduceList(state.list, listActions.updateSorter(makeSortFun(action.sortKeyFun, action.desc))),
- }
-
- case SELECT_FLOW:
- return {
- ...state,
- selected: [action.id],
- }
-
- case WS_MSG:
- return {
- ...state,
- list: reduceList(state.list, listActions.handleWsMsg(action.msg)),
+ list: reduceList(state.list, listActions.remove(action.item.id)),
+ views: reduceViews(state.views, viewsActions.remove(action.item.id)),
}
case REQUEST:
return {
...state,
- list: reduceList(state.list, listActions.request())
+ list: reduceList(state.list, listActions.request()),
}
case RECEIVE:
+ const list = reduceList(state.list, listActions.receive(action.list))
return {
...state,
- list: reduceList(state.list, listActions.receive(action.list))
+ list,
+ views: reduceViews(state.views, viewsActions.receive(list)),
}
default:
- return state
- }
-}
-
-function makeFilterFun(filter) {
- return filter ? Filt.parse(filter) : () => true
-}
-
-function makeSortFun(sortKeyFun, desc) {
- return (a, b) => {
- const ka = sortKeyFun(a)
- const kb = sortKeyFun(b)
- if (ka > kb) {
- return desc ? -1 : 1
- }
- if (ka < kb) {
- return desc ? 1 : -1
- }
- return 0
- }
-}
-
-/**
- * @public
- */
-export function updateFilter(filter) {
- return { type: UPDATE_FILTER, filter }
-}
-
-/**
- * @public
- */
-export function updateHighlight(highlight) {
- return { type: UPDATE_HIGHLIGHT, highlight }
-}
-
-/**
- * @public
- */
-export function updateSorter(column, desc, sortKeyFun) {
- return { type: UPDATE_SORTER, column, desc, sortKeyFun }
-}
-
-/**
- * @public
- */
-export function select(id) {
- return (dispatch, getState) => {
- dispatch({ type: SELECT_FLOW, currentSelection: getState().flows.selected[0], id })
+ return {
+ ...state,
+ list: reduceList(state.list, action),
+ views: reduceViews(state.views, action),
+ }
}
}
diff --git a/web/src/js/ducks/utils/list.js b/web/src/js/ducks/utils/list.js
index fd8ac106..b95a4527 100644
--- a/web/src/js/ducks/utils/list.js
+++ b/web/src/js/ducks/utils/list.js
@@ -1,99 +1,50 @@
+import _ from 'lodash'
import * as websocketActions from '../websocket'
-export const UPDATE_FILTER = 'LIST_UPDATE_FILTER'
-export const UPDATE_SORTER = 'LIST_UPDATE_SORTER'
-export const ADD = 'LIST_ADD'
-export const UPDATE = 'LIST_UPDATE'
-export const REMOVE = 'LIST_REMOVE'
+export const SET = 'LIST_SET'
+export const CLEAR = 'LIST_CLEAR'
export const UNKNOWN_CMD = 'LIST_UNKNOWN_CMD'
export const REQUEST = 'LIST_REQUEST'
export const RECEIVE = 'LIST_RECEIVE'
-export const FETCH_ERROR = 'LIST_FETCH_ERROR'
-export const SYM_FILTER = Symbol('LIST_SYM_FILTER')
-export const SYM_SORTER = Symbol('LIST_SYM_SORTER')
-export const SYM_PENDING = Symbol('LIST_SYM_PENDING')
-
-// @todo add indexOf map if necessary
const defaultState = {
- raw: [],
- data: [],
- byId: {},
- isFetching: false,
- [SYM_FILTER]: () => true,
- [SYM_SORTER]: () => 0,
- [SYM_PENDING]: [],
+ data: {},
+ pendingActions: null,
}
export default function reduce(state = defaultState, action) {
- if (state.isFetching && action.type !== RECEIVE) {
+ if (state.pendingActions && action.type !== RECEIVE) {
return {
...state,
- [SYM_PENDING]: [...state[SYM_PENDING], action]
+ pendingActions: [...state.pendingActions, action]
}
}
switch (action.type) {
- case UPDATE_FILTER:
+ case SET:
return {
...state,
- [SYM_FILTER]: action.filter,
- data: state.raw.filter(action.filter).sort(state[SYM_SORTER]),
+ data: { ...state.data, [action.id]: null, [action.item.id]: action.item }
}
- case UPDATE_SORTER:
+ case CLEAR:
return {
...state,
- [SYM_SORTER]: action.sorter,
- data: state.data.slice().sort(state[SYM_SORTER]),
- }
-
- case ADD:
- let data = state.data
- if (state[SYM_FILTER](action.item)) {
- data = [...state.data, action.item].sort(state[SYM_SORTER])
- }
- return {
- ...state,
- data,
- raw: [...state.raw, action.item],
- byId: { ...state.byId, [action.item.id]: action.item },
- }
-
- case UPDATE:
- // @todo optimize if necessary
- const raw = state.raw.map(item => item.id === action.id ? action.item : item)
- return {
- ...state,
- raw,
- data: raw.filter(state[SYM_FILTER]).sort(state[SYM_SORTER]),
- byId: { ...state.byId, [action.id]: null, [action.item.id]: action.item },
- }
-
- case REMOVE:
- // @todo optimize if necessary
- return {
- ...state,
- raw: state.raw.filter(item => item.id !== action.id),
- data: state.data.filter(item => item.id !== action.id),
- byId: { ...state.byId, [action.id]: null },
+ data: { ...state.data, [action.id]: null }
}
case REQUEST:
return {
...state,
- isFetching: true,
+ pendingActions: []
}
case RECEIVE:
- return state[SYM_PENDING].reduce(reduce, {
+ return state.pendingActions.reduce(reduce, {
...state,
- [SYM_PENDING]: [],
- isFetching: false,
- raw: action.list,
- data: action.list.filter(state[SYM_FILTER]).sort(state[SYM_SORTER]),
- byId: _.fromPairs(action.list.map(item => [item.id, item])),
+ pendingActions: null,
+ data: _.fromPairs(action.list.map(item => [item.id, item])),
})
default:
@@ -101,26 +52,44 @@ export default function reduce(state = defaultState, action) {
}
}
-export function updateFilter(filter) {
- return { type: UPDATE_FILTER, filter }
+/**
+ * @public
+ */
+export function add(item) {
+ return { type: SET, id: item.id, item }
}
-export function updateSorter(sorter) {
- return { type: UPDATE_SORTER, sorter }
+/**
+ * @public
+ */
+export function update(id, item) {
+ return { type: SET, id, item }
}
-export function add(item) {
- return { type: ADD, item }
+/**
+ * @public
+ */
+export function remove(id) {
+ return { type: CLEAR, id }
}
-export function update(id, item) {
- return { type: UPDATE, id, item }
+/**
+ * @public
+ */
+export function request() {
+ return { type: REQUEST }
}
-export function remove(id) {
- return { type: REMOVE, id }
+/**
+ * @public
+ */
+export function receive(list) {
+ return { type: RECEIVE, list }
}
+/**
+ * @public websocket
+ */
export function handleWsMsg(msg) {
switch (msg.cmd) {
@@ -137,15 +106,3 @@ export function handleWsMsg(msg) {
return { type: UNKNOWN_CMD, msg }
}
}
-
-export function request() {
- return { type: REQUEST }
-}
-
-export function receive(list) {
- return { type: RECEIVE, list }
-}
-
-export function fetchError(error) {
- return { type: FETCH_ERROR, error }
-}
diff --git a/web/src/js/ducks/utils/view.js b/web/src/js/ducks/utils/view.js
new file mode 100755
index 00000000..adf7fc6a
--- /dev/null
+++ b/web/src/js/ducks/utils/view.js
@@ -0,0 +1,139 @@
+import _ from 'lodash'
+
+export const UPDATE_FILTER = 'VIEW_UPDATE_FILTER'
+export const UPDATE_SORTER = 'VIEW_UPDATE_SORTER'
+export const ADD = 'VIEW_ADD'
+export const UPDATE = 'VIEW_UPDATE'
+export const REMOVE = 'VIEW_REMOVE'
+export const RECEIVE = 'VIEW_RECEIVE'
+
+const defaultState = {
+ data: [],
+ indexOf: {},
+}
+
+export default function reduce(state = defaultState, action) {
+ switch (action.type) {
+
+ case UPDATE_FILTER:
+ const data = action.list.data.filter(action.filter).sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index])),
+ }
+
+ case UPDATE_SORTER:
+ const data = state.data.slice().sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index]))
+ }
+
+ case ADD:
+ if (!action.filter(action.item)) {
+ return state
+ }
+ return {
+ ...state,
+ ...sortedInsert(state, action.item, action.sorter),
+ }
+
+ case REMOVE:
+ return {
+ ...state,
+ ...sortedRemove(state, action.id),
+ }
+
+ case UPDATE:
+ const nextState = {
+ ...state,
+ ...sortedRemove(state, action.id),
+ }
+ if (!action.filter(action.item)) {
+ return nextState
+ }
+ return {
+ ...nextState,
+ ...sortedInsert(nextState, action.item, action.sorter)
+ }
+
+ case RECEIVE:
+ const data = action.list.data.filter(action.filter).sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index])),
+ }
+
+ default:
+ return state
+ }
+}
+
+export function updateFilter(list, filter, sorter) {
+ return { type: UPDATE_FILTER, list, filter, sorter }
+}
+
+export function updateSorter(sorter) {
+ return { type: UPDATE_SORTER, sorter }
+}
+
+export function add(item, filter, sorter) {
+ return { type: ADD, item, filter, sorter }
+}
+
+export function update(id, item, filter, sorter) {
+ return { type: UPDATE, id, item, filter, sorter }
+}
+
+export function remove(id) {
+ return { type: REMOVE, id }
+}
+
+export function receive(list, filter, sorter) {
+ return { type: RECEIVE, list, filter, sorter }
+}
+
+function sortedInsert(state, item, sorter) {
+ const index = sortedIndex(state.data, item, sorter)
+ const data = [...state.data]
+ const indexOf = { ...state.indexOf }
+
+ data.splice(index, 0, item)
+ for (let i = data.length - 1; i >= index; i--) {
+ indexOf[data[i].id] = i
+ }
+
+ return { data, indexOf }
+}
+
+function sortedRemove(state, id) {
+ const index = state.indexOf[id]
+ const data = [...state.data]
+ const indexOf = { ...state.indexOf, [id]: null }
+
+ data.splice(index, 1)
+ for (let i = data.length - 1; i >= index; i--) {
+ indexOf[data[i].id] = i
+ }
+
+ return { data, indexOf }
+}
+
+function sortedIndex(list, item, sorter) {
+ let low = 0
+ let high = list.length
+
+ while (low < high) {
+ const middle = (low + high) >>> 1
+ if (sorter(item, list[middle]) > 0) {
+ low = middle + 1
+ } else {
+ high = middle
+ }
+ }
+
+ return low
+}
diff --git a/web/src/js/ducks/views.js b/web/src/js/ducks/views.js
new file mode 100755
index 00000000..88b4d355
--- /dev/null
+++ b/web/src/js/ducks/views.js
@@ -0,0 +1,35 @@
+import { combineReducers } from 'redux'
+import * as viewActions from './utils/view'
+import main from './views/main.js'
+
+export default combineReducers({
+ main,
+})
+
+/**
+ * @public
+ */
+export function add(item) {
+ return { type: ADD, item }
+}
+
+/**
+ * @public
+ */
+export function update(id, item) {
+ return { type: UPDATE, id, item }
+}
+
+/**
+ * @public
+ */
+export function remove(id) {
+ return { type: REMOVE, id }
+}
+
+/**
+ * @public
+ */
+export function receive(list) {
+ return { type: RECEIVE, list }
+}
diff --git a/web/src/js/ducks/views/main.js b/web/src/js/ducks/views/main.js
new file mode 100755
index 00000000..a9700584
--- /dev/null
+++ b/web/src/js/ducks/views/main.js
@@ -0,0 +1,166 @@
+import reduceView, * as viewActions from '../utils/list'
+import * as viewsActions from '../views'
+
+export const UPDATE_FILTER = 'MAIN_VIEW_UPDATE_FILTER'
+export const UPDATE_SORTER = 'MAIN_VIEW_UPDATE_SORTER'
+export const UPDATE_HIGHLIGHT = 'MAIN_VIEW_UPDATE_HIGHLIGHT'
+export const SELECT = 'MAIN_VIEW_SELECT'
+
+const defaultState = {
+ filter: null,
+ sorter: null,
+ highlight: null,
+ selected: [],
+ view: null,
+}
+
+export default function reduce(state = defaultState, action) {
+ switch (action.type) {
+
+ case UPDATE_HIGHLIGHT:
+ return {
+ ...state,
+ highlight: action.highlight,
+ }
+
+ case SELECT:
+ return {
+ ...state,
+ selected: [action.id]
+ }
+
+ case UPDATE_FILTER:
+ return {
+ ...state,
+ filter: action.filter,
+ view: reduceView(
+ state.view,
+ viewActions.updateFilter(
+ action.list,
+ makeFilter(action.filter),
+ makeSorter(state.sorter)
+ )
+ ),
+ }
+
+ case UPDATE_SORTER:
+ const sorter = { column: action.column, desc: action.desc }
+ return {
+ ...state,
+ sorter,
+ view: reduceView(
+ state.view,
+ viewActions.updateSorter(
+ makeSorter(sorter)
+ )
+ ),
+ }
+
+ case viewsActions.ADD:
+ return {
+ ...state,
+ view: reduceView(
+ state.view,
+ viewActions.add(
+ action.item,
+ makeFilter(state.filter),
+ makeSorter(state.sorter)
+ )
+ ),
+ }
+
+ case viewsActions.UPDATE:
+ return {
+ ...state,
+ view: reduceView(
+ state.view,
+ viewActions.update(
+ action.id,
+ action.item,
+ makeFilter(state.filter),
+ makeSorter(state.sorter)
+ )
+ ),
+ }
+
+ case viewsActions.REMOVE:
+ return {
+ ...state,
+ view: reduceView(state.view, viewActions.remove(action.id)),
+ }
+
+ case viewsActions.RECEIVE:
+ return {
+ ...state,
+ view: reduceView(
+ state.view,
+ viewActions.receive(
+ action.list,
+ makeFilter(state.filter),
+ makeSorter(state.sorter)
+ )
+ ),
+ }
+
+ default:
+ return {
+ ...state,
+ view: reduceView(state.view, action)
+ }
+ }
+}
+
+/**
+ * @public
+ */
+export function updateFilter(filter) {
+ return (dispatch, getState) => {
+ return { type: UPDATE_FILTER, filter, list: getState().flows.list }
+ }
+}
+
+/**
+ * @public
+ */
+export function updateHighlight(highlight) {
+ return { type: UPDATE_HIGHLIGHT, highlight }
+}
+
+/**
+ * @public
+ */
+export function updateSorter(column, desc) {
+ return { type: UPDATE_SORTER, column, desc }
+}
+
+/**
+ * @public
+ */
+export function select(id) {
+ return { type: SELECT, currentSelection: getState().flows.views.main.selected[0], id }
+}
+
+/**
+ * @private
+ */
+function makeFilter(filter) {
+ return filter ? Filt.parse(filter) : () => true
+}
+
+/**
+ * @private
+ */
+function makeSorter(column, desc) {
+ const sortKeyFun = sortKeyFuns[column]
+ return (a, b) => {
+ const ka = sortKeyFun(a)
+ const kb = sortKeyFun(b)
+ if (ka > kb) {
+ return desc ? -1 : 1
+ }
+ if (ka < kb) {
+ return desc ? 1 : -1
+ }
+ return 0
+ }
+}