import type { WidgetType } from "constants/WidgetConstants"; import type { EvaluationReduxAction, ReduxAction, UpdateCanvasPayload, AnyReduxAction, } from "@appsmith/constants/ReduxActionConstants"; import { ReduxActionTypes, ReduxActionErrorTypes, WidgetReduxActionTypes, ReplayReduxActionTypes, } from "@appsmith/constants/ReduxActionConstants"; import type { DynamicPath } from "utils/DynamicBindingUtils"; import AnalyticsUtil from "utils/AnalyticsUtil"; import type { WidgetOperation } from "widgets/BaseWidget"; import type { FetchPageRequest, FetchPageResponse, PageLayout, SavePageResponse, UpdatePageRequest, UpdatePageResponse, } from "api/PageApi"; import type { UrlDataState } from "reducers/entityReducers/appReducer"; import type { APP_MODE } from "entities/App"; import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; import type { GenerateTemplatePageRequest } from "api/PageApi"; import type { ENTITY_TYPE } from "@appsmith/entities/AppsmithConsole/utils"; import type { Replayable } from "entities/Replay/ReplayEntity/ReplayEditor"; import * as Sentry from "@sentry/react"; export interface FetchPageListPayload { applicationId: string; mode: APP_MODE; } export interface ClonePageActionPayload { id: string; blockNavigation?: boolean; } export interface CreatePageActionPayload { applicationId: string; name: string; layouts: Partial[]; blockNavigation?: boolean; } export interface updateLayoutOptions { isRetry?: boolean; shouldReplay?: boolean; updatedWidgetIds?: string[]; } export const fetchPage = ( pageId: string, isFirstLoad = false, pageWithMigratedDsl?: FetchPageResponse, ): ReduxAction => { return { type: ReduxActionTypes.FETCH_PAGE_INIT, payload: { id: pageId, isFirstLoad, pageWithMigratedDsl, }, }; }; export const fetchPublishedPage = ( pageId: string, bustCache = false, firstLoad = false, pageWithMigratedDsl?: FetchPageResponse, ) => ({ type: ReduxActionTypes.FETCH_PUBLISHED_PAGE_INIT, payload: { pageId, bustCache, firstLoad, pageWithMigratedDsl, }, }); export const fetchPageSuccess = (): EvaluationReduxAction => { return { type: ReduxActionTypes.FETCH_PAGE_SUCCESS, payload: undefined, }; }; export const fetchPublishedPageSuccess = (): EvaluationReduxAction => ({ type: ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS, payload: undefined, }); /** * After all page entities are fetched like DSL, actions and JsObjects, * we trigger evaluation using this redux action, here we supply postEvalActions * to trigger action after evaluation has been completed like executeOnPageLoadAction * * @param {Array} postEvalActions */ export const fetchAllPageEntityCompletion = ( postEvalActions: Array, ) => ({ type: ReduxActionTypes.FETCH_ALL_PAGE_ENTITY_COMPLETION, postEvalActions, payload: undefined, }); export const updateCurrentPage = ( id: string, slug?: string, permissions?: string[], ) => ({ type: ReduxActionTypes.SWITCH_CURRENT_PAGE_ID, payload: { id, slug, permissions }, }); export const initCanvasLayout = ( payload: UpdateCanvasPayload, ): ReduxAction => { return { type: ReduxActionTypes.INIT_CANVAS_LAYOUT, payload, }; }; export const setLastUpdatedTime = (payload: number): ReduxAction => ({ type: ReduxActionTypes.SET_LAST_UPDATED_TIME, payload, }); export const savePageSuccess = (payload: SavePageResponse) => { return { type: ReduxActionTypes.SAVE_PAGE_SUCCESS, payload, }; }; export const updateWidgetNameSuccess = () => { return { type: ReduxActionTypes.UPDATE_WIDGET_NAME_SUCCESS, }; }; export const deletePageSuccess = () => { return { type: ReduxActionTypes.DELETE_PAGE_SUCCESS, }; }; export const updateAndSaveLayout = ( widgets: CanvasWidgetsReduxState, options: updateLayoutOptions = {}, ) => { const { isRetry, shouldReplay, updatedWidgetIds } = options; return { type: ReduxActionTypes.UPDATE_LAYOUT, payload: { widgets, isRetry, shouldReplay, updatedWidgetIds }, }; }; export const saveLayout = (isRetry?: boolean) => { return { type: ReduxActionTypes.SAVE_PAGE_INIT, payload: { isRetry }, }; }; export const createPage = ( applicationId: string, pageName: string, layouts: Partial[], orgId: string, blockNavigation?: boolean, instanceId?: string, ) => { AnalyticsUtil.logEvent("CREATE_PAGE", { pageName, orgId, instanceId, }); return { type: ReduxActionTypes.CREATE_PAGE_INIT, payload: { applicationId, name: pageName, layouts, blockNavigation, }, }; }; export const createNewPageFromEntities = ( applicationId: string, pageName: string, orgId: string, blockNavigation?: boolean, instanceId?: string, ) => { AnalyticsUtil.logEvent("CREATE_PAGE", { pageName, orgId, instanceId, }); return { type: ReduxActionTypes.CREATE_NEW_PAGE_FROM_ENTITIES, payload: { applicationId, name: pageName, blockNavigation, }, }; }; /** * action to clone page * * @param pageId * @param blockNavigation * @returns */ export const clonePageInit = (pageId: string, blockNavigation?: boolean) => { return { type: ReduxActionTypes.CLONE_PAGE_INIT, payload: { id: pageId, blockNavigation, }, }; }; export const clonePageSuccess = ( pageId: string, pageName: string, layoutId: string, pageSlug: string, ) => { return { type: ReduxActionTypes.CLONE_PAGE_SUCCESS, payload: { pageId, pageName, layoutId, pageSlug, }, }; }; export const updatePage = (payload: UpdatePageRequest) => { // Update page *needs* id to be there. We found certain scenarios // where this was not happening and capturing the error to know gather // more info: https://github.com/appsmithorg/appsmith/issues/16435 if (!payload.id) { Sentry.captureException( new Error("Attempting to update page without page id"), ); } return { type: ReduxActionTypes.UPDATE_PAGE_INIT, payload, }; }; export const updatePageSuccess = (payload: UpdatePageResponse) => { return { type: ReduxActionTypes.UPDATE_PAGE_SUCCESS, payload, }; }; export const updatePageError = (payload: UpdatePageErrorPayload) => { return { type: ReduxActionErrorTypes.UPDATE_PAGE_ERROR, payload, }; }; export interface UpdatePageErrorPayload { request: UpdatePageRequest; error: unknown; } export interface WidgetAddChild { widgetId: string; widgetName?: string; type: WidgetType; leftColumn: number; topRow: number; columns: number; rows: number; parentRowSpace: number; parentColumnSpace: number; newWidgetId: string; tabId: string; props?: Record; dynamicBindingPathList?: DynamicPath[]; } export interface WidgetRemoveChild { widgetId: string; childWidgetId: string; } export interface WidgetDelete { widgetId?: string; parentId?: string; disallowUndo?: boolean; isShortcut?: boolean; } export interface MultipleWidgetDeletePayload { widgetIds: string[]; disallowUndo?: boolean; isShortcut?: boolean; } export interface WidgetResize { widgetId: string; parentId: string; leftColumn?: number; rightColumn?: number; topRow?: number; bottomRow?: number; mobileLeftColumn?: number; mobileRightColumn?: number; mobileTopRow?: number; mobileBottomRow?: number; snapColumnSpace: number; snapRowSpace: number; } export interface ModalWidgetResize { height: number; width: number; widgetId: string; canvasWidgetId: string; } export interface WidgetAddChildren { widgetId: string; children: Array<{ type: WidgetType; widgetId: string; parentId: string; parentRowSpace: number; parentColumnSpace: number; leftColumn: number; rightColumn: number; topRow: number; bottomRow: number; isLoading: boolean; }>; } export interface WidgetUpdateProperty { widgetId: string; propertyPath: string; propertyValue: any; } export const updateWidget = ( operation: WidgetOperation, widgetId: string, payload: any, ): ReduxAction< | WidgetAddChild | WidgetResize | WidgetDelete | WidgetAddChildren | WidgetUpdateProperty > => { return { type: WidgetReduxActionTypes["WIDGET_" + operation], payload: { widgetId, ...payload }, }; }; export const setUrlData = ( payload: UrlDataState, ): ReduxAction => { return { type: ReduxActionTypes.SET_URL_DATA, payload, }; }; export const setAppMode = (payload: APP_MODE): ReduxAction => { return { type: ReduxActionTypes.SET_APP_MODE, payload, }; }; export const updateAppStore = ( payload: Record, ): EvaluationReduxAction> => { return { type: ReduxActionTypes.UPDATE_APP_STORE, payload, }; }; export interface ReduxActionWithExtraParams extends ReduxAction { extraParams: Record; } export interface GenerateCRUDSuccess { page: { layouts: Array; id: string; name: string; isDefault?: boolean; slug: string; description?: string; }; isNewPage: boolean; } export const generateTemplateSuccess = (payload: GenerateCRUDSuccess) => { return { type: ReduxActionTypes.GENERATE_TEMPLATE_PAGE_SUCCESS, payload, }; }; export const generateTemplateError = () => { return { type: ReduxActionErrorTypes.GENERATE_TEMPLATE_PAGE_ERROR, }; }; export const generateTemplateToUpdatePage = ({ applicationId, columns, datasourceId, mode, pageId, pluginSpecificParams, searchColumn, tableName, }: GenerateTemplatePageRequest): ReduxActionWithExtraParams => { return { type: ReduxActionTypes.GENERATE_TEMPLATE_PAGE_INIT, payload: { pageId, tableName, datasourceId, applicationId, columns, searchColumn, pluginSpecificParams, }, extraParams: { mode, }, }; }; export function updateReplayEntity( entityId: string, entity: Replayable, entityType: ENTITY_TYPE, ) { return { type: ReduxActionTypes.UPDATE_REPLAY_ENTITY, payload: { entityId, entity, entityType }, }; } export function undoAction() { return { type: ReduxActionTypes.UNDO_REDO_OPERATION, payload: { operation: ReplayReduxActionTypes.UNDO, }, }; } export function redoAction() { return { type: ReduxActionTypes.UNDO_REDO_OPERATION, payload: { operation: ReplayReduxActionTypes.REDO, }, }; } /** * action for delete page * * @param pageId * @param pageName * @returns */ export const deletePage = (pageId: string) => { return { type: ReduxActionTypes.DELETE_PAGE_INIT, payload: { id: pageId, }, }; }; /** * action for set page as default * * @param pageId * @param applicationId * @returns */ export const setPageAsDefault = (pageId: string, applicationId?: string) => { return { type: ReduxActionTypes.SET_DEFAULT_APPLICATION_PAGE_INIT, payload: { id: pageId, applicationId, }, }; }; /** * action for updating order of a page * * @param pageId * @param applicationId * @returns */ export const setPageOrder = ( applicationId: string, pageId: string, order: number, ) => { return { type: ReduxActionTypes.SET_PAGE_ORDER_INIT, payload: { pageId: pageId, order: order, applicationId, }, }; }; export const resetPageList = () => ({ type: ReduxActionTypes.RESET_PAGE_LIST, }); export const resetApplicationWidgets = () => ({ type: ReduxActionTypes.RESET_APPLICATION_WIDGET_STATE_REQUEST, }); export const fetchPageDSLs = (payload?: any) => ({ type: ReduxActionTypes.POPULATE_PAGEDSLS_INIT, payload, }); export const setupPage = ( pageId: string, isFirstLoad = false, pageWithMigratedDsl?: FetchPageResponse, ): ReduxAction => ({ type: ReduxActionTypes.SETUP_PAGE_INIT, payload: { id: pageId, isFirstLoad, pageWithMigratedDsl, }, }); export const setupPublishedPage = ( pageId: string, bustCache = false, firstLoad = false, pageWithMigratedDsl?: FetchPageResponse, ) => ({ type: ReduxActionTypes.SETUP_PUBLISHED_PAGE_INIT, payload: { pageId, bustCache, firstLoad, pageWithMigratedDsl, }, });