Skip to content

Commit d52aa53

Browse files
authored
Merge pull request #36337 from appsmithorg/release
16/09 Daily Promotion
2 parents 7c9dfc0 + 71261b1 commit d52aa53

File tree

11 files changed

+327
-53
lines changed

11 files changed

+327
-53
lines changed

app/client/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
"node-forge": "^1.3.0",
164164
"normalizr": "^3.3.0",
165165
"object-hash": "^3.0.0",
166-
"path-to-regexp": "^6.2.0",
166+
"path-to-regexp": "^6.3.0",
167167
"popper.js": "^1.15.0",
168168
"prismjs": "^1.27.0",
169169
"proxy-memoize": "^1.2.0",

app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx

+32-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
import React from "react";
1+
import React, { useCallback } from "react";
22
import { IDEToolbar } from "IDE";
33
import { Button, Menu, MenuContent, MenuTrigger, Tooltip } from "@appsmith/ads";
44
import { modText } from "utils/helpers";
5+
import { usePluginActionContext } from "../PluginActionContext";
6+
import { useDispatch } from "react-redux";
7+
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
8+
import { runAction } from "../../actions/pluginActionActions";
59

610
interface PluginActionToolbarProps {
711
runOptions?: React.ReactNode;
@@ -10,6 +14,25 @@ interface PluginActionToolbarProps {
1014
}
1115

1216
const PluginActionToolbar = (props: PluginActionToolbarProps) => {
17+
const { action, datasource, plugin } = usePluginActionContext();
18+
const dispatch = useDispatch();
19+
const handleRunClick = useCallback(() => {
20+
AnalyticsUtil.logEvent("RUN_QUERY_CLICK", {
21+
actionName: action.name,
22+
actionId: action.id,
23+
pluginName: plugin.name,
24+
datasourceId: datasource?.id,
25+
isMock: datasource?.isMock,
26+
});
27+
dispatch(runAction(action.id));
28+
}, [
29+
action.id,
30+
action.name,
31+
datasource?.id,
32+
datasource?.isMock,
33+
dispatch,
34+
plugin.name,
35+
]);
1336
return (
1437
<IDEToolbar>
1538
<IDEToolbar.Left>{props.children}</IDEToolbar.Left>
@@ -20,7 +43,7 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => {
2043
placement="topRight"
2144
showArrow={false}
2245
>
23-
<Button kind="primary" size="sm">
46+
<Button kind="primary" onClick={handleRunClick} size="sm">
2447
Run
2548
</Button>
2649
</Tooltip>
@@ -30,7 +53,7 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => {
3053
size="sm"
3154
startIcon="settings-2-line"
3255
/>
33-
<Menu>
56+
<Menu key={action.id}>
3457
<MenuTrigger>
3558
<Button
3659
isIconButton
@@ -39,7 +62,12 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => {
3962
startIcon="more-2-fill"
4063
/>
4164
</MenuTrigger>
42-
<MenuContent loop style={{ zIndex: 100 }} width="200px">
65+
<MenuContent
66+
key={action.id}
67+
loop
68+
style={{ zIndex: 100 }}
69+
width="200px"
70+
>
4371
{props.menuContent}
4472
</MenuContent>
4573
</Menu>
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from "react";
22
import { PluginActionToolbar } from "PluginActionEditor";
3-
import { ConvertToModuleCTA } from "./ConvertToModule";
3+
import AppPluginActionMenu from "./PluginActionMoreActions";
44

55
const AppPluginActionToolbar = () => {
6-
return <PluginActionToolbar menuContent={<ConvertToModuleCTA />} />;
6+
return <PluginActionToolbar menuContent={<AppPluginActionMenu />} />;
77
};
88

99
export default AppPluginActionToolbar;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import React, { useCallback, useMemo, useState } from "react";
2+
import {
3+
getHasDeleteActionPermission,
4+
getHasManageActionPermission,
5+
} from "ee/utils/BusinessFeatures/permissionPageHelpers";
6+
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
7+
import { FEATURE_FLAG } from "ee/entities/FeatureFlag";
8+
import { usePluginActionContext } from "PluginActionEditor";
9+
import {
10+
MenuItem,
11+
MenuSub,
12+
MenuSubContent,
13+
MenuSubTrigger,
14+
} from "@appsmith/ads";
15+
import {
16+
CONFIRM_CONTEXT_DELETE,
17+
CONTEXT_COPY,
18+
CONTEXT_DELETE,
19+
CONTEXT_MOVE,
20+
createMessage,
21+
} from "ee/constants/messages";
22+
import { useDispatch, useSelector } from "react-redux";
23+
import {
24+
copyActionRequest,
25+
deleteAction,
26+
moveActionRequest,
27+
} from "actions/pluginActionActions";
28+
import { getCurrentPageId } from "selectors/editorSelectors";
29+
import type { Page } from "entities/Page";
30+
import { getPageList } from "ee/selectors/entitiesSelector";
31+
import { ConvertToModuleCTA } from "./ConvertToModule";
32+
33+
const PageMenuItem = (props: {
34+
page: Page;
35+
onSelect: (id: string) => void;
36+
}) => {
37+
const handleOnSelect = useCallback(() => {
38+
props.onSelect(props.page.pageId);
39+
}, [props]);
40+
return <MenuItem onSelect={handleOnSelect}>{props.page.pageName}</MenuItem>;
41+
};
42+
43+
const Copy = () => {
44+
const menuPages = useSelector(getPageList);
45+
const { action } = usePluginActionContext();
46+
const dispatch = useDispatch();
47+
48+
const copyActionToPage = useCallback(
49+
(pageId: string) =>
50+
dispatch(
51+
copyActionRequest({
52+
id: action.id,
53+
destinationPageId: pageId,
54+
name: action.name,
55+
}),
56+
),
57+
[action.id, action.name, dispatch],
58+
);
59+
60+
return (
61+
<MenuSub>
62+
<MenuSubTrigger startIcon="duplicate">
63+
{createMessage(CONTEXT_COPY)}
64+
</MenuSubTrigger>
65+
<MenuSubContent>
66+
{menuPages.map((page) => {
67+
return (
68+
<PageMenuItem
69+
key={page.basePageId}
70+
onSelect={copyActionToPage}
71+
page={page}
72+
/>
73+
);
74+
})}
75+
</MenuSubContent>
76+
</MenuSub>
77+
);
78+
};
79+
80+
const Move = () => {
81+
const dispatch = useDispatch();
82+
const { action } = usePluginActionContext();
83+
84+
const currentPageId = useSelector(getCurrentPageId);
85+
const allPages = useSelector(getPageList);
86+
const menuPages = useMemo(() => {
87+
return allPages.filter((page) => page.pageId !== currentPageId);
88+
}, [allPages, currentPageId]);
89+
90+
const moveActionToPage = useCallback(
91+
(destinationPageId: string) =>
92+
dispatch(
93+
moveActionRequest({
94+
id: action.id,
95+
destinationPageId,
96+
originalPageId: currentPageId,
97+
name: action.name,
98+
}),
99+
),
100+
[dispatch, action.id, action.name, currentPageId],
101+
);
102+
103+
return (
104+
<MenuSub>
105+
<MenuSubTrigger startIcon="swap-horizontal">
106+
{createMessage(CONTEXT_MOVE)}
107+
</MenuSubTrigger>
108+
<MenuSubContent>
109+
{menuPages.length > 1 ? (
110+
menuPages.map((page) => {
111+
return (
112+
<PageMenuItem
113+
key={page.basePageId}
114+
onSelect={moveActionToPage}
115+
page={page}
116+
/>
117+
);
118+
})
119+
) : (
120+
<MenuItem key="no-pages">No pages</MenuItem>
121+
)}
122+
</MenuSubContent>
123+
</MenuSub>
124+
);
125+
};
126+
127+
const Delete = () => {
128+
const dispatch = useDispatch();
129+
const { action } = usePluginActionContext();
130+
131+
const [confirmDelete, setConfirmDelete] = useState(false);
132+
133+
const deleteActionFromPage = useCallback(() => {
134+
dispatch(deleteAction({ id: action.id, name: action.name }));
135+
}, [action.id, action.name, dispatch]);
136+
137+
const handleSelect = useCallback(() => {
138+
confirmDelete ? deleteActionFromPage() : setConfirmDelete(true);
139+
}, [confirmDelete, deleteActionFromPage]);
140+
141+
const menuLabel = confirmDelete
142+
? createMessage(CONFIRM_CONTEXT_DELETE)
143+
: createMessage(CONTEXT_DELETE);
144+
145+
return (
146+
<MenuItem
147+
className="t--apiFormDeleteBtn error-menuitem"
148+
onSelect={handleSelect}
149+
startIcon="trash"
150+
>
151+
{menuLabel}
152+
</MenuItem>
153+
);
154+
};
155+
156+
const AppPluginActionMenu = () => {
157+
const { action } = usePluginActionContext();
158+
159+
const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled);
160+
const isChangePermitted = getHasManageActionPermission(
161+
isFeatureEnabled,
162+
action.userPermissions,
163+
);
164+
const isDeletePermitted = getHasDeleteActionPermission(
165+
isFeatureEnabled,
166+
action?.userPermissions,
167+
);
168+
169+
return (
170+
<>
171+
<ConvertToModuleCTA />
172+
{isChangePermitted && (
173+
<>
174+
<Copy />
175+
<Move />
176+
</>
177+
)}
178+
{isDeletePermitted && <Delete />}
179+
</>
180+
);
181+
};
182+
183+
export default AppPluginActionMenu;

app/client/yarn.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -13391,7 +13391,7 @@ __metadata:
1339113391
node-forge: ^1.3.0
1339213392
normalizr: ^3.3.0
1339313393
object-hash: ^3.0.0
13394-
path-to-regexp: ^6.2.0
13394+
path-to-regexp: ^6.3.0
1339513395
pg: ^8.11.3
1339613396
plop: ^3.1.1
1339713397
popper.js: ^1.15.0
@@ -27112,10 +27112,10 @@ __metadata:
2711227112
languageName: node
2711327113
linkType: hard
2711427114

27115-
"path-to-regexp@npm:^6.2.0":
27116-
version: 6.2.0
27117-
resolution: "path-to-regexp@npm:6.2.0"
27118-
checksum: a6aca74d2d6e2e7594d812f653cf85e9cb5054d3a8d80f099722a44ef6ad22639b02078e5ea83d11db16321c3e4359e3f1ab0274fa78dad0754a6e53f630b0fc
27115+
"path-to-regexp@npm:^6.3.0":
27116+
version: 6.3.0
27117+
resolution: "path-to-regexp@npm:6.3.0"
27118+
checksum: eca78602e6434a1b6799d511d375ec044e8d7e28f5a48aa5c28d57d8152fb52f3fc62fb1cfc5dfa2198e1f041c2a82ed14043d75740a2fe60e91b5089a153250
2711927119
languageName: node
2712027120
linkType: hard
2712127121

app/server/appsmith-interfaces/src/main/java/com/appsmith/external/models/DatasourceConfiguration.java

+2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ public class DatasourceConfiguration implements AppsmithDomain {
3434
@JsonView({Views.Public.class, FromRequest.class})
3535
AuthenticationDTO authentication;
3636

37+
@JsonView({Views.Public.class, FromRequest.class})
3738
SSHConnection sshProxy;
3839

40+
@JsonView({Views.Public.class, FromRequest.class})
3941
Boolean sshProxyEnabled;
4042

4143
@JsonView({Views.Public.class, FromRequest.class, Git.class})

app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaMigration.java

+30-22
Original file line numberDiff line numberDiff line change
@@ -67,28 +67,38 @@ public Mono<ApplicationJson> migrateApplicationJsonToLatestSchema(
6767
// TODO: make import flow migration reactive
6868
return Mono.just(migrateServerSchema(appJson))
6969
.flatMap(migratedApplicationJson -> {
70-
if (migratedApplicationJson.getServerSchemaVersion() == 9
71-
&& Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration(
72-
migratedApplicationJson))) {
73-
return jsonSchemaMigrationHelper
74-
.addDatasourceConfigurationToDefaultRestApiActions(
75-
baseApplicationId, branchName, migratedApplicationJson)
76-
.map(applicationJsonWithMigration10 -> {
77-
applicationJsonWithMigration10.setServerSchemaVersion(10);
78-
return applicationJsonWithMigration10;
79-
});
70+
// In Server version 9, there was a bug where the Embedded REST API datasource URL
71+
// was not being persisted correctly. Once the bug was fixed,
72+
// any previously uncommitted changes started appearing as uncommitted modifications
73+
// in the apps. To automatically commit these changes
74+
// (which were now appearing as uncommitted), a migration process was needed.
75+
// This migration fetches the datasource URL from the database
76+
// and serializes it in Git if the URL exists.
77+
// If the URL is missing, it copies the empty datasource configuration
78+
// if the configuration is present in the database.
79+
// Otherwise, it leaves the configuration unchanged.
80+
// Due to an update in the migration logic after version 10 was shipped,
81+
// the entire migration process was moved to version 11.
82+
// This adjustment ensures that the same operation can be
83+
// performed again for the changes introduced in version 10.
84+
if (migratedApplicationJson.getServerSchemaVersion() == 9) {
85+
migratedApplicationJson.setServerSchemaVersion(10);
86+
}
87+
88+
if (migratedApplicationJson.getServerSchemaVersion() == 10) {
89+
if (Boolean.TRUE.equals(MigrationHelperMethods.doesRestApiRequireMigration(
90+
migratedApplicationJson))) {
91+
return jsonSchemaMigrationHelper
92+
.addDatasourceConfigurationToDefaultRestApiActions(
93+
baseApplicationId, branchName, migratedApplicationJson);
94+
}
95+
96+
migratedApplicationJson.setServerSchemaVersion(11);
8097
}
8198

82-
migratedApplicationJson.setServerSchemaVersion(10);
8399
return Mono.just(migratedApplicationJson);
84100
})
85101
.map(migratedAppJson -> {
86-
if (applicationJson
87-
.getServerSchemaVersion()
88-
.equals(jsonSchemaVersions.getServerVersion())) {
89-
return applicationJson;
90-
}
91-
92102
applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion());
93103
return applicationJson;
94104
});
@@ -193,16 +203,14 @@ private ApplicationJson nonReactiveServerMigrationForImport(ApplicationJson appl
193203

194204
switch (applicationJson.getServerSchemaVersion()) {
195205
case 9:
206+
applicationJson.setServerSchemaVersion(10);
207+
case 10:
196208
// this if for cases where we have empty datasource configs
197209
MigrationHelperMethods.migrateApplicationJsonToVersionTen(applicationJson, Map.of());
198-
applicationJson.setServerSchemaVersion(10);
210+
applicationJson.setServerSchemaVersion(11);
199211
default:
200212
}
201213

202-
if (applicationJson.getServerSchemaVersion().equals(jsonSchemaVersions.getServerVersion())) {
203-
return applicationJson;
204-
}
205-
206214
applicationJson.setServerSchemaVersion(jsonSchemaVersions.getServerVersion());
207215
return applicationJson;
208216
}

app/server/appsmith-server/src/main/java/com/appsmith/server/migrations/JsonSchemaVersionsFallback.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
@Component
66
public class JsonSchemaVersionsFallback {
7-
private static final Integer serverVersion = 10;
7+
private static final Integer serverVersion = 11;
88
public static final Integer clientVersion = 1;
99

1010
public Integer getServerVersion() {

0 commit comments

Comments
 (0)