Merge branch 'feat/reactive-actions-run-behaviour' of https://github.com/appsmithorg/appsmith into feat/reactive-actions-run-behaviour

This commit is contained in:
Ankita Kinger 2025-04-30 11:17:23 +05:30
commit 0c8bd0bd2f
34 changed files with 85 additions and 83 deletions

View File

@ -51,10 +51,10 @@ export class JSEditor {
"div.t--js-response-parse-error-call-out";
private _onPageLoadSwitch = (functionName: string) =>
`.${functionName}-on-page-load-setting
input[role="switch"]`;
`.${functionName}-run-behavior
input[role="combobox"]`;
private _onPageLoadSwitchStatus = (functionName: string) =>
`//div[contains(@class, '${functionName}-on-page-load-setting')]//label/input`;
`//div[contains(@class, '${functionName}-run-behavior-setting')]//label/input`;
private _jsObjName = this.locator._activeEntityTab;
public _jsObjTxt = this.locator._activeEntityTabInput;

View File

@ -13,7 +13,7 @@ import {
isPluginActionSettingsOpen,
openPluginActionSettings,
} from "../../store";
import { THEME } from "../../constants/PluginActionConstants";
import { THEME } from "../../types/PluginActionTypes";
import { type DocsLink, openDoc } from "constants/DocumentationLinks";
import { ToolbarSettingsPopover } from "IDE";

View File

@ -12,11 +12,13 @@ export const RUN_BEHAVIOR = {
label: "On page load",
subText: "Query runs when the page loads or when manually triggered",
value: ActionRunBehaviour.ON_PAGE_LOAD,
children: "On page load",
},
MANUAL: {
label: "Manual",
subText: "Query only runs when called in an event or JS with .run()",
value: ActionRunBehaviour.MANUAL,
children: "Manual",
},
};

View File

