diff --git a/frontend/src/app.js b/frontend/src/app.js index 5738bfd85562ba22c2b6429d82ddf122ccb46f7d..fbf5542a7e247083b7752762a03b4d126c4e1852 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -41,6 +41,7 @@ import { reducer as form } from "redux-form"; import * as datamodel from 'metabase/admin/datamodel/reducers'; import questions from 'metabase/questions/questions'; import labels from 'metabase/questions/labels'; +import undo from 'metabase/questions/undo'; import { registerAnalyticsClickListener } from "metabase/lib/analytics"; @@ -83,6 +84,7 @@ Metabase.config(['$routeProvider', '$locationProvider', function($routeProvider, datamodel: combineReducers(datamodel), questions, labels, + undo, form, router, user: (state = null) => state diff --git a/frontend/src/questions/containers/UndoListing.jsx b/frontend/src/questions/containers/UndoListing.jsx index f7bf50408faa95c02ff8e334af557f794afeafe9..2ff7f4b28f218a5c8ad82b6e361ed3eb38dcbd8a 100644 --- a/frontend/src/questions/containers/UndoListing.jsx +++ b/frontend/src/questions/containers/UndoListing.jsx @@ -3,7 +3,7 @@ import { connect } from "react-redux"; import S from "./UndoListing.css"; -import { dismissUndo, performUndo } from "../questions"; +import { dismissUndo, performUndo } from "../undo"; import { getUndos } from "../selectors"; import Icon from "metabase/components/Icon"; diff --git a/frontend/src/questions/questions.js b/frontend/src/questions/questions.js index 8a46960ba86c8cb4236fa97f9b26223764624502..95de4867938b8ba2aae1107fdf746bc9235b82c9 100644 --- a/frontend/src/questions/questions.js +++ b/frontend/src/questions/questions.js @@ -6,6 +6,7 @@ import i from "icepick"; import _ from "underscore"; import { getSelectedEntities } from "./selectors"; +import { addUndo } from "./undo"; const card = new Schema('cards'); const label = new Schema('labels'); @@ -22,9 +23,6 @@ const SET_ALL_SELECTED = 'metabase/questions/SET_ALL_SELECTED'; const SET_FAVORITED = 'metabase/questions/SET_FAVORITED'; const SET_ARCHIVED = 'metabase/questions/SET_ARCHIVED'; const SET_LABELED = 'metabase/questions/SET_LABELED'; -const ADD_UNDO = 'metabase/questions/ADD_UNDO'; -const DISMISS_UNDO = 'metabase/questions/DISMISS_UNDO'; -const PERFORM_UNDO = 'metabase/questions/PERFORM_UNDO'; export const selectSection = createThunkAction(SELECT_SECTION, (section = "all", slug = null, type = "cards") => { return async (dispatch, getState) => { @@ -75,24 +73,26 @@ export const setFavorited = createThunkAction(SET_FAVORITED, (cardId, favorited) } }); -export const setArchived = createThunkAction(SET_ARCHIVED, (cardId, archived, showUndo = true) => { +export const setArchived = createThunkAction(SET_ARCHIVED, (cardId, archived, undoable = true) => { return async (dispatch, getState) => { if (cardId == null) { // bulk archive let selected = getSelectedEntities(getState()).filter(item => item.archived !== archived); selected.map(item => dispatch(setArchived(item.id, archived, false))); // TODO: errors - dispatch(addUndo( - selected.length + " question were " + (archived ? "archived" : "unarchived"), - selected.map(item => setArchived(cardId, !archived, false)) - )); + if (undoable) { + dispatch(addUndo( + selected.length + " question were " + (archived ? "archived" : "unarchived"), + selected.map(item => setArchived(item.id, !archived, false)) + )); + } } else { let card = { ...getState().questions.entities.cards[cardId], archived: archived }; let response = await CardApi.update(card); - if (showUndo) { + if (undoable) { dispatch(addUndo("Question was " + (archived ? "archived" : "unarchived"), [ setArchived(cardId, !archived, false) ])); @@ -129,30 +129,6 @@ export const setSearchText = createAction(SET_SEARCH_TEXT); export const setItemSelected = createAction(SET_ITEM_SELECTED); export const setAllSelected = createAction(SET_ALL_SELECTED); -let nextUndoId = 0; - -export const addUndo = createThunkAction(ADD_UNDO, (message, actions) => { - return (dispatch, getState) => { - let id = nextUndoId++; - setTimeout(() => dispatch(dismissUndo(id)), 5000); - return { id, message, actions }; - }; -}); - -export const dismissUndo = createAction(DISMISS_UNDO); - -export const performUndo = createThunkAction(PERFORM_UNDO, (undoId) => { - return (dispatch, getState) => { - let undo = _.findWhere(getState().questions.undos, { id: undoId }); - if (undo) { - undo.actions.map(action => - dispatch(action) - ); - dispatch(dismissUndo(undoId)); - } - }; -}); - const initialState = { entities: {}, type: "cards", @@ -187,7 +163,7 @@ export default function(state = initialState, { type, payload, error }) { case SET_FAVORITED: if (error) { return state; - } else { + } else if (payload && payload.id != null) { state = i.assocIn(state, ["entities", "cards", payload.id], { ...state.entities.cards[payload.id], ...payload @@ -199,10 +175,11 @@ export default function(state = initialState, { type, payload, error }) { } return state; } + return state; case SET_ARCHIVED: if (error) { return state; - } else { + } else if (payload && payload.id != null) { state = i.assocIn(state, ["entities", "cards", payload.id], { ...state.entities.cards[payload.id], ...payload @@ -216,13 +193,11 @@ export default function(state = initialState, { type, payload, error }) { } return state; } + return state; case SET_LABELED: if (error) { return state; - } else { - if (payload.id == null) { - return state; - } + } else if (payload && payload.id != null) { state = i.assocIn(state, ["entities", "cards", payload.id], { ...state.entities.cards[payload.id], ...payload @@ -234,10 +209,7 @@ export default function(state = initialState, { type, payload, error }) { } return state; } - case ADD_UNDO: - return { ...state, undos: state.undos.concat(payload) }; - case DISMISS_UNDO: - return { ...state, undos: state.undos.filter(undo => undo.id !== payload) }; + return state; default: return state; } diff --git a/frontend/src/questions/selectors.js b/frontend/src/questions/selectors.js index 70a9cd35f5a730e66982d6e55a67dc22e6fc2969..c366df30fd156a7744a0f0cc42c26f8be64f02e2 100644 --- a/frontend/src/questions/selectors.js +++ b/frontend/src/questions/selectors.js @@ -161,4 +161,4 @@ export const getSectionName = createSelector( } ); -export const getUndos = (state) => state.questions.undos; +export const getUndos = (state) => state.undo; diff --git a/frontend/src/questions/undo.js b/frontend/src/questions/undo.js new file mode 100644 index 0000000000000000000000000000000000000000..25cc917b5f5a4956ffb62b38e477d0e59cc36e46 --- /dev/null +++ b/frontend/src/questions/undo.js @@ -0,0 +1,51 @@ + +import { createAction, createThunkAction } from "metabase/lib/redux"; + +import _ from "underscore"; + +const ADD_UNDO = 'metabase/questions/ADD_UNDO'; +const DISMISS_UNDO = 'metabase/questions/DISMISS_UNDO'; +const PERFORM_UNDO = 'metabase/questions/PERFORM_UNDO'; + +let nextUndoId = 0; + +export const addUndo = createThunkAction(ADD_UNDO, (message, actions) => { + return (dispatch, getState) => { + let id = nextUndoId++; + setTimeout(() => dispatch(dismissUndo(id)), 5000); + return { id, message, actions }; + }; +}); + +export const dismissUndo = createAction(DISMISS_UNDO); + +export const performUndo = createThunkAction(PERFORM_UNDO, (undoId) => { + return (dispatch, getState) => { + let undo = _.findWhere(getState().undo, { id: undoId }); + console.log("undo", undo) + if (undo) { + undo.actions.map(action => + dispatch(action) + ); + dispatch(dismissUndo(undoId)); + } + }; +}); + +export default function(state = [], { type, payload, error }) { + switch (type) { + case ADD_UNDO: + if (error) { + console.warn("ADD_UNDO", payload); + return state; + } + return state.concat(payload); + case DISMISS_UNDO: + if (error) { + console.warn("DISMISS_UNDO", payload); + return state; + } + return state.filter(undo => undo.id !== payload); + } + return state; +}