import _ from 'lodash' import { clone } from '@baserow/modules/core/utils/object' import ViewService from '@baserow/modules/database/services/view' /** * This store mixin can in combination with a view, if it needs to store options per * field. I noticed that we needed exactly the same code for the grid, gallery and * form view, so it made sense to make something reusable. * * @TODO add this mixin to the other view stores. Currently it's only used by the * gallery view. */ export default () => { const state = () => ({ fieldOptions: {}, }) const mutations = { REPLACE_ALL_FIELD_OPTIONS(state, fieldOptions) { state.fieldOptions = fieldOptions }, UPDATE_ALL_FIELD_OPTIONS(state, fieldOptions) { state.fieldOptions = _.merge({}, state.fieldOptions, fieldOptions) }, UPDATE_FIELD_OPTIONS_OF_FIELD(state, { fieldId, values }) { if (Object.prototype.hasOwnProperty.call(state.fieldOptions, fieldId)) { Object.assign(state.fieldOptions[fieldId], values) } else { state.fieldOptions = Object.assign({}, state.fieldOptions, { [fieldId]: values, }) } }, DELETE_FIELD_OPTIONS(state, fieldId) { if (Object.prototype.hasOwnProperty.call(state.fieldOptions, fieldId)) { delete state.fieldOptions[fieldId] } }, } const actions = { /** * Updates the field options of a given field and also makes an API request to the * backend with the changed values. If the request fails the action is reverted. */ async updateFieldOptionsOfField( { commit, getters, rootGetters }, { field, values, oldValues, readOnly = false, undoRedoActionGroupId = null, } ) { commit('UPDATE_FIELD_OPTIONS_OF_FIELD', { fieldId: field.id, values, }) const viewId = getters.getViewId if (!readOnly) { const updateValues = { field_options: {} } updateValues.field_options[field.id] = values try { await ViewService(this.$client).updateFieldOptions({ viewId, values: updateValues, undoRedoActionGroupId, }) } catch (error) { commit('UPDATE_FIELD_OPTIONS_OF_FIELD', { fieldId: field.id, values: oldValues, }) throw error } } }, /** * Updates the field options of a given field in the store. So no API request to * the backend is made. */ setFieldOptionsOfField({ commit }, { field, values }) { commit('UPDATE_FIELD_OPTIONS_OF_FIELD', { fieldId: field.id, values, }) }, /** * Replaces all field options with new values and also makes an API request to the * backend with the changed values. If the request fails the action is reverted. */ async updateAllFieldOptions( { dispatch, getters, rootGetters }, { newFieldOptions, oldFieldOptions, readOnly = false } ) { dispatch('forceUpdateAllFieldOptions', newFieldOptions) const viewId = getters.getViewId if (!readOnly) { const updateValues = { field_options: newFieldOptions } try { await ViewService(this.$client).updateFieldOptions({ viewId, values: updateValues, }) } catch (error) { dispatch('forceUpdateAllFieldOptions', oldFieldOptions) throw error } } }, /** * Forcefully updates all field options without making a call to the backend. */ forceUpdateAllFieldOptions({ commit }, fieldOptions) { commit('UPDATE_ALL_FIELD_OPTIONS', fieldOptions) }, /** * Updates the order of all the available field options. The provided order parameter * should be an array containing the field ids in the correct order. */ async updateFieldOptionsOrder( { commit, getters, dispatch }, { order, readOnly = false } ) { const oldFieldOptions = clone(getters.getAllFieldOptions) const newFieldOptions = clone(getters.getAllFieldOptions) // Update the order of the field options that have not been provided in the order. // They will get a position that places them after the provided field ids. let i = 0 Object.keys(newFieldOptions).forEach((fieldId) => { if (!order.includes(parseInt(fieldId))) { newFieldOptions[fieldId].order = order.length + i i++ } }) // Update create the field options and set the correct order value. order.forEach((fieldId, index) => { const id = fieldId.toString() if (Object.prototype.hasOwnProperty.call(newFieldOptions, id)) { newFieldOptions[fieldId.toString()].order = index } }) return await dispatch('updateAllFieldOptions', { oldFieldOptions, newFieldOptions, readOnly, }) }, /** * Deletes the field options of the provided field id if they exist. */ forceDeleteFieldOptions({ commit }, fieldId) { commit('DELETE_FIELD_OPTIONS', fieldId) }, } const getters = { getAllFieldOptions(state) { return state.fieldOptions }, } return { namespaced: true, state, getters, actions, mutations, } }