diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/index.ts b/app/client/packages/design-system/widgets/src/components/Avatar/index.ts
deleted file mode 100644
index 3bd16e178a..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./src";
diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx b/app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx
deleted file mode 100644
index d6c7dc28ed..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/src/Avatar.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from "react";
-import { clsx } from "clsx";
-import { Text } from "@appsmith/wds";
-
-import styles from "./styles.module.css";
-import type { AvatarProps } from "./types";
-import { getTypographyClassName } from "@appsmith/wds-theming";
-
-export const Avatar = (props: AvatarProps) => {
- const { className, label, size, src, ...rest } = props;
-
- const getLabelInitials = (label: string) => {
- const names = label.split(" ");
-
- if (names.length === 1) {
- return `${names[0].charAt(0)}`;
- }
-
- return `${names[0].charAt(0)}${names[1]?.charAt(0)}`;
- };
-
- return (
-
- {Boolean(src) ? (
-
- ) : (
-
- {getLabelInitials(label)}
-
- )}
-
- );
-};
diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts b/app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts
deleted file mode 100644
index 3a8b659aee..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/src/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from "./types";
-export * from "./Avatar";
diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css
deleted file mode 100644
index abeb0956b1..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/src/styles.module.css
+++ /dev/null
@@ -1,31 +0,0 @@
-.avatar {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: var(--icon-size-3);
- height: var(--icon-size-3);
-}
-
-.avatar[data-size="small"] {
- width: var(--icon-size-2);
- height: var(--icon-size-2);
-}
-
-.avatar[data-size="large"] {
- width: var(--icon-size-4);
- height: var(--icon-size-4);
-}
-
-/* if the avatar has div, that means no source is provided. For this case, we want to add a background color and border radius */
-.avatar:has(div) {
- background-color: var(--color-bg-assistive);
- color: var(--color-fg-on-assistive);
- border-radius: var(--border-radius-elevation-3);
-}
-
-.avatarImage {
- border-radius: inherit;
- height: 100%;
- object-fit: contain;
- aspect-ratio: 1 / 1;
-}
diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts b/app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts
deleted file mode 100644
index 3731a231d9..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/src/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { HTMLProps } from "react";
-
-export interface AvatarProps extends Omit, "size"> {
- /** The label of the avatar */
- label: string;
- /** The image source of the avatar */
- src?: string;
- /** The size of the avatar
- *
- * @default "medium"
- */
- size?: "small" | "medium" | "large";
-}
diff --git a/app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx b/app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx
deleted file mode 100644
index 10ca22796e..0000000000
--- a/app/client/packages/design-system/widgets/src/components/Avatar/stories/Avatar.stories.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from "react";
-import { Avatar, Flex } from "@appsmith/wds";
-import type { Meta, StoryObj } from "@storybook/react";
-
-const meta: Meta = {
- title: "WDS/Widgets/Avatar",
- component: Avatar,
-};
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- label: "John Doe",
- },
-};
-
-export const WithImage: Story = {
- args: {
- label: "Jane Smith",
- src: "https://assets.appsmith.com/integrations/25720743.png",
- },
-};
-
-export const SingleInitial: Story = {
- args: {
- label: "Alice",
- },
-};
-
-export const Sizes: Story = {
- args: {
- label: "Alice",
- },
- render: (args) => (
-
-
-
-
-
- ),
-};
diff --git a/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx b/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx
index 6f439aa2ac..55ff67d953 100644
--- a/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx
+++ b/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Heading.tsx
@@ -19,6 +19,7 @@ const createHeading = (
fontWeight={fontWeight}
ref={ref as Ref}
size={size}
+ wordBreak="break-word"
>
{children}
diff --git a/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx b/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx
index 29582c3a0c..b90e52e110 100644
--- a/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx
+++ b/app/client/packages/design-system/widgets/src/components/Markdown/src/mdComponents/Link.tsx
@@ -10,7 +10,13 @@ export const a = (props: LinkProps) => {
const { children, href } = props;
return (
-
+
{children}
);
diff --git a/app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css b/app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css
index 96036ed4d1..7b60c6ee7e 100644
--- a/app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css
+++ b/app/client/packages/design-system/widgets/src/components/Markdown/src/styles.module.css
@@ -97,7 +97,7 @@
background-color: var(--color-bg-elevation-2);
border-radius: var(--border-radius-elevation-3);
outline: var(--border-width-1) solid var(--color-bg-neutral-subtle);
- margin-bottom: var(--spacing-2);
+ margin-bottom: var(--inner-spacing-2);
overflow: auto;
}
diff --git a/app/client/packages/design-system/widgets/src/index.ts b/app/client/packages/design-system/widgets/src/index.ts
index 911e15b14c..277f078a90 100644
--- a/app/client/packages/design-system/widgets/src/index.ts
+++ b/app/client/packages/design-system/widgets/src/index.ts
@@ -29,7 +29,6 @@ export * from "./components/Radio";
export * from "./components/ListBox";
export * from "./components/ListBoxItem";
export * from "./components/MenuItem";
-export * from "./components/Avatar";
export * from "./components/Markdown";
export * from "./utils";
diff --git a/app/client/src/WidgetProvider/constants.ts b/app/client/src/WidgetProvider/constants.ts
index 0627b51862..cb0837d608 100644
--- a/app/client/src/WidgetProvider/constants.ts
+++ b/app/client/src/WidgetProvider/constants.ts
@@ -208,6 +208,10 @@ export enum BlueprintOperationTypes {
UPDATE_CREATE_PARAMS_BEFORE_ADD = "UPDATE_CREATE_PARAMS_BEFORE_ADD",
}
+export enum BlueprintOperationActionTypes {
+ CREATE_OR_UPDATE_DATASOURCE_WITH_ACTION = "CREATE_OR_UPDATE_DATASOURCE_WITH_ACTION",
+}
+
export type FlattenedWidgetProps = WidgetProps & {
children?: string[];
};
diff --git a/app/client/src/ce/pages/Applications/index.tsx b/app/client/src/ce/pages/Applications/index.tsx
index 4bbdf51459..df8d6176a5 100644
--- a/app/client/src/ce/pages/Applications/index.tsx
+++ b/app/client/src/ce/pages/Applications/index.tsx
@@ -752,7 +752,7 @@ export function ApplicationsSection(props: any) {
) {
createNewApplication(
getNextEntityName(
- "Untitled application ",
+ isAnvilEnabled ? "AI app " : "Untitled application ",
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
applications.map((el: any) => el.name),
diff --git a/app/client/src/layoutSystems/anvil/editor/styles.module.css b/app/client/src/layoutSystems/anvil/editor/styles.module.css
index 1e40e18533..3d2ccdd43a 100644
--- a/app/client/src/layoutSystems/anvil/editor/styles.module.css
+++ b/app/client/src/layoutSystems/anvil/editor/styles.module.css
@@ -3,4 +3,12 @@
& > * {
pointer-events: none;
}
+
+ /*
+ This is a temporary solution. According to the product requirements, we need to make AI chat widget interactive.
+ This code can be deleted when full-fledged inline editing feature is implemented.
+ */
+ & [data-widget-name*="AIChat"] > * {
+ pointer-events: all;
+ }
}
diff --git a/app/client/src/sagas/ActionSagas.ts b/app/client/src/sagas/ActionSagas.ts
index 60c375e769..92e2a26ef9 100644
--- a/app/client/src/sagas/ActionSagas.ts
+++ b/app/client/src/sagas/ActionSagas.ts
@@ -1,3 +1,56 @@
+import { toast } from "@appsmith/ads";
+import { objectKeys } from "@appsmith/utils";
+import { fetchDatasourceStructure } from "actions/datasourceActions";
+import {
+ setIdeEditorViewMode,
+ setShowQueryCreateNewModal,
+} from "actions/ideActions";
+import {
+ closeQueryActionTab,
+ closeQueryActionTabSuccess,
+ copyActionError,
+ copyActionSuccess,
+ createActionInit,
+ createActionSuccess,
+ createNewApiAction,
+ createNewQueryAction,
+ deleteActionSuccess,
+ fetchActionsForPage,
+ fetchActionsForPageSuccess,
+ type FetchActionsPayload,
+ moveActionError,
+ moveActionSuccess,
+ type SetActionPropertyPayload,
+ updateAction,
+ updateActionData,
+ updateActionProperty,
+ updateActionSuccess,
+} from "actions/pluginActionActions";
+import { setSnipingMode as setSnipingModeAction } from "actions/propertyPaneActions";
+import type { ActionCreateUpdateResponse } from "api/ActionAPI";
+import ActionAPI from "api/ActionAPI";
+import type { ApiResponse } from "api/ApiResponses";
+import type { FetchPageRequest, FetchPageResponse } from "api/PageApi";
+import PageApi from "api/PageApi";
+import type { Plugin } from "api/PluginApi";
+import { EditorModes } from "components/editorComponents/CodeEditor/EditorConfig";
+import {
+ fixActionPayloadForMongoQuery,
+ getConfigInitialValues,
+} from "components/formControls/utils";
+import { INTEGRATION_TABS } from "constants/routes";
+import {
+ API_EDITOR_FORM_NAME,
+ QUERY_EDITOR_FORM_NAME,
+} from "ee/constants/forms";
+import {
+ ACTION_COPY_SUCCESS,
+ ACTION_MOVE_SUCCESS,
+ createMessage,
+ ERROR_ACTION_COPY_FAIL,
+ ERROR_ACTION_MOVE_FAIL,
+ ERROR_ACTION_RENAME_FAIL,
+} from "ee/constants/messages";
import type {
EvaluationReduxAction,
ReduxAction,
@@ -6,6 +59,61 @@ import {
ReduxActionErrorTypes,
ReduxActionTypes,
} from "ee/constants/ReduxActionConstants";
+import { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
+import { CreateNewActionKey } from "ee/entities/Engine/actionHelpers";
+import { EditorViewMode, IDE_TYPE } from "ee/entities/IDE/constants";
+import { getIDETypeByUrl } from "ee/entities/IDE/utils";
+import type { ActionData } from "ee/reducers/entityReducers/actionsReducer";
+import {
+ apiEditorIdURL,
+ builderURL,
+ integrationEditorURL,
+ queryEditorIdURL,
+ saasEditorApiIdURL,
+} from "ee/RouteBuilder";
+import { updateActionAPICall } from "ee/sagas/ApiCallerSagas";
+import {
+ generateDestinationIdInfoForQueryDuplication,
+ resolveParentEntityMetadata,
+} from "ee/sagas/helpers";
+import { updateCanvasWithDSL } from "ee/sagas/PageSagas";
+import {
+ getAction,
+ getCurrentPageNameByActionId,
+ getDatasource,
+ getDatasources,
+ getDatasourceStructureById,
+ getEditorConfig,
+ getNewEntityName,
+ getPageNameByPageId,
+ getPlugin,
+ getSettingConfig,
+} from "ee/selectors/entitiesSelector";
+import AnalyticsUtil from "ee/utils/AnalyticsUtil";
+import type {
+ Action,
+ ActionViewMode,
+ ApiAction,
+ ApiActionConfig,
+ BaseAction,
+ CreateActionDefaultsParams,
+ SlashCommandPayload,
+} from "entities/Action";
+import {
+ ActionCreationSourceTypeEnum,
+ isAPIAction,
+ isGraphqlPlugin,
+ PluginPackageName,
+ PluginType,
+ SlashCommand,
+} from "entities/Action";
+import LOG_TYPE from "entities/AppsmithConsole/logtype";
+import type { Datasource, DatasourceStructure } from "entities/Datasource";
+import { get, isEmpty, merge } from "lodash";
+import { DEFAULT_API_ACTION_CONFIG } from "PluginActionEditor/constants/ApiEditorConstants";
+import { DEFAULT_GRAPHQL_ACTION_CONFIG } from "PluginActionEditor/constants/GraphQLEditorConstants";
+import { transformRestAction } from "PluginActionEditor/transformers/RestActionTransformer";
+import { getFormValues } from "redux-form";
import {
all,
call,
@@ -18,137 +126,28 @@ import {
takeEvery,
takeLatest,
} from "redux-saga/effects";
-import type { Datasource, DatasourceStructure } from "entities/Datasource";
-import type { ActionCreateUpdateResponse } from "api/ActionAPI";
-import ActionAPI from "api/ActionAPI";
-import type { ApiResponse } from "api/ApiResponses";
-import type { FetchPageRequest, FetchPageResponse } from "api/PageApi";
-import PageApi from "api/PageApi";
-import { updateCanvasWithDSL } from "ee/sagas/PageSagas";
-import {
- closeQueryActionTab,
- closeQueryActionTabSuccess,
- createNewApiAction,
- createNewQueryAction,
- type FetchActionsPayload,
- type SetActionPropertyPayload,
-} from "actions/pluginActionActions";
-import {
- copyActionError,
- copyActionSuccess,
- createActionInit,
- createActionSuccess,
- deleteActionSuccess,
- fetchActionsForPage,
- fetchActionsForPageSuccess,
- moveActionError,
- moveActionSuccess,
- updateAction,
- updateActionData,
- updateActionProperty,
- updateActionSuccess,
-} from "actions/pluginActionActions";
-import { getDynamicBindingsChangesSaga } from "utils/DynamicBindingUtils";
-import { validateResponse } from "./ErrorSagas";
-import { transformRestAction } from "PluginActionEditor/transformers/RestActionTransformer";
import {
getCurrentBasePageId,
getCurrentPageId,
} from "selectors/editorSelectors";
-import AnalyticsUtil from "ee/utils/AnalyticsUtil";
-import type {
- Action,
- ActionViewMode,
- ApiAction,
- ApiActionConfig,
- BaseAction,
- CreateActionDefaultsParams,
- SlashCommandPayload,
-} from "entities/Action";
-import { isGraphqlPlugin, ActionCreationSourceTypeEnum } from "entities/Action";
-import {
- isAPIAction,
- PluginPackageName,
- PluginType,
- SlashCommand,
-} from "entities/Action";
-import type { ActionData } from "ee/reducers/entityReducers/actionsReducer";
-import {
- getAction,
- getCurrentPageNameByActionId,
- getDatasource,
- getDatasourceStructureById,
- getDatasources,
- getEditorConfig,
- getPageNameByPageId,
- getPlugin,
- getSettingConfig,
- getNewEntityName,
-} from "ee/selectors/entitiesSelector";
-import history from "utils/history";
-import { INTEGRATION_TABS } from "constants/routes";
-import {
- ACTION_COPY_SUCCESS,
- ACTION_MOVE_SUCCESS,
- createMessage,
- ERROR_ACTION_COPY_FAIL,
- ERROR_ACTION_MOVE_FAIL,
- ERROR_ACTION_RENAME_FAIL,
-} from "ee/constants/messages";
-import { get, isEmpty, merge } from "lodash";
-import {
- fixActionPayloadForMongoQuery,
- getConfigInitialValues,
-} from "components/formControls/utils";
+import { getIsSideBySideEnabled } from "selectors/ideSelectors";
+import { convertToBaseParentEntityIdSelector } from "selectors/pageListSelectors";
import AppsmithConsole from "utils/AppsmithConsole";
-import { ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
-import LOG_TYPE from "entities/AppsmithConsole/logtype";
-import type { Plugin } from "api/PluginApi";
+import { getDynamicBindingsChangesSaga } from "utils/DynamicBindingUtils";
+import { getDefaultTemplateActionConfig } from "utils/editorContextUtils";
import { shouldBeDefined } from "utils/helpers";
+import history from "utils/history";
+import { setAIPromptTriggered } from "utils/storage";
+import { sendAnalyticsEventSaga } from "./AnalyticsSaga";
+import { validateResponse } from "./ErrorSagas";
+import FocusRetention from "./FocusRetentionSaga";
import {
- apiEditorIdURL,
- builderURL,
- integrationEditorURL,
- queryEditorIdURL,
- saasEditorApiIdURL,
-} from "ee/RouteBuilder";
-import {
- RequestPayloadAnalyticsPath,
checkAndLogErrorsIfCyclicDependency,
enhanceRequestPayloadWithEventData,
getFromServerWhenNoPrefetchedResult,
+ RequestPayloadAnalyticsPath,
} from "./helper";
-import { setSnipingMode as setSnipingModeAction } from "actions/propertyPaneActions";
-import { toast } from "@appsmith/ads";
-import { getFormValues } from "redux-form";
-import {
- API_EDITOR_FORM_NAME,
- QUERY_EDITOR_FORM_NAME,
-} from "ee/constants/forms";
-import { DEFAULT_GRAPHQL_ACTION_CONFIG } from "PluginActionEditor/constants/GraphQLEditorConstants";
-import { DEFAULT_API_ACTION_CONFIG } from "PluginActionEditor/constants/ApiEditorConstants";
-import { fetchDatasourceStructure } from "actions/datasourceActions";
-import { setAIPromptTriggered } from "utils/storage";
-import { getDefaultTemplateActionConfig } from "utils/editorContextUtils";
-import { sendAnalyticsEventSaga } from "./AnalyticsSaga";
-import { EditorModes } from "components/editorComponents/CodeEditor/EditorConfig";
-import { updateActionAPICall } from "ee/sagas/ApiCallerSagas";
-import FocusRetention from "./FocusRetentionSaga";
-import {
- generateDestinationIdInfoForQueryDuplication,
- resolveParentEntityMetadata,
-} from "ee/sagas/helpers";
import { handleQueryEntityRedirect } from "./IDESaga";
-import { EditorViewMode, IDE_TYPE } from "ee/entities/IDE/constants";
-import { getIDETypeByUrl } from "ee/entities/IDE/utils";
-import {
- setIdeEditorViewMode,
- setShowQueryCreateNewModal,
-} from "actions/ideActions";
-import { getIsSideBySideEnabled } from "selectors/ideSelectors";
-import { CreateNewActionKey } from "ee/entities/Engine/actionHelpers";
-import { objectKeys } from "@appsmith/utils";
-import { convertToBaseParentEntityIdSelector } from "selectors/pageListSelectors";
export const DEFAULT_PREFIX = {
QUERY: "Query",
@@ -283,9 +282,7 @@ export function* getPluginActionDefaultValues(pluginId: string) {
*/
export function* createActionRequestSaga(
actionPayload: ReduxAction<
- // TODO: Fix this the next time the file is edited
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- Partial & { eventData: any; pluginId: string }
+ Partial & { eventData?: unknown; pluginId: string }
>,
) {
const payload = { ...actionPayload.payload };
@@ -314,13 +311,11 @@ export function* createActionRequestSaga(
DEFAULT_PREFIX.QUERY;
}
- const name: string = yield select(getNewEntityName, {
+ payload.name = yield select(getNewEntityName, {
prefix,
parentEntityId,
parentEntityKey,
});
-
- payload.name = name;
}
yield put(createActionInit(payload));
diff --git a/app/client/src/sagas/DatasourcesSagas.ts b/app/client/src/sagas/DatasourcesSagas.ts
index 40cff1e2c2..a7496c2b5d 100644
--- a/app/client/src/sagas/DatasourcesSagas.ts
+++ b/app/client/src/sagas/DatasourcesSagas.ts
@@ -33,7 +33,11 @@ import {
getCurrentBasePageId,
getCurrentPageId,
} from "selectors/editorSelectors";
-import type { DatasourceGroupByPluginCategory } from "ee/selectors/entitiesSelector";
+import {
+ type DatasourceGroupByPluginCategory,
+ getActions,
+ getDatasourceByPluginId,
+} from "ee/selectors/entitiesSelector";
import {
getDatasource,
getDatasourceActionRouteInfo,
@@ -80,7 +84,6 @@ import type {
import {
AuthenticationStatus,
FilePickerActionStatus,
- ToastMessageType,
} from "entities/Datasource";
import {
INTEGRATION_TABS,
@@ -93,6 +96,10 @@ import {
DATASOURCE_DB_FORM,
DATASOURCE_REST_API_FORM,
} from "ee/constants/forms";
+import type { ActionDataState } from "ee/reducers/entityReducers/actionsReducer";
+import { setIdeEditorViewMode } from "../actions/ideActions";
+import { EditorViewMode } from "ee/entities/IDE/constants";
+import { createActionRequestSaga } from "./ActionSagas";
import { validateResponse } from "./ErrorSagas";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import type { GetFormData } from "selectors/formSelectors";
@@ -121,7 +128,7 @@ import localStorage from "utils/localStorage";
import log from "loglevel";
import { APPSMITH_TOKEN_STORAGE_KEY } from "pages/Editor/SaaSEditor/constants";
import { checkAndGetPluginFormConfigsSaga } from "sagas/PluginSagas";
-import { PluginPackageName, PluginType } from "entities/Action";
+import { type Action, PluginPackageName, PluginType } from "entities/Action";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import { isDynamicValue } from "utils/DynamicBindingUtils";
import { getQueryParams } from "utils/URLUtils";
@@ -149,12 +156,10 @@ import {
saasEditorDatasourceIdURL,
} from "ee/RouteBuilder";
import {
- DATASOURCE_NAME_DEFAULT_PREFIX,
GOOGLE_SHEET_FILE_PICKER_OVERLAY_CLASS,
GOOGLE_SHEET_SPECIFIC_SHEETS_SCOPE,
TEMP_DATASOURCE_ID,
} from "constants/Datasource";
-import { getUntitledDatasourceSequence } from "utils/DatasourceSagaUtils";
import { toast } from "@appsmith/ads";
import { fetchPluginFormConfig } from "actions/pluginActions";
import { addClassToDocumentRoot } from "pages/utils";
@@ -175,7 +180,11 @@ import { getCurrentGitBranch } from "selectors/gitSyncSelectors";
import FocusRetention from "./FocusRetentionSaga";
import { identifyEntityFromPath } from "../navigation/FocusEntity";
import { MAX_DATASOURCE_SUGGESTIONS } from "constants/DatasourceEditorConstants";
-import { getFromServerWhenNoPrefetchedResult } from "./helper";
+import {
+ getFromServerWhenNoPrefetchedResult,
+ getInitialActionPayload,
+ getInitialDatasourcePayload,
+} from "./helper";
import { executeGoogleApi } from "./loadGoogleApi";
import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers";
import { getCurrentModuleId } from "ee/selectors/modulesSelector";
@@ -1061,9 +1070,6 @@ function* createTempDatasourceFromFormSaga(
);
const initialValues: unknown = yield call(getConfigInitialValues, formConfig);
- const dsList: Datasource[] = yield select(getDatasources);
- const sequence = getUntitledDatasourceSequence(dsList);
-
let datasourceType = actionPayload?.payload?.type;
if (!actionPayload?.payload.type) {
@@ -1076,25 +1082,11 @@ function* createTempDatasourceFromFormSaga(
}
const defaultEnvId = getDefaultEnvId();
+ const initialPayload: Datasource = yield getInitialDatasourcePayload(
+ actionPayload.payload.pluginId,
+ datasourceType,
+ );
- const initialPayload = {
- id: TEMP_DATASOURCE_ID,
- name: DATASOURCE_NAME_DEFAULT_PREFIX + sequence,
- type: datasourceType,
- pluginId: actionPayload.payload.pluginId,
- new: false,
- datasourceStorages: {
- [defaultEnvId]: {
- datasourceId: TEMP_DATASOURCE_ID,
- environmentId: defaultEnvId,
- isValid: false,
- datasourceConfiguration: {
- properties: [],
- },
- toastMessage: ToastMessageType.EMPTY_TOAST_MESSAGE,
- },
- },
- };
const payload = merge(initialPayload, actionPayload.payload);
payload.datasourceStorages[defaultEnvId] = merge(
@@ -1128,7 +1120,60 @@ function* createTempDatasourceFromFormSaga(
);
}
-function* createDatasourceFromFormSaga(
+/**
+ * Verifies whether a datasource for the specified plugin exists. If it does not, creates one.
+ * Then, creates an action for the datasource based on passed action configuration.
+ * @returns Action - return the created Action
+ * @param pluginPackageName - determine whether a datasource exists by its pluginPackageName.
+ * @param actionConfig - configuration for action creation
+ * @param datasourceName - name with which the datasource will be created
+ */
+export function* createOrUpdateDataSourceWithAction(
+ pluginPackageName: PluginPackageName,
+ actionConfig: Action,
+ datasourceName?: string,
+) {
+ const plugin: Plugin = yield select(
+ getPluginByPackageName,
+ pluginPackageName,
+ );
+ const datasources: Datasource[] = yield select(
+ getDatasourceByPluginId,
+ plugin.id,
+ );
+ const pageId: string = yield select(getCurrentPageId);
+ const datasourcePayload: Datasource = yield getInitialDatasourcePayload(
+ plugin.id,
+ plugin.type,
+ datasourceName,
+ );
+
+ if (datasources.length === 0) {
+ yield createDatasourceFromFormSaga({
+ payload: datasourcePayload,
+ type: ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT,
+ });
+ }
+
+ const actionPayload: Datasource = yield getInitialActionPayload(
+ pageId,
+ plugin.id,
+ actionConfig,
+ );
+
+ yield createActionRequestSaga({
+ payload: actionPayload,
+ type: ReduxActionTypes.CREATE_ACTION_REQUEST,
+ });
+
+ yield put(setIdeEditorViewMode(EditorViewMode.SplitScreen));
+
+ const actions: ActionDataState = yield select(getActions);
+
+ return actions[actions.length - 1];
+}
+
+export function* createDatasourceFromFormSaga(
actionPayload: ReduxActionWithCallbacks,
) {
try {
diff --git a/app/client/src/sagas/WidgetBlueprintSagas.ts b/app/client/src/sagas/WidgetBlueprintSagas.ts
index 10d36ba137..6e2cd0c6db 100644
--- a/app/client/src/sagas/WidgetBlueprintSagas.ts
+++ b/app/client/src/sagas/WidgetBlueprintSagas.ts
@@ -1,4 +1,8 @@
-import type { WidgetBlueprint } from "WidgetProvider/constants";
+import type { ActionData } from "ee/reducers/entityReducers/actionsReducer";
+import {
+ BlueprintOperationActionTypes,
+ type WidgetBlueprint,
+} from "WidgetProvider/constants";
import type { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import type { WidgetProps } from "widgets/BaseWidget";
import { generateReactKey } from "utils/generators";
@@ -13,6 +17,8 @@ import * as log from "loglevel";
import { toast } from "@appsmith/ads";
import type { LayoutSystemTypes } from "layoutSystems/types";
import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
+import type { Action, PluginPackageName } from "../entities/Action";
+import { createOrUpdateDataSourceWithAction } from "./DatasourcesSagas";
function buildView(view: WidgetBlueprint["view"], widgetId: string) {
const children = [];
@@ -60,12 +66,15 @@ export interface UpdatePropertyArgs {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
propertyValue: any;
}
-export type BlueprintOperationAddActionFn = () => void;
+export type BlueprintOperationAddActionFn = (
+ widget: WidgetProps & { children?: WidgetProps[] },
+) => Generator;
export type BlueprintOperationModifyPropsFn = (
widget: WidgetProps & { children?: WidgetProps[] },
widgets: { [widgetId: string]: FlattenedWidgetProps },
parent?: WidgetProps,
layoutSystemType?: LayoutSystemTypes,
+ addActionResult?: ActionData,
) => UpdatePropertyArgs[] | undefined;
export interface ChildOperationFnResponse {
@@ -97,10 +106,20 @@ export type BlueprintOperationFunction =
| BlueprintBeforeOperationsFn;
export type BlueprintOperationType = keyof typeof BlueprintOperationTypes;
+export type BlueprintOperationActionType =
+ keyof typeof BlueprintOperationActionTypes;
+
+export interface BlueprintOperationActionPayload {
+ pluginPackageName: PluginPackageName;
+ actionConfig: Action;
+ datasourceName?: string;
+}
export interface BlueprintOperation {
type: BlueprintOperationType;
fn: BlueprintOperationFunction;
+ actionType?: BlueprintOperationActionType;
+ payload?: BlueprintOperationActionPayload;
}
export function* executeWidgetBlueprintOperations(
@@ -109,13 +128,19 @@ export function* executeWidgetBlueprintOperations(
widgetId: string,
) {
const layoutSystemType: LayoutSystemTypes = yield select(getLayoutSystemType);
+ let addActionResult: ActionData = {} as ActionData;
- operations.forEach((operation: BlueprintOperation) => {
+ for (const operation of operations) {
const widget: WidgetProps & { children?: string[] | WidgetProps[] } = {
...widgets[widgetId],
};
switch (operation.type) {
+ case BlueprintOperationTypes.ADD_ACTION:
+ addActionResult =
+ yield executeWidgetBlueprintAddActionOperations(operation);
+
+ break;
case BlueprintOperationTypes.MODIFY_PROPS:
if (widget.children && widget.children.length > 0) {
widget.children = (widget.children as string[]).map(
@@ -130,6 +155,7 @@ export function* executeWidgetBlueprintOperations(
widgets,
get(widgets, widget.parentId || "", undefined),
layoutSystemType,
+ addActionResult,
);
updatePropertyPayloads &&
@@ -139,13 +165,44 @@ export function* executeWidgetBlueprintOperations(
});
break;
}
- });
+ }
const result: { [widgetId: string]: FlattenedWidgetProps } = yield widgets;
return result;
}
+/**
+ * this saga executes the blueprint add action operation
+ * @param operation
+ */
+function* executeWidgetBlueprintAddActionOperations(
+ operation: BlueprintOperation,
+) {
+ switch (operation.actionType) {
+ case BlueprintOperationActionTypes.CREATE_OR_UPDATE_DATASOURCE_WITH_ACTION:
+ if (
+ !operation.payload?.pluginPackageName ||
+ !operation.payload?.actionConfig
+ )
+ return;
+
+ const { actionConfig, datasourceName, pluginPackageName } =
+ operation.payload;
+
+ // TODO Add the event to the watcher to avoid importing it and the associated cyclic dependencies.
+ // https://github.com/appsmithorg/appsmith-ee/pull/5368#discussion_r1804419760
+ const createdAction: ActionData =
+ yield createOrUpdateDataSourceWithAction(
+ pluginPackageName,
+ actionConfig,
+ datasourceName,
+ );
+
+ return createdAction;
+ }
+}
+
/**
* this saga executes the blueprint child operation
*
diff --git a/app/client/src/sagas/helper.ts b/app/client/src/sagas/helper.ts
index c720022a3f..bdb6cfc740 100644
--- a/app/client/src/sagas/helper.ts
+++ b/app/client/src/sagas/helper.ts
@@ -1,9 +1,14 @@
import { createMessage } from "ee/constants/messages";
import type { LayoutOnLoadActionErrors } from "constants/AppsmithActionConstants/ActionConstants";
+import type {
+ ActionData,
+ ActionDataState,
+} from "ee/reducers/entityReducers/actionsReducer";
import type {
FormEvalOutput,
ConditionalOutput,
} from "reducers/evaluationReducers/formEvaluationReducer";
+import { select } from "redux-saga/effects";
import AppsmithConsole from "utils/AppsmithConsole";
import LOG_TYPE from "entities/AppsmithConsole/logtype";
import type { Log } from "entities/AppsmithConsole";
@@ -22,6 +27,18 @@ import { isPlainObject, isString } from "lodash";
import { DATA_BIND_REGEX_GLOBAL } from "constants/BindingsConstants";
import { apiFailureResponseInterceptor } from "api/interceptors";
import { klonaLiteWithTelemetry } from "utils/helpers";
+import { getDefaultEnvId } from "ee/api/ApiUtils";
+import {
+ getActions,
+ getDatasourceByPluginId,
+ getDatasources,
+} from "ee/selectors/entitiesSelector";
+import {
+ DATASOURCE_NAME_DEFAULT_PREFIX,
+ TEMP_DATASOURCE_ID,
+} from "../constants/Datasource";
+import { type Datasource, ToastMessageType } from "../entities/Datasource";
+import { getNextEntityName } from "utils/AppsmithUtils";
// function to extract all objects that have dynamic values
export const extractFetchDynamicValueFormConfigs = (
@@ -249,3 +266,63 @@ export function* getFromServerWhenNoPrefetchedResult(
return yield apiEffect();
}
+
+export function* getInitialDatasourcePayload(
+ pluginId: string,
+ pluginType?: string,
+ defaultDatasourceName: string = DATASOURCE_NAME_DEFAULT_PREFIX,
+) {
+ const dsList: Datasource[] = yield select(getDatasources);
+ const datasourceName = getNextEntityName(
+ defaultDatasourceName,
+ dsList.map((el: Datasource) => el.name),
+ );
+ const defaultEnvId = getDefaultEnvId();
+
+ return {
+ id: TEMP_DATASOURCE_ID,
+ name: datasourceName,
+ type: pluginType,
+ pluginId: pluginId,
+ new: false,
+ datasourceStorages: {
+ [defaultEnvId]: {
+ datasourceId: TEMP_DATASOURCE_ID,
+ environmentId: defaultEnvId,
+ isValid: false,
+ datasourceConfiguration: {
+ url: "",
+ properties: [],
+ },
+ toastMessage: ToastMessageType.EMPTY_TOAST_MESSAGE,
+ },
+ },
+ };
+}
+
+export function* getInitialActionPayload(
+ pageId: string,
+ pluginId: string,
+ actionConfig: Action,
+) {
+ const updatedAiDatasources: Datasource[] = yield select(
+ getDatasourceByPluginId,
+ pluginId,
+ );
+
+ const actions: ActionDataState = yield select(getActions);
+ const actionName = getNextEntityName(
+ actionConfig.name,
+ actions.map((el: ActionData) => el.config.name),
+ );
+
+ return {
+ pageId,
+ pluginId: updatedAiDatasources[0].pluginId,
+ datasource: {
+ id: updatedAiDatasources[0].id,
+ },
+ name: actionName,
+ actionConfiguration: actionConfig.actionConfiguration,
+ };
+}
diff --git a/app/client/src/utils/DatasourceSagaUtils.tsx b/app/client/src/utils/DatasourceSagaUtils.tsx
deleted file mode 100644
index c5cd4943b4..0000000000
--- a/app/client/src/utils/DatasourceSagaUtils.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { DATASOURCE_NAME_DEFAULT_PREFIX } from "constants/Datasource";
-import type { Datasource } from "entities/Datasource";
-
-/**
- *
- * @param datasoures Array of datasource objects
- * @returns next sequence number for untitled datasources
- */
-export function getUntitledDatasourceSequence(
- dsList: Array,
-): number {
- let maxSeq = Number.MIN_VALUE;
-
- dsList
- .filter((ele) => ele.name.includes(DATASOURCE_NAME_DEFAULT_PREFIX))
- .forEach((ele) => {
- const seq = parseInt(ele.name.split(" ")[2]);
-
- if (!isNaN(seq) && maxSeq < seq) {
- maxSeq = seq;
- }
- });
-
- return maxSeq === Number.MIN_VALUE ? 1 : maxSeq + 1;
-}