feat: Show Crud Info Modal data from backend (#6882)
CRUD Info modal which pops up on successful CRUD generation, will now have dynamic data for each CRUD template. Modal success `message` and `Image` to explain the working of the CRUD template is fetched from the backend. Co-authored-by: Abhijeet <ABHI.NAGARNAIK@GMAIL.COM>
This commit is contained in:
parent
058055331a
commit
dc86c9b82b
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -319,25 +319,20 @@ export interface ReduxActionWithExtraParams<T> extends ReduxAction<T> {
|
|||
extraParams: Record<any, any>;
|
||||
}
|
||||
|
||||
export const generateTemplateSuccess = ({
|
||||
isNewPage,
|
||||
layoutId,
|
||||
pageId,
|
||||
pageName,
|
||||
}: {
|
||||
layoutId: string;
|
||||
pageId: string;
|
||||
pageName: string;
|
||||
export type GenerateCRUDSuccess = {
|
||||
page: {
|
||||
layouts: Array<any>;
|
||||
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,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<HeaderContents>
|
||||
<Heading> {GEN_CRUD_INFO_DIALOG_HEADING()}</Heading>
|
||||
</HeaderContents>
|
||||
<>
|
||||
<Content>
|
||||
<Text
|
||||
className="info-subtitle"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: successMessage,
|
||||
}}
|
||||
type={TextType.P1}
|
||||
/>
|
||||
<ImageWrapper>
|
||||
<InfoImage alt="CRUD Info" src={getInfoImage()} />
|
||||
</ImageWrapper>
|
||||
</Content>
|
||||
|
||||
<ActionButtonWrapper>
|
||||
<ActionButton
|
||||
category={Category.primary}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
size={Size.medium}
|
||||
text="GOT IT"
|
||||
/>
|
||||
</ActionButtonWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<Dialog
|
||||
canEscapeKeyClose
|
||||
|
|
@ -118,37 +175,24 @@ function GenCRUDSuccessModal(props: Props) {
|
|||
setModalClose={onClose}
|
||||
>
|
||||
<Wrapper>
|
||||
<Header />
|
||||
<Content>
|
||||
<Text className="info-title" type={TextType.H4}>
|
||||
{GEN_CRUD_INFO_DIALOG_TITLE()}
|
||||
</Text>
|
||||
|
||||
<Text className="info-subtitle" type={TextType.P1}>
|
||||
{GEN_CRUD_INFO_DIALOG_SUBTITLE()}
|
||||
</Text>
|
||||
<ImageWrapper>
|
||||
<InfoImage alt="CRUD Info" src={getInfoImage()} />
|
||||
</ImageWrapper>
|
||||
</Content>
|
||||
|
||||
<ActionButtonWrapper>
|
||||
<ActionButton
|
||||
category={Category.primary}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
size={Size.medium}
|
||||
text="GOT IT"
|
||||
/>
|
||||
</ActionButtonWrapper>
|
||||
{step === STEP.SHOW_SUCCESS_GIF ? (
|
||||
<SuccessContentWrapper>
|
||||
<SuccessImage alt="Success" src={getSuccessGIF()} width="50px" />
|
||||
<Heading> {createMessage(GEN_CRUD_SUCCESS_MESSAGE)}</Heading>
|
||||
<Desc>{createMessage(GEN_CRUD_SUCCESS_DESC)}</Desc>
|
||||
</SuccessContentWrapper>
|
||||
) : null}
|
||||
{step === STEP.SHOW_INFO ? (
|
||||
<InfoContent onClose={onClose} successMessage={successMessage} />
|
||||
) : null}
|
||||
</Wrapper>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
crudInfoModalOpen: getCrudInfoModalOpen(state),
|
||||
crudInfoModalOpen: getCrudInfoModalData(state).crudInfoModalOpen,
|
||||
generateCRUDSuccessInfo: getCrudInfoModalData(state).generateCRUDSuccessInfo,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(GenCRUDSuccessModal);
|
||||
|
|
|
|||
|
|
@ -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<GenerateCRUDSuccess>,
|
||||
) => {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<boolean>,
|
||||
action: ReduxAction<SetCrudInfoModalOpenPayload>,
|
||||
) => {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.appsmith.server.controllers;
|
|||
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 class PageController {
|
|||
|
||||
@PostMapping("/crud-page")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public Mono<ResponseDTO<PageDTO>> createCRUDPage(@RequestBody @NonNull CRUDPageResourceDTO resource) {
|
||||
public Mono<ResponseDTO<CRUDPageResponseDTO>> 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 class PageController {
|
|||
|
||||
@PutMapping("/crud-page/{pageId}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Mono<ResponseDTO<PageDTO>> createCRUDPage(@PathVariable String pageId,
|
||||
@NonNull @RequestBody CRUDPageResourceDTO resource) {
|
||||
public Mono<ResponseDTO<CRUDPageResponseDTO>> 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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.appsmith.server.acl.AclPermission;
|
|||
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.NewPage;
|
|||
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<PageDTO> createPageFromDBTable(String pageId, CRUDPageResourceDTO pageResourceDTO) {
|
||||
public Mono<CRUDPageResponseDTO> createPageFromDBTable(String pageId, CRUDPageResourceDTO pageResourceDTO) {
|
||||
|
||||
/*
|
||||
1. Fetch page from the application
|
||||
|
|
@ -349,7 +351,14 @@ public class CreateDBTablePageSolution {
|
|||
|| 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 @@ public class CreateDBTablePageSolution {
|
|||
return actionConfiguration;
|
||||
}
|
||||
|
||||
private Mono<PageDTO> 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 <b>" + displayWidget + "</b> from the <b>" + plugin.getName()
|
||||
+ " Datasource</b>. You can use the <b>" + updateWidget + "</b> to modify it. Since all your " +
|
||||
"data is already connected you can add more queries and modify the bindings";
|
||||
|
||||
return successMessage;
|
||||
}
|
||||
|
||||
private Mono<CRUDPageResponseDTO> sendGenerateCRUDPageAnalyticsEvent(CRUDPageResponseDTO crudPage, Datasource datasource, String pluginName) {
|
||||
PageDTO page = crudPage.getPage();
|
||||
return sessionUserService.getCurrentUser()
|
||||
.map(currentUser -> {
|
||||
try {
|
||||
|
|
@ -897,7 +920,7 @@ public class CreateDBTablePageSolution {
|
|||
} catch (Exception e) {
|
||||
log.warn("Error sending generate CRUD DB table page data point", e);
|
||||
}
|
||||
return page;
|
||||
return crudPage;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.appsmith.server.domains.NewAction;
|
|||
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 @@ public class CreateDBTablePageSolutionTests {
|
|||
@WithUserDetails(value = "api_user")
|
||||
public void createPageWithInvalidApplicationIdTest() {
|
||||
|
||||
Mono<PageDTO> resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), resource);
|
||||
Mono<CRUDPageResponseDTO> resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), resource);
|
||||
|
||||
StepVerifier
|
||||
.create(resultMono)
|
||||
|
|
@ -202,7 +203,7 @@ public class CreateDBTablePageSolutionTests {
|
|||
invalidDatasource.setDatasourceConfiguration(new DatasourceConfiguration());
|
||||
|
||||
resource.setDatasourceId(invalidDatasource.getId());
|
||||
Mono<PageDTO> resultMono = datasourceService.create(invalidDatasource)
|
||||
Mono<CRUDPageResponseDTO> resultMono = datasourceService.create(invalidDatasource)
|
||||
.flatMap(datasource -> {
|
||||
resource.setApplicationId(testApp.getId());
|
||||
resource.setDatasourceId(datasource.getId());
|
||||
|
|
@ -220,7 +221,7 @@ public class CreateDBTablePageSolutionTests {
|
|||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void createPageWithInvalidRequestBodyTest() {
|
||||
Mono<PageDTO> resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), new CRUDPageResourceDTO());
|
||||
Mono<CRUDPageResponseDTO> resultMono = solution.createPageFromDBTable(testApp.getPages().get(0).getId(), new CRUDPageResourceDTO());
|
||||
|
||||
StepVerifier
|
||||
.create(resultMono)
|
||||
|
|
@ -234,11 +235,12 @@ public class CreateDBTablePageSolutionTests {
|
|||
public void createPageWithNullPageId() {
|
||||
|
||||
resource.setApplicationId(testApp.getId());
|
||||
Mono<PageDTO> resultMono = solution.createPageFromDBTable(null, resource);
|
||||
Mono<CRUDPageResponseDTO> 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 class CreateDBTablePageSolutionTests {
|
|||
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 class CreateDBTablePageSolutionTests {
|
|||
newPage.setName("crud-admin-page");
|
||||
|
||||
Mono<PageDTO> 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 class CreateDBTablePageSolutionTests {
|
|||
PageDTO newPage = new PageDTO();
|
||||
newPage.setApplicationId(testApp.getId());
|
||||
newPage.setName("crud-admin-page-mysql");
|
||||
StringBuilder pluginName = new StringBuilder();
|
||||
|
||||
Mono<Datasource> 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 class CreateDBTablePageSolutionTests {
|
|||
return datasourceService.create(datasource);
|
||||
});
|
||||
|
||||
Mono<PageDTO> resultMono = datasourceMono
|
||||
Mono<CRUDPageResponseDTO> resultMono = datasourceMono
|
||||
.flatMap(datasource1 -> {
|
||||
resource.setDatasourceId(datasource1.getId());
|
||||
return applicationPageService.createPage(newPage);
|
||||
|
|
@ -323,9 +330,10 @@ public class CreateDBTablePageSolutionTests {
|
|||
.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<NewAction> actions = tuple.getT2();
|
||||
Layout layout = page.getLayouts().get(0);
|
||||
assertThat(page.getName()).isEqualTo(newPage.getName());
|
||||
|
|
@ -351,6 +359,9 @@ public class CreateDBTablePageSolutionTests {
|
|||
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 class CreateDBTablePageSolutionTests {
|
|||
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 class CreateDBTablePageSolutionTests {
|
|||
.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 class CreateDBTablePageSolutionTests {
|
|||
.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 class CreateDBTablePageSolutionTests {
|
|||
public void createPageWithNullPageIdForS3() {
|
||||
|
||||
resource.setApplicationId(testApp.getId());
|
||||
StringBuilder pluginName = new StringBuilder();
|
||||
|
||||
Mono<Datasource> datasourceMono = pluginRepository.findByName("S3")
|
||||
.flatMap(plugin -> {
|
||||
|
|
@ -530,19 +545,21 @@ public class CreateDBTablePageSolutionTests {
|
|||
datasource.setOrganizationId(testOrg.getId());
|
||||
datasource.setName("S3-CRUD-Page-Table-DS");
|
||||
datasource.setDatasourceConfiguration(datasourceConfiguration);
|
||||
pluginName.append(plugin.getName());
|
||||
return datasourceService.create(datasource);
|
||||
});
|
||||
|
||||
Mono<PageDTO> resultMono = datasourceMono
|
||||
Mono<CRUDPageResponseDTO> 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<NewAction> actions = tuple.getT2();
|
||||
Layout layout = page.getLayouts().get(0);
|
||||
assertThat(page.getName()).isEqualTo("SampleTable");
|
||||
|
|
@ -561,6 +578,9 @@ public class CreateDBTablePageSolutionTests {
|
|||
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 class CreateDBTablePageSolutionTests {
|
|||
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 class CreateDBTablePageSolutionTests {
|
|||
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())))
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user