Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable post run actions for plugin queries #39325

Merged
merged 21 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0798017
create: add type for postRunActions
ayushpahwa Feb 18, 2025
31203e1
create: add enums for post run action forms
ayushpahwa Feb 18, 2025
ed4269e
create: add map for post run action names to components
ayushpahwa Feb 18, 2025
9c93dd6
create: add util func for post run actions
ayushpahwa Feb 18, 2025
74d5293
create: add container to show post run action forms
ayushpahwa Feb 18, 2025
9067b98
update: add usage of post run actions container
ayushpahwa Feb 18, 2025
d167f28
update: set action response parsing func to export
ayushpahwa Feb 23, 2025
33e108e
Merge branch 'release' into feat/action-post-run-container
ayushpahwa Feb 23, 2025
ae20b23
update: remove redundant dependency on action data
ayushpahwa Feb 23, 2025
045b910
Sync changes from EE excluding enterprise directory
ayushpahwa Feb 23, 2025
e399717
test: add coverage for post run action utils
ayushpahwa Feb 24, 2025
3c7f878
refactor: rename file for post run actions utils
ayushpahwa Feb 24, 2025
2051228
update: add test id to post run action container
ayushpahwa Feb 24, 2025
afe8491
test: add coverage for changes in response component
ayushpahwa Feb 24, 2025
b0ec2a5
refactor: move test file to parent folder
ayushpahwa Feb 24, 2025
d82a256
update: fix import of file under test
ayushpahwa Feb 24, 2025
7519292
update: remove redundant type export
ayushpahwa Feb 24, 2025
5e6b07f
update: move util function out for reusability
ayushpahwa Feb 24, 2025
e38b25f
test: add coverage for util function
ayushpahwa Feb 24, 2025
c693f5b
update: fix cyclic deps
ayushpahwa Feb 24, 2025
75b1335
Merge branch 'release' into feat/action-post-run-container
ayushpahwa Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ const defaultProps = {
responseTabHeight: 200,
};

// mock the postrunactionmap
jest.mock("ee/components/PostActionRunComponents", () => ({
PostRunActionComponentMap: {
test_modal: () => <div data-testid="t--post-run-action-test-modal-form" />,
},
}));

const storeData = getIDETestState({});

describe("Response", () => {
Expand All @@ -36,6 +43,7 @@ describe("Response", () => {

beforeEach(() => {
store = mockStore(storeData);
jest.clearAllMocks();
});

/** Test use prepared statement warning **/
Expand Down Expand Up @@ -208,4 +216,152 @@ describe("Response", () => {
container.querySelector("[data-testid='t--prepared-statement-warning']"),
).toBeNull();
});

it("6. Should show post run action container when post run action exists", () => {
const postRunAction = {
type: "FORM",
name: "test_modal",
};
const actionResponse = {
isExecutionSuccess: true,
body: [{ key: "value" }],
postRunAction,
dataTypes: [{ dataType: "JSON" }],
responseDisplayFormat: "JSON",
} as unknown as ActionResponse;

store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: actionResponse,
},
],
},
});

const props = {
...defaultProps,
actionResponse,
currentContentType: "JSON",
};

const { getByTestId } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<Response {...props} />
</Router>
</ThemeProvider>
</Provider>,
);

// Check if post run action container is showing
expect(getByTestId("t--post-run-action-container")).not.toBeNull();
expect(getByTestId("t--post-run-action-test-modal-form")).not.toBeNull();
});

it("7. Should not show post run action container when post run action doesn't exist", () => {
const actionResponse = {
isExecutionSuccess: true,
body: [{ key: "value" }],
dataTypes: [{ dataType: "JSON" }],
responseDisplayFormat: "JSON",
} as unknown as ActionResponse;

store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: actionResponse,
},
],
},
});

const props = {
...defaultProps,
actionResponse,
};

const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<Response {...props} />
</Router>
</ThemeProvider>
</Provider>,
);

// Check if post run action container is not showing
expect(
container.querySelector("[data-testid='t--post-run-action-container']"),
).toBeNull();
});

it("8. Should not show post run action container when correct mapping is not found", () => {
const postRunAction = {
type: "FORM",
name: "invalid_modal",
};
const actionResponse = {
isExecutionSuccess: true,
body: [{ key: "value" }],
postRunAction,
dataTypes: [{ dataType: "JSON" }],
responseDisplayFormat: "JSON",
} as unknown as ActionResponse;

store = mockStore({
...storeData,
entities: {
...storeData.entities,
actions: [
{
config: {
id: "test-action-id",
name: "Test Action",
},
isLoading: false,
data: actionResponse,
},
],
},
});

const props = {
...defaultProps,
actionResponse,
};

const { container } = render(
<Provider store={store}>
<ThemeProvider theme={lightTheme}>
<Router>
<Response {...props} />
</Router>
</ThemeProvider>
</Provider>,
);

// Check if post run action container is not showing
expect(
container.querySelector("[data-testid='t--post-run-action-container']"),
).toBeNull();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { RESPONSE_TABLE_HEIGHT_OFFSET } from "./constants";
import * as Styled from "./styles";
import { checkForPreparedStatement, parseActionResponse } from "./utils";
import ActionExecutionInProgressView from "./components/ActionExecutionInProgressView";
import { checkForPostRunAction } from "./utils/postRunActionsUtil";
import PostActionRunContainer from "./components/PostActionRunContainer";

interface ResponseProps {
action: Action;
Expand Down Expand Up @@ -126,6 +128,9 @@ export function Response(props: ResponseProps) {
checkForPreparedStatement(action) && errorMessage,
);

const showPostRunAction =
actionResponse && checkForPostRunAction(actionResponse?.postRunAction);

const actionSource: SourceEntity = useMemo(
() => ({
type: ENTITY_TYPE.ACTION,
Expand Down Expand Up @@ -267,6 +272,11 @@ export function Response(props: ResponseProps) {
}
/>
</Styled.Response>
{showPostRunAction && (
<PostActionRunContainer
postRunAction={actionResponse?.postRunAction}
/>
)}
<ContentTypeSelector
contentTypeOptions={contentTypeOptions}
currentContentType={currentContentType}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { getPostRunActionName } from "../utils/postRunActionsUtil";
import styled from "styled-components";
import { PostRunActionComponentMap } from "ee/components/PostActionRunComponents";
import type { PostRunActionNamesInterface } from "ee/components/PostActionRunComponents/types";
import type { PostActionRunConfig } from "api/types";

interface Props {
postRunAction?: PostActionRunConfig;
}

const Container = styled.div`
border: 1px solid var(--ads-v2-color-border);
z-index: 100;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: auto;
padding-bottom: var(--ads-bottom-bar-height);
background-color: var(--ads-v2-color-bg);
`;

export default function PostActionRunContainer({ postRunAction }: Props) {
if (!postRunAction) {
return null;
}

const name: string = getPostRunActionName(postRunAction);
const Component = PostRunActionComponentMap[
name as PostRunActionNamesInterface
] as React.ComponentType;

if (!Component) {
return null;
}

return (
<Container data-testid="t--post-run-action-container">
<Component />
</Container>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
checkForPostRunAction,
getPostRunActionName,
} from "./postRunActionsUtil";
import type { PostActionRunConfig } from "api/types";

describe("checkForPostRunAction", () => {
it("should return true for valid post run action", () => {
const validAction: PostActionRunConfig = {
type: "FORM",
name: "some_name",
};

expect(checkForPostRunAction(validAction)).toBe(true);
});

it("should return false for undefined input", () => {
expect(checkForPostRunAction(undefined)).toBe(false);
});

it("should return false for input without type property", () => {
const invalidAction = {
name: "some_name",
};

expect(checkForPostRunAction(invalidAction as PostActionRunConfig)).toBe(
false,
);
});
});

describe("getPostRunActionName", () => {
it("should return name for valid post run action", () => {
const validAction: PostActionRunConfig = {
type: "FORM",
name: "test_action",
};

expect(getPostRunActionName(validAction)).toBe("test_action");
});

it("should return empty string for undefined input", () => {
expect(getPostRunActionName(undefined)).toBe("");
});

it("should return empty string for action without name", () => {
const actionWithoutName: PostActionRunConfig = {
type: "FORM",
name: "",
};

expect(getPostRunActionName(actionWithoutName)).toBe("");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { PostActionRunConfig } from "api/types";

export function checkForPostRunAction(postRunAction?: PostActionRunConfig) {
if (
postRunAction &&
typeof postRunAction === "object" &&
"type" in postRunAction
) {
return true;
}

return false;
}

export function getPostRunActionName(postRunAction?: PostActionRunConfig) {
if (!postRunAction) {
return "";
}

const { name } = postRunAction;

if (!name) {
return "";
}

return name;
}
2 changes: 2 additions & 0 deletions app/client/src/api/ActionAPI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { Action, ActionViewMode } from "entities/Action";
import type { APIRequest } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
import type { PostActionRunConfig } from "./types";

export interface Property {
key: string;
Expand Down Expand Up @@ -86,6 +87,7 @@ export interface ActionResponse {
readableError?: string;
responseDisplayFormat?: string;
pluginErrorDetails?: PluginErrorDetails;
postRunAction?: PostActionRunConfig;
}

//This contains the error details from the plugin that is sent to the client in the response
Expand Down
6 changes: 6 additions & 0 deletions app/client/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ export type AxiosResponseData<T> = AxiosResponse<ApiResponse<T>>["data"];
export type ErrorHandler = (
error: AxiosError<ApiResponse>,
) => Promise<unknown | null>;

export interface PostActionRunConfig {
type: "FORM";
name: string;
config?: Record<string, unknown>;
}
6 changes: 6 additions & 0 deletions app/client/src/ce/components/PostActionRunComponents/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { PostRunActionNamesInterface } from "./types";

export const PostRunActionComponentMap: Record<
PostRunActionNamesInterface,
React.ElementType
> = {};
4 changes: 4 additions & 0 deletions app/client/src/ce/components/PostActionRunComponents/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const PostRunActionNames = {} as const;

export type PostRunActionNamesInterface =
(typeof PostRunActionNames)[keyof typeof PostRunActionNames];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "ce/components/PostActionRunComponents";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "ce/components/PostActionRunComponents/types";
Loading
Loading