diff --git a/app/client/src/actions/crudInfoModalActions.ts b/app/client/src/actions/crudInfoModalActions.ts index 2dd88b7874e5..484507a74e24 100644 --- a/app/client/src/actions/crudInfoModalActions.ts +++ b/app/client/src/actions/crudInfoModalActions.ts @@ -1,6 +1,14 @@ import { ReduxActionTypes } from "constants/ReduxActionConstants"; -export const setCrudInfoModalOpen = (payload: boolean) => { +export type SetCrudInfoModalOpenPayload = { + open: boolean; + generateCRUDSuccessInfo?: { + successImageUrl: string; + successMessage: string; + }; +}; + +export const setCrudInfoModalData = (payload: SetCrudInfoModalOpenPayload) => { return { type: ReduxActionTypes.SET_CRUD_INFO_MODAL_OPEN, payload, diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index bdd0b56dc208..0505709eca82 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -319,25 +319,20 @@ export interface ReduxActionWithExtraParams extends ReduxAction { extraParams: Record; } -export const generateTemplateSuccess = ({ - isNewPage, - layoutId, - pageId, - pageName, -}: { - layoutId: string; - pageId: string; - pageName: string; +export type GenerateCRUDSuccess = { + page: { + layouts: Array; + id: string; + name: string; + isDefault?: boolean; + }; isNewPage: boolean; -}) => { +}; + +export const generateTemplateSuccess = (payload: GenerateCRUDSuccess) => { return { type: ReduxActionTypes.GENERATE_TEMPLATE_PAGE_SUCCESS, - payload: { - layoutId, - pageId, - pageName, - isNewPage, - }, + payload, }; }; diff --git a/app/client/src/constants/messages.ts b/app/client/src/constants/messages.ts index 472828d37587..2bcf5551c021 100644 --- a/app/client/src/constants/messages.ts +++ b/app/client/src/constants/messages.ts @@ -395,11 +395,13 @@ export const GENERATE_PAGE_ACTION_SUBTITLE = () => export const GENERATE_PAGE_FORM_TITLE = () => "Generate from Data"; -export const GEN_CRUD_INFO_DIALOG_HEADING = () => +export const GEN_CRUD_SUCCESS_MESSAGE = () => "Hurray! Your application is ready to use."; +export const GEN_CRUD_SUCCESS_DESC = () => + "Search through your data in the table and update it using the form"; export const GEN_CRUD_INFO_DIALOG_TITLE = () => "How it works?"; export const GEN_CRUD_INFO_DIALOG_SUBTITLE = () => - "Search through your data in the table and update it using the form."; + "CRUD page is generated from selected datasource. You can use the Form to modify the data. Since all your data is already connected you can add more queries and modify the bindings"; // Actions Right pane export const SEE_CONNECTED_ENTITIES = () => "See all connected entities"; diff --git a/app/client/src/pages/Editor/GeneratePage/components/CrudInfoModal.tsx b/app/client/src/pages/Editor/GeneratePage/components/CrudInfoModal.tsx index ae23ff8e6cca..578d2ef337c2 100644 --- a/app/client/src/pages/Editor/GeneratePage/components/CrudInfoModal.tsx +++ b/app/client/src/pages/Editor/GeneratePage/components/CrudInfoModal.tsx @@ -1,47 +1,43 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import styled from "styled-components"; import { connect, useDispatch } from "react-redux"; import { AppState } from "reducers"; import AnalyticsUtil from "utils/AnalyticsUtil"; import Button, { Category, Size } from "components/ads/Button"; import Text, { TextType } from "components/ads/Text"; -import { getCrudInfoModalOpen } from "selectors/crudInfoModalSelectors"; -import { setCrudInfoModalOpen } from "actions/crudInfoModalActions"; +import { getCrudInfoModalData } from "selectors/crudInfoModalSelectors"; +import { setCrudInfoModalData } from "actions/crudInfoModalActions"; import { Colors } from "constants/Colors"; import { S3_BUCKET_URL } from "constants/ThirdPartyConstants"; import Dialog from "components/ads/DialogComponent"; -import { GEN_CRUD_INFO_DIALOG_HEADING } from "../../../../constants/messages"; +import { GenerateCRUDSuccessInfoData } from "../../../../reducers/uiReducers/crudInfoModalReducer"; import { GEN_CRUD_INFO_DIALOG_SUBTITLE, - GEN_CRUD_INFO_DIALOG_TITLE, + GEN_CRUD_SUCCESS_MESSAGE, + GEN_CRUD_SUCCESS_DESC, + createMessage, } from "constants/messages"; +import { getTypographyByKey } from "constants/DefaultTheme"; type Props = { crudInfoModalOpen: boolean; + generateCRUDSuccessInfo: GenerateCRUDSuccessInfoData | null; }; -const HeaderContents = styled.div` - padding: ${(props) => props.theme.spaces[9]}px; - display: flex; - justify-content: space-between; - align-items: center; - padding-bottom: ${(props) => props.theme.spaces[7]}px; - background-color: ${Colors.FOAM}; -`; +const getSuccessGIF = () => `${S3_BUCKET_URL}/crud/check_mark_verified.gif`; const Heading = styled.div` - color: ${(props) => props.theme.colors.modal.headerText}; + color: ${Colors.CODE_GRAY}; display: flex; justify-content: center; font-size: 20px; line-height: 24px; - color: ${(props) => props.theme.colors.success.dark}; `; const ActionButtonWrapper = styled.div` display: flex; - justify-content: flex-end; + justify-content: center; margin: 30px 0px 0px; `; @@ -63,17 +59,22 @@ const Content = styled.div` flex-direction: column; `; +const Desc = styled.p` + ${(props) => getTypographyByKey(props, "p1")} + color: ${Colors.DOVE_GRAY2}; + margin-top: 8px; +`; + const Wrapper = styled.div` display: flex; flex-direction: column; height: 100%; - - .info-title { - font-weight: bold; - } + max-height: 700px; + min-height: 500px; .info-subtitle { padding-top: 5px; + text-align: center; } `; @@ -89,27 +90,83 @@ const ImageWrapper = styled.div` justify-content: center; `; -function Header() { +const SuccessContentWrapper = styled.div` + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; +`; + +const SuccessImage = styled.img` + margin: ${(props) => props.theme.spaces[6]}px; +`; + +const STEP = { + SHOW_SUCCESS_GIF: "show_success_gif", + SHOW_INFO: "show_info", +}; + +function InfoContent({ + onClose, + successMessage, +}: { + onClose: () => void; + successMessage: string; +}) { return ( - - {GEN_CRUD_INFO_DIALOG_HEADING()} - + <> + + + + + + + + + { + onClose(); + }} + size={Size.medium} + text="GOT IT" + /> + + ); } - const getInfoImage = (): string => `${S3_BUCKET_URL}/crud/working-flow-chart.png`; function GenCRUDSuccessModal(props: Props) { - const { crudInfoModalOpen } = props; + const { crudInfoModalOpen, generateCRUDSuccessInfo } = props; const dispatch = useDispatch(); + const [step, setStep] = useState(STEP.SHOW_SUCCESS_GIF); const onClose = () => { AnalyticsUtil.logEvent("CLOSE_GEN_PAGE_INFO_MODAL"); - dispatch(setCrudInfoModalOpen(false)); + dispatch(setCrudInfoModalData({ open: false })); }; + const successMessage = + (generateCRUDSuccessInfo && generateCRUDSuccessInfo.successMessage) || + createMessage(GEN_CRUD_INFO_DIALOG_SUBTITLE); + + useEffect(() => { + setTimeout(() => { + setStep(STEP.SHOW_INFO); + }, 2000); + }, [setStep]); + return ( -
- - - {GEN_CRUD_INFO_DIALOG_TITLE()} - - - - {GEN_CRUD_INFO_DIALOG_SUBTITLE()} - - - - - - - - { - onClose(); - }} - size={Size.medium} - text="GOT IT" - /> - + {step === STEP.SHOW_SUCCESS_GIF ? ( + + + {createMessage(GEN_CRUD_SUCCESS_MESSAGE)} + {createMessage(GEN_CRUD_SUCCESS_DESC)} + + ) : null} + {step === STEP.SHOW_INFO ? ( + + ) : null}
); } const mapStateToProps = (state: AppState) => ({ - crudInfoModalOpen: getCrudInfoModalOpen(state), + crudInfoModalOpen: getCrudInfoModalData(state).crudInfoModalOpen, + generateCRUDSuccessInfo: getCrudInfoModalData(state).generateCRUDSuccessInfo, }); export default connect(mapStateToProps)(GenCRUDSuccessModal); diff --git a/app/client/src/reducers/entityReducers/pageListReducer.tsx b/app/client/src/reducers/entityReducers/pageListReducer.tsx index 3e6111a973a8..56cb03e15b84 100644 --- a/app/client/src/reducers/entityReducers/pageListReducer.tsx +++ b/app/client/src/reducers/entityReducers/pageListReducer.tsx @@ -7,6 +7,7 @@ import { ReduxActionErrorTypes, } from "constants/ReduxActionConstants"; import { createReducer } from "utils/AppsmithUtils"; +import { GenerateCRUDSuccess } from "actions/pageActions"; const initialState: PageListReduxState = { pages: [], @@ -114,27 +115,24 @@ export const pageListReducer = createReducer(initialState, { }, [ReduxActionTypes.GENERATE_TEMPLATE_PAGE_SUCCESS]: ( state: PageListReduxState, - action: ReduxAction<{ - pageName: string; - pageId: string; - layoutId: string; - isDefault: boolean; - isNewPage: boolean; - }>, + action: ReduxAction, ) => { const _state = state; if (action.payload.isNewPage) { _state.pages = state.pages.map((page) => ({ ...page, latest: false })); const newPage = { - pageName: action.payload.pageName, - pageId: action.payload.pageId, - layoutId: action.payload.layoutId, - isDefault: action.payload.isDefault, + pageName: action.payload.page.name, + pageId: action.payload.page.id, + layoutId: action.payload.page.layouts[0].id, + isDefault: !!action.payload.page.isDefault, }; _state.pages.push({ ...newPage, latest: true }); } - return { ..._state, isGeneratingTemplatePage: false }; + return { + ..._state, + isGeneratingTemplatePage: false, + }; }, [ReduxActionErrorTypes.GENERATE_TEMPLATE_PAGE_ERROR]: ( state: PageListReduxState, diff --git a/app/client/src/reducers/uiReducers/crudInfoModalReducer.ts b/app/client/src/reducers/uiReducers/crudInfoModalReducer.ts index e460553cc909..e006481f4338 100644 --- a/app/client/src/reducers/uiReducers/crudInfoModalReducer.ts +++ b/app/client/src/reducers/uiReducers/crudInfoModalReducer.ts @@ -1,21 +1,33 @@ import { createReducer } from "utils/AppsmithUtils"; import { ReduxAction, ReduxActionTypes } from "constants/ReduxActionConstants"; +import { SetCrudInfoModalOpenPayload } from "actions/crudInfoModalActions"; const initialState: CrudInfoModalReduxState = { crudInfoModalOpen: false, + generateCRUDSuccessInfo: null, }; const crudInfoModalReducer = createReducer(initialState, { [ReduxActionTypes.SET_CRUD_INFO_MODAL_OPEN]: ( state: CrudInfoModalReduxState, - action: ReduxAction, + action: ReduxAction, ) => { - return { ...state, crudInfoModalOpen: action.payload }; + return { + ...state, + crudInfoModalOpen: action.payload.open, + generateCRUDSuccessInfo: action.payload.generateCRUDSuccessInfo, + }; }, }); +export type GenerateCRUDSuccessInfoData = { + successImageUrl: string; + successMessage: string; +}; + export interface CrudInfoModalReduxState { crudInfoModalOpen: boolean; + generateCRUDSuccessInfo: GenerateCRUDSuccessInfoData | null; } export default crudInfoModalReducer; diff --git a/app/client/src/sagas/PageSagas.tsx b/app/client/src/sagas/PageSagas.tsx index 6b680ad7347f..d06a53e77791 100644 --- a/app/client/src/sagas/PageSagas.tsx +++ b/app/client/src/sagas/PageSagas.tsx @@ -67,7 +67,7 @@ import { import { getDataTree } from "selectors/dataTreeSelectors"; import { IncorrectBindingError, validateResponse } from "./ErrorSagas"; import { executePageLoadActions } from "actions/widgetActions"; -import { ApiResponse } from "api/ApiResponses"; +import { ApiResponse, GenericApiResponse } from "api/ApiResponses"; import { getCurrentApplicationId, getCurrentLayoutId, @@ -101,7 +101,7 @@ import { generateTemplateSuccess, } from "../actions/pageActions"; import { getAppMode } from "selectors/applicationSelectors"; -import { setCrudInfoModalOpen } from "actions/crudInfoModalActions"; +import { setCrudInfoModalData } from "actions/crudInfoModalActions"; import { selectMultipleWidgetsAction } from "actions/widgetSelectionActions"; const getWidgetName = (state: AppState, widgetId: string) => @@ -898,26 +898,29 @@ export function* generateTemplatePageSaga( try { const request: GenerateTemplatePageRequest = action.payload; // if pageId is available in request, it will just update that page else it will generate new page. - const response: ApiResponse = yield call( - PageApi.generateTemplatePage, - request, - ); + const response: GenericApiResponse<{ + page: any; + successImageUrl: string; + successMessage: string; + }> = yield call(PageApi.generateTemplatePage, request); const isValidResponse: boolean = yield validateResponse(response); if (isValidResponse) { - const pageId = response.data.id; + const pageId = response.data.page.id; const applicationId = - response.data.applicationId || request.applicationId; + response.data.page.applicationId || request.applicationId; yield handleFetchedPage({ - fetchPageResponse: response, + fetchPageResponse: { + data: response.data.page, + responseMeta: response.responseMeta, + }, pageId, }); + // TODO : Add this to onSuccess (Redux Action) yield put( generateTemplateSuccess({ - pageId: response.data.id, - pageName: response.data.name, - layoutId: response.data.layouts[0].id, + page: response.data.page, isNewPage: !request.pageId, // if pageId if not defined, that means a new page is generated. }), ); @@ -931,7 +934,15 @@ export function* generateTemplatePageSaga( variant: Variant.success, }); - yield put(setCrudInfoModalOpen(true)); + yield put( + setCrudInfoModalData({ + open: true, + generateCRUDSuccessInfo: { + successImageUrl: response.data.successImageUrl, + successMessage: response.data.successMessage, + }, + }), + ); } } catch (error) { yield put(generateTemplateError()); diff --git a/app/client/src/selectors/crudInfoModalSelectors.ts b/app/client/src/selectors/crudInfoModalSelectors.ts index c2667b981273..8a89449fa1ec 100644 --- a/app/client/src/selectors/crudInfoModalSelectors.ts +++ b/app/client/src/selectors/crudInfoModalSelectors.ts @@ -1,4 +1,24 @@ import { AppState } from "reducers"; +import { createSelector } from "reselect"; +import { + CrudInfoModalReduxState, + GenerateCRUDSuccessInfoData, +} from "reducers/uiReducers/crudInfoModalReducer"; -export const getCrudInfoModalOpen = (state: AppState): boolean => - state.ui.crudInfoModal.crudInfoModalOpen; +export type CrudInfoModalData = { + crudInfoModalOpen: boolean; + generateCRUDSuccessInfo: GenerateCRUDSuccessInfoData | null; +}; + +const getCrudInfoModalState = (state: AppState): CrudInfoModalReduxState => + state.ui.crudInfoModal; + +export const getCrudInfoModalData = createSelector( + getCrudInfoModalState, + (crudInfoModal) => { + return { + crudInfoModalOpen: crudInfoModal.crudInfoModalOpen, + generateCRUDSuccessInfo: crudInfoModal.generateCRUDSuccessInfo, + }; + }, +); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/Resources.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/Resources.java new file mode 100644 index 000000000000..588daaa0ea34 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/Resources.java @@ -0,0 +1,7 @@ +package com.appsmith.server.constants; + +public class Resources { + + public static final String GENERATE_CRUD_PAGE_SUCCESS_URL_TABULAR = "https://assets.appsmith.com/crud/working-flow-chart.png"; + +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/PageController.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/PageController.java index 93af1e2d6271..ec531c59f1ef 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/PageController.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/controllers/PageController.java @@ -3,6 +3,7 @@ import com.appsmith.server.constants.Url; import com.appsmith.server.dtos.ApplicationPagesDTO; import com.appsmith.server.dtos.CRUDPageResourceDTO; +import com.appsmith.server.dtos.CRUDPageResponseDTO; import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.dtos.ResponseDTO; import com.appsmith.server.services.ApplicationPageService; @@ -57,7 +58,7 @@ public Mono> createPage(@Valid @RequestBody PageDTO resourc @PostMapping("/crud-page") @ResponseStatus(HttpStatus.CREATED) - public Mono> createCRUDPage(@RequestBody @NonNull CRUDPageResourceDTO resource) { + public Mono> createCRUDPage(@RequestBody @NonNull CRUDPageResourceDTO resource) { log.debug("Going to create crud-page"); return createDBTablePageSolution.createPageFromDBTable(null, resource) .map(created -> new ResponseDTO<>(HttpStatus.CREATED.value(), created, null)); @@ -65,8 +66,8 @@ public Mono> createCRUDPage(@RequestBody @NonNull CRUDPageR @PutMapping("/crud-page/{pageId}") @ResponseStatus(HttpStatus.OK) - public Mono> createCRUDPage(@PathVariable String pageId, - @NonNull @RequestBody CRUDPageResourceDTO resource) { + public Mono> createCRUDPage(@PathVariable String pageId, + @NonNull @RequestBody CRUDPageResourceDTO resource) { log.debug("Going to update resource {}", pageId); return createDBTablePageSolution.createPageFromDBTable(pageId, resource) .map(created -> new ResponseDTO<>(HttpStatus.CREATED.value(), created, null)); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/CRUDPageResponseDTO.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/CRUDPageResponseDTO.java new file mode 100644 index 000000000000..0deec432a018 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/CRUDPageResponseDTO.java @@ -0,0 +1,24 @@ +package com.appsmith.server.dtos; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * This class will hold the fields that will be consumed by the client after the successful CRUD page generation + */ +@NoArgsConstructor +@Getter +@Setter +public class CRUDPageResponseDTO { + + PageDTO page; + + // This field will give some guidelines how to interact with the widgets on the canvas created by CreateDBTablePageSolution + // e.g. We have generated the table from Datasource. You can use the Form> to modify it. Since all your data is + // already connected you can add more queries and modify the bindings + String successMessage; + + // This field will be used to display the image on how to use the template application + String successImageUrl; +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java index 41f83ee802ff..d7593cc08b1b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/CreateDBTablePageSolution.java @@ -11,6 +11,7 @@ import com.appsmith.server.constants.AnalyticsEvents; import com.appsmith.server.constants.Entity; import com.appsmith.server.constants.FieldName; +import com.appsmith.server.constants.Resources; import com.appsmith.server.domains.ApplicationJson; import com.appsmith.server.domains.Datasource; import com.appsmith.server.domains.Layout; @@ -19,6 +20,7 @@ import com.appsmith.server.domains.Plugin; import com.appsmith.server.dtos.ActionDTO; import com.appsmith.server.dtos.CRUDPageResourceDTO; +import com.appsmith.server.dtos.CRUDPageResponseDTO; import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; @@ -119,7 +121,7 @@ public class CreateDBTablePageSolution { * @param pageResourceDTO * @return generated pageDTO from the template resource */ - public Mono createPageFromDBTable(String pageId, CRUDPageResourceDTO pageResourceDTO) { + public Mono createPageFromDBTable(String pageId, CRUDPageResourceDTO pageResourceDTO) { /* 1. Fetch page from the application @@ -349,7 +351,14 @@ public Mono createPageFromDBTable(String pageId, CRUDPageResourceDTO pa || StringUtils.equals(actionDTO.getName(), LIST_QUERY) ? layoutActionService.setExecuteOnLoad(actionDTO.getId(), true) : Mono.just(actionDTO)) .then(applicationPageService.getPage(savedPageId, false) - .flatMap(pageDTO -> sendGenerateCRUDPageAnalyticsEvent(pageDTO, datasource, plugin.getName())) + .flatMap(pageDTO -> { + CRUDPageResponseDTO crudPage = new CRUDPageResponseDTO(); + crudPage.setPage(pageDTO); + crudPage.setSuccessMessage(createSuccessMessage(plugin)); + // Update the S3 image once received + crudPage.setSuccessImageUrl(Resources.GENERATE_CRUD_PAGE_SUCCESS_URL_TABULAR); + return sendGenerateCRUDPageAnalyticsEvent(crudPage, datasource, plugin.getName()); + }) ); }); } @@ -881,7 +890,21 @@ else if (actionConfiguration.getBody().matches("(?s).*,[\\W]*?(?i)WHERE.*")) { return actionConfiguration; } - private Mono sendGenerateCRUDPageAnalyticsEvent(PageDTO page, Datasource datasource, String pluginName) { + private String createSuccessMessage(Plugin plugin) { + + String displayWidget = Entity.S3_PLUGIN_PACKAGE_NAME.equals(plugin.getPackageName()) ? "LIST" : "TABLE"; + String updateWidget = Entity.S3_PLUGIN_PACKAGE_NAME.equals(plugin.getPackageName()) ? "FILEPICKER" : "FORM"; + + // Field used to send success message after the successful page creation + String successMessage = "We have generated the " + displayWidget + " from the " + plugin.getName() + + " Datasource. You can use the " + updateWidget + " to modify it. Since all your " + + "data is already connected you can add more queries and modify the bindings"; + + return successMessage; + } + + private Mono sendGenerateCRUDPageAnalyticsEvent(CRUDPageResponseDTO crudPage, Datasource datasource, String pluginName) { + PageDTO page = crudPage.getPage(); return sessionUserService.getCurrentUser() .map(currentUser -> { try { @@ -897,7 +920,7 @@ private Mono sendGenerateCRUDPageAnalyticsEvent(PageDTO page, Datasourc } catch (Exception e) { log.warn("Error sending generate CRUD DB table page data point", e); } - return page; + return crudPage; }); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java index 80ba76de0eba..b37364619122 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/solutions/CreateDBTablePageSolutionTests.java @@ -16,6 +16,7 @@ import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.Plugin; import com.appsmith.server.dtos.CRUDPageResourceDTO; +import com.appsmith.server.dtos.CRUDPageResponseDTO; import com.appsmith.server.dtos.PageDTO; import com.appsmith.server.exceptions.AppsmithError; import com.appsmith.server.exceptions.AppsmithException; @@ -182,7 +183,7 @@ Mono> getActions(String pageId) { @WithUserDetails(value = "api_user") public void createPageWithInvalidApplicationIdTest() { - Mono resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), resource); + Mono resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), resource); StepVerifier .create(resultMono) @@ -202,7 +203,7 @@ public void createPageWithInvalidDatasourceTest() { invalidDatasource.setDatasourceConfiguration(new DatasourceConfiguration()); resource.setDatasourceId(invalidDatasource.getId()); - Mono resultMono = datasourceService.create(invalidDatasource) + Mono resultMono = datasourceService.create(invalidDatasource) .flatMap(datasource -> { resource.setApplicationId(testApp.getId()); resource.setDatasourceId(datasource.getId()); @@ -220,7 +221,7 @@ public void createPageWithInvalidDatasourceTest() { @Test @WithUserDetails(value = "api_user") public void createPageWithInvalidRequestBodyTest() { - Mono resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), new CRUDPageResourceDTO()); + Mono resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), new CRUDPageResourceDTO()); StepVerifier .create(resultMono) @@ -234,11 +235,12 @@ public void createPageWithInvalidRequestBodyTest() { public void createPageWithNullPageId() { resource.setApplicationId(testApp.getId()); - Mono resultMono = solution.createPageFromDBTable(null, resource); + Mono resultMono = solution.createPageFromDBTable(null, resource); StepVerifier .create(resultMono) - .assertNext(page -> { + .assertNext(crudPage -> { + PageDTO page = crudPage.getPage(); Layout layout = page.getLayouts().get(0); assertThat(page.getName()).isEqualTo("SampleTable"); assertThat(page.getLayouts()).isNotEmpty(); @@ -249,6 +251,8 @@ public void createPageWithNullPageId() { assertThat(layout.getActionsUsedInDynamicBindings()).isNotEmpty(); assertThat(layout.getDsl().get("children").toString().replaceAll(specialCharactersRegex, "")) .containsIgnoringCase(dropdownOptions.replaceAll(specialCharactersRegex, "")); + assertThat(crudPage.getSuccessMessage()).isNotNull(); + assertThat(crudPage.getSuccessImageUrl()).isNotNull(); }) .verifyComplete(); } @@ -263,7 +267,8 @@ public void createPageWithValidPageIdForPostgresqlDS() { newPage.setName("crud-admin-page"); Mono resultMono = applicationPageService.createPage(newPage) - .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)); + .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) @@ -303,9 +308,11 @@ public void createPageWithValidPageIdForMySqlDS() { PageDTO newPage = new PageDTO(); newPage.setApplicationId(testApp.getId()); newPage.setName("crud-admin-page-mysql"); + StringBuilder pluginName = new StringBuilder(); Mono datasourceMono = pluginRepository.findByName("Mysql") .flatMap(plugin -> { + pluginName.append(plugin.getName()); Datasource datasource = new Datasource(); datasource.setPluginId(plugin.getId()); datasource.setOrganizationId(testOrg.getId()); @@ -315,7 +322,7 @@ public void createPageWithValidPageIdForMySqlDS() { return datasourceService.create(datasource); }); - Mono resultMono = datasourceMono + Mono resultMono = datasourceMono .flatMap(datasource1 -> { resource.setDatasourceId(datasource1.getId()); return applicationPageService.createPage(newPage); @@ -323,9 +330,10 @@ public void createPageWithValidPageIdForMySqlDS() { .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)); StepVerifier - .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) + .create(resultMono.zipWhen(crudPageResponseDTO -> getActions(crudPageResponseDTO.getPage().getId()))) .assertNext(tuple -> { - PageDTO page = tuple.getT1(); + CRUDPageResponseDTO crudPageResponseDTO = tuple.getT1(); + PageDTO page = crudPageResponseDTO.getPage(); List actions = tuple.getT2(); Layout layout = page.getLayouts().get(0); assertThat(page.getName()).isEqualTo(newPage.getName()); @@ -351,6 +359,9 @@ public void createPageWithValidPageIdForMySqlDS() { assertThat(action.getUnpublishedAction().getExecuteOnLoad()).isFalse(); } } + assertThat(crudPageResponseDTO.getSuccessMessage()).containsIgnoringCase(pluginName); + assertThat(crudPageResponseDTO.getSuccessMessage()).containsIgnoringCase("TABLE"); + assertThat(crudPageResponseDTO.getSuccessImageUrl()).isNotNull(); }) .verifyComplete(); } @@ -380,7 +391,8 @@ public void createPageWithValidPageIdForRedshiftDS() { resource.setDatasourceId(datasource1.getId()); return applicationPageService.createPage(newPage); }) - .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)); + .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) @@ -433,7 +445,8 @@ public void createPageWithNullPageIdForMSSqlDS() { .flatMap(datasource1 -> { resource.setDatasourceId(datasource1.getId()); return solution.createPageFromDBTable(null, resource); - }); + }) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) @@ -486,7 +499,8 @@ public void createPageWithNullPageIdForSnowflake() { .flatMap(datasource1 -> { resource.setDatasourceId(datasource1.getId()); return solution.createPageFromDBTable(null, resource); - }); + }) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) @@ -522,6 +536,7 @@ public void createPageWithNullPageIdForSnowflake() { public void createPageWithNullPageIdForS3() { resource.setApplicationId(testApp.getId()); + StringBuilder pluginName = new StringBuilder(); Mono datasourceMono = pluginRepository.findByName("S3") .flatMap(plugin -> { @@ -530,19 +545,21 @@ public void createPageWithNullPageIdForS3() { datasource.setOrganizationId(testOrg.getId()); datasource.setName("S3-CRUD-Page-Table-DS"); datasource.setDatasourceConfiguration(datasourceConfiguration); + pluginName.append(plugin.getName()); return datasourceService.create(datasource); }); - Mono resultMono = datasourceMono + Mono resultMono = datasourceMono .flatMap(datasource1 -> { resource.setDatasourceId(datasource1.getId()); return solution.createPageFromDBTable(null, resource); }); StepVerifier - .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) + .create(resultMono.zipWhen(crudPageResponseDTO -> getActions(crudPageResponseDTO.getPage().getId()))) .assertNext(tuple -> { - PageDTO page = tuple.getT1(); + CRUDPageResponseDTO crudPage = tuple.getT1(); + PageDTO page = crudPage.getPage(); List actions = tuple.getT2(); Layout layout = page.getLayouts().get(0); assertThat(page.getName()).isEqualTo("SampleTable"); @@ -561,6 +578,9 @@ public void createPageWithNullPageIdForS3() { assertThat(actionConfiguration.getPluginSpecifiedTemplates().get(1).getValue().toString()) .isEqualTo(resource.getTableName()); } + + assertThat(crudPage.getSuccessMessage()).containsIgnoringCase(pluginName); + assertThat(crudPage.getSuccessMessage()).containsIgnoringCase("LIST"); }) .verifyComplete(); } @@ -596,7 +616,8 @@ public void createPageWithValidPageIdForGoogleSheet() { resource.setDatasourceId(datasource1.getId()); return applicationPageService.createPage(newPage); }) - .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)); + .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId()))) @@ -656,7 +677,8 @@ public void createPageWithValidPageIdForMongoDB() { resource.setDatasourceId(datasource1.getId()); return applicationPageService.createPage(newPage); }) - .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)); + .flatMap(savedPage -> solution.createPageFromDBTable(savedPage.getId(), resource)) + .map(crudPageResponseDTO -> crudPageResponseDTO.getPage()); StepVerifier .create(resultMono.zipWhen(pageDTO -> getActions(pageDTO.getId())))