chore: add new ADD_ACTION blueprint operation type (#37078)
## Description This PR is CE part of main [EE PR](https://github.com/appsmithorg/appsmith-ee/pull/5368). This PR implements a new ADD_ACTION blueprint operation type. ## Automation /ok-to-test tags="@tag.All" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/11508513702> > Commit: ef5ed889ab5711bab162c2a947758da3726f64b5 > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11508513702&attempt=3" target="_blank">Cypress dashboard</a>. > Tags: `@tag.All` > Spec: > <hr>Fri, 25 Oct 2024 07:17:20 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new enum for handling data source creation and updates. - Enhanced application creation logic with updated naming conventions based on layout features. - Improved workspace management functionalities, including application import and user invitation processes. - **Bug Fixes** - Enhanced error handling and state management across various components and sagas. - **Documentation** - Added comments to clarify temporary solutions in CSS for widget interactions. - **Chores** - Removed obsolete Avatar component and related files, streamlining the design system. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
56ef4309e1
commit
839e89e8ea
|
|
@ -1 +0,0 @@
|
|||
export * from "./src";
|
||||
|
|
@ -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 (
|
||||
<span
|
||||
className={clsx(styles.avatar, className)}
|
||||
{...rest}
|
||||
data-size={size ? size : undefined}
|
||||
>
|
||||
{Boolean(src) ? (
|
||||
<img alt={label} className={styles.avatarImage} src={src} />
|
||||
) : (
|
||||
<Text className={getTypographyClassName("body")} fontWeight={500}>
|
||||
{getLabelInitials(label)}
|
||||
</Text>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
export * from "./types";
|
||||
export * from "./Avatar";
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import type { HTMLProps } from "react";
|
||||
|
||||
export interface AvatarProps extends Omit<HTMLProps<HTMLSpanElement>, "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";
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import React from "react";
|
||||
import { Avatar, Flex } from "@appsmith/wds";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
const meta: Meta<typeof Avatar> = {
|
||||
title: "WDS/Widgets/Avatar",
|
||||
component: Avatar,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Avatar>;
|
||||
|
||||
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) => (
|
||||
<Flex gap="spacing-2">
|
||||
<Avatar {...args} size="small" />
|
||||
<Avatar {...args} size="medium" />
|
||||
<Avatar {...args} size="large" />
|
||||
</Flex>
|
||||
),
|
||||
};
|
||||
|
|
@ -19,6 +19,7 @@ const createHeading = (
|
|||
fontWeight={fontWeight}
|
||||
ref={ref as Ref<HTMLDivElement>}
|
||||
size={size}
|
||||
wordBreak="break-word"
|
||||
>
|
||||
{children}
|
||||
</Text>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,13 @@ export const a = (props: LinkProps) => {
|
|||
const { children, href } = props;
|
||||
|
||||
return (
|
||||
<Link data-component="a" href={href} rel="noreferrer" target="_blank">
|
||||
<Link
|
||||
data-component="a"
|
||||
href={href}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
wordBreak="break-word"
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Action> & { eventData: any; pluginId: string }
|
||||
Partial<Action> & { 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));
|
||||
|
|
|
|||
|
|
@ -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<Datasource, unknown, unknown>,
|
||||
) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Datasource>,
|
||||
): 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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user