aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/ducks/utils/view.js
diff options
context:
space:
mode:
Diffstat (limited to 'web/src/js/ducks/utils/view.js')
-rwxr-xr-x[-rw-r--r--]web/src/js/ducks/utils/view.js243
1 files changed, 133 insertions, 110 deletions
diff --git a/web/src/js/ducks/utils/view.js b/web/src/js/ducks/utils/view.js
index 01d57b17..3b552378 100644..100755
--- a/web/src/js/ducks/utils/view.js
+++ b/web/src/js/ducks/utils/view.js
@@ -1,134 +1,157 @@
-import {ADD, UPDATE, REMOVE, REQUEST_LIST, RECEIVE_LIST} from "./list"
-
-const defaultFilterFn = x => true
-const defaultSortFn = false
-
-const makeCompareFn = sortFn => {
- let compareFn = (a, b) => {
- let akey = sortFn(a),
- bkey = sortFn(b)
- if (akey < bkey) {
- return -1
- } else if (akey > bkey) {
- return 1
- } else {
- return 0
- }
- }
- // need to adjust sortedIndexOf as well
- // if (sortFn.reverse)
- // return (a, b) => compareFn(b, a)
- return compareFn
-}
+import _ from 'lodash'
-const sortedInsert = (list, sortFn, item) => {
- let l = [...list, item]
- l.indexOf = x => sortedIndexOf(l, x, sortFn)
- let compareFn = makeCompareFn(sortFn)
-
- // only sort if sorting order is not correct yet
- if (sortFn && compareFn(list[list.length - 1], item) > 0) {
- // TODO: This is untested
- console.debug("sorting view...")
- l.sort(compareFn)
- }
- return l
-}
+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 sortedRemove = (list, sortFn, item) => {
- let itemId = item.id
- let l = list.filter(x => x.id !== itemId)
- l.indexOf = x => sortedIndexOf(l, x, sortFn)
- return l
+const defaultState = {
+ data: [],
+ indexOf: {},
}
-export function sortedIndexOf(list, value, sortFn) {
- if (!sortFn) {
- sortFn = x => 0 // This triggers the linear search for flows that have the same sort value.
- }
+export default function reduce(state = defaultState, action) {
+ switch (action.type) {
- let low = 0,
- high = list.length,
- val = sortFn(value),
- mid;
- while (low < high) {
- mid = (low + high) >>> 1;
- if (sortFn(list[mid]) < val) {
- low = mid + 1
- } else {
- high = mid
+ case UPDATE_FILTER: {
+ const data = _.values(action.list.data).filter(action.filter).sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index])),
+ }
}
- }
- // Two flows may have the same sort value.
- // we previously determined the leftmost flow with the same sort value,
- // so no we need to scan linearly
- while (list[low].id !== value.id && sortFn(list[low + 1]) === val) {
- low++
- }
- return low;
-}
+ case UPDATE_SORTER: {
+ const data = [...state.data].sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index]))
+ }
+ }
-// for when the list changes
-export function updateViewList(currentView, currentList, nextList, action, filterFn = defaultFilterFn, sortFn = defaultSortFn) {
- switch (action.cmd) {
- case REQUEST_LIST:
- return currentView
- case RECEIVE_LIST:
- return updateViewFilter(nextList, filterFn, sortFn)
case ADD:
- if (filterFn(action.item)) {
- return sortedInsert(currentView, sortFn, action.item)
+ if (state.indexOf[action.item.id] != null || !action.filter(action.item)) {
+ return state
}
- return currentView
- case UPDATE:
- // let's determine if it's in the view currently and if it should be in the view.
- let currentItemState = currentList.byId[action.item.id],
- nextItemState = action.item,
- isInView = filterFn(currentItemState),
- shouldBeInView = filterFn(nextItemState)
-
- if (!isInView && shouldBeInView)
- return sortedInsert(currentView, sortFn, action.item)
- if (isInView && !shouldBeInView)
- return sortedRemove(currentView, sortFn, action.item)
- if (isInView && shouldBeInView) {
- let s = [...currentView]
- s.indexOf = x => sortedIndexOf(s, x, sortFn)
- s[s.indexOf(currentItemState)] = nextItemState
- if (sortFn && sortFn(currentItemState) !== sortFn(nextItemState))
- s.sort(makeCompareFn(sortFn))
- return s
+ return {
+ ...state,
+ ...sortedInsert(state, action.item, action.sorter),
}
- return currentView
+
case REMOVE:
- let isInView_ = filterFn(currentList.byId[action.item.id])
- if (isInView_) {
- return sortedRemove(currentView, sortFn, action.item)
+ if (state.indexOf[action.item.id] == null) {
+ return state
+ }
+ return {
+ ...state,
+ ...sortedRemove(state, action.id),
+ }
+
+ case UPDATE: {
+ if (state.indexOf[action.item.id] == null) {
+ return
+ }
+ const nextState = {
+ ...state,
+ ...sortedRemove(state, action.id),
}
- return currentView
+ if (!action.filter(action.item)) {
+ return nextState
+ }
+ return {
+ ...nextState,
+ ...sortedInsert(nextState, action.item, action.sorter)
+ }
+ }
+
+ case RECEIVE: {
+ const data = _.values(action.list.data).filter(action.filter).sort(action.sorter)
+ return {
+ ...state,
+ data,
+ indexOf: _.fromPairs(data.map((item, index) => [item.id, index])),
+ }
+ }
+
default:
- console.error("Unknown list action: ", action)
- return currentView
+ return state
}
}
-export function updateViewFilter(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) {
- let filtered = list.list.filter(filterFn)
- if (sortFn){
- filtered.sort(makeCompareFn(sortFn))
+export function updateFilter(list, filter = defaultFilter, sorter = defaultSorter) {
+ return { type: UPDATE_FILTER, list, filter, sorter }
+}
+
+export function updateSorter(sorter = defaultSorter) {
+ return { type: UPDATE_SORTER, sorter }
+}
+
+export function add(item, filter = defaultFilter, sorter = defaultSorter) {
+ return { type: ADD, item, filter, sorter }
+}
+
+export function update(id, item, filter = defaultFilter, sorter = defaultSorter) {
+ return { type: UPDATE, id, item, filter, sorter }
+}
+
+export function remove(id) {
+ return { type: REMOVE, id }
+}
+
+export function receive(list, filter = defaultFilter, sorter = defaultSorter) {
+ 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
}
- filtered.indexOf = x => sortedIndexOf(filtered, x, sortFn)
- return filtered
+ return { data, indexOf }
}
-export function updateViewSort(list, sortFn = defaultSortFn) {
- let sorted = [...list]
- if (sortFn) {
- sorted.sort(makeCompareFn(sortFn))
+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
}
- sorted.indexOf = x => sortedIndexOf(sorted, x, sortFn)
- return sorted
+ 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
+}
+
+function defaultFilter() {
+ return true
+}
+
+function defaultSorter(a, b) {
+ return 0
}