blob: 8bcf9f634380a4f2cce22bc5c110680fc6ef773d [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import ActionTypes from './actiontypes';
import Helpers from '../helpers';
const initialState = {
isLoaded: false,
filters: [],
changes: [],
filteredChanges: [],
maxChangesListed: 100,
showingSubset: false,
lastSequenceNum: null
};
function updateChanges(state, seqNum, changes) {
const newState = {
...state,
// make a note of the most recent sequence number. This is used for a point of reference for polling for new changes
lastSequenceNum: seqNum,
isLoaded: true
};
// mark any additional changes that come after first page load as "new" so we can add a nice highlight effect
// when the new row is rendered
const firstBatch = newState.changes.length === 0;
newState.changes.forEach((change) => {
change.isNew = false;
});
const newChanges = changes.map((change) => {
const seq = Helpers.getSeqNum(change.seq);
return {
id: change.id,
seq: seq,
deleted: _.has(change, 'deleted') ? change.deleted : false,
changes: change.changes,
doc: change.doc, // only populated with ?include_docs=true
isNew: !firstBatch
};
});
// add the new changes to the start of the list
newState.changes = newChanges.concat(newState.changes);
updateFilteredChanges(newState);
return newState;
}
function addFilter(state, filter) {
const newFilters = state.filters.slice();
newFilters.push(filter);
const newState = {
...state,
filters: newFilters
};
updateFilteredChanges(newState);
return newState;
}
function removeFilter(state, filter) {
const newFilters = state.filters.slice();
const idx = newFilters.indexOf(filter);
if (idx >= 0) {
newFilters.splice(idx, 1);
}
const newState = {
...state,
filters: newFilters
};
updateFilteredChanges(newState);
return newState;
}
function updateFilteredChanges(state) {
state.showingSubset = false;
let numMatches = 0;
state.filteredChanges = state.changes.filter((change) => {
if (numMatches >= state.maxChangesListed) {
state.showingSubset = true;
return false;
}
let changeStr = JSON.stringify(change);
let match = state.filters.every((filter) => {
return new RegExp(filter, 'i').test(changeStr);
});
if (match) {
numMatches++;
}
return match;
});
}
export default function changes (state = initialState, action) {
switch (action.type) {
case ActionTypes.UPDATE_CHANGES:
// only bother updating the list of changes if the seq num has changed
if (state.lastSequenceNum !== action.seqNum) {
return updateChanges(state, action.seqNum, action.changes);
}
return state;
case ActionTypes.ADD_CHANGES_FILTER_ITEM:
return addFilter(state, action.filter);
case ActionTypes.REMOVE_CHANGES_FILTER_ITEM:
return removeFilter(state, action.filter);
default:
return state;
}
}