From 6aa577958b59817b3532ddacd638b572138a89f6 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Mon, 16 Sep 2024 11:36:44 +0530 Subject: [PATCH 1/4] chore: Add common items in the Toolbar of AppPluginEditor (#36324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds Copy / Move / Delete actions in the toolbar for AppPluginEditor Fixes #35532 ## Automation /ok-to-test tags="@tag.Datasource" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: 39aea09368b83f8fdb529f7842a472b0668d0b23 > Cypress dashboard. > Tags: `@tag.Datasource` > Spec: >
Mon, 16 Sep 2024 05:58:25 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit - **New Features** - Introduced a new toolbar for executing plugin actions with analytics tracking. - Added a new interface for managing plugin actions, including options to copy, move, and delete actions. - Updated the toolbar to include a new action menu for enhanced user interaction. - **Bug Fixes** - Ensured unique identification of menu items in the toolbar for better functionality. --- .../components/PluginActionToolbar.tsx | 36 +++- .../components/AppPluginActionToolbar.tsx | 4 +- .../components/PluginActionMoreActions.tsx | 183 ++++++++++++++++++ 3 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 app/client/src/ce/pages/Editor/AppPluginActionEditor/components/PluginActionMoreActions.tsx diff --git a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx index 75ee4dc86bd..0d2e4f718d7 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx @@ -1,7 +1,11 @@ -import React from "react"; +import React, { useCallback } from "react"; import { IDEToolbar } from "IDE"; import { Button, Menu, MenuContent, MenuTrigger, Tooltip } from "@appsmith/ads"; import { modText } from "utils/helpers"; +import { usePluginActionContext } from "../PluginActionContext"; +import { useDispatch } from "react-redux"; +import AnalyticsUtil from "ee/utils/AnalyticsUtil"; +import { runAction } from "../../actions/pluginActionActions"; interface PluginActionToolbarProps { runOptions?: React.ReactNode; @@ -10,6 +14,25 @@ interface PluginActionToolbarProps { } const PluginActionToolbar = (props: PluginActionToolbarProps) => { + const { action, datasource, plugin } = usePluginActionContext(); + const dispatch = useDispatch(); + const handleRunClick = useCallback(() => { + AnalyticsUtil.logEvent("RUN_QUERY_CLICK", { + actionName: action.name, + actionId: action.id, + pluginName: plugin.name, + datasourceId: datasource?.id, + isMock: datasource?.isMock, + }); + dispatch(runAction(action.id)); + }, [ + action.id, + action.name, + datasource?.id, + datasource?.isMock, + dispatch, + plugin.name, + ]); return ( {props.children} @@ -20,7 +43,7 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => { placement="topRight" showArrow={false} > - @@ -30,7 +53,7 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => { size="sm" startIcon="settings-2-line" /> - + diff --git a/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/AppPluginActionToolbar.tsx b/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/AppPluginActionToolbar.tsx index ab44ba573b3..8606cee42fb 100644 --- a/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/AppPluginActionToolbar.tsx +++ b/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/AppPluginActionToolbar.tsx @@ -1,9 +1,9 @@ import React from "react"; import { PluginActionToolbar } from "PluginActionEditor"; -import { ConvertToModuleCTA } from "./ConvertToModule"; +import AppPluginActionMenu from "./PluginActionMoreActions"; const AppPluginActionToolbar = () => { - return } />; + return } />; }; export default AppPluginActionToolbar; diff --git a/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/PluginActionMoreActions.tsx b/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/PluginActionMoreActions.tsx new file mode 100644 index 00000000000..d8d37c754dd --- /dev/null +++ b/app/client/src/ce/pages/Editor/AppPluginActionEditor/components/PluginActionMoreActions.tsx @@ -0,0 +1,183 @@ +import React, { useCallback, useMemo, useState } from "react"; +import { + getHasDeleteActionPermission, + getHasManageActionPermission, +} from "ee/utils/BusinessFeatures/permissionPageHelpers"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "ee/entities/FeatureFlag"; +import { usePluginActionContext } from "PluginActionEditor"; +import { + MenuItem, + MenuSub, + MenuSubContent, + MenuSubTrigger, +} from "@appsmith/ads"; +import { + CONFIRM_CONTEXT_DELETE, + CONTEXT_COPY, + CONTEXT_DELETE, + CONTEXT_MOVE, + createMessage, +} from "ee/constants/messages"; +import { useDispatch, useSelector } from "react-redux"; +import { + copyActionRequest, + deleteAction, + moveActionRequest, +} from "actions/pluginActionActions"; +import { getCurrentPageId } from "selectors/editorSelectors"; +import type { Page } from "entities/Page"; +import { getPageList } from "ee/selectors/entitiesSelector"; +import { ConvertToModuleCTA } from "./ConvertToModule"; + +const PageMenuItem = (props: { + page: Page; + onSelect: (id: string) => void; +}) => { + const handleOnSelect = useCallback(() => { + props.onSelect(props.page.pageId); + }, [props]); + return {props.page.pageName}; +}; + +const Copy = () => { + const menuPages = useSelector(getPageList); + const { action } = usePluginActionContext(); + const dispatch = useDispatch(); + + const copyActionToPage = useCallback( + (pageId: string) => + dispatch( + copyActionRequest({ + id: action.id, + destinationPageId: pageId, + name: action.name, + }), + ), + [action.id, action.name, dispatch], + ); + + return ( + + + {createMessage(CONTEXT_COPY)} + + + {menuPages.map((page) => { + return ( + + ); + })} + + + ); +}; + +const Move = () => { + const dispatch = useDispatch(); + const { action } = usePluginActionContext(); + + const currentPageId = useSelector(getCurrentPageId); + const allPages = useSelector(getPageList); + const menuPages = useMemo(() => { + return allPages.filter((page) => page.pageId !== currentPageId); + }, [allPages, currentPageId]); + + const moveActionToPage = useCallback( + (destinationPageId: string) => + dispatch( + moveActionRequest({ + id: action.id, + destinationPageId, + originalPageId: currentPageId, + name: action.name, + }), + ), + [dispatch, action.id, action.name, currentPageId], + ); + + return ( + + + {createMessage(CONTEXT_MOVE)} + + + {menuPages.length > 1 ? ( + menuPages.map((page) => { + return ( + + ); + }) + ) : ( + No pages + )} + + + ); +}; + +const Delete = () => { + const dispatch = useDispatch(); + const { action } = usePluginActionContext(); + + const [confirmDelete, setConfirmDelete] = useState(false); + + const deleteActionFromPage = useCallback(() => { + dispatch(deleteAction({ id: action.id, name: action.name })); + }, [action.id, action.name, dispatch]); + + const handleSelect = useCallback(() => { + confirmDelete ? deleteActionFromPage() : setConfirmDelete(true); + }, [confirmDelete, deleteActionFromPage]); + + const menuLabel = confirmDelete + ? createMessage(CONFIRM_CONTEXT_DELETE) + : createMessage(CONTEXT_DELETE); + + return ( + + {menuLabel} + + ); +}; + +const AppPluginActionMenu = () => { + const { action } = usePluginActionContext(); + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + const isChangePermitted = getHasManageActionPermission( + isFeatureEnabled, + action.userPermissions, + ); + const isDeletePermitted = getHasDeleteActionPermission( + isFeatureEnabled, + action?.userPermissions, + ); + + return ( + <> + + {isChangePermitted && ( + <> + + + + )} + {isDeletePermitted && } + + ); +}; + +export default AppPluginActionMenu; From 31a6223d49769878a95ebafaadb4dbfb3608cf2c Mon Sep 17 00:00:00 2001 From: sneha122 Date: Mon, 16 Sep 2024 11:39:11 +0530 Subject: [PATCH 2/4] fix: consolidated api test file split to ce (#36318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Split ConsolidatedAPIServiceImplTest file to CE as we need to write modules related tests in EE. EE Test PR: https://github.com/appsmithorg/appsmith-ee/pull/5140 Fixes #36276 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: fe51aaa8aa141cbbfc4c04d39422e1bcca01868c > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Sun, 15 Sep 2024 15:46:52 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **Refactor** - The package structure for the test class has been reorganized to better categorize services. - **Tests** - Enhanced test functionality by incorporating additional service imports, potentially improving test coverage and functionality. Co-authored-by: β€œsneha122” <β€œsneha@appsmith.com”> --- .../{ => ce}/ConsolidatedAPIServiceImplTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) rename app/server/appsmith-server/src/test/java/com/appsmith/server/services/{ => ce}/ConsolidatedAPIServiceImplTest.java (98%) diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java similarity index 98% rename from app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java rename to app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java index cddb33847c5..97e651a6b2e 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ConsolidatedAPIServiceImplTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/ce/ConsolidatedAPIServiceImplTest.java @@ -1,4 +1,4 @@ -package com.appsmith.server.services; +package com.appsmith.server.services.ce; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Datasource; @@ -32,6 +32,14 @@ import com.appsmith.server.plugins.base.PluginService; import com.appsmith.server.repositories.ApplicationRepository; import com.appsmith.server.repositories.NewPageRepository; +import com.appsmith.server.services.ApplicationPageService; +import com.appsmith.server.services.ConsolidatedAPIService; +import com.appsmith.server.services.MockDataService; +import com.appsmith.server.services.ProductAlertService; +import com.appsmith.server.services.SessionUserService; +import com.appsmith.server.services.TenantService; +import com.appsmith.server.services.UserDataService; +import com.appsmith.server.services.UserService; import com.appsmith.server.themes.base.ThemeService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; From 37282997dca99840a05f2c303321bae070c79b53 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Mon, 16 Sep 2024 11:47:50 +0530 Subject: [PATCH 3/4] chore(deps): Upgrade path-to-regexp from 6.2.0 to 6.3.0 (#36295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Shadow PR: https://github.com/appsmithorg/appsmith/pull/36292 Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v6.2.0...v6.3.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: direct:production ... ## Automation /ok-to-test tags="@tag.Sanity" ### :mag: Cypress test results > [!TIP] > 🟒 🟒 🟒 All cypress tests have passed! πŸŽ‰ πŸŽ‰ πŸŽ‰ > Workflow run: > Commit: a3536c944cdb766a47f038d271bcafbdef4132cf > Cypress dashboard. > Tags: `@tag.Sanity` > Spec: >
Fri, 13 Sep 2024 05:35:17 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **Chores** - Updated the `path-to-regexp` package to version 6.3.0, which may enhance performance and introduce new features for improved URL path matching and parsing. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- app/client/package.json | 2 +- app/client/yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/client/package.json b/app/client/package.json index 82f9cec123b..500d3c2a328 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -163,7 +163,7 @@ "node-forge": "^1.3.0", "normalizr": "^3.3.0", "object-hash": "^3.0.0", - "path-to-regexp": "^6.2.0", + "path-to-regexp": "^6.3.0", "popper.js": "^1.15.0", "prismjs": "^1.27.0", "proxy-memoize": "^1.2.0", diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 03470d21a80..cbd1c58cd4b 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -13391,7 +13391,7 @@ __metadata: node-forge: ^1.3.0 normalizr: ^3.3.0 object-hash: ^3.0.0 - path-to-regexp: ^6.2.0 + path-to-regexp: ^6.3.0 pg: ^8.11.3 plop: ^3.1.1 popper.js: ^1.15.0 @@ -27112,10 +27112,10 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:^6.2.0": - version: 6.2.0 - resolution: "path-to-regexp@npm:6.2.0" - checksum: a6aca74d2d6e2e7594d812f653cf85e9cb5054d3a8d80f099722a44ef6ad22639b02078e5ea83d11db16321c3e4359e3f1ab0274fa78dad0754a6e53f630b0fc +"path-to-regexp@npm:^6.3.0": + version: 6.3.0 + resolution: "path-to-regexp@npm:6.3.0" + checksum: eca78602e6434a1b6799d511d375ec044e8d7e28f5a48aa5c28d57d8152fb52f3fc62fb1cfc5dfa2198e1f041c2a82ed14043d75740a2fe60e91b5089a153250 languageName: node linkType: hard From 71261b1e6e5dae84c3e69a345451bb3b551a4afe Mon Sep 17 00:00:00 2001 From: Manish Kumar <107841575+sondermanish@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:24:08 +0530 Subject: [PATCH 4/4] chore: autocommit migration for annotation and embedded datasource changes. (#36261) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description - Added autocommit migration to avoid uncommited changes on some of the applications. Fixes #`Issue Number` _or_ Fixes `Issue URL` ## Automation /ok-to-test tags="@tag.Git" ### :mag: Cypress test results > [!IMPORTANT] > 🟣 🟣 🟣 Your tests are running. > Tests running at: > Commit: 0013cdec8894922d3cae386a8d8d7b8aebc3837d > Workflow: `PR Automation test suite` > Tags: `@tag.Git` > Spec: `` >
Mon, 16 Sep 2024 06:20:40 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No ## Summary by CodeRabbit - **New Features** - Updated the server version from 10 to 11, enhancing compatibility and functionality related to JSON schema handling. - Improved logic for default REST datasource migrations, making it more robust and accessible. - Added support for SSH connection configurations in datasource management. - **Bug Fixes** - Added null checks to prevent potential errors during datasource migrations, enhancing overall reliability. - **Refactor** - Streamlined filtering logic for actions, improving code readability and maintainability. --- .../models/DatasourceConfiguration.java | 2 + .../migrations/JsonSchemaMigration.java | 52 +++++++++++-------- .../JsonSchemaVersionsFallback.java | 2 +- .../migrations/MigrationHelperMethods.java | 50 ++++++++++++++---- .../utils/JsonSchemaMigrationHelper.java | 29 ++++++++--- 5 files changed, 95 insertions(+), 40 deletions(-) diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java index 5a81b66b730..637879eb75b 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java @@ -34,8 +34,10 @@ public class DatasourceConfiguration implements AppsmithDomain { @JsonView({Views.Public.class, FromRequest.class}) AuthenticationDTO authentication; + @JsonView({Views.Public.class, FromRequest.class}) SSHConnection sshProxy; + @JsonView({Views.Public.class, FromRequest.class}) Boolean sshProxyEnabled; @JsonView({Views.Public.class, FromRequest.class, Git.class}) diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java index 03d543dd3d0..badec22d19e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java @@ -67,28 +67,38 @@ public Mono migrateApplicationJsonToLatestSchema( // TODO: make import flow migration reactive return Mono.just(migrateServerSchema(appJson)) .flatMap(migratedApplicationJson -> { - if (migratedApplicationJson.getServerSchemaVersion() == 9 - && Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration( - migratedApplicationJson))) { - return jsonSchemaMigrationHelper - .addDatasourceConfigurationToDefaultRestApiActions( - baseApplicationId, branchName, migratedApplicationJson) - .map(applicationJsonWithMigration10 -> { - applicationJsonWithMigration10.setServerSchemaVersion(10); - return applicationJsonWithMigration10; - }); + // In Server version 9, there was a bug where the Embedded REST API datasource URL + // was not being persisted correctly. Once the bug was fixed, + // any previously uncommitted changes started appearing as uncommitted modifications + // in the apps. To automatically commit these changes + // (which were now appearing as uncommitted), a migration process was needed. + // This migration fetches the datasource URL from the database + // and serializes it in Git if the URL exists. + // If the URL is missing, it copies the empty datasource configuration + // if the configuration is present in the database. + // Otherwise, it leaves the configuration unchanged. + // Due to an update in the migration logic after version 10 was shipped, + // the entire migration process was moved to version 11. + // This adjustment ensures that the same operation can be + // performed again for the changes introduced in version 10. + if (migratedApplicationJson.getServerSchemaVersion() == 9) { + migratedApplicationJson.setServerSchemaVersion(10); + } + + if (migratedApplicationJson.getServerSchemaVersion() == 10) { + if (Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration( + migratedApplicationJson))) { + return jsonSchemaMigrationHelper + .addDatasourceConfigurationToDefaultRestApiActions( + baseApplicationId, branchName, migratedApplicationJson); + } + + migratedApplicationJson.setServerSchemaVersion(11); } - migratedApplicationJson.setServerSchemaVersion(10); return Mono.just(migratedApplicationJson); }) .map(migratedAppJson -> { - if (applicationJson - .getServerSchemaVersion() - .equals(jsonSchemaVersions.getServerVersion())) { - return applicationJson; - } - applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion()); return applicationJson; }); @@ -193,16 +203,14 @@ private ApplicationJson nonReactiveServerMigrationForImport(ApplicationJson appl switch (applicationJson.getServerSchemaVersion()) { case 9: + applicationJson.setServerSchemaVersion(10); + case 10: // this if for cases where we have empty datasource configs MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, Map.of()); - applicationJson.setServerSchemaVersion(10); + applicationJson.setServerSchemaVersion(11); default: } - if (applicationJson.getServerSchemaVersion().equals(jsonSchemaVersions.getServerVersion())) { - return applicationJson; - } - applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion()); return applicationJson; } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java index 06518c18b4e..c85b95bed5d 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java @@ -4,7 +4,7 @@ @Component public class JsonSchemaVersionsFallback { - private static final Integer serverVersion = 10; + private static final Integer serverVersion = 11; public static final Integer clientVersion = 1; public Integer getServerVersion() { diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java index 87e3d93e6ff..277a3ac5768 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/MigrationHelperMethods.java @@ -44,6 +44,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.appsmith.external.constants.PluginConstants.PackageName.GRAPHQL_PLUGIN; +import static com.appsmith.external.constants.PluginConstants.PackageName.REST_API_PLUGIN; import static com.appsmith.server.constants.ResourceModes.EDIT; import static com.appsmith.server.constants.ResourceModes.VIEW; import static org.springframework.data.mongodb.core.query.Criteria.where; @@ -1235,13 +1237,34 @@ public static void setThemeSettings(Application.ThemeSetting themeSetting) { } } - private static boolean conditionForDefaultRestDatasourceMigration(NewAction action) { + public static boolean conditionForDefaultRestDatasource(NewAction action) { + if (action.getUnpublishedAction() == null + || action.getUnpublishedAction().getDatasource() == null) { + return false; + } + Datasource actionDatasource = action.getUnpublishedAction().getDatasource(); + // probable check for the default rest datasource action is. + // it has no datasource id and action's plugin id is either rest-api or graphql plugin. + boolean probableCheckForDefaultRestDatasource = !org.springframework.util.StringUtils.hasText( + actionDatasource.getId()) + && (REST_API_PLUGIN.equals(action.getPluginId()) || GRAPHQL_PLUGIN.equals(action.getPluginId())); + // condition to check if the action is default rest datasource. // it has no datasource id and name is equal to DEFAULT_REST_DATASOURCE - boolean isActionDefaultRestDatasource = !org.springframework.util.StringUtils.hasText(actionDatasource.getId()) - && PluginConstants.DEFAULT_REST_DATASOURCE.equals(actionDatasource.getName()); + boolean certainCheckForDefaultRestDatasource = + !org.springframework.util.StringUtils.hasText(actionDatasource.getId()) + && PluginConstants.DEFAULT_REST_DATASOURCE.equals(actionDatasource.getName()); + + // Two separate types of checks over here, it's either the obvious certain way to identify or + // the likely chance that the datasource is present. + return certainCheckForDefaultRestDatasource || probableCheckForDefaultRestDatasource; + } + + private static boolean conditionForDefaultRestDatasourceMigration(NewAction action) { + boolean isActionDefaultRestDatasource = conditionForDefaultRestDatasource(action); + Datasource actionDatasource = action.getUnpublishedAction().getDatasource(); // condition to check if the action has missing url or has no config at all boolean isDatasourceConfigurationOrUrlMissing = actionDatasource.getDatasourceConfiguration() == null @@ -1322,18 +1345,25 @@ public static void setDatasourceConfigDetailsInDefaultRestDatasourceForActions( if (defaultDatasourceActionMap.containsKey(action.getGitSyncId())) { NewAction actionFromMap = defaultDatasourceActionMap.get(action.getGitSyncId()); + // NPE check to avoid migration failures + if (actionFromMap.getUnpublishedAction() == null + || actionFromMap.getUnpublishedAction().getDatasource() == null + || actionFromMap.getUnpublishedAction().getDatasource().getDatasourceConfiguration() == null) { + return; + } + + // set the datasource config in the json action only if the datasource config from db is not null, + // else it'll start to show as uncommited changes. DatasourceConfiguration datasourceConfigurationFromDBAction = actionFromMap.getUnpublishedAction().getDatasource().getDatasourceConfiguration(); - if (datasourceConfigurationFromDBAction != null) { - datasourceConfiguration.setUrl(datasourceConfigurationFromDBAction.getUrl()); - } - } + // At this point it's established that datasource config of db action is not null. + datasourceConfiguration.setUrl(datasourceConfigurationFromDBAction.getUrl()); + actionDatasource.setDatasourceConfiguration(datasourceConfiguration); - if (!org.springframework.util.StringUtils.hasText(datasourceConfiguration.getUrl())) { + } else { datasourceConfiguration.setUrl(""); + actionDatasource.setDatasourceConfiguration(datasourceConfiguration); } - - actionDatasource.setDatasourceConfiguration(datasourceConfiguration); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java index 934bf79c6ed..1f1e27de8c7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/utils/JsonSchemaMigrationHelper.java @@ -1,6 +1,8 @@ package com.appsmith.server.migrations.utils; import com.appsmith.external.constants.PluginConstants; +import com.appsmith.external.models.Datasource; +import com.appsmith.external.models.PluginType; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.domains.Application; import com.appsmith.server.domains.NewAction; @@ -51,14 +53,27 @@ public Mono addDatasourceConfigurationToDefaultRestApiActions( return false; } - boolean reverseFlag = StringUtils.hasText(action.getUnpublishedAction() - .getDatasource() - .getId()) - || !PluginConstants.DEFAULT_REST_DATASOURCE.equals(action.getUnpublishedAction() - .getDatasource() - .getName()); + Datasource actionDatasource = + action.getUnpublishedAction().getDatasource(); - return !reverseFlag; + // lenient probable check for the default rest datasource action is. + // As we don't have any harm in the allowing API actions present in db. + // it has no datasource id and action's plugin type is API + boolean probableCheckForDefaultRestDatasource = + !org.springframework.util.StringUtils.hasText(actionDatasource.getId()) + && PluginType.API.equals(action.getPluginType()); + + // condition to check if the action is default rest datasource. + // it has no datasource id and name is equal to DEFAULT_REST_DATASOURCE + boolean certainCheckForDefaultRestDatasource = + !org.springframework.util.StringUtils.hasText(actionDatasource.getId()) + && PluginConstants.DEFAULT_REST_DATASOURCE.equals( + actionDatasource.getName()); + + // Two separate types of checks over here, it's either the obvious certain way to + // identify or + // the likely chance that the datasource is present. + return certainCheckForDefaultRestDatasource || probableCheckForDefaultRestDatasource; }) .collectMap(NewAction::getGitSyncId); })