chore: Updating generate page interaction to show it in a modal following the IDE 2.0 interaction pattern (#37414)
## Description Updating generate page interaction to show it in a modal following the IDE 2.0 interaction pattern Fixes [#32952](https://github.com/appsmithorg/appsmith/issues/32952) ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11900113834> > Commit: 3903c44fe5a6c7db0d22d9cf982c28a1380f4546 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11900113834&attempt=2" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Mon, 18 Nov 2024 21:26:44 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes - **New Features** - Introduced a modal for generating pages, enhancing user interaction. - Added new action types and constants for managing page generation processes. - Updated UI messages for clarity in the page generation context. - Improved handling of datasource selection and page generation in various components. - **Bug Fixes** - Improved error handling in various components to prevent silent failures. - **Refactor** - Streamlined routing logic by removing deprecated paths and functions. - Transitioned from direct navigation to modal-based interactions for page generation. - Enhanced control flow and error handling within components. - **Chores** - Updated import paths for better organization of action-related functions within the Redux architecture. - **Tests** - Enhanced test cases for CRUD operations, ensuring better validation and error handling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
afd2fcc1fa
commit
72eb2cd4cb
|
|
@ -47,6 +47,7 @@ describe(
|
|||
dataSources._dropdownOption,
|
||||
"worldCountryInfo",
|
||||
);
|
||||
agHelper.GetNClick(dataSources._generatePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage("ABW", "Aruba", "North America", "Code");
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ describe(
|
|||
assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated
|
||||
agHelper.GetNClick(dataSources._selectTableDropdown, 0, true);
|
||||
agHelper.GetNClickByContains(dataSources._dropdownOption, "customers");
|
||||
agHelper.GetNClick(dataSources._generatePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"103",
|
||||
|
|
@ -110,6 +112,7 @@ describe(
|
|||
it("3. Generate CRUD page from datasource present in ACTIVE section", function () {
|
||||
EditorNavigation.SelectEntityByName(dsName, EntityType.Datasource);
|
||||
dataSources.SelectTableFromPreviewSchemaList("employees");
|
||||
agHelper.GetNClick(dataSources._datasourceCardGeneratePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"1002",
|
||||
|
|
@ -311,9 +314,6 @@ describe(
|
|||
col3Text: string,
|
||||
jsonFromHeader: string,
|
||||
) {
|
||||
agHelper.GetNClick(
|
||||
`${dataSources._generatePageBtn}, ${dataSources._datasourceCardGeneratePageBtn}`,
|
||||
);
|
||||
assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201);
|
||||
agHelper.AssertContains("Successfully generated a page");
|
||||
//assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes
|
||||
|
|
|
|||
|
|
@ -399,9 +399,7 @@ describe(
|
|||
col3Text: string,
|
||||
jsonFromHeader: string,
|
||||
) {
|
||||
agHelper.GetNClick(
|
||||
`${dataSources._generatePageBtn}, ${dataSources._datasourceCardGeneratePageBtn}`,
|
||||
);
|
||||
agHelper.GetNClick(dataSources._datasourceCardGeneratePageBtn);
|
||||
assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201);
|
||||
agHelper.AssertContains("Successfully generated a page");
|
||||
//assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ describe(
|
|||
assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated
|
||||
agHelper.GetNClick(dataSources._selectTableDropdown, 0, true);
|
||||
agHelper.GetNClickByContains(dataSources._dropdownOption, "film");
|
||||
agHelper.GetNClick(dataSources._generatePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"ACADEMY DINOSAUR",
|
||||
|
|
@ -86,6 +87,7 @@ describe(
|
|||
assertHelper.AssertNetworkStatus("@getDatasourceStructure"); //Making sure table dropdown is populated
|
||||
agHelper.GetNClick(dataSources._selectTableDropdown, 0, true);
|
||||
agHelper.GetNClickByContains(dataSources._dropdownOption, "suppliers");
|
||||
agHelper.GetNClick(dataSources._generatePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"Exotic Liquids",
|
||||
|
|
@ -104,6 +106,7 @@ describe(
|
|||
it("3. Generate CRUD page from datasource present in ACTIVE section", function () {
|
||||
EditorNavigation.SelectEntityByName(dsName, EntityType.Datasource);
|
||||
dataSources.SelectTableFromPreviewSchemaList("public.orders");
|
||||
agHelper.GetNClick(dataSources._datasourceCardGeneratePageBtn);
|
||||
|
||||
GenerateCRUDNValidateDeployPage(
|
||||
"VINET",
|
||||
|
|
@ -135,9 +138,6 @@ describe(
|
|||
col3Text: string,
|
||||
jsonFromHeader: string,
|
||||
) {
|
||||
agHelper.GetNClick(
|
||||
`${dataSources._generatePageBtn}, ${dataSources._datasourceCardGeneratePageBtn}`,
|
||||
);
|
||||
assertHelper.AssertNetworkStatus("@replaceLayoutWithCRUDPage", 201);
|
||||
agHelper.AssertContains("Successfully generated a page");
|
||||
//assertHelper.AssertNetworkStatus("@getActions", 200);//Since failing sometimes
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ describe(
|
|||
200,
|
||||
);
|
||||
|
||||
agHelper.AssertContains("Generate from data");
|
||||
agHelper.AssertContains("Generate a page based on your data");
|
||||
agHelper.GetNClick(generatePage.selectTableDropdown);
|
||||
agHelper.GetNClickByContains(
|
||||
generatePage.dropdownOption,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import {
|
||||
ADD_PATH,
|
||||
ADMIN_SETTINGS_PATH,
|
||||
GEN_TEMPLATE_FORM_ROUTE,
|
||||
GEN_TEMPLATE_URL,
|
||||
getViewerCustomPath,
|
||||
getViewerPath,
|
||||
TEMPLATES_PATH,
|
||||
|
|
@ -122,12 +120,6 @@ export const saasEditorApiIdURL = (
|
|||
}`,
|
||||
});
|
||||
|
||||
export const generateTemplateFormURL = (props: URLBuilderParams): string =>
|
||||
urlBuilder.build({
|
||||
...props,
|
||||
suffix: `${GEN_TEMPLATE_URL}${GEN_TEMPLATE_FORM_ROUTE}`,
|
||||
});
|
||||
|
||||
export const onboardingCheckListUrl = (props: URLBuilderParams): string =>
|
||||
urlBuilder.build({
|
||||
...props,
|
||||
|
|
|
|||
|
|
@ -1070,6 +1070,17 @@ const CurlImportActionErrorTypes = {
|
|||
SUBMIT_CURL_FORM_ERROR: "SUBMIT_CURL_FORM_ERROR",
|
||||
};
|
||||
|
||||
const GeneratePageActionTypes = {
|
||||
SET_GENERATE_PAGE_MODAL_OPEN: "SET_GENERATE_PAGE_MODAL_OPEN",
|
||||
SET_GENERATE_PAGE_MODAL_CLOSE: "SET_GENERATE_PAGE_MODAL_CLOSE",
|
||||
SUBMIT_GENERATE_PAGE_FORM_INIT: "SUBMIT_GENERATE_PAGE_FORM_INIT",
|
||||
SUBMIT_GENERATE_PAGE_FORM_SUCCESS: "SUBMIT_GENERATE_PAGE_FORM_SUCCESS",
|
||||
};
|
||||
|
||||
const GeneratePageActionErrorTypes = {
|
||||
SUBMIT_GENERATE_PAGE_FORM_ERROR: "SUBMIT_GENERATE_PAGE_FORM_ERROR",
|
||||
};
|
||||
|
||||
const BatchUpdateActionTypes = {
|
||||
BATCHED_UPDATE: "BATCHED_UPDATE",
|
||||
EXECUTE_BATCH: "EXECUTE_BATCH",
|
||||
|
|
@ -1276,12 +1287,13 @@ export const ReduxActionTypes = {
|
|||
...AppSettingsActionTypes,
|
||||
...BatchUpdateActionTypes,
|
||||
...BuildingBlocksActionTypes,
|
||||
...DatasourceEditorActionTypes,
|
||||
...CurlImportActionTypes,
|
||||
...DatasourceEditorActionTypes,
|
||||
...ErrorManagementActionTypes,
|
||||
...ExplorerActionTypes,
|
||||
...EvaluationActionTypes,
|
||||
...FeatureFlagActionTypes,
|
||||
...GeneratePageActionTypes,
|
||||
...GitActionTypes,
|
||||
...HelpActionTypes,
|
||||
...IDEActionTypes,
|
||||
|
|
@ -1324,6 +1336,7 @@ export const ReduxActionErrorTypes = {
|
|||
...DatasourceEditorActionErrorTypes,
|
||||
...EvaluationActionErrorTypes,
|
||||
...FeatureFlagActionErrorTypes,
|
||||
...GeneratePageActionErrorTypes,
|
||||
...GitActionErrorTypes,
|
||||
...IDEActionErrorTypes,
|
||||
...ImportExportActionErrorTypes,
|
||||
|
|
|
|||
|
|
@ -752,7 +752,10 @@ export const BUILD_FROM_SCRATCH_ACTION_TITLE = () => "Build with drag & drop";
|
|||
|
||||
export const GENERATE_PAGE_ACTION_TITLE = () => "Generate page with data";
|
||||
|
||||
export const GENERATE_PAGE_FORM_TITLE = () => "Generate from data";
|
||||
export const GENERATE_PAGE_FORM_TITLE = () =>
|
||||
"Generate a page based on your data";
|
||||
export const GENERATE_PAGE_FORM_SUB_TITLE = () =>
|
||||
"Use your datasource's schema to generate a simple CRUD page.";
|
||||
|
||||
export const GEN_CRUD_SUCCESS_MESSAGE = () =>
|
||||
"Hurray! Your application is ready for use.";
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@ export const APP_LIBRARIES_EDITOR_PATH = `/libraries`;
|
|||
export const APP_PACKAGES_EDITOR_PATH = `/packages`;
|
||||
export const APP_SETTINGS_EDITOR_PATH = `/settings`;
|
||||
export const SAAS_GSHEET_EDITOR_ID_PATH = `/saas/google-sheets-plugin/datasources/:datasourceId`;
|
||||
export const GEN_TEMPLATE_URL = "generate-page";
|
||||
export const GENERATE_TEMPLATE_PATH = `/${GEN_TEMPLATE_URL}`;
|
||||
export const GEN_TEMPLATE_FORM_ROUTE = "/form";
|
||||
export const GENERATE_TEMPLATE_FORM_PATH = `${GENERATE_TEMPLATE_PATH}${GEN_TEMPLATE_FORM_ROUTE}`;
|
||||
export const BUILDER_CHECKLIST_PATH = `/checklist`;
|
||||
export const ADMIN_SETTINGS_PATH = "/settings";
|
||||
export const ADMIN_SETTINGS_CATEGORY_DEFAULT_PATH = "/settings/general";
|
||||
|
|
@ -124,10 +120,6 @@ export const matchViewerForkPath = (pathName: string) =>
|
|||
match(`${VIEWER_PATH}${VIEWER_FORK_PATH}`)(pathName) ||
|
||||
match(`${VIEWER_CUSTOM_PATH}${VIEWER_FORK_PATH}`)(pathName) ||
|
||||
match(`${VIEWER_PATH_DEPRECATED}${VIEWER_FORK_PATH}`)(pathName);
|
||||
export const matchGeneratePagePath = (pathName: string) =>
|
||||
match(`${BUILDER_PATH}${GENERATE_TEMPLATE_FORM_PATH}`)(pathName) ||
|
||||
match(`${BUILDER_CUSTOM_PATH}${GENERATE_TEMPLATE_FORM_PATH}`)(pathName) ||
|
||||
match(`${BUILDER_PATH_DEPRECATED}${GENERATE_TEMPLATE_FORM_PATH}`)(pathName);
|
||||
|
||||
export const matchAppLibrariesPath = (pathName: string) =>
|
||||
match(`${BUILDER_PATH}${APP_LIBRARIES_EDITOR_PATH}`)(pathName);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { generateTemplateFormURL } from "ee/RouteBuilder";
|
||||
import {
|
||||
GENERATE_NEW_PAGE_BUTTON_TEXT,
|
||||
createMessage,
|
||||
|
|
@ -18,7 +17,7 @@ import type { ApiDatasourceForm } from "entities/Datasource/RestAPIForm";
|
|||
import NewActionButton from "pages/Editor/DataSourceEditor/NewActionButton";
|
||||
import { useShowPageGenerationOnHeader } from "pages/Editor/DataSourceEditor/hooks";
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
getCurrentApplicationId,
|
||||
getCurrentBasePageId,
|
||||
|
|
@ -26,10 +25,10 @@ import {
|
|||
} from "selectors/editorSelectors";
|
||||
import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors";
|
||||
import { isEnabledForPreviewData } from "utils/editorContextUtils";
|
||||
import history from "utils/history";
|
||||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { EditorNames } from "./";
|
||||
import { getCurrentApplication } from "ee/selectors/applicationSelectors";
|
||||
import { openGeneratePageModal } from "pages/Editor/GeneratePage/store/generatePageActions";
|
||||
|
||||
export interface HeaderActionProps {
|
||||
datasource: Datasource | ApiDatasourceForm | undefined;
|
||||
|
|
@ -47,7 +46,7 @@ export const useHeaderActions = (
|
|||
showReconnectButton = false,
|
||||
}: HeaderActionProps,
|
||||
) => {
|
||||
const basePageId = useSelector(getCurrentBasePageId);
|
||||
const dispatch = useDispatch();
|
||||
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
|
||||
const releaseDragDropBuildingBlocks = useFeatureFlag(
|
||||
FEATURE_FLAG.release_drag_drop_building_blocks_enabled,
|
||||
|
|
@ -97,13 +96,10 @@ export const useHeaderActions = (
|
|||
}
|
||||
|
||||
AnalyticsUtil.logEvent("DATASOURCE_CARD_GEN_CRUD_PAGE_ACTION");
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: (datasource as Datasource).id,
|
||||
new_page: true,
|
||||
},
|
||||
dispatch(
|
||||
openGeneratePageModal({
|
||||
datasourceId: (datasource as Datasource).id,
|
||||
new_page: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
BUILDER_PATH_DEPRECATED,
|
||||
DATA_SOURCES_EDITOR_ID_PATH,
|
||||
DATA_SOURCES_EDITOR_LIST_PATH,
|
||||
GENERATE_TEMPLATE_FORM_PATH,
|
||||
INTEGRATION_EDITOR_PATH,
|
||||
JS_COLLECTION_EDITOR_PATH,
|
||||
JS_COLLECTION_ID_PATH,
|
||||
|
|
@ -33,7 +32,6 @@ import {
|
|||
import DatasourceForm from "pages/Editor/SaaSEditor/DatasourceForm";
|
||||
import DataSourceEditor from "pages/Editor/DataSourceEditor";
|
||||
import DatasourceBlankState from "pages/Editor/DataSourceEditor/DatasourceBlankState";
|
||||
import GeneratePage from "pages/Editor/GeneratePage";
|
||||
import type { RouteProps } from "react-router";
|
||||
import { useSelector } from "react-redux";
|
||||
import { combinedPreviewModeSelector } from "selectors/editorSelectors";
|
||||
|
|
@ -139,12 +137,6 @@ function useRoutes(path: string): RouteReturnType[] {
|
|||
exact: true,
|
||||
path: `${path}${SAAS_EDITOR_DATASOURCE_ID_PATH}`,
|
||||
},
|
||||
{
|
||||
key: "GeneratePage",
|
||||
component: isPreviewMode ? WidgetsEditor : GeneratePage,
|
||||
exact: true,
|
||||
path: `${path}${GENERATE_TEMPLATE_FORM_PATH}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import {
|
|||
createNewAPIBasedOnParentEntity,
|
||||
createNewJSCollectionBasedOnParentEntity,
|
||||
} from "ee/actions/helpers";
|
||||
import { openCurlImportModal } from "pages/Editor/CurlImport/helpers";
|
||||
import { openCurlImportModal } from "pages/Editor/CurlImport/store/curlImportActions";
|
||||
|
||||
export type SelectEvent =
|
||||
| React.MouseEvent
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import {
|
|||
} from "selectors/curlImportSelectors";
|
||||
import { submit } from "redux-form";
|
||||
import { CURL_IMPORT_FORM } from "ee/constants/forms";
|
||||
import { closeCurlImportModal, openCurlImportModal } from "./helpers";
|
||||
import {
|
||||
closeCurlImportModal,
|
||||
openCurlImportModal,
|
||||
} from "./store/curlImportActions";
|
||||
import CurlLogo from "assets/images/Curl-logo.svg";
|
||||
import { createMessage, IMPORT_BTN_LABEL } from "ee/constants/messages";
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { submitCurlImportForm } from "../../../actions/importActions";
|
||||
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
|
||||
export interface CurlImportFormValues {
|
||||
curl: string;
|
||||
|
|
@ -17,15 +16,3 @@ export const curlImportSubmitHandler = (
|
|||
) => {
|
||||
dispatch(submitCurlImportForm(values));
|
||||
};
|
||||
|
||||
export const openCurlImportModal = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURL_MODAL_OPEN,
|
||||
};
|
||||
};
|
||||
|
||||
export const closeCurlImportModal = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURL_MODAL_CLOSE,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
|
||||
export interface CurlImportFormValues {
|
||||
curl: string;
|
||||
contextId: string;
|
||||
name: string;
|
||||
contextType: ActionParentEntityTypeInterface;
|
||||
}
|
||||
|
||||
export const openCurlImportModal = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURL_MODAL_OPEN,
|
||||
};
|
||||
};
|
||||
|
||||
export const closeCurlImportModal = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_CURL_MODAL_CLOSE,
|
||||
};
|
||||
};
|
||||
|
|
@ -52,7 +52,6 @@ const FieldWrapper = styled.div`
|
|||
export const ViewModeWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-bottom: 1px solid var(--ads-v2-color-border);
|
||||
padding: var(--ads-v2-spaces-7) 0;
|
||||
gap: var(--ads-v2-spaces-4);
|
||||
overflow: auto;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ import React, { useMemo, useState } from "react";
|
|||
import { AddButtonWrapper, EntityClassNames } from "../Entity";
|
||||
import EntityAddButton from "../Entity/AddButton";
|
||||
import styled from "styled-components";
|
||||
import history from "utils/history";
|
||||
import { generateTemplateFormURL } from "ee/RouteBuilder";
|
||||
import { useParams } from "react-router";
|
||||
import { useDispatch } from "react-redux";
|
||||
import type { ExplorerURLParams } from "ee/pages/Editor/Explorer/helpers";
|
||||
|
|
@ -32,6 +30,7 @@ import {
|
|||
LayoutSystemFeatures,
|
||||
useLayoutSystemFeatures,
|
||||
} from "layoutSystems/common/useLayoutSystemFeatures";
|
||||
import { openGeneratePageModal } from "pages/Editor/GeneratePage/store/generatePageActions";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.title {
|
||||
|
|
@ -85,7 +84,7 @@ function AddPageContextMenu({
|
|||
items.push({
|
||||
title: createMessage(GENERATE_PAGE_ACTION_TITLE),
|
||||
icon: "database-2-line",
|
||||
onClick: () => history.push(generateTemplateFormURL({ basePageId })),
|
||||
onClick: () => dispatch(openGeneratePageModal()),
|
||||
"data-testid": "generate-page",
|
||||
key: "GENERATE_PAGE",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,23 +11,25 @@ import {
|
|||
} from "ee/selectors/entitiesSelector";
|
||||
|
||||
import type { Datasource } from "entities/Datasource";
|
||||
import { fetchDatasourceStructure } from "actions/datasourceActions";
|
||||
import {
|
||||
fetchDatasourceStructure,
|
||||
setDatasourceViewModeFlag,
|
||||
} from "actions/datasourceActions";
|
||||
import { generateTemplateToUpdatePage } from "actions/pageActions";
|
||||
import { useLocation } from "react-router";
|
||||
import { INTEGRATION_TABS } from "constants/routes";
|
||||
import history from "utils/history";
|
||||
import { getQueryParams } from "utils/URLUtils";
|
||||
import { getIsGeneratingTemplatePage } from "selectors/pageListSelectors";
|
||||
import {
|
||||
getGeneratePageModalParams,
|
||||
getIsGeneratingTemplatePage,
|
||||
} from "selectors/pageListSelectors";
|
||||
import DataSourceOption, {
|
||||
CONNECT_NEW_DATASOURCE_OPTION_ID,
|
||||
DatasourceImage,
|
||||
} from "../DataSourceOption";
|
||||
import { getQueryStringfromObject } from "ee/entities/URLRedirect/URLAssembly";
|
||||
import type { DropdownOption } from "@appsmith/ads-old";
|
||||
import { Button, Icon, Text, Select, Option, Tooltip } from "@appsmith/ads";
|
||||
import GoogleSheetForm from "./GoogleSheetForm";
|
||||
import {
|
||||
GENERATE_PAGE_FORM_TITLE,
|
||||
createMessage,
|
||||
GEN_CRUD_DATASOURCE_DROPDOWN_LABEL,
|
||||
} from "ee/constants/messages";
|
||||
|
|
@ -70,6 +72,7 @@ import equal from "fast-deep-equal";
|
|||
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
|
||||
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
|
||||
import { getHasCreateDatasourcePermission } from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { closeGeneratePageModal } from "../../store/generatePageActions";
|
||||
|
||||
// ---------- Styles ----------
|
||||
|
||||
|
|
@ -77,24 +80,11 @@ const TooltipWrapper = styled.div`
|
|||
margin-left: 6px;
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
border: none;
|
||||
`;
|
||||
|
||||
const FormWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const DescWrapper = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const Row = styled.p`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
@ -218,7 +208,7 @@ const DatasourceOptionSelectedView = (props: any) => {
|
|||
|
||||
function GeneratePageForm() {
|
||||
const dispatch = useDispatch();
|
||||
const querySearch = useLocation().search;
|
||||
const params = useSelector(getGeneratePageModalParams);
|
||||
|
||||
const basePageId = useSelector(getCurrentBasePageId);
|
||||
const pageId = useSelector(getCurrentPageId);
|
||||
|
|
@ -539,10 +529,9 @@ function GeneratePageForm() {
|
|||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (querySearch) {
|
||||
const queryParams = getQueryParams();
|
||||
const datasourceId = queryParams.datasourceId;
|
||||
const generateNewPage = queryParams.new_page;
|
||||
if (params?.datasourceId || params?.new_page) {
|
||||
const datasourceId = params.datasourceId;
|
||||
const generateNewPage = params.new_page;
|
||||
|
||||
if (datasourceId) {
|
||||
if (generateNewPage || numberOfEntities > 0) {
|
||||
|
|
@ -552,15 +541,9 @@ function GeneratePageForm() {
|
|||
}
|
||||
|
||||
setDatasourceIdToBeSelected(datasourceId);
|
||||
delete queryParams.datasourceId;
|
||||
delete queryParams.new_page;
|
||||
const redirectURL =
|
||||
window.location.pathname + getQueryStringfromObject(queryParams);
|
||||
|
||||
history.replace(redirectURL);
|
||||
}
|
||||
}
|
||||
}, [numberOfEntities, querySearch, setDatasourceIdToBeSelected]);
|
||||
}, [numberOfEntities, params, setDatasourceIdToBeSelected]);
|
||||
|
||||
const routeToCreateNewDatasource = () => {
|
||||
AnalyticsUtil.logEvent("GEN_CRUD_PAGE_CREATE_NEW_DATASOURCE");
|
||||
|
|
@ -577,6 +560,7 @@ function GeneratePageForm() {
|
|||
AnalyticsUtil.logEvent("NAVIGATE_TO_CREATE_NEW_DATASOURCE_PAGE", {
|
||||
entryPoint,
|
||||
});
|
||||
dispatch(closeGeneratePageModal());
|
||||
};
|
||||
|
||||
const generatePageAction = (data: GeneratePagePayload) => {
|
||||
|
|
@ -602,6 +586,7 @@ function GeneratePageForm() {
|
|||
|
||||
AnalyticsUtil.logEvent("GEN_CRUD_PAGE_FORM_SUBMIT");
|
||||
dispatch(generateTemplateToUpdatePage(payload));
|
||||
dispatch(closeGeneratePageModal());
|
||||
};
|
||||
|
||||
const handleFormSubmit = () => {
|
||||
|
|
@ -625,6 +610,8 @@ function GeneratePageForm() {
|
|||
});
|
||||
|
||||
history.push(redirectURL);
|
||||
dispatch(setDatasourceViewModeFlag(false));
|
||||
dispatch(closeGeneratePageModal());
|
||||
};
|
||||
|
||||
// if the datasource has basic information to connect to db it is considered as a valid structure hence isValid true.
|
||||
|
|
@ -682,250 +669,247 @@ function GeneratePageForm() {
|
|||
!selectedTable.value || !showSubmitButton || isSelectedTableEmpty;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Wrapper>
|
||||
<DescWrapper>
|
||||
<Text kind="heading-m">{GENERATE_PAGE_FORM_TITLE()}</Text>
|
||||
</DescWrapper>
|
||||
</Wrapper>
|
||||
<FormWrapper>
|
||||
<FormWrapper>
|
||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
||||
<Label>{createMessage(GEN_CRUD_DATASOURCE_DROPDOWN_LABEL)}</Label>
|
||||
<Select
|
||||
data-testid="t--datasource-dropdown"
|
||||
getPopupContainer={(triggerNode) => triggerNode.parentNode.parentNode}
|
||||
onChange={(value) => {
|
||||
if (value === CONNECT_NEW_DATASOURCE_OPTION_ID) {
|
||||
routeToCreateNewDatasource();
|
||||
} else {
|
||||
onSelectDataSource(
|
||||
value,
|
||||
dataSourceOptions.find((ds) => ds.value === value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
style={{ width: DROPDOWN_DIMENSION.WIDTH }}
|
||||
value={
|
||||
selectedDatasource?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
? {
|
||||
key: selectedDatasource?.value,
|
||||
label: (
|
||||
<DatasourceOptionSelectedView
|
||||
iconType={GeneratePageSelectedViewIconEnum.PLUGIN_ICON}
|
||||
option={selectedDatasource}
|
||||
pluginImages={pluginImages}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: selectedDatasource
|
||||
}
|
||||
// TODO: This needs to be fixed. Removed for cypress tests to pass
|
||||
virtual={false}
|
||||
>
|
||||
{dataSourceOptions.map((option) => {
|
||||
const isConnectNewDataSourceBtn =
|
||||
CONNECT_NEW_DATASOURCE_OPTION_ID ===
|
||||
(option as DropdownOption).id;
|
||||
const isSupportedForTemplate = (option as DropdownOption)?.data
|
||||
?.isSupportedForTemplate;
|
||||
const isNotSupportedDatasource =
|
||||
!isSupportedForTemplate && !isConnectNewDataSourceBtn;
|
||||
|
||||
return (
|
||||
<Option
|
||||
disabled={isNotSupportedDatasource}
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
>
|
||||
<DataSourceOption
|
||||
dataTestid="t--datasource-dropdown-option"
|
||||
extraProps={{ routeToCreateNewDatasource }}
|
||||
key={(option as DropdownOption).id}
|
||||
option={option}
|
||||
optionWidth={DROPDOWN_DIMENSION.WIDTH}
|
||||
/>
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</SelectWrapper>
|
||||
{selectedDatasource.value ? (
|
||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
||||
<Label>{createMessage(GEN_CRUD_DATASOURCE_DROPDOWN_LABEL)}</Label>
|
||||
<Label>
|
||||
Select {pluginField.TABLE} from
|
||||
<Bold>{selectedDatasource.label}</Bold>
|
||||
</Label>
|
||||
|
||||
<Select
|
||||
data-testid="t--datasource-dropdown"
|
||||
onChange={(value) => {
|
||||
if (value === CONNECT_NEW_DATASOURCE_OPTION_ID) {
|
||||
routeToCreateNewDatasource();
|
||||
} else {
|
||||
onSelectDataSource(
|
||||
value,
|
||||
dataSourceOptions.find((ds) => ds.value === value),
|
||||
);
|
||||
}
|
||||
}}
|
||||
style={{ width: DROPDOWN_DIMENSION.WIDTH }}
|
||||
data-testid="t--table-dropdown"
|
||||
getPopupContainer={(triggerNode) =>
|
||||
triggerNode.parentNode.parentNode
|
||||
}
|
||||
isDisabled={!!tableDropdownErrorMsg}
|
||||
isLoading={fetchingDatasourceConfigs}
|
||||
isValid={!tableDropdownErrorMsg}
|
||||
onChange={(value) =>
|
||||
onSelectTable(
|
||||
value,
|
||||
datasourceTableOptions.find(
|
||||
(table) => table.value === value,
|
||||
) as DatasourceTableDropdownOption,
|
||||
)
|
||||
}
|
||||
value={
|
||||
selectedDatasource?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
selectedTable?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
? {
|
||||
key: selectedDatasource?.value,
|
||||
key: selectedTable?.value,
|
||||
label: (
|
||||
<DatasourceOptionSelectedView
|
||||
iconType={GeneratePageSelectedViewIconEnum.PLUGIN_ICON}
|
||||
option={selectedDatasource}
|
||||
pluginImages={pluginImages}
|
||||
iconType={GeneratePageSelectedViewIconEnum.ADS_ICON}
|
||||
option={selectedTable}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: selectedDatasource
|
||||
: selectedTable
|
||||
}
|
||||
// TODO: This needs to be fixed. Removed for cypress tests to pass
|
||||
virtual={false}
|
||||
>
|
||||
{dataSourceOptions.map((option) => {
|
||||
const isConnectNewDataSourceBtn =
|
||||
CONNECT_NEW_DATASOURCE_OPTION_ID ===
|
||||
(option as DropdownOption).id;
|
||||
const isSupportedForTemplate = (option as DropdownOption)?.data
|
||||
?.isSupportedForTemplate;
|
||||
const isNotSupportedDatasource =
|
||||
!isSupportedForTemplate && !isConnectNewDataSourceBtn;
|
||||
|
||||
{datasourceTableOptions.map((table) => {
|
||||
return (
|
||||
<Option
|
||||
disabled={isNotSupportedDatasource}
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
>
|
||||
<DataSourceOption
|
||||
dataTestid="t--datasource-dropdown-option"
|
||||
extraProps={{ routeToCreateNewDatasource }}
|
||||
key={(option as DropdownOption).id}
|
||||
option={option}
|
||||
optionWidth={DROPDOWN_DIMENSION.WIDTH}
|
||||
/>
|
||||
<Option key={table.value} value={table.value}>
|
||||
<OptionWrapper>
|
||||
<StyledIconWrapper>
|
||||
<Icon
|
||||
color={table?.iconColor}
|
||||
name={table.icon as string}
|
||||
size={table.iconSize}
|
||||
/>
|
||||
</StyledIconWrapper>
|
||||
<Text renderAs="p">{table.label}</Text>
|
||||
</OptionWrapper>
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
{tableDropdownErrorMsg && (
|
||||
<ErrorMsg className="ads-dropdown-errorMsg">
|
||||
{tableDropdownErrorMsg}
|
||||
</ErrorMsg>
|
||||
)}
|
||||
</SelectWrapper>
|
||||
{selectedDatasource.value ? (
|
||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
||||
<Label>
|
||||
Select {pluginField.TABLE} from
|
||||
<Bold>{selectedDatasource.label}</Bold>
|
||||
</Label>
|
||||
|
||||
<Select
|
||||
data-testid="t--table-dropdown"
|
||||
isDisabled={!!tableDropdownErrorMsg}
|
||||
isLoading={fetchingDatasourceConfigs}
|
||||
isValid={!tableDropdownErrorMsg}
|
||||
onChange={(value) =>
|
||||
onSelectTable(
|
||||
value,
|
||||
datasourceTableOptions.find(
|
||||
(table) => table.value === value,
|
||||
) as DatasourceTableDropdownOption,
|
||||
)
|
||||
}
|
||||
value={
|
||||
selectedTable?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
? {
|
||||
key: selectedTable?.value,
|
||||
label: (
|
||||
<DatasourceOptionSelectedView
|
||||
iconType={GeneratePageSelectedViewIconEnum.ADS_ICON}
|
||||
option={selectedTable}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: selectedTable
|
||||
}
|
||||
// TODO: This needs to be fixed. Removed for cypress tests to pass
|
||||
virtual={false}
|
||||
>
|
||||
{datasourceTableOptions.map((table) => {
|
||||
return (
|
||||
<Option key={table.value} value={table.value}>
|
||||
<OptionWrapper>
|
||||
<StyledIconWrapper>
|
||||
<Icon
|
||||
color={table?.iconColor}
|
||||
name={table.icon as string}
|
||||
size={table.iconSize}
|
||||
/>
|
||||
</StyledIconWrapper>
|
||||
<Text renderAs="p">{table.label}</Text>
|
||||
</OptionWrapper>
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
{tableDropdownErrorMsg && (
|
||||
<ErrorMsg className="ads-dropdown-errorMsg">
|
||||
{tableDropdownErrorMsg}
|
||||
</ErrorMsg>
|
||||
)}
|
||||
</SelectWrapper>
|
||||
) : null}
|
||||
{showEditDatasourceBtn && (
|
||||
<div>
|
||||
<Button kind="primary" onClick={goToEditDatasource} size="md">
|
||||
Edit datasource
|
||||
</Button>
|
||||
) : null}
|
||||
{showEditDatasourceBtn && (
|
||||
<div>
|
||||
<Button kind="primary" onClick={goToEditDatasource} size="md">
|
||||
Edit datasource
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{!isGoogleSheetPlugin ? (
|
||||
<>
|
||||
{showSearchableColumn && (
|
||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
||||
<Row>
|
||||
Select a searchable {pluginField.COLUMN} from the selected
|
||||
{pluginField.TABLE}
|
||||
<TooltipWrapper>
|
||||
<Tooltip content="Only string values are allowed for searchable column">
|
||||
<Icon name="question-line" size="md" />
|
||||
</Tooltip>
|
||||
</TooltipWrapper>
|
||||
</Row>
|
||||
<Select
|
||||
data-testid="t--table-dropdown"
|
||||
getPopupContainer={(triggerNode) =>
|
||||
triggerNode.parentNode.parentNode
|
||||
}
|
||||
isDisabled={selectedTableColumnOptions.length === 0}
|
||||
onChange={(value) =>
|
||||
onSelectColumn(
|
||||
value,
|
||||
selectedTableColumnOptions.find(
|
||||
(column) => column.value === value,
|
||||
),
|
||||
)
|
||||
}
|
||||
value={
|
||||
selectedColumn?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
? {
|
||||
key: selectedColumn?.value,
|
||||
label: (
|
||||
<DatasourceOptionSelectedView
|
||||
iconType={GeneratePageSelectedViewIconEnum.ADS_ICON}
|
||||
option={selectedColumn}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: selectedColumn
|
||||
}
|
||||
virtual={false}
|
||||
>
|
||||
{selectedTableColumnOptions.map((column) => {
|
||||
return (
|
||||
<Option key={column.value} value={column.value}>
|
||||
<OptionWrapper>
|
||||
<StyledIconWrapper>
|
||||
<Icon
|
||||
color={column?.iconColor}
|
||||
name={column.icon as string}
|
||||
size={column.iconSize}
|
||||
/>
|
||||
</StyledIconWrapper>
|
||||
<Text renderAs="p">{column.label}</Text>
|
||||
<Text
|
||||
className="datasource-sub-text"
|
||||
color="var(--ads-v2-color-fg-muted)"
|
||||
renderAs="span"
|
||||
>
|
||||
{column.subText}
|
||||
</Text>
|
||||
</OptionWrapper>
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<HelperMsg>
|
||||
{selectedTableColumnOptions.length === 0
|
||||
? `* Optional (No searchable ${pluginField.COLUMN} to select)`
|
||||
: "* Optional"}
|
||||
</HelperMsg>
|
||||
</SelectWrapper>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<GeneratePageSubmitBtn
|
||||
disabled={submitButtonDisable}
|
||||
isLoading={!!isGeneratingTemplatePage}
|
||||
onSubmit={handleFormSubmit}
|
||||
showSubmitButton={!!showSubmitButton}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!isGoogleSheetPlugin ? (
|
||||
<>
|
||||
{showSearchableColumn && (
|
||||
<SelectWrapper width={DROPDOWN_DIMENSION.WIDTH}>
|
||||
<Row>
|
||||
Select a searchable {pluginField.COLUMN} from the
|
||||
selected
|
||||
{pluginField.TABLE}
|
||||
<TooltipWrapper>
|
||||
<Tooltip content="Only string values are allowed for searchable column">
|
||||
<Icon name="question-line" size="md" />
|
||||
</Tooltip>
|
||||
</TooltipWrapper>
|
||||
</Row>
|
||||
<Select
|
||||
data-testid="t--table-dropdown"
|
||||
isDisabled={selectedTableColumnOptions.length === 0}
|
||||
onChange={(value) =>
|
||||
onSelectColumn(
|
||||
value,
|
||||
selectedTableColumnOptions.find(
|
||||
(column) => column.value === value,
|
||||
),
|
||||
)
|
||||
}
|
||||
value={
|
||||
selectedColumn?.label !== DEFAULT_DROPDOWN_OPTION?.label
|
||||
? {
|
||||
key: selectedColumn?.value,
|
||||
label: (
|
||||
<DatasourceOptionSelectedView
|
||||
iconType={
|
||||
GeneratePageSelectedViewIconEnum.ADS_ICON
|
||||
}
|
||||
option={selectedColumn}
|
||||
/>
|
||||
),
|
||||
}
|
||||
: selectedColumn
|
||||
}
|
||||
virtual={false}
|
||||
>
|
||||
{selectedTableColumnOptions.map((column) => {
|
||||
return (
|
||||
<Option key={column.value} value={column.value}>
|
||||
<OptionWrapper>
|
||||
<StyledIconWrapper>
|
||||
<Icon
|
||||
color={column?.iconColor}
|
||||
name={column.icon as string}
|
||||
size={column.iconSize}
|
||||
/>
|
||||
</StyledIconWrapper>
|
||||
<Text renderAs="p">{column.label}</Text>
|
||||
<Text
|
||||
className="datasource-sub-text"
|
||||
color="var(--ads-v2-color-fg-muted)"
|
||||
renderAs="span"
|
||||
>
|
||||
{column.subText}
|
||||
</Text>
|
||||
</OptionWrapper>
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
<HelperMsg>
|
||||
{selectedTableColumnOptions.length === 0
|
||||
? `* Optional (No searchable ${pluginField.COLUMN} to select)`
|
||||
: "* Optional"}
|
||||
</HelperMsg>
|
||||
</SelectWrapper>
|
||||
)}
|
||||
<div className="mt-4">
|
||||
<GeneratePageSubmitBtn
|
||||
disabled={submitButtonDisable}
|
||||
isLoading={!!isGeneratingTemplatePage}
|
||||
onSubmit={handleFormSubmit}
|
||||
showSubmitButton={!!showSubmitButton}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<GoogleSheetForm
|
||||
generatePageAction={generatePageAction}
|
||||
googleSheetPluginId={selectedDatasourcePluginId}
|
||||
renderSubmitButton={({
|
||||
disabled,
|
||||
isLoading,
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit: () => void;
|
||||
disabled: boolean;
|
||||
isLoading: boolean;
|
||||
}) => (
|
||||
<GeneratePageSubmitBtn
|
||||
disabled={disabled}
|
||||
isLoading={!!isGeneratingTemplatePage || isLoading}
|
||||
onSubmit={onSubmit}
|
||||
showSubmitButton={!!showSubmitButton}
|
||||
/>
|
||||
)}
|
||||
selectedDatasource={selectedDatasource}
|
||||
selectedSpreadsheet={selectedTable}
|
||||
sheetColumnsHeaderProps={sheetColumnsHeaderProps}
|
||||
sheetsListProps={sheetsListProps}
|
||||
spreadSheetsProps={spreadSheetsProps}
|
||||
/>
|
||||
)}
|
||||
</FormWrapper>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<GoogleSheetForm
|
||||
generatePageAction={generatePageAction}
|
||||
googleSheetPluginId={selectedDatasourcePluginId}
|
||||
renderSubmitButton={({
|
||||
disabled,
|
||||
isLoading,
|
||||
onSubmit,
|
||||
}: {
|
||||
onSubmit: () => void;
|
||||
disabled: boolean;
|
||||
isLoading: boolean;
|
||||
}) => (
|
||||
<GeneratePageSubmitBtn
|
||||
disabled={disabled}
|
||||
isLoading={!!isGeneratingTemplatePage || isLoading}
|
||||
onSubmit={onSubmit}
|
||||
showSubmitButton={!!showSubmitButton}
|
||||
/>
|
||||
)}
|
||||
selectedDatasource={selectedDatasource}
|
||||
selectedSpreadsheet={selectedTable}
|
||||
sheetColumnsHeaderProps={sheetColumnsHeaderProps}
|
||||
sheetsListProps={sheetsListProps}
|
||||
spreadSheetsProps={spreadSheetsProps}
|
||||
/>
|
||||
)}
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,9 @@ function GoogleSheetForm(props: Props) {
|
|||
|
||||
<Select
|
||||
data-testid="t--sheetName-dropdown"
|
||||
getPopupContainer={(triggerNode) =>
|
||||
triggerNode.parentNode.parentNode
|
||||
}
|
||||
isLoading={isFetchingSheetsList}
|
||||
onChange={(value) =>
|
||||
onSelectSheetOption(
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import GeneratePageForm from "./GeneratePageForm/GeneratePageForm";
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
padding: var(--ads-v2-spaces-7) 0;
|
||||
`;
|
||||
|
||||
function PageContent() {
|
||||
return (
|
||||
<Container>
|
||||
<GeneratePageForm />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageContent;
|
||||
|
|
@ -1,54 +1,52 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import PageContent from "./components/PageContent";
|
||||
import { Text } from "@appsmith/ads";
|
||||
import { BackButton } from "components/utils/helperComponents";
|
||||
import React, { useCallback } from "react";
|
||||
import {
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
Text,
|
||||
} from "@appsmith/ads";
|
||||
import {
|
||||
createMessage,
|
||||
GENERATE_PAGE_FORM_TITLE,
|
||||
GENERATE_PAGE_FORM_SUB_TITLE,
|
||||
} from "ee/constants/messages";
|
||||
import GeneratePageForm from "./components/GeneratePageForm/GeneratePageForm";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { getIsGeneratePageModalOpen } from "selectors/pageListSelectors";
|
||||
import {
|
||||
closeGeneratePageModal,
|
||||
openGeneratePageModal,
|
||||
} from "./store/generatePageActions";
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
padding: var(--ads-v2-spaces-7);
|
||||
`;
|
||||
function GeneratePageModal() {
|
||||
const dispatch = useDispatch();
|
||||
const isOpen = useSelector(getIsGeneratePageModalOpen);
|
||||
|
||||
const HeadingContainer = styled.div`
|
||||
display: flex;
|
||||
padding-top: var(--ads-v2-spaces-4);
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
width: 100%;
|
||||
|
||||
> a {
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
function GeneratePage() {
|
||||
const isGenerateFormPage = window.location.pathname.includes("/form");
|
||||
const heading = isGenerateFormPage ? "Quick page wizard" : "New page";
|
||||
const handleModalOpenChange = useCallback(
|
||||
(modalState: boolean) => {
|
||||
if (modalState) {
|
||||
dispatch(openGeneratePageModal());
|
||||
} else {
|
||||
dispatch(closeGeneratePageModal());
|
||||
}
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{isGenerateFormPage ? (
|
||||
<Header>
|
||||
<BackButton />
|
||||
</Header>
|
||||
) : null}
|
||||
|
||||
<HeadingContainer>
|
||||
<Text kind="heading-l">{heading}</Text>
|
||||
</HeadingContainer>
|
||||
{isGenerateFormPage ? (
|
||||
<Text renderAs="p">
|
||||
Auto create a simple CRUD interface on top of your data
|
||||
</Text>
|
||||
) : null}
|
||||
|
||||
<PageContent />
|
||||
</Container>
|
||||
<Modal onOpenChange={handleModalOpenChange} open={isOpen}>
|
||||
<ModalContent style={{ width: "444px" }}>
|
||||
<ModalHeader>{createMessage(GENERATE_PAGE_FORM_TITLE)}</ModalHeader>
|
||||
<ModalBody>
|
||||
<Text renderAs="p">
|
||||
{createMessage(GENERATE_PAGE_FORM_SUB_TITLE)}
|
||||
</Text>
|
||||
<GeneratePageForm />
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default GeneratePage;
|
||||
export default GeneratePageModal;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
import type { GeneratePageModalParams } from "reducers/entityReducers/pageListReducer";
|
||||
|
||||
export const openGeneratePageModal = (payload?: GeneratePageModalParams) => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_GENERATE_PAGE_MODAL_OPEN,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
|
||||
export const closeGeneratePageModal = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_GENERATE_PAGE_MODAL_CLOSE,
|
||||
};
|
||||
};
|
||||
|
|
@ -21,7 +21,6 @@ import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
|||
import NewActionButton from "../DataSourceEditor/NewActionButton";
|
||||
import {
|
||||
datasourcesEditorIdURL,
|
||||
generateTemplateFormURL,
|
||||
saasEditorDatasourceIdURL,
|
||||
} from "ee/RouteBuilder";
|
||||
import {
|
||||
|
|
@ -57,6 +56,7 @@ import {
|
|||
} from "ee/utils/BusinessFeatures/permissionPageHelpers";
|
||||
import { useEditorType } from "ee/hooks";
|
||||
import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors";
|
||||
import { openGeneratePageModal } from "../GeneratePage/store/generatePageActions";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 15px;
|
||||
|
|
@ -266,13 +266,10 @@ function DatasourceCard(props: DatasourceCardProps) {
|
|||
}
|
||||
|
||||
AnalyticsUtil.logEvent("DATASOURCE_CARD_GEN_CRUD_PAGE_ACTION");
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: datasource.id,
|
||||
new_page: true,
|
||||
},
|
||||
dispatch(
|
||||
openGeneratePageModal({
|
||||
datasourceId: datasource.id,
|
||||
new_page: true,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import { PartialImportModal } from "components/editorComponents/PartialImportExp
|
|||
import type { Page } from "entities/Page";
|
||||
import { AppCURLImportModal } from "ee/pages/Editor/CurlImport";
|
||||
import { IDE_HEADER_HEIGHT } from "IDE";
|
||||
import GeneratePageModal from "./GeneratePage";
|
||||
|
||||
interface EditorProps {
|
||||
currentApplicationId?: string;
|
||||
|
|
@ -210,6 +211,7 @@ class Editor extends Component<Props> {
|
|||
<PartialExportModal />
|
||||
<PartialImportModal />
|
||||
<AppCURLImportModal />
|
||||
<GeneratePageModal />
|
||||
</GlobalHotKeys>
|
||||
</div>
|
||||
<RequestConfirmationModal />
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
import { Flex } from "@appsmith/ads";
|
||||
import {
|
||||
ADD_PAGE_FROM_TEMPLATE_MODAL,
|
||||
createMessage,
|
||||
} from "ee/constants/messages";
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const BackText = styled.div<{ width?: number; hidden?: boolean }>`
|
||||
${(props) => props.hidden && "visibility: hidden;"}
|
||||
`;
|
||||
const HeaderWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.back-button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
interface TemplateModalHeaderProps {
|
||||
className?: string;
|
||||
|
|
@ -22,9 +11,9 @@ interface TemplateModalHeaderProps {
|
|||
|
||||
function TemplateModalHeader(props: TemplateModalHeaderProps) {
|
||||
return (
|
||||
<HeaderWrapper className={props.className}>
|
||||
<BackText>{createMessage(ADD_PAGE_FROM_TEMPLATE_MODAL.title)}</BackText>
|
||||
</HeaderWrapper>
|
||||
<Flex alignItems="center" className={props.className}>
|
||||
{createMessage(ADD_PAGE_FROM_TEMPLATE_MODAL.title)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ import type { Page } from "entities/Page";
|
|||
const initialState: PageListReduxState = {
|
||||
pages: [],
|
||||
isGeneratingTemplatePage: false,
|
||||
generatePage: {
|
||||
modalOpen: false,
|
||||
params: {},
|
||||
},
|
||||
baseApplicationId: "",
|
||||
applicationId: "",
|
||||
currentBasePageId: "",
|
||||
|
|
@ -235,6 +239,27 @@ export const pageListReducer = createReducer(initialState, {
|
|||
},
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SET_GENERATE_PAGE_MODAL_OPEN]: (
|
||||
state: PageListReduxState,
|
||||
action: ReduxAction<GeneratePageModalParams>,
|
||||
) => {
|
||||
return {
|
||||
...state,
|
||||
generatePage: {
|
||||
modalOpen: true,
|
||||
params: action.payload || {},
|
||||
},
|
||||
};
|
||||
},
|
||||
[ReduxActionTypes.SET_GENERATE_PAGE_MODAL_CLOSE]: (
|
||||
state: PageListReduxState,
|
||||
) => ({
|
||||
...state,
|
||||
generatePage: {
|
||||
...state.generatePage,
|
||||
modalOpen: false,
|
||||
},
|
||||
}),
|
||||
[ReduxActionTypes.GENERATE_TEMPLATE_PAGE_INIT]: (
|
||||
state: PageListReduxState,
|
||||
) => {
|
||||
|
|
@ -299,6 +324,11 @@ export interface AppLayoutConfig {
|
|||
type: SupportedLayouts;
|
||||
}
|
||||
|
||||
export interface GeneratePageModalParams {
|
||||
datasourceId?: string;
|
||||
new_page?: boolean;
|
||||
}
|
||||
|
||||
export interface PageListReduxState {
|
||||
pages: Page[];
|
||||
baseApplicationId: string;
|
||||
|
|
@ -309,6 +339,10 @@ export interface PageListReduxState {
|
|||
defaultPageId: string;
|
||||
appLayout?: AppLayoutConfig;
|
||||
isGeneratingTemplatePage?: boolean;
|
||||
generatePage?: {
|
||||
modalOpen: boolean;
|
||||
params?: GeneratePageModalParams;
|
||||
};
|
||||
loading: Record<string, boolean>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,6 @@ import {
|
|||
import {
|
||||
apiEditorIdURL,
|
||||
datasourcesEditorIdURL,
|
||||
generateTemplateFormURL,
|
||||
integrationEditorURL,
|
||||
saasEditorDatasourceIdURL,
|
||||
} from "ee/RouteBuilder";
|
||||
|
|
@ -189,6 +188,7 @@ import { executeGoogleApi } from "./loadGoogleApi";
|
|||
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
|
||||
import { getCurrentModuleId } from "ee/selectors/modulesSelector";
|
||||
import type { ApplicationPayload } from "entities/Application";
|
||||
import { openGeneratePageModalWithSelectedDS } from "../utils/GeneratePageUtils";
|
||||
|
||||
function* fetchDatasourcesSaga(
|
||||
action: ReduxAction<
|
||||
|
|
@ -339,42 +339,36 @@ export function* addMockDbToDatasources(actionPayload: addMockDb) {
|
|||
const isGeneratePageInitiator =
|
||||
getIsGeneratePageInitiator(isGeneratePageMode);
|
||||
|
||||
if (isGeneratePageInitiator) {
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: response.data.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
if (skipRedirection) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "";
|
||||
const plugin: Plugin = yield select(getPlugin, response.data.pluginId);
|
||||
|
||||
if (plugin && plugin.type === PluginType.SAAS) {
|
||||
url = saasEditorDatasourceIdURL({
|
||||
basePageId,
|
||||
pluginPackageName: plugin.packageName,
|
||||
datasourceId: response.data.id,
|
||||
params: {
|
||||
viewMode: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
url = datasourcesEditorIdURL({
|
||||
basePageId,
|
||||
datasourceId: response.data.id,
|
||||
params: omit(getQueryParams(), "viewMode"),
|
||||
});
|
||||
}
|
||||
|
||||
history.push(url);
|
||||
if (skipRedirection) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "";
|
||||
const plugin: Plugin = yield select(getPlugin, response.data.pluginId);
|
||||
|
||||
if (plugin && plugin.type === PluginType.SAAS) {
|
||||
url = saasEditorDatasourceIdURL({
|
||||
basePageId,
|
||||
pluginPackageName: plugin.packageName,
|
||||
datasourceId: response.data.id,
|
||||
params: {
|
||||
viewMode: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
url = datasourcesEditorIdURL({
|
||||
basePageId,
|
||||
datasourceId: response.data.id,
|
||||
params: omit(getQueryParams(), "viewMode"),
|
||||
});
|
||||
}
|
||||
|
||||
history.push(url);
|
||||
|
||||
yield call(openGeneratePageModalWithSelectedDS, {
|
||||
shouldOpenModalWIthSelectedDS: Boolean(isGeneratePageInitiator),
|
||||
datasourceId: response.data.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
yield put({
|
||||
|
|
@ -1519,7 +1513,6 @@ function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) {
|
|||
const actionRouteInfo = get(state, "ui.datasourcePane.actionRouteInfo");
|
||||
const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap =
|
||||
yield select(getGenerateCRUDEnabledPluginMap);
|
||||
const basePageId: string = yield select(getCurrentBasePageId);
|
||||
const updatedDatasource = action.payload;
|
||||
|
||||
const { queryParams = {} } = action;
|
||||
|
|
@ -1529,19 +1522,6 @@ function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) {
|
|||
);
|
||||
|
||||
if (
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId]
|
||||
) {
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: updatedDatasource.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
actionRouteInfo &&
|
||||
updatedDatasource.id === actionRouteInfo.datasourceId &&
|
||||
action.redirect
|
||||
|
|
@ -1554,6 +1534,15 @@ function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) {
|
|||
);
|
||||
}
|
||||
|
||||
yield call(openGeneratePageModalWithSelectedDS, {
|
||||
shouldOpenModalWIthSelectedDS: Boolean(
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId],
|
||||
),
|
||||
datasourceId: updatedDatasource.id,
|
||||
});
|
||||
|
||||
yield put({
|
||||
type: ReduxActionTypes.STORE_AS_DATASOURCE_COMPLETE,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ import type { EventLocation } from "ee/utils/analyticsUtilTypes";
|
|||
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
|
||||
import {
|
||||
datasourcesEditorIdURL,
|
||||
generateTemplateFormURL,
|
||||
integrationEditorURL,
|
||||
queryEditorIdURL,
|
||||
} from "ee/RouteBuilder";
|
||||
|
|
@ -85,6 +84,7 @@ import {
|
|||
import { TEMP_DATASOURCE_ID } from "constants/Datasource";
|
||||
import { doesPluginRequireDatasource } from "ee/entities/Engine/actionHelpers";
|
||||
import { convertToBasePageIdSelector } from "selectors/pageListSelectors";
|
||||
import { openGeneratePageModalWithSelectedDS } from "../utils/GeneratePageUtils";
|
||||
|
||||
// Called whenever the query being edited is changed via the URL or query pane
|
||||
function* changeQuerySaga(actionPayload: ReduxAction<ChangeQueryPayload>) {
|
||||
|
|
@ -464,25 +464,7 @@ function* handleDatasourceCreatedSaga(
|
|||
const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap =
|
||||
yield select(getGenerateCRUDEnabledPluginMap);
|
||||
|
||||
// isGeneratePageInitiator ensures that datasource is being created from generate page with data
|
||||
// then we check if the current plugin is supported for generate page with data functionality
|
||||
// and finally isDBCreated ensures that datasource is not in temporary state and
|
||||
// user has explicitly saved the datasource, before redirecting back to generate page
|
||||
if (
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId] &&
|
||||
isDBCreated
|
||||
) {
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: updatedDatasource.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
!currentApplicationIdForCreateNewApp ||
|
||||
(!!currentApplicationIdForCreateNewApp && payload.id !== TEMP_DATASOURCE_ID)
|
||||
) {
|
||||
|
|
@ -498,6 +480,20 @@ function* handleDatasourceCreatedSaga(
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// isGeneratePageInitiator ensures that datasource is being created from generate page with data
|
||||
// then we check if the current plugin is supported for generate page with data functionality
|
||||
// and finally isDBCreated ensures that datasource is not in temporary state and
|
||||
// user has explicitly saved the datasource, before redirecting back to generate page
|
||||
yield call(openGeneratePageModalWithSelectedDS, {
|
||||
shouldOpenModalWIthSelectedDS: Boolean(
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId] &&
|
||||
isDBCreated,
|
||||
),
|
||||
datasourceId: updatedDatasource.id,
|
||||
});
|
||||
}
|
||||
|
||||
function* handleNameChangeSaga(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { all, put, select, takeEvery } from "redux-saga/effects";
|
||||
import { all, call, put, select, takeEvery } from "redux-saga/effects";
|
||||
import type { ApplicationPayload } from "entities/Application";
|
||||
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
|
||||
import { ReduxActionTypes } from "ee/constants/ReduxActionConstants";
|
||||
|
|
@ -10,11 +10,7 @@ import {
|
|||
import type { Action } from "entities/Action";
|
||||
import { PluginType } from "entities/Action";
|
||||
import type { GenerateCRUDEnabledPluginMap, Plugin } from "api/PluginApi";
|
||||
import {
|
||||
generateTemplateFormURL,
|
||||
saasEditorApiIdURL,
|
||||
saasEditorDatasourceIdURL,
|
||||
} from "ee/RouteBuilder";
|
||||
import { saasEditorApiIdURL, saasEditorDatasourceIdURL } from "ee/RouteBuilder";
|
||||
import { getCurrentBasePageId } from "selectors/editorSelectors";
|
||||
import type { CreateDatasourceSuccessAction } from "actions/datasourceActions";
|
||||
import { getQueryParams } from "utils/URLUtils";
|
||||
|
|
@ -28,6 +24,7 @@ import {
|
|||
} from "ee/selectors/applicationSelectors";
|
||||
import { TEMP_DATASOURCE_ID } from "constants/Datasource";
|
||||
import { convertToBasePageIdSelector } from "selectors/pageListSelectors";
|
||||
import { openGeneratePageModalWithSelectedDS } from "../utils/GeneratePageUtils";
|
||||
|
||||
function* handleDatasourceCreatedSaga(
|
||||
actionPayload: CreateDatasourceSuccessAction,
|
||||
|
|
@ -63,25 +60,7 @@ function* handleDatasourceCreatedSaga(
|
|||
const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap =
|
||||
yield select(getGenerateCRUDEnabledPluginMap);
|
||||
|
||||
// isGeneratePageInitiator ensures that datasource is being created from generate page with data
|
||||
// then we check if the current plugin is supported for generate page with data functionality
|
||||
// and finally isDBCreated ensures that datasource is not in temporary state and
|
||||
// user has explicitly saved the datasource, before redirecting back to generate page
|
||||
if (
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId] &&
|
||||
isDBCreated
|
||||
) {
|
||||
history.push(
|
||||
generateTemplateFormURL({
|
||||
basePageId,
|
||||
params: {
|
||||
datasourceId: updatedDatasource.id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
!currentApplicationIdForCreateNewApp ||
|
||||
(!!currentApplicationIdForCreateNewApp && payload.id !== TEMP_DATASOURCE_ID)
|
||||
) {
|
||||
|
|
@ -98,6 +77,20 @@ function* handleDatasourceCreatedSaga(
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// isGeneratePageInitiator ensures that datasource is being created from generate page with data
|
||||
// then we check if the current plugin is supported for generate page with data functionality
|
||||
// and finally isDBCreated ensures that datasource is not in temporary state and
|
||||
// user has explicitly saved the datasource, before redirecting back to generate page
|
||||
yield call(openGeneratePageModalWithSelectedDS, {
|
||||
shouldOpenModalWIthSelectedDS: Boolean(
|
||||
isGeneratePageInitiator &&
|
||||
updatedDatasource.pluginId &&
|
||||
generateCRUDSupportedPlugin[updatedDatasource.pluginId] &&
|
||||
isDBCreated,
|
||||
),
|
||||
datasourceId: updatedDatasource.id,
|
||||
});
|
||||
}
|
||||
|
||||
function* handleActionCreatedSaga(actionPayload: ReduxAction<Action>) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ export const getIsGeneratingTemplatePage = createSelector(
|
|||
(pageList: PageListReduxState) => pageList.isGeneratingTemplatePage,
|
||||
);
|
||||
|
||||
export const getIsGeneratePageModalOpen = (state: AppState) =>
|
||||
state.entities.pageList.generatePage?.modalOpen;
|
||||
|
||||
export const getGeneratePageModalParams = (state: AppState) =>
|
||||
state.entities.pageList.generatePage?.params;
|
||||
|
||||
export const convertToPageIdSelector = (state: AppState, basePageId: string) =>
|
||||
state.entities.pageList.pages?.find((page) => page.basePageId === basePageId)
|
||||
?.pageId;
|
||||
|
|
|
|||
18
app/client/src/utils/GeneratePageUtils.ts
Normal file
18
app/client/src/utils/GeneratePageUtils.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { openGeneratePageModal } from "pages/Editor/GeneratePage/store/generatePageActions";
|
||||
import { put } from "redux-saga/effects";
|
||||
|
||||
export function* openGeneratePageModalWithSelectedDS({
|
||||
datasourceId,
|
||||
shouldOpenModalWIthSelectedDS,
|
||||
}: {
|
||||
shouldOpenModalWIthSelectedDS: boolean;
|
||||
datasourceId: string;
|
||||
}) {
|
||||
if (shouldOpenModalWIthSelectedDS) {
|
||||
yield put(
|
||||
openGeneratePageModal({
|
||||
datasourceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user