import { createReducer } from "utils/AppsmithUtils"; import { ReduxActionTypes, ReduxAction, ReduxActionErrorTypes, } from "constants/ReduxActionConstants"; import { ActionResponse } from "api/ActionAPI"; import { ExecuteErrorPayload } from "constants/ActionConstants"; import _ from "lodash"; import { RapidApiAction, RestAction } from "entities/Action"; import { UpdateActionPropertyActionPayload } from "actions/actionActions"; import produce from "immer"; import { Datasource } from "api/DatasourcesApi"; export interface ActionData { isLoading: boolean; config: RestAction | RapidApiAction; data?: ActionResponse; } export type ActionDataState = ActionData[]; export interface PartialActionData { isLoading: boolean; config: Partial; data?: ActionResponse; } const initialState: ActionDataState = []; const actionsReducer = createReducer(initialState, { [ReduxActionTypes.FETCH_ACTIONS_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => { return action.payload.map(action => { const foundAction = state.find(currentAction => { return currentAction.config.id === action.id; }); return { isLoading: false, config: action, data: foundAction?.data, }; }); }, [ReduxActionTypes.FETCH_ACTIONS_VIEW_MODE_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => action.payload.map(a => ({ isLoading: false, config: a, })), [ReduxActionTypes.FETCH_ACTIONS_FOR_PAGE_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => { if (action.payload.length > 0) { const payloadActionMap = _.keyBy(action.payload, "id"); return state.map((stateAction: ActionData) => { if (stateAction.config.pageId === action.payload[0].pageId) { return { data: stateAction.data, isLoading: false, config: payloadActionMap[stateAction.config.id], }; } return stateAction; }); } return state; }, [ReduxActionTypes.SUBMIT_CURL_FORM_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ) => state.concat([{ config: action.payload, isLoading: false }]), [ReduxActionErrorTypes.FETCH_ACTIONS_ERROR]: () => initialState, [ReduxActionErrorTypes.FETCH_ACTIONS_VIEW_MODE_ERROR]: () => initialState, [ReduxActionTypes.CREATE_ACTION_INIT]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.concat([ { config: { ...action.payload, id: action.payload.name }, isLoading: false, }, ]), [ReduxActionTypes.CREATE_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.map(a => { if ( a.config.pageId === action.payload.pageId && a.config.id === action.payload.name ) { return { ...a, config: action.payload }; } return a; }), [ReduxActionTypes.CREATE_ACTION_ERROR]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.filter( a => a.config.name !== action.payload.name && a.config.id !== action.payload.name, ), [ReduxActionTypes.UPDATE_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction<{ data: RestAction }>, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.data.id) return { ...a, config: action.payload.data }; return a; }), [ReduxActionTypes.UPDATE_ACTION_PROPERTY]: ( state: ActionDataState, action: ReduxAction, ) => state.map(a => { if (a.config.id === action.payload.id) { return _.set(a, `config.${action.payload.field}`, action.payload.value); } return a; }), [ReduxActionTypes.DELETE_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction<{ id: string }>, ): ActionDataState => state.filter(a => a.config.id !== action.payload.id), [ReduxActionTypes.EXECUTE_API_ACTION_REQUEST]: ( state: ActionDataState, action: ReduxAction<{ id: string }>, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.id) { return { ...a, isLoading: true, }; } return a; }), [ReduxActionTypes.EXECUTE_API_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction<{ id: string; response: ActionResponse }>, ): PartialActionData[] => { const foundAction = state.find(stateAction => { return stateAction.config.id === action.payload.id; }); if (foundAction) { return state.map(stateAction => { if (stateAction.config.id === action.payload.id) { return { ...stateAction, isLoading: false, data: action.payload.response, }; } return stateAction; }); } else { const partialAction: PartialActionData = { isLoading: false, config: { id: action.payload.id }, data: action.payload.response, }; return [...state, partialAction]; } }, [ReduxActionErrorTypes.EXECUTE_ACTION_ERROR]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.actionId) { return { ...a, isLoading: false, data: action.payload.error }; } return a; }), [ReduxActionTypes.RUN_ACTION_REQUEST]: ( state: ActionDataState, action: ReduxAction<{ id: string }>, ): ActionDataState => state.map(a => { if (action.payload.id === a.config.id) { return { ...a, isLoading: true, }; } return a; }), [ReduxActionTypes.RUN_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction<{ [id: string]: ActionResponse }>, ): ActionDataState => { const actionId = Object.keys(action.payload)[0]; return state.map(a => { if (a.config.id === actionId) { return { ...a, isLoading: false, data: action.payload[actionId] }; } return a; }); }, [ReduxActionErrorTypes.RUN_ACTION_ERROR]: ( state: ActionDataState, action: ReduxAction<{ id: string }>, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.id) { return { ...a, isLoading: false }; } return a; }), [ReduxActionTypes.MOVE_ACTION_INIT]: ( state: ActionDataState, action: ReduxAction<{ id: string; destinationPageId: string; name: string; }>, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.id) { return { ...a, config: { ...a.config, name: action.payload.name, pageId: action.payload.destinationPageId, }, }; } return a; }), [ReduxActionTypes.MOVE_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.id) { return { ...a, config: action.payload }; } return a; }), [ReduxActionErrorTypes.MOVE_ACTION_ERROR]: ( state: ActionDataState, action: ReduxAction<{ id: string; originalPageId: string }>, ): ActionDataState => state.map(a => { if (a.config.id === action.payload.id) { return { ...a, config: { ...a.config, pageId: action.payload.originalPageId, }, }; } return a; }), [ReduxActionTypes.COPY_ACTION_INIT]: ( state: ActionDataState, action: ReduxAction<{ id: string; destinationPageId: string; name: string; }>, ): ActionDataState => state.concat( state .filter(a => a.config.id === action.payload.id) .map(a => ({ ...a, config: { ...a.config, id: "TEMP_COPY_ID", name: action.payload.name, pageId: action.payload.destinationPageId, }, })), ), [ReduxActionTypes.COPY_ACTION_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ): ActionDataState => state.map(a => { if ( a.config.pageId === action.payload.pageId && a.config.name === action.payload.name ) { return { ...a, config: action.payload, }; } return a; }), [ReduxActionErrorTypes.COPY_ACTION_ERROR]: ( state: ActionDataState, action: ReduxAction<{ id: string; destinationPageId: string; name: string; }>, ): ActionDataState => state.filter(a => { if (a.config.pageId === action.payload.destinationPageId) { if (a.config.id === action.payload.id) { return a.config.name !== action.payload.name; } return true; } return true; }), [ReduxActionTypes.SET_ACTION_TO_EXECUTE_ON_PAGELOAD]: ( state: ActionDataState, actionIds: ReduxAction, ) => { return produce(state, draft => { draft.forEach((action, index) => { if (actionIds.payload.indexOf(action.config.id) > -1) { draft[index].config.executeOnLoad = true; } }); }); }, [ReduxActionTypes.FETCH_DATASOURCES_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ) => { const datasources = action.payload; return state.map(action => { const datasourceId = action.config.datasource.id; if (datasourceId) { const datasource = datasources.find( datasource => datasource.id === datasourceId, ); return { ...action, config: { ...action.config, datasource: datasource || action.config.datasource, // fallback to original datasource if datasource not available. }, }; } return action; }); }, [ReduxActionTypes.UPDATE_DATASOURCE_SUCCESS]: ( state: ActionDataState, action: ReduxAction, ) => { const datasource = action.payload; return state.map(action => { const datasourceId = action.config.datasource.id; if (datasourceId && datasource.id === datasourceId) { return { ...action, config: { ...action.config, datasource: datasource, }, }; } return action; }); }, }); export default actionsReducer;