Skip to content
Snippets Groups Projects
Commit 2f12eb25 authored by Tom Robinson's avatar Tom Robinson
Browse files

Merge similar undo objects

parent 1f6376c3
No related branches found
No related tags found
No related merge requests found
......@@ -43,8 +43,8 @@ export default class UndoListing extends Component {
transitionLeaveTimeout={300}
>
{ undos.map(undo =>
<li key={undo.id} className={S.undo}>
<span className={S.message}>{undo.message}</span>
<li key={undo._domId} className={S.undo}>
<span className={S.message}>{typeof undo.message === "function" ? undo.message(undo) : undo.message}</span>
<span className={S.actions}>
<a className={S.undoButton} onClick={() => performUndo(undo.id)}>Undo</a>
<Icon className={S.dismissButton} name="close" onClick={() => dismissUndo(undo.id)} />
......
......@@ -5,6 +5,8 @@ import { normalize, Schema, arrayOf } from 'normalizr';
import i from "icepick";
import _ from "underscore";
import { inflect } from "metabase/lib/formatting";
import { getSelectedEntities } from "./selectors";
import { addUndo } from "./undo";
......@@ -73,6 +75,15 @@ export const setFavorited = createThunkAction(SET_FAVORITED, (cardId, favorited)
}
});
function createUndo(type, actions) {
return {
type: type,
count: actions.length,
message: (undo) => undo.count + " " + inflect(null, undo.count, "question was", "question were") + " " + type,
actions: actions
};
}
export const setArchived = createThunkAction(SET_ARCHIVED, (cardId, archived, undoable = false) => {
return async (dispatch, getState) => {
if (cardId == null) {
......@@ -81,10 +92,10 @@ export const setArchived = createThunkAction(SET_ARCHIVED, (cardId, archived, un
selected.map(item => dispatch(setArchived(item.id, archived)));
// TODO: errors
if (undoable) {
dispatch(addUndo(
selected.length + " question were " + (archived ? "archived" : "unarchived"),
dispatch(addUndo(createUndo(
archived ? "archived" : "unarchived",
selected.map(item => setArchived(item.id, !archived))
));
)));
}
} else {
let card = {
......@@ -93,10 +104,10 @@ export const setArchived = createThunkAction(SET_ARCHIVED, (cardId, archived, un
};
let response = await CardApi.update(card);
if (undoable) {
dispatch(addUndo(
"Question was " + (archived ? "archived" : "unarchived"),
dispatch(addUndo(createUndo(
archived ? "archived" : "unarchived",
[setArchived(cardId, !archived)]
));
)));
}
return response;
}
......@@ -111,10 +122,10 @@ export const setLabeled = createThunkAction(SET_LABELED, (cardId, labelId, label
selected.map(item => dispatch(setLabeled(item.id, labelId, labeled)));
// TODO: errors
if (undoable) {
dispatch(addUndo(
"Label was " + (labeled ? "added to" : "removed from") + " " + selected.length + " questions",
dispatch(addUndo(createUndo(
labeled ? "labeled" : "unlabeled",
selected.map(item => setLabeled(item.id, labelId, !labeled))
));
)));
}
} else {
const state = getState();
......@@ -127,10 +138,10 @@ export const setLabeled = createThunkAction(SET_LABELED, (cardId, labelId, label
if (labels.length !== newLabels.length) {
await CardApi.updateLabels({ cardId, label_ids: newLabels });
if (undoable) {
dispatch(addUndo(
"Label was " + (labeled ? "added" : "removed"),
dispatch(addUndo(createUndo(
labeled ? "labeled" : "unlabeled",
[setLabeled(cardId, labelId, !labeled)]
));
)));
}
return { id: cardId, labels: newLabels, _changedLabelSlug: labelSlug, _changedLabeled: labeled };
}
......
......@@ -9,11 +9,11 @@ const PERFORM_UNDO = 'metabase/questions/PERFORM_UNDO';
let nextUndoId = 0;
export const addUndo = createThunkAction(ADD_UNDO, (message, actions) => {
export const addUndo = createThunkAction(ADD_UNDO, (undo) => {
return (dispatch, getState) => {
let id = nextUndoId++;
setTimeout(() => dispatch(dismissUndo(id)), 5000);
return { id, message, actions };
return { ...undo, id, _domId: id };
};
});
......@@ -38,7 +38,18 @@ export default function(state = [], { type, payload, error }) {
console.warn("ADD_UNDO", payload);
return state;
}
return state.concat(payload);
let previous = state[state.length - 1];
// if last undo was same type then merge them
if (previous && payload.type != null && payload.type === previous.type) {
return state.slice(0, -1).concat({
...payload,
count: previous.count + payload.count,
actions: [...previous.actions, ...payload.actions],
_domId: previous._domId // use original _domId so we don't get funky animations swapping for the new one
});
} else {
return state.concat(payload);
}
case DISMISS_UNDO:
if (error) {
console.warn("DISMISS_UNDO", payload);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment