import WorkflowActionService from '@baserow/modules/builder/services/workflowAction' import PublishedBuilderService from '@baserow/modules/builder/services/publishedBuilder' import _ from 'lodash' const updateContext = { updateTimeout: null, promiseResolve: null, lastUpdatedValues: null, valuesToUpdate: {}, } export function populateWorkflowAction(workflowAction) { return { ...workflowAction, _: { loading: false, dispatching: false, }, } } const state = {} const mutations = { ADD_ITEM(state, { page, workflowAction }) { page.workflowActions.push(populateWorkflowAction(workflowAction)) }, SET_ITEMS(state, { page, workflowActions }) { page.workflowActions = workflowActions.map((workflowAction) => populateWorkflowAction(workflowAction) ) }, DELETE_ITEM(state, { page, workflowActionId }) { const index = page.workflowActions.findIndex( (workflowAction) => workflowAction.id === workflowActionId ) if (index > -1) { page.workflowActions.splice(index, 1) } }, UPDATE_ITEM(state, { page, workflowAction: workflowActionToUpdate, values }) { const index = page.workflowActions.findIndex( (wa) => wa.id === workflowActionToUpdate.id ) page.workflowActions.splice(index, 1, { ...page.workflowActions[index], ...values, }) }, SET_ITEM(state, { page, workflowAction: workflowActionToSet, values }) { page.workflowActions = page.workflowActions.map((workflowAction) => workflowAction.id === workflowActionToSet.id ? populateWorkflowAction(values) : workflowAction ) }, ORDER_ITEMS(state, { page, order }) { page.workflowActions.forEach((workflowAction) => { const index = order.findIndex((value) => value === workflowAction.id) workflowAction.order = index === -1 ? 0 : index + 1 }) }, SET_LOADING(state, { workflowAction, value }) { workflowAction._.loading = value }, SET_DISPATCHING(state, { workflowAction, isDispatching }) { workflowAction._.dispatching = isDispatching }, } const actions = { forceCreate({ commit }, { page, workflowAction }) { commit('ADD_ITEM', { page, workflowAction }) }, forceDelete({ commit }, { page, workflowActionId }) { commit('DELETE_ITEM', { page, workflowActionId }) }, forceUpdate({ commit }, { page, workflowAction, values }) { commit('UPDATE_ITEM', { page, workflowAction, values }) }, forceSet({ commit }, { page, workflowAction, values }) { commit('SET_ITEM', { page, workflowAction, values }) }, forceOrder({ commit }, { page, order }) { commit('ORDER_ITEMS', { page, order }) }, async create( { dispatch }, { page, workflowActionType, eventType, configuration = null } ) { const { data: workflowAction } = await WorkflowActionService( this.$client ).create(page.id, workflowActionType, eventType, configuration) await dispatch('forceCreate', { page, workflowAction }) return workflowAction }, async fetch({ commit }, { page }) { const { data: workflowActions } = await WorkflowActionService( this.$client ).fetchAll(page.id) commit('SET_ITEMS', { page, workflowActions }) }, async fetchPublished({ commit }, { page }) { const { data: workflowActions } = await PublishedBuilderService( this.$client ).fetchWorkflowActions(page.id) commit('SET_ITEMS', { page, workflowActions }) }, async delete({ dispatch }, { page, workflowAction }) { dispatch('forceDelete', { page, workflowActionId: workflowAction.id }) try { await WorkflowActionService(this.$client).delete(workflowAction.id) } catch (error) { await dispatch('forceCreate', { page, workflowAction }) throw error } }, async updateDebounced( { dispatch, commit }, { page, workflowAction, values } ) { // These values should not be updated via a regular update request const excludeValues = ['order'] const oldValues = {} Object.keys(values).forEach((name) => { if ( Object.prototype.hasOwnProperty.call(workflowAction, name) && !excludeValues.includes(name) ) { oldValues[name] = workflowAction[name] // Accumulate the changed values to send all the ongoing changes with the // final request updateContext.valuesToUpdate[name] = values[name] } }) await dispatch('forceUpdate', { page, workflowAction, values: updateContext.valuesToUpdate, }) return new Promise((resolve, reject) => { const fire = async () => { commit('SET_LOADING', { workflowAction, value: true }) const toUpdate = updateContext.valuesToUpdate updateContext.valuesToUpdate = {} try { const { data } = await WorkflowActionService(this.$client).update( workflowAction.id, toUpdate ) updateContext.lastUpdatedValues = null excludeValues.forEach((name) => { delete data[name] }) await dispatch('forceUpdate', { page, workflowAction, values: data, }) resolve() } catch (error) { await dispatch('forceUpdate', { page, workflowAction, values: updateContext.lastUpdatedValues, }) updateContext.lastUpdatedValues = null reject(error) } updateContext.lastUpdatedValues = null commit('SET_LOADING', { workflowAction, value: false }) } if (updateContext.promiseResolve) { updateContext.promiseResolve() updateContext.promiseResolve = null } clearTimeout(updateContext.updateTimeout) if (!updateContext.lastUpdatedValues) { updateContext.lastUpdatedValues = oldValues } updateContext.updateTimeout = setTimeout(fire, 500) updateContext.promiseResolve = resolve }) }, async dispatchAction({ dispatch }, { workflowActionId, data }) { const { data: result } = await WorkflowActionService(this.$client).dispatch( workflowActionId, data ) return result }, async order({ commit, getters }, { page, order, element = null }) { const workflowActions = element !== null ? getters.getElementWorkflowActions(page, element.id) : getters.getWorkflowActions(page) const oldOrder = workflowActions.map(({ id }) => id) commit('ORDER_ITEMS', { page, order }) try { await WorkflowActionService(this.$client).order( page.id, order, element.id ) } catch (error) { commit('ORDER_ITEMS', { page, order: oldOrder }) throw error } }, setDispatching({ commit }, { workflowAction, isDispatching }) { commit('SET_DISPATCHING', { workflowAction, isDispatching }) }, } const getters = { getWorkflowActions: (state) => (page) => { return page.workflowActions.map((w) => w).sort((a, b) => a.order - b.order) }, getWorkflowActionById: (state, getters) => (page, workflowActionId) => { return getters .getWorkflowActions(page) .find((workflowAction) => workflowAction.id === workflowActionId) }, getElementWorkflowActions: (state) => (page, elementId) => { return page.workflowActions .filter((workflowAction) => workflowAction.element_id === elementId) .sort((a, b) => a.order - b.order) }, getElementPreviousWorkflowActions: (state, getters) => (page, elementId, workflowActionId) => { return _.takeWhile( getters.getElementWorkflowActions(page, elementId), (workflowAction) => workflowAction.id !== workflowActionId ) }, getLoading: (state) => (workflowAction) => { return workflowAction._?.loading }, getDispatching: (state) => (workflowAction) => { return workflowAction._?.dispatching }, } export default { namespaced: true, state, mutations, actions, getters, }