Finish up the queryTransitions refactor

pull/10616/head
Will Piers 2016-10-31 15:18:19 -07:00
parent d3a2c2e962
commit 8bc46b1cae
3 changed files with 138 additions and 114 deletions

View File

@ -175,6 +175,7 @@ describe('Chronograf.Reducers.queryConfig', () => {
const nextState = reducer(initialState, action);
console.log('im nextstate :)', nextState)
expect(nextState[queryId].tags).to.eql({
k1: ['v0', 'v1'],
k2: ['foo'],

View File

@ -1,7 +1,16 @@
import defaultQueryConfig from 'src/utils/defaultQueryConfig';
import {chooseNamespace, chooseMeasurement, toggleField} from 'src/utils/queryTransitions';
import {
applyFuncsToField,
chooseMeasurement,
chooseNamespace,
chooseTag,
groupByTag,
groupByTime,
toggleField,
toggleTagAcceptance,
updateRawQuery,
} from 'src/utils/queryTransitions';
import update from 'react-addons-update';
import u from 'updeep';
export default function queryConfigs(state = {}, action) {
switch (action.type) {
@ -12,19 +21,19 @@ export default function queryConfigs(state = {}, action) {
case 'CHOOSE_NAMESPACE': {
const {queryId, database, retentionPolicy} = action.payload;
const nextQueryConfig = chooseNamespace(defaultQueryConfig(queryId), {database, retentionPolicy});
const nextState = update(state, {
[queryId]: {$set: nextQueryConfig},
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
return nextState;
}
case 'CHOOSE_MEASUREMENT': {
const {queryId, measurement} = action.payload;
const nextQueryConfig = chooseMeasurement(state[queryId], measurement);
const nextState = update(state, {
[queryId]: {$set: nextQueryConfig},
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
return nextState;
}
case 'CREATE_PANEL':
@ -48,26 +57,20 @@ export default function queryConfigs(state = {}, action) {
case 'GROUP_BY_TIME': {
const {queryId, time} = action.payload;
const nextState = update(state, {
[queryId]: {
groupBy: {
time: {$set: time},
},
},
});
const nextQueryConfig = groupByTime(state[queryId], time);
return nextState;
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
}
case 'TOGGLE_TAG_ACCEPTANCE': {
const {queryId} = action.payload;
const nextState = update(state, {
[queryId]: {
areTagsAccepted: {$set: !state[queryId].areTagsAccepted},
},
});
const nextQueryConfig = toggleTagAcceptance(state[queryId]);
return nextState;
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
}
case 'DELETE_QUERY': {
@ -91,115 +94,36 @@ export default function queryConfigs(state = {}, action) {
case 'APPLY_FUNCS_TO_FIELD': {
const {queryId, fieldFunc} = action.payload;
const {field, funcs} = fieldFunc;
const shouldRemoveFuncs = funcs.length === 0;
const nextQueryConfig = applyFuncsToField(state[queryId], fieldFunc);
const nextState = update(state, {
[queryId]: {$apply: (queryConfig) => {
const nextFields = queryConfig.fields.map((f) => {
// If one field has no funcs, all fields must have no funcs
if (shouldRemoveFuncs) {
return update(f, {funcs: {$set: []}});
}
if (f.field === field || !f.funcs || !f.funcs.length) {
return update(f, {funcs: {$set: funcs}});
}
return f;
});
// If there are no functions, then there should be no GROUP BY time
if (shouldRemoveFuncs) {
const nextGroupBy = update(state[queryId].groupBy, {time: {$set: null}});
return update(queryConfig, {fields: {$set: nextFields}, groupBy: {$set: nextGroupBy}});
}
return update(queryConfig, {fields: {$set: nextFields}});
}},
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
return nextState;
}
case 'CHOOSE_TAG': {
const {queryId, tag} = action.payload;
const nextQueryConfig = chooseTag(state[queryId], tag);
const tagValues = state[queryId].tags[tag.key];
const shouldRemoveTag = tagValues && tagValues.length === 1 && tagValues[0] === tag.value;
if (shouldRemoveTag) {
const nextState = update(state, {
[queryId]: {
tags: {$apply: (tags) => {
const tagsCopy = Object.assign({}, tags);
delete tagsCopy[tag.key];
return tagsCopy;
}},
},
});
return nextState;
}
const nextState = update(state, {
[queryId]: {
tags: {
[tag.key]: {$apply: (vals) => {
if (!vals) {
return [tag.value];
}
// If the tag value is already selected, deselect it by removing it from the list
const valsCopy = vals.slice();
const i = valsCopy.indexOf(tag.value);
if (i > -1) {
valsCopy.splice(i, 1);
return valsCopy;
}
return update(valsCopy, {$push: [tag.value]});
}},
},
},
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
return nextState;
}
case 'GROUP_BY_TAG': {
const {queryId, tagKey} = action.payload;
const nextState = update(state, {
[queryId]: {
groupBy: {
tags: {$apply: (groupByTags) => {
// If the tag value is already selected, deselect it by removing it from the list
const groupByTagsCopy = groupByTags.slice();
const i = groupByTagsCopy.indexOf(tagKey);
if (i > -1) {
groupByTagsCopy.splice(i, 1);
return groupByTagsCopy;
}
return update(groupByTagsCopy, {$push: [tagKey]});
}},
},
},
const nextQueryConfig = groupByTag(state[queryId], tagKey);
return Object.assign({}, state, {
[queryId]: nextQueryConfig,
});
return nextState;
}
case 'UPDATE_RAW_QUERY': {
const {queryID, text} = action.payload;
const updateQuery = {
[queryID]: {
rawText: u.constant(text),
},
};
return u(updateQuery, state);
const nextQueryConfig = updateRawQuery(state[queryID], text);
return Object.assign({}, state, {
[queryID]: nextQueryConfig,
});
}
}
return state;

View File

@ -33,3 +33,102 @@ export function toggleField(query, {field, funcs}) {
fields: query.fields.concat({field, funcs}),
});
}
export function groupByTime(query, time) {
return Object.assign({}, query, {
groupBy: Object.assign({}, query.groupBy, {
time,
}),
});
}
export function toggleTagAcceptance(query) {
return Object.assign({}, query, {
areTagsAccepted: !query.areTagsAccepted,
});
}
export function applyFuncsToField(query, {field, funcs}) {
const shouldRemoveFuncs = funcs.length === 0;
const nextFields = query.fields.map((f) => {
// If one field has no funcs, all fields must have no funcs
if (shouldRemoveFuncs) {
return Object.assign({}, f, {funcs: []});
}
// If there is a func applied to only one field, add it to the other fields
if (f.field === field || !f.funcs || !f.funcs.length) {
return Object.assign({}, f, {funcs});
}
return f;
});
// If there are no functions, then there should be no GROUP BY time
if (shouldRemoveFuncs) {
const nextGroupBy = Object.assign({}, query.groupBy, {time: null});
return Object.assign({}, query, {
fields: nextFields,
groupBy: nextGroupBy,
});
}
return Object.assign({}, query, {fields: nextFields});
}
export function updateRawQuery(query, rawText) {
return Object.assign({}, query, {
rawText,
});
}
export function groupByTag(query, tagKey) {
const oldTags = query.groupBy.tags;
let newTags;
// Toggle the presence of the tagKey
if (oldTags.includes(tagKey)) {
const i = oldTags.indexOf(tagKey);
newTags = oldTags.slice();
newTags.splice(i, 1);
} else {
newTags = oldTags.concat(tagKey);
}
return Object.assign({}, query, {
groupBy: Object.assign({}, query.groupBy, {tags: newTags}),
});
}
export function chooseTag(query, tag) {
const tagValues = query.tags[tag.key];
const shouldRemoveTag = tagValues && tagValues.length === 1 && tagValues[0] === tag.value;
if (shouldRemoveTag) {
const newTags = Object.assign({}, query.tags);
delete newTags[tag.key];
return Object.assign({}, query, {tags: newTags});
}
const oldTagValues = query.tags[tag.key];
if (!oldTagValues) {
return updateTagValues([tag.value]);
}
// If the tag value is already selected, deselect it by removing it from the list
const tagValuesCopy = oldTagValues.slice();
const i = tagValuesCopy.indexOf(tag.value);
if (i > -1) {
tagValuesCopy.splice(i, 1);
return updateTagValues(tagValuesCopy);
}
return updateTagValues(query.tags[tag.key].concat(tag.value));
function updateTagValues(newTagValues) {
return Object.assign({}, query, {
tags: Object.assign({}, query.tags, {
[tag.key]: newTagValues,
}),
});
}
}