@ -20,7 +20,7 @@ import type { EventLocation } from "ee/utils/analyticsUtilTypes";
import type { GenerateDestinationIdInfoReturnType } from "ee/sagas/helpers";
import type { Span } from "instrumentation/types";
import type { EvaluationReduxAction } from "./EvaluationReduxActionTypes";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export const createActionRequest = (
payload: Partial<Action>,

View File

@ -10,7 +10,7 @@ import type { APIRequest } from "constants/AppsmithActionConstants/ActionConstan
import type { WidgetType } from "constants/WidgetConstants";
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
import type { PostActionRunConfig } from "./types";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export interface Property {
key: string;

View File

@ -9,7 +9,7 @@ import type {
import type { DSLWidget } from "WidgetProvider/constants";
import type { FetchApplicationResponse } from "ee/api/ApplicationApi";
import type { APP_MODE } from "entities/App";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export interface FetchPageRequest {
pageId: string;

View File

@ -3,7 +3,7 @@ import type {
FieldEntityInformation,
TEditorModes,
} from "components/editorComponents/CodeEditor/EditorConfig";
import type { EntityNavigationData } from "selectors/navigationSelectors";
import type { EntityNavigationData } from "entities/DataTree/dataTreeTypes";
import React from "react";
import type CodeMirror from "codemirror";

View File

@ -13,7 +13,7 @@ import type {
UpdateActionPropertyActionPayload,
} from "actions/pluginActionActions";
import { klona } from "klona";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export interface ActionData {
isLoading: boolean;

View File

@ -8,7 +8,7 @@ import {
import { set, keyBy, findIndex, unset } from "lodash";
import { create } from "mutative";
import { klona } from "klona";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export const initialState: JSCollectionDataState = [];

View File

@ -1,5 +1,5 @@
import type { ModuleInstance } from "ee/constants/ModuleInstanceConstants";
import type { EntityNavigationData } from "selectors/navigationSelectors";
import type { EntityNavigationData } from "entities/DataTree/dataTreeTypes";
export const getModuleInstanceNavigationData = (
/* eslint-disable @typescript-eslint/no-unused-vars */

View File

@ -1,8 +1,10 @@
import type CodeMirror from "codemirror";
import type { EntityTypeValue } from "ee/entities/DataTree/types";
import type { DataTree } from "entities/DataTree/dataTreeTypes";
import type {
DataTree,
EntityNavigationData,
} from "entities/DataTree/dataTreeTypes";
import type { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
import type { EntityNavigationData } from "selectors/navigationSelectors";
import type { ExpectedValueExample } from "utils/validation/common";
import { editorSQLModes } from "./sql/config";

View File

@ -1,7 +1,7 @@
import type {
EntityNavigationData,
NavigationData,
} from "selectors/navigationSelectors";
} from "entities/DataTree/dataTreeTypes";
import type { MarkHelper } from "../EditorConfig";
export const NAVIGATE_TO_ATTRIBUTE = "data-navigate-to";

View File

@ -18,7 +18,7 @@ import type { FeatureFlags } from "ee/entities/FeatureFlag";
import type {
EntityNavigationData,
NavigationData,
} from "selectors/navigationSelectors";
} from "entities/DataTree/dataTreeTypes";
import { getAIContext } from "ee/components/editorComponents/GPT/trigger";
import type { Plugin } from "entities/Plugin";

View File

@ -14,7 +14,7 @@ import { APPSMITH_AI } from "ee/components/editorComponents/GPT/trigger";
import { DatasourceCreateEntryPoints } from "constants/Datasource";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import BetaCard from "../BetaCard";
import type { NavigationData } from "selectors/navigationSelectors";
import type { NavigationData } from "entities/DataTree/dataTreeTypes";
import type { AIEditorContext } from "ee/components/editorComponents/GPT";
import type { EntityTypeValue } from "ee/entities/DataTree/types";
import history, { NavigationMethod } from "utils/history";

View File

@ -122,7 +122,7 @@ import { updateCustomDef } from "utils/autocomplete/customDefUtils";
import { shouldFocusOnPropertyControl } from "utils/editorContextUtils";
import { getEntityLintErrors } from "selectors/lintingSelectors";
import { getCodeCommentKeyMap, handleCodeComment } from "./utils/codeComment";
import type { EntityNavigationData } from "selectors/navigationSelectors";
import type { EntityNavigationData } from "entities/DataTree/dataTreeTypes";
import { getEntitiesForNavigation } from "selectors/navigationSelectors";
import history, { NavigationMethod } from "utils/history";
import { CursorPositionOrigin } from "ee/reducers/uiReducers/editorContextReducer";

View File

@ -1,5 +1,5 @@
import { getJSResponseViewState, JSResponseState } from "./utils";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
const TEST_JS_FUNCTION_ID = "627ccff468e1fa5185b7f901";
const TEST_JS_FUNCTION_BASE_ID = "627ccff468e1fa5185b7f912";

View File

@ -9,7 +9,7 @@ import {
import {
RUN_BEHAVIOR,
RUN_BEHAVIOR_VALUES,
} from "PluginActionEditor/constants/PluginActionConstants";
} from "PluginActionEditor/types/PluginActionTypes";
export default [
{

View File

@ -1,7 +1,7 @@
import {
RUN_BEHAVIOR,
RUN_BEHAVIOR_VALUES,
} from "PluginActionEditor/constants/PluginActionConstants";
} from "PluginActionEditor/types/PluginActionTypes";
export default [
{

View File

@ -1,7 +1,7 @@
import {
RUN_BEHAVIOR,
RUN_BEHAVIOR_VALUES,
} from "PluginActionEditor/constants/PluginActionConstants";
} from "PluginActionEditor/types/PluginActionTypes";
export default [
{

View File

@ -10,7 +10,7 @@ import {
type Plugin,
type PluginName,
} from "../Plugin";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export enum PaginationType {
NONE = "NONE",

View File

@ -3,6 +3,7 @@ import type {
DataTreeEntityObject,
UnEvalTreeEntityObject,
AppsmithEntity,
EntityTypeValue,
} from "ee/entities/DataTree/types";
export interface unEvalAndConfigTree {
@ -23,3 +24,23 @@ export type UnEvalTreeEntity = UnEvalTreeEntityObject | AppsmithEntity;
export interface UnEvalTree {
[entityName: string]: UnEvalTreeEntity;
}
export interface NavigationData {
name: string;
id: string;
type: EntityTypeValue;
isfunction?: boolean;
url: string | undefined;
navigable: boolean;
children: EntityNavigationData;
key?: string;
pluginName?: string;
pluginId?: string;
isMock?: boolean;
datasourceId?: string;
actionType?: string;
widgetType?: string;
value?: boolean | string;
}
export type EntityNavigationData = Record<string, NavigationData>;

View File

@ -2,13 +2,8 @@ import React from "react";
import "@testing-library/jest-dom";
import { render, screen } from "test/testUtils";
import { JSFunctionSettings } from "./JSFunctionSettings";
import { useFeatureFlag } from "utils/hooks/useFeatureFlag";
import { JSObjectFactory } from "test/factories/Actions/JSObject";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
// Mock the useFeatureFlag hook
jest.mock("utils/hooks/useFeatureFlag");
const mockUseFeatureFlag = useFeatureFlag as jest.Mock;
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
const JSObject = JSObjectFactory.build();
@ -21,9 +16,7 @@ describe("JSFunctionSettings", () => {
jest.clearAllMocks();
});
it("disables the switch when the component is disabled", () => {
mockUseFeatureFlag.mockReturnValue(true);
it("disables the run behavior when the component is disabled", () => {
render(
<JSFunctionSettings
actions={actions}
@ -35,9 +28,7 @@ describe("JSFunctionSettings", () => {
expect(screen.getByLabelText(actions[0].name)).toBeDisabled();
});
it("renders the correct number of switches for the actions", () => {
mockUseFeatureFlag.mockReturnValue(true);
it("renders the correct number of dropdowns for the actions", () => {
render(
<JSFunctionSettings
actions={actions}
@ -46,12 +37,10 @@ describe("JSFunctionSettings", () => {
/>,
);
expect(screen.getAllByRole("switch")).toHaveLength(actions.length);
expect(screen.getAllByRole(`combobox`)).toHaveLength(actions.length);
});
it("renders the switch state correctly", () => {
mockUseFeatureFlag.mockReturnValue(true);
it("renders the run behavior correctly", () => {
const updatedJSActions = [
{
...actions[0],
@ -71,10 +60,14 @@ describe("JSFunctionSettings", () => {
/>,
);
const switchElement1 = screen.getByLabelText(updatedJSActions[0].name);
const switchElement2 = screen.getByLabelText(updatedJSActions[1].name);
const selectedItem1 = screen.getByText("On page load", {
selector: ".myFun1-run-behavior-setting .rc-select-selection-item",
});
const selectedItem2 = screen.getByText("Manual", {
selector: ".myFun2-run-behavior-setting .rc-select-selection-item",
});
expect(switchElement1).toBeChecked();
expect(switchElement2).not.toBeChecked();
expect(selectedItem1).toBeInTheDocument();
expect(selectedItem2).toBeInTheDocument();
});
});

View File

@ -14,8 +14,10 @@ import {
} from "ee/constants/messages";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import type { OnUpdateSettingsProps } from "../types";
import type { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { RUN_BEHAVIOR_VALUES } from "PluginActionEditor/constants/PluginActionConstants";
import {
RUN_BEHAVIOR_VALUES,
type ActionRunBehaviourType,
} from "PluginActionEditor/types/PluginActionTypes";
import styled from "styled-components";
const OptionLabel = styled(Text)`
@ -45,10 +47,11 @@ interface FunctionSettingsRowProps extends Omit<Props, "actions"> {
const FunctionSettingRow = (props: FunctionSettingsRowProps) => {
const [runBehavior, setRunBehavior] = useState(props.action.runBehavior);
const options = RUN_BEHAVIOR_VALUES as Omit<SelectOptionProps, "children">[];
const options = RUN_BEHAVIOR_VALUES as SelectOptionProps[];
const selectedValue = options.find((opt) => opt.value === runBehavior);
const onSelectOptions = useCallback(
(newRunBehavior: ActionRunBehaviour) => {
(newRunBehavior: ActionRunBehaviourType) => {
setRunBehavior(newRunBehavior);
props.onUpdateSettings?.({
value: newRunBehavior,
@ -67,29 +70,30 @@ const FunctionSettingRow = (props: FunctionSettingsRowProps) => {
return (
<Flex
alignItems="center"
className={`t--async-js-function-settings ${props.action.name}-on-page-load-setting`}
className={`t--async-js-function-settings ${props.action.name}-run-behavior-setting`}
gap="spaces-4"
id={`${props.action.name}-settings`}
justifyContent="space-between"
key={props.action.id}
w="100%"
>
<Text renderAs="label">{props.action.name}</Text>
<Text htmlFor={props.action.id} renderAs="label">
{props.action.name}
</Text>
<StyledSelect
data-testid={`execute-on-page-load-${props.action.id}`}
defaultValue={runBehavior}
defaultValue={selectedValue}
id={props.action.id}
isDisabled={props.disabled}
listHeight={240}
onSelect={onSelectOptions}
size="sm"
value={runBehavior}
virtual
value={selectedValue}
>
{options.map((option) => (
<Option
aria-label={option.label}
disabled={option.disabled}
isDisabled={option.isDisabled}
key={option.value}
label={option.label}
value={option.value}

View File

@ -1,6 +1,6 @@
import type { JSAction } from "entities/JSCollection";
import type { DropdownOption } from "@appsmith/ads-old";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export interface OnUpdateSettingsProps {
value: ActionRunBehaviourType;

View File

@ -6,7 +6,7 @@ import {
getJSActionOption,
} from "./JSEditorToolbar/utils";
import { NO_FUNCTION_DROPDOWN_OPTION } from "./JSEditorToolbar/constants";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
const BASE_JS_OBJECT_BODY = `export default {
myVar1: [],

View File

@ -169,7 +169,7 @@ import {
selectGitOpsModalOpen,
} from "selectors/gitModSelectors";
import { createActionExecutionResponse } from "./PluginActionSagaUtils";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
import { appsmithTelemetry } from "instrumentation";
interface FilePickerInstumentationObject {

View File

@ -147,7 +147,7 @@ import {
import { handleQueryEntityRedirect } from "./IDESaga";
import type { EvaluationReduxAction } from "actions/EvaluationReduxActionTypes";
import { IDE_TYPE } from "ee/IDE/Interfaces/IDETypes";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export const DEFAULT_PREFIX = {
QUERY: "Query",

View File

@ -101,7 +101,7 @@ import { updateJSCollectionAPICall } from "ee/sagas/ApiCallerSagas";
import { convertToBasePageIdSelector } from "selectors/pageListSelectors";
import { getIsAnvilEnabledInCurrentApplication } from "layoutSystems/anvil/integrations/selectors";
import { fetchActionsForPage } from "actions/pluginActionActions";
import type { ActionRunBehaviourType } from "PluginActionEditor/constants/PluginActionConstants";
import type { ActionRunBehaviourType } from "PluginActionEditor/types/PluginActionTypes";
export interface GenerateDefaultJSObjectProps {
name: string;

View File

@ -1,4 +1,3 @@
import type { EntityTypeValue } from "ee/entities/DataTree/types";
import {
ACTION_TYPE,
JSACTION_TYPE,
@ -34,26 +33,7 @@ import { PluginType } from "entities/Plugin";
import type { StoredDatasource } from "entities/Action";
import type { Datasource } from "entities/Datasource";
import { getModuleInstanceNavigationData } from "ee/utils/moduleInstanceNavigationData";
export interface NavigationData {
name: string;
id: string;
type: EntityTypeValue;
isfunction?: boolean;
url: string | undefined;
navigable: boolean;
children: EntityNavigationData;
key?: string;
pluginName?: string;
pluginId?: string;
isMock?: boolean;
datasourceId?: string;
actionType?: string;
widgetType?: string;
value?: boolean | string;
}
export type EntityNavigationData = Record<string, NavigationData>;
import type { EntityNavigationData } from "entities/DataTree/dataTreeTypes";
export const getModulesData = createSelector(
getModuleInstances,

View File

@ -1,7 +1,7 @@
import type { JSActionEntity } from "ee/entities/DataTree/types";
import type { DataTree } from "entities/DataTree/dataTreeTypes";
import type { JSCollectionData } from "ee/reducers/entityReducers/jsActionsReducer";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
export const getJsActionPeekData = (
jsAction: JSCollectionData,

View File

@ -3,7 +3,7 @@ import type { JSCollection, JSAction, Variable } from "entities/JSCollection";
import { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import AppsmithConsole from "utils/AppsmithConsole";
import { ActionRunBehaviour } from "PluginActionEditor/constants/PluginActionConstants";
import { ActionRunBehaviour } from "PluginActionEditor/types/PluginActionTypes";
export interface ParsedJSSubAction {
name: string;

View File

@ -7,7 +7,7 @@ import { jsCollectionIdURL } from "ee/RouteBuilder";
import type {
EntityNavigationData,
NavigationData,
} from "selectors/navigationSelectors";
} from "entities/DataTree/dataTreeTypes";
import { createNavData } from "./common";
export const getJsChildrenNavData = (

View File

@ -2,7 +2,7 @@ import type { WidgetEntity } from "ee/entities/DataTree/types";
import type { DataTree } from "entities/DataTree/dataTreeTypes";
import { ENTITY_TYPE } from "ee/entities/DataTree/types";
import { builderURL } from "ee/RouteBuilder";
import type { EntityNavigationData } from "selectors/navigationSelectors";
import type { EntityNavigationData } from "entities/DataTree/dataTreeTypes";
import { createNavData } from "./common";
export const getWidgetChildrenNavData = (

View File

@ -2,7 +2,7 @@ import type { EntityTypeValue } from "ee/entities/DataTree/types";
import type {
EntityNavigationData,
NavigationData,
} from "selectors/navigationSelectors";
} from "entities/DataTree/dataTreeTypes";
export const createNavData = (general: {
name: string;