diff --git a/app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/defaultConfig.ts b/app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/defaultConfig.ts index 77e0374f4092..96c2cb632ec2 100644 --- a/app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/defaultConfig.ts +++ b/app/client/src/modules/ui-builder/ui/wds/WDSAIChatWidget/widget/config/defaultConfig.ts @@ -1,5 +1,12 @@ import { ResponsiveBehavior } from "layoutSystems/common/utils/constants"; -import type { WidgetDefaultProps } from "WidgetProvider/constants"; +import { + BlueprintOperationTypes, + type WidgetDefaultProps, +} from "WidgetProvider/constants"; +import { createOrUpdateDataSourceWithAction } from "sagas/DatasourcesSagas"; +import { PluginPackageName } from "entities/Action"; +import type { ActionData } from "ee/reducers/entityReducers/actionsReducer"; +import type { WidgetProps } from "widgets/BaseWidget"; export const defaultsConfig = { isVisible: true, @@ -9,4 +16,27 @@ export const defaultsConfig = { responsiveBehavior: ResponsiveBehavior.Fill, initialAssistantMessage: "", initialAssistantSuggestions: [], + blueprint: { + operations: [ + { + type: BlueprintOperationTypes.ADD_ACTION, + fn: function* (widget: WidgetProps & { children?: WidgetProps[] }) { + const action: ActionData = yield createOrUpdateDataSourceWithAction( + PluginPackageName.APPSMITH_AI, + { + usecase: { data: "TEXT_CLASSIFY" }, + }, + ); + + return [ + { + widgetId: widget.widgetId, + propertyName: "query", + propertyValue: action.config.name, + }, + ]; + }, + }, + ], + }, } as unknown as WidgetDefaultProps; diff --git a/app/client/src/sagas/ActionSagas.ts b/app/client/src/sagas/ActionSagas.ts index 8bb94aa0c5b4..f43742766e8e 100644 --- a/app/client/src/sagas/ActionSagas.ts +++ b/app/client/src/sagas/ActionSagas.ts @@ -281,7 +281,7 @@ 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?: any; pluginId: string } >, ) { const payload = { ...actionPayload.payload }; diff --git a/app/client/src/sagas/DatasourcesSagas.ts b/app/client/src/sagas/DatasourcesSagas.ts index 40cff1e2c294..19bef26f20d4 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,8 @@ import { DATASOURCE_DB_FORM, DATASOURCE_REST_API_FORM, } from "ee/constants/forms"; +import type { ActionDataState } from "ee/reducers/entityReducers/actionsReducer"; +import { createActionRequestSaga } from "./ActionSagas"; import { validateResponse } from "./ErrorSagas"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import type { GetFormData } from "selectors/formSelectors"; @@ -149,12 +154,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 +178,10 @@ 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, + getInitialDatasourcePayload, +} from "./helper"; import { executeGoogleApi } from "./loadGoogleApi"; import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers"; import { getCurrentModuleId } from "ee/selectors/modulesSelector"; @@ -1061,9 +1067,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 +1079,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 +1117,58 @@ function* createTempDatasourceFromFormSaga( ); } -function* createDatasourceFromFormSaga( +export function* createOrUpdateDataSourceWithAction( + pluginPackageName: PluginPackageName, + formData: Record, +) { + const plugin: Plugin = yield select( + getPluginByPackageName, + pluginPackageName, + ); + const aiDatasources: Datasource[] = yield select( + getDatasourceByPluginId, + plugin.id, + ); + const pageId: string = yield select(getCurrentPageId); + const datasourcePayload: Datasource = yield getInitialDatasourcePayload( + plugin.id, + plugin.type, + ); + + if (aiDatasources.length === 0) { + yield createDatasourceFromFormSaga({ + payload: datasourcePayload, + type: ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT, + }); + } + + const updatedAiDatasources: Datasource[] = yield select( + getDatasourceByPluginId, + plugin.id, + ); + + const actionPayload = { + pageId, + pluginId: updatedAiDatasources[0].pluginId, + datasource: { + id: updatedAiDatasources[0].id, + }, + actionConfiguration: { + formData, + }, + }; + + yield createActionRequestSaga({ + payload: actionPayload, + type: ReduxActionTypes.CREATE_ACTION_REQUEST, + }); + + 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 10d36ba13746..2cf892ccb04d 100644 --- a/app/client/src/sagas/WidgetBlueprintSagas.ts +++ b/app/client/src/sagas/WidgetBlueprintSagas.ts @@ -60,7 +60,9 @@ 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 }, @@ -110,12 +112,27 @@ export function* executeWidgetBlueprintOperations( ) { const layoutSystemType: LayoutSystemTypes = yield select(getLayoutSystemType); - operations.forEach((operation: BlueprintOperation) => { + for (const operation of operations) { const widget: WidgetProps & { children?: string[] | WidgetProps[] } = { ...widgets[widgetId], }; switch (operation.type) { + case BlueprintOperationTypes.ADD_ACTION: + if (operation.fn) { + const updatePropertyPayloads: UpdatePropertyArgs[] | undefined = + yield (operation.fn as BlueprintOperationAddActionFn)( + widget as WidgetProps & { children?: WidgetProps[] }, + ); + + updatePropertyPayloads && + updatePropertyPayloads.forEach((params: UpdatePropertyArgs) => { + widgets[params.widgetId][params.propertyName] = + params.propertyValue; + }); + } + + break; case BlueprintOperationTypes.MODIFY_PROPS: if (widget.children && widget.children.length > 0) { widget.children = (widget.children as string[]).map( @@ -139,7 +156,7 @@ export function* executeWidgetBlueprintOperations( }); break; } - }); + } const result: { [widgetId: string]: FlattenedWidgetProps } = yield widgets; diff --git a/app/client/src/sagas/helper.ts b/app/client/src/sagas/helper.ts index c720022a3f5a..7e55e578161d 100644 --- a/app/client/src/sagas/helper.ts +++ b/app/client/src/sagas/helper.ts @@ -4,6 +4,7 @@ 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 +23,14 @@ 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 { getDatasources } from "ee/selectors/entitiesSelector"; +import { + DATASOURCE_NAME_DEFAULT_PREFIX, + TEMP_DATASOURCE_ID, +} from "../constants/Datasource"; +import { type Datasource, ToastMessageType } from "../entities/Datasource"; +import { getUntitledDatasourceSequence } from "../utils/DatasourceSagaUtils"; // function to extract all objects that have dynamic values export const extractFetchDynamicValueFormConfigs = ( @@ -249,3 +258,32 @@ export function* getFromServerWhenNoPrefetchedResult( return yield apiEffect(); } + +export function* getInitialDatasourcePayload( + pluginId: string, + pluginType?: string, +) { + const dsList: Datasource[] = yield select(getDatasources); + const sequence = getUntitledDatasourceSequence(dsList); + const defaultEnvId = getDefaultEnvId(); + + return { + id: TEMP_DATASOURCE_ID, + name: DATASOURCE_NAME_DEFAULT_PREFIX + sequence, + type: pluginType, + pluginId: pluginId, + new: false, + datasourceStorages: { + [defaultEnvId]: { + datasourceId: TEMP_DATASOURCE_ID, + environmentId: defaultEnvId, + isValid: false, + datasourceConfiguration: { + url: "", + properties: [], + }, + toastMessage: ToastMessageType.EMPTY_TOAST_MESSAGE, + }, + }, + }; +}