From 3626b93b53b6c7717fb7c067acec45a880effc79 Mon Sep 17 00:00:00 2001 From: sneha122 Date: Tue, 7 Jan 2025 11:51:08 +0530 Subject: [PATCH] feat: paragon frontend ds creation implementation added (#38456) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR adds CE changes for the paragon integrations, with this whenever anybody is using CE version, paragon integrations will be visible but once they click on it, it will ask for them to put in email id and request access. It's counterpart EE PR handles the paragon integration creation and authorisation in appsmith. EE PR: https://github.com/appsmithorg/appsmith-ee/pull/5859 EE PR which has both CE and EE changes to ensure all things are working smoothly: https://github.com/appsmithorg/appsmith-ee/pull/5866 Fixes #`38406` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Datasource" ### :mag: Cypress test results > [!TIP] > ๐ŸŸข ๐ŸŸข ๐ŸŸข All cypress tests have passed! ๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰ > Workflow run: > Commit: 9c1e06b557bc8d5d0d59e7bad3e70df6582900fa > Cypress dashboard. > Tags: `@tag.Datasource` > Spec: >
Mon, 06 Jan 2025 07:10:57 UTC ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [x] No ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Added support for External SaaS datasources and plugins. - Introduced new actions and configurations for External SaaS integration. - **Refactor** - Restructured datasource-related sagas and import paths. - Updated selectors and constants to support new plugin type. - **Code Improvements** - Enhanced datasource management and integration capabilities. - Improved modularity of saga functions. Co-authored-by: โ€œsneha122โ€ <โ€œsneha@appsmith.comโ€> --- .../src/{ => ce}/sagas/DatasourcesSagas.ts | 192 ++++-------------- app/client/src/ce/sagas/index.tsx | 2 +- .../src/ce/selectors/entitiesSelector.ts | 3 +- .../ActionConstants.tsx | 4 + .../ApiDatasourceFormsButtonConfig.ts | 1 + app/client/src/ee/sagas/DatasourcesSagas.ts | 140 +++++++++++++ app/client/src/entities/Action/index.ts | 12 +- app/client/src/entities/Datasource/index.ts | 12 +- app/client/src/entities/JSCollection/index.ts | 2 +- .../EntityNavigation/ActionPane/index.ts | 1 + .../pages/Editor/IntegrationEditor/NewApi.tsx | 4 +- app/client/src/sagas/WidgetBlueprintSagas.ts | 2 +- app/client/test/sagas.ts | 2 +- 13 files changed, 221 insertions(+), 156 deletions(-) rename app/client/src/{ => ce}/sagas/DatasourcesSagas.ts (92%) create mode 100644 app/client/src/ee/sagas/DatasourcesSagas.ts diff --git a/app/client/src/sagas/DatasourcesSagas.ts b/app/client/src/ce/sagas/DatasourcesSagas.ts similarity index 92% rename from app/client/src/sagas/DatasourcesSagas.ts rename to app/client/src/ce/sagas/DatasourcesSagas.ts index 841be4eae9..85b2129654 100644 --- a/app/client/src/sagas/DatasourcesSagas.ts +++ b/app/client/src/ce/sagas/DatasourcesSagas.ts @@ -1,14 +1,5 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { - all, - call, - fork, - put, - select, - take, - takeEvery, - takeLatest, -} from "redux-saga/effects"; +import { all, call, fork, put, select, take } from "redux-saga/effects"; import { change, getFormInitialValues, @@ -26,7 +17,6 @@ import type { import { ReduxActionErrorTypes, ReduxActionTypes, - ReduxFormActionTypes, } from "ee/constants/ReduxActionConstants"; import { getCurrentApplicationId, @@ -97,10 +87,10 @@ import { DATASOURCE_REST_API_FORM, } from "ee/constants/forms"; import type { ActionDataState } from "ee/reducers/entityReducers/actionsReducer"; -import { setIdeEditorViewMode } from "../actions/ideActions"; +import { setIdeEditorViewMode } from "../../actions/ideActions"; import { EditorViewMode } from "ee/entities/IDE/constants"; -import { createActionRequestSaga } from "./ActionSagas"; -import { validateResponse } from "./ErrorSagas"; +import { createActionRequestSaga } from "../../sagas/ActionSagas"; +import { validateResponse } from "../../sagas/ErrorSagas"; import AnalyticsUtil from "ee/utils/AnalyticsUtil"; import type { GetFormData } from "selectors/formSelectors"; import { getFormData } from "selectors/formSelectors"; @@ -176,21 +166,21 @@ import { } from "ee/selectors/environmentSelectors"; import { waitForFetchEnvironments } from "ee/sagas/EnvironmentSagas"; import { getCurrentGitBranch } from "selectors/gitSyncSelectors"; -import FocusRetention from "./FocusRetentionSaga"; -import { identifyEntityFromPath } from "../navigation/FocusEntity"; +import FocusRetention from "../../sagas/FocusRetentionSaga"; +import { identifyEntityFromPath } from "../../navigation/FocusEntity"; import { MAX_DATASOURCE_SUGGESTIONS } from "constants/DatasourceEditorConstants"; import { getFromServerWhenNoPrefetchedResult, getInitialActionPayload, getInitialDatasourcePayload, -} from "./helper"; -import { executeGoogleApi } from "./loadGoogleApi"; +} from "../../sagas/helper"; +import { executeGoogleApi } from "../../sagas/loadGoogleApi"; import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers"; import { getCurrentModuleId } from "ee/selectors/modulesSelector"; import type { ApplicationPayload } from "entities/Application"; -import { openGeneratePageModalWithSelectedDS } from "../utils/GeneratePageUtils"; +import { openGeneratePageModalWithSelectedDS } from "../../utils/GeneratePageUtils"; -function* fetchDatasourcesSaga( +export function* fetchDatasourcesSaga( action: ReduxAction< | { workspaceId?: string; datasources?: ApiResponse } | undefined @@ -224,7 +214,7 @@ function* fetchDatasourcesSaga( } } -function* handleFetchDatasourceStructureOnLoad() { +export function* handleFetchDatasourceStructureOnLoad() { try { // we fork to prevent the call from blocking yield fork(fetchDatasourceStructureOnLoad); @@ -257,7 +247,7 @@ function* fetchDatasourceStructureOnLoad() { } catch (error) {} } -function* fetchMockDatasourcesSaga(action?: { +export function* fetchMockDatasourcesSaga(action?: { payload?: { mockDatasources?: ApiResponse }; }) { const mockDatasources = action?.payload?.mockDatasources; @@ -527,7 +517,7 @@ const getConnectionMethod = ( } }; -function* updateDatasourceSaga( +export function* updateDatasourceSaga( actionPayload: ReduxActionWithCallbacks< Datasource & { isInsideReconnectModal: boolean; currEditingEnvId?: string }, unknown, @@ -703,7 +693,7 @@ function* updateDatasourceSaga( } } -function* redirectAuthorizationCodeSaga( +export function* redirectAuthorizationCodeSaga( actionPayload: ReduxAction<{ contextId: string; contextType: ActionParentEntityTypeInterface; @@ -757,7 +747,7 @@ function* redirectAuthorizationCodeSaga( } } -function* getOAuthAccessTokenSaga( +export function* getOAuthAccessTokenSaga( actionPayload: ReduxAction<{ datasourceId: string }>, ) { const { datasourceId } = actionPayload.payload; @@ -854,7 +844,7 @@ function* getOAuthAccessTokenSaga( } } -function* updateDatasourceNameSaga( +export function* updateDatasourceNameSaga( actionPayload: ReduxAction<{ id: string; name: string }>, ) { try { @@ -889,13 +879,13 @@ function* updateDatasourceNameSaga( } } -function* handleDatasourceNameChangeFailureSaga( +export function* handleDatasourceNameChangeFailureSaga( action: ReduxAction<{ oldName: string }>, ) { yield put(change(DATASOURCE_DB_FORM, "name", action.payload.oldName)); } -function* testDatasourceSaga(actionPayload: ReduxAction) { +export function* testDatasourceSaga(actionPayload: ReduxAction) { let workspaceId: string = yield select(getCurrentWorkspaceId); // test button within the import modal @@ -1053,7 +1043,7 @@ function* testDatasourceSaga(actionPayload: ReduxAction) { } } -function* createTempDatasourceFromFormSaga( +export function* createTempDatasourceFromFormSaga( actionPayload: ReduxAction, ) { yield call(checkAndGetPluginFormConfigsSaga, actionPayload.payload.pluginId); @@ -1169,7 +1159,11 @@ export function* createOrUpdateDataSourceWithAction( } export function* createDatasourceFromFormSaga( - actionPayload: ReduxActionWithCallbacks, + actionPayload: ReduxActionWithCallbacks< + Datasource | CreateDatasourceConfig, + unknown, + unknown + >, ) { try { const workspaceId: string = yield select(getCurrentWorkspaceId); @@ -1323,7 +1317,7 @@ export function* createDatasourceFromFormSaga( } } -function* changeDatasourceSaga( +export function* changeDatasourceSaga( actionPayload: ReduxAction<{ datasource: Datasource; shouldNotRedirect?: boolean; @@ -1382,7 +1376,7 @@ function* changeDatasourceSaga( ); } -function* switchDatasourceSaga( +export function* switchDatasourceSaga( action: ReduxAction<{ datasourceId: string; shouldNotRedirect: boolean; @@ -1396,7 +1390,7 @@ function* switchDatasourceSaga( } } -function* formValueChangeSaga( +export function* formValueChangeSaga( actionPayload: ReduxActionWithMeta, ) { const { field, form } = actionPayload.meta; @@ -1435,7 +1429,7 @@ function* updateDraftsSaga(form: string) { } } -function* storeAsDatasourceSaga() { +export function* storeAsDatasourceSaga() { const { values } = yield select(getFormData, API_EDITOR_FORM_NAME); // const applicationId: string = yield select(getCurrentApplicationId); const application: ApplicationPayload = yield select(getCurrentApplication); @@ -1509,7 +1503,9 @@ function* storeAsDatasourceSaga() { yield put(changeDatasource({ datasource: createdDatasource })); } -function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) { +export function* updateDatasourceSuccessSaga( + action: UpdateDatasourceSuccessAction, +) { const state: AppState = yield select(); const actionRouteInfo = get(state, "ui.datasourcePane.actionRouteInfo"); const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap = @@ -1549,7 +1545,7 @@ function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) { }); } -function* fetchDatasourceStructureSaga( +export function* fetchDatasourceStructureSaga( action: ReduxAction<{ id: string; ignoreCache: boolean; @@ -1668,7 +1664,7 @@ function* fetchDatasourceStructureSaga( } } -function* addAndFetchDatasourceStructureSaga( +export function* addAndFetchDatasourceStructureSaga( action: ReduxAction, ) { const plugin: Plugin = yield select((state: AppState) => @@ -1698,7 +1694,7 @@ function* addAndFetchDatasourceStructureSaga( } } -function* refreshDatasourceStructure( +export function* refreshDatasourceStructure( action: ReduxAction<{ id: string; schemaRefreshContext: DatasourceStructureContext; @@ -1796,7 +1792,7 @@ function* refreshDatasourceStructure( }); } -function* executeDatasourceQuerySaga( +export function* executeDatasourceQuerySaga( // TODO: Fix this the next time the file is edited // eslint-disable-next-line @typescript-eslint/no-explicit-any action: executeDatasourceQueryReduxAction, @@ -1850,7 +1846,7 @@ function* executeDatasourceQuerySaga( } } -function* initializeFormWithDefaults( +export function* initializeFormWithDefaults( action: ReduxAction<{ pluginType: string }>, ) { const formName = @@ -1888,7 +1884,7 @@ function* initializeFormWithDefaults( } } -function* filePickerActionCallbackSaga( +export function* filePickerActionCallbackSaga( actionPayload: ReduxAction<{ action: FilePickerActionStatus; datasourceId: string; @@ -1975,7 +1971,7 @@ function* filePickerActionCallbackSaga( } } -function* fetchGsheetSpreadhsheets( +export function* fetchGsheetSpreadhsheets( action: ReduxAction<{ datasourceId: string; pluginId: string; @@ -2075,7 +2071,7 @@ function* fetchGsheetSpreadhsheets( } } -function* fetchGsheetSheets( +export function* fetchGsheetSheets( action: ReduxAction<{ datasourceId: string; pluginId: string; @@ -2123,7 +2119,7 @@ function* fetchGsheetSheets( } } -function* fetchGsheetColumns( +export function* fetchGsheetColumns( action: ReduxAction<{ datasourceId: string; pluginId: string; @@ -2175,7 +2171,7 @@ function* fetchGsheetColumns( } } -function* loadFilePickerSaga() { +export function* loadFilePickerSaga() { // This adds overlay on document body // This is done for google sheets file picker, as file picker needs to be shown on blank page // when overlay needs to be shown, we get showPicker search param in redirect url @@ -2199,7 +2195,7 @@ function* loadFilePickerSaga() { } } -function* updateDatasourceAuthStateSaga( +export function* updateDatasourceAuthStateSaga( actionPayload: ReduxAction<{ authStatus: AuthenticationStatus; datasource: Datasource; @@ -2250,7 +2246,7 @@ function* updateDatasourceAuthStateSaga( } } -function* datasourceDiscardActionSaga( +export function* datasourceDiscardActionSaga( actionPayload: ReduxAction<{ pluginId: string; }>, @@ -2270,7 +2266,7 @@ function* datasourceDiscardActionSaga( }); } -function* setDatasourceViewModeSaga( +export function* setDatasourceViewModeSaga( action: ReduxAction<{ datasourceId: string; viewMode: boolean }>, ) { //Set the view mode flag in store @@ -2281,103 +2277,3 @@ function* setDatasourceViewModeSaga( payload: action.payload.datasourceId, }); } - -export function* watchDatasourcesSagas() { - yield all([ - takeEvery(ReduxActionTypes.FETCH_DATASOURCES_INIT, fetchDatasourcesSaga), - takeEvery( - ReduxActionTypes.FETCH_MOCK_DATASOURCES_INIT, - fetchMockDatasourcesSaga, - ), - takeEvery( - ReduxActionTypes.ADD_MOCK_DATASOURCES_INIT, - addMockDbToDatasources, - ), - takeEvery( - ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT, - createDatasourceFromFormSaga, - ), - takeEvery( - ReduxActionTypes.CREATE_TEMP_DATASOURCE_FROM_FORM_SUCCESS, - createTempDatasourceFromFormSaga, - ), - takeEvery(ReduxActionTypes.UPDATE_DATASOURCE_INIT, updateDatasourceSaga), - takeEvery( - ReduxActionTypes.UPDATE_DATASOURCE_NAME, - updateDatasourceNameSaga, - ), - takeEvery( - ReduxActionErrorTypes.UPDATE_DATASOURCE_NAME_ERROR, - handleDatasourceNameChangeFailureSaga, - ), - takeEvery(ReduxActionTypes.TEST_DATASOURCE_INIT, testDatasourceSaga), - takeEvery(ReduxActionTypes.DELETE_DATASOURCE_INIT, deleteDatasourceSaga), - takeEvery(ReduxActionTypes.CHANGE_DATASOURCE, changeDatasourceSaga), - takeLatest(ReduxActionTypes.SWITCH_DATASOURCE, switchDatasourceSaga), - takeEvery(ReduxActionTypes.STORE_AS_DATASOURCE_INIT, storeAsDatasourceSaga), - takeEvery( - ReduxActionTypes.UPDATE_DATASOURCE_SUCCESS, - updateDatasourceSuccessSaga, - ), - takeEvery( - ReduxActionTypes.REDIRECT_AUTHORIZATION_CODE, - redirectAuthorizationCodeSaga, - ), - takeEvery(ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN, getOAuthAccessTokenSaga), - takeEvery( - ReduxActionTypes.FETCH_DATASOURCE_STRUCTURE_INIT, - fetchDatasourceStructureSaga, - ), - takeEvery( - ReduxActionTypes.REFRESH_DATASOURCE_STRUCTURE_INIT, - refreshDatasourceStructure, - ), - takeEvery( - ReduxActionTypes.EXECUTE_DATASOURCE_QUERY_INIT, - executeDatasourceQuerySaga, - ), - takeEvery( - ReduxActionTypes.INITIALIZE_DATASOURCE_FORM_WITH_DEFAULTS, - initializeFormWithDefaults, - ), - // Intercepting the redux-form change actionType to update drafts and track change history - takeEvery(ReduxFormActionTypes.VALUE_CHANGE, formValueChangeSaga), - takeEvery(ReduxFormActionTypes.ARRAY_PUSH, formValueChangeSaga), - takeEvery(ReduxFormActionTypes.ARRAY_REMOVE, formValueChangeSaga), - takeEvery( - ReduxActionTypes.FILE_PICKER_CALLBACK_ACTION, - filePickerActionCallbackSaga, - ), - takeLatest( - ReduxActionTypes.FETCH_GSHEET_SPREADSHEETS, - fetchGsheetSpreadhsheets, - ), - takeLatest(ReduxActionTypes.FETCH_GSHEET_SHEETS, fetchGsheetSheets), - takeLatest(ReduxActionTypes.FETCH_GSHEET_COLUMNS, fetchGsheetColumns), - takeEvery(ReduxActionTypes.LOAD_FILE_PICKER_ACTION, loadFilePickerSaga), - takeEvery( - ReduxActionTypes.UPDATE_DATASOURCE_AUTH_STATE, - updateDatasourceAuthStateSaga, - ), - takeEvery( - ReduxActionTypes.DATASOURCE_DISCARD_ACTION, - datasourceDiscardActionSaga, - ), - takeEvery( - ReduxActionTypes.ADD_AND_FETCH_MOCK_DATASOURCE_STRUCTURE_INIT, - addAndFetchDatasourceStructureSaga, - ), - takeEvery( - ReduxActionTypes.FETCH_DATASOURCES_SUCCESS, - handleFetchDatasourceStructureOnLoad, - ), - takeEvery( - ReduxActionTypes.SOFT_REFRESH_DATASOURCE_STRUCTURE, - handleFetchDatasourceStructureOnLoad, - ), - takeEvery( - ReduxActionTypes.SET_DATASOURCE_EDITOR_MODE, - setDatasourceViewModeSaga, - ), - ]); -} diff --git a/app/client/src/ce/sagas/index.tsx b/app/client/src/ce/sagas/index.tsx index af60e7dc4b..dc529cd165 100644 --- a/app/client/src/ce/sagas/index.tsx +++ b/app/client/src/ce/sagas/index.tsx @@ -16,7 +16,7 @@ import autoLayoutDraggingSagas from "sagas/CanvasSagas/AutoLayoutDraggingSagas"; import draggingCanvasSagas from "sagas/CanvasSagas/DraggingCanvasSagas"; import selectionCanvasSagas from "sagas/CanvasSagas/SelectionCanvasSagas"; import curlImportSagas from "sagas/CurlImportSagas"; -import { watchDatasourcesSagas } from "sagas/DatasourcesSagas"; +import { watchDatasourcesSagas } from "ee/sagas/DatasourcesSagas"; import debuggerSagas from "sagas/DebuggerSagas"; import editorContextSagas from "sagas/editorContextSagas"; import errorSagas from "sagas/ErrorSagas"; diff --git a/app/client/src/ce/selectors/entitiesSelector.ts b/app/client/src/ce/selectors/entitiesSelector.ts index 5cc97210bc..cf7870b146 100644 --- a/app/client/src/ce/selectors/entitiesSelector.ts +++ b/app/client/src/ce/selectors/entitiesSelector.ts @@ -127,7 +127,8 @@ export const getDatasourcesGroupedByPluginCategory = createSelector( if ( plugin.type === PluginType.SAAS || - plugin.type === PluginType.REMOTE + plugin.type === PluginType.REMOTE || + plugin.type === PluginType.EXTERNAL_SAAS ) { return PluginCategory.SAAS; } diff --git a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx index 912eaa8aab..27c177ebce 100644 --- a/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx +++ b/app/client/src/constants/AppsmithActionConstants/ActionConstants.tsx @@ -177,6 +177,7 @@ export const defaultActionSettings: Record = { [PluginType.JS]: [], [PluginType.AI]: saasActionSettingsConfig, [PluginType.INTERNAL]: saasActionSettingsConfig, + [PluginType.EXTERNAL_SAAS]: saasActionSettingsConfig, }; // TODO: Fix this the next time the file is edited @@ -189,6 +190,7 @@ export const defaultActionEditorConfigs: Record = { [PluginType.JS]: [], [PluginType.AI]: [], [PluginType.INTERNAL]: [], + [PluginType.EXTERNAL_SAAS]: [], }; export const defaultActionDependenciesConfig: Record< @@ -202,6 +204,7 @@ export const defaultActionDependenciesConfig: Record< [PluginType.JS]: {}, [PluginType.AI]: {}, [PluginType.INTERNAL]: {}, + [PluginType.EXTERNAL_SAAS]: {}, }; export const defaultDatasourceFormButtonConfig: Record = { @@ -212,4 +215,5 @@ export const defaultDatasourceFormButtonConfig: Record = { [PluginType.JS]: [], [PluginType.AI]: apiActionDatasourceFormButtonConfig.AI, [PluginType.INTERNAL]: [], + [PluginType.EXTERNAL_SAAS]: apiActionDatasourceFormButtonConfig.EXTERNAL_SAAS, }; diff --git a/app/client/src/constants/AppsmithActionConstants/formConfig/ApiDatasourceFormsButtonConfig.ts b/app/client/src/constants/AppsmithActionConstants/formConfig/ApiDatasourceFormsButtonConfig.ts index f3da2b19c3..1c92924281 100644 --- a/app/client/src/constants/AppsmithActionConstants/formConfig/ApiDatasourceFormsButtonConfig.ts +++ b/app/client/src/constants/AppsmithActionConstants/formConfig/ApiDatasourceFormsButtonConfig.ts @@ -4,4 +4,5 @@ export default { SAAS: ["CANCEL", "SAVE_AND_AUTHORIZE"], REMOTE: ["CANCEL", "SAVE"], AI: ["TEST", "CANCEL", "SAVE"], + EXTERNAL_SAAS: ["CANCEL", "SAVE_AND_AUTHORIZE"], }; diff --git a/app/client/src/ee/sagas/DatasourcesSagas.ts b/app/client/src/ee/sagas/DatasourcesSagas.ts new file mode 100644 index 0000000000..423b951142 --- /dev/null +++ b/app/client/src/ee/sagas/DatasourcesSagas.ts @@ -0,0 +1,140 @@ +export { createOrUpdateDataSourceWithAction } from "ce/sagas/DatasourcesSagas"; +import { + ReduxActionErrorTypes, + ReduxActionTypes, + ReduxFormActionTypes, +} from "ee/constants/ReduxActionConstants"; +import { all, takeEvery, takeLatest } from "redux-saga/effects"; +import { + addAndFetchDatasourceStructureSaga, + addMockDbToDatasources, + changeDatasourceSaga, + createDatasourceFromFormSaga, + datasourceDiscardActionSaga, + deleteDatasourceSaga, + executeDatasourceQuerySaga, + fetchDatasourcesSaga, + fetchDatasourceStructureSaga, + fetchGsheetColumns, + fetchGsheetSheets, + fetchGsheetSpreadhsheets, + fetchMockDatasourcesSaga, + filePickerActionCallbackSaga, + formValueChangeSaga, + getOAuthAccessTokenSaga, + handleDatasourceNameChangeFailureSaga, + handleFetchDatasourceStructureOnLoad, + initializeFormWithDefaults, + loadFilePickerSaga, + redirectAuthorizationCodeSaga, + refreshDatasourceStructure, + setDatasourceViewModeSaga, + storeAsDatasourceSaga, + switchDatasourceSaga, + testDatasourceSaga, + updateDatasourceAuthStateSaga, + updateDatasourceNameSaga, + updateDatasourceSaga, + updateDatasourceSuccessSaga, + createTempDatasourceFromFormSaga as CE_createTempDatasourceFromFormSaga, +} from "ce/sagas/DatasourcesSagas"; + +export function* watchDatasourcesSagas() { + yield all([ + takeEvery(ReduxActionTypes.FETCH_DATASOURCES_INIT, fetchDatasourcesSaga), + takeEvery( + ReduxActionTypes.FETCH_MOCK_DATASOURCES_INIT, + fetchMockDatasourcesSaga, + ), + takeEvery( + ReduxActionTypes.ADD_MOCK_DATASOURCES_INIT, + addMockDbToDatasources, + ), + takeEvery( + ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT, + createDatasourceFromFormSaga, + ), + takeEvery( + ReduxActionTypes.CREATE_TEMP_DATASOURCE_FROM_FORM_SUCCESS, + CE_createTempDatasourceFromFormSaga, + ), + takeEvery(ReduxActionTypes.UPDATE_DATASOURCE_INIT, updateDatasourceSaga), + takeEvery( + ReduxActionTypes.UPDATE_DATASOURCE_NAME, + updateDatasourceNameSaga, + ), + takeEvery( + ReduxActionErrorTypes.UPDATE_DATASOURCE_NAME_ERROR, + handleDatasourceNameChangeFailureSaga, + ), + takeEvery(ReduxActionTypes.TEST_DATASOURCE_INIT, testDatasourceSaga), + takeEvery(ReduxActionTypes.DELETE_DATASOURCE_INIT, deleteDatasourceSaga), + takeEvery(ReduxActionTypes.CHANGE_DATASOURCE, changeDatasourceSaga), + takeLatest(ReduxActionTypes.SWITCH_DATASOURCE, switchDatasourceSaga), + takeEvery(ReduxActionTypes.STORE_AS_DATASOURCE_INIT, storeAsDatasourceSaga), + takeEvery( + ReduxActionTypes.UPDATE_DATASOURCE_SUCCESS, + updateDatasourceSuccessSaga, + ), + takeEvery( + ReduxActionTypes.REDIRECT_AUTHORIZATION_CODE, + redirectAuthorizationCodeSaga, + ), + takeEvery(ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN, getOAuthAccessTokenSaga), + takeEvery( + ReduxActionTypes.FETCH_DATASOURCE_STRUCTURE_INIT, + fetchDatasourceStructureSaga, + ), + takeEvery( + ReduxActionTypes.REFRESH_DATASOURCE_STRUCTURE_INIT, + refreshDatasourceStructure, + ), + takeEvery( + ReduxActionTypes.EXECUTE_DATASOURCE_QUERY_INIT, + executeDatasourceQuerySaga, + ), + takeEvery( + ReduxActionTypes.INITIALIZE_DATASOURCE_FORM_WITH_DEFAULTS, + initializeFormWithDefaults, + ), + // Intercepting the redux-form change actionType to update drafts and track change history + takeEvery(ReduxFormActionTypes.VALUE_CHANGE, formValueChangeSaga), + takeEvery(ReduxFormActionTypes.ARRAY_PUSH, formValueChangeSaga), + takeEvery(ReduxFormActionTypes.ARRAY_REMOVE, formValueChangeSaga), + takeEvery( + ReduxActionTypes.FILE_PICKER_CALLBACK_ACTION, + filePickerActionCallbackSaga, + ), + takeLatest( + ReduxActionTypes.FETCH_GSHEET_SPREADSHEETS, + fetchGsheetSpreadhsheets, + ), + takeLatest(ReduxActionTypes.FETCH_GSHEET_SHEETS, fetchGsheetSheets), + takeLatest(ReduxActionTypes.FETCH_GSHEET_COLUMNS, fetchGsheetColumns), + takeEvery(ReduxActionTypes.LOAD_FILE_PICKER_ACTION, loadFilePickerSaga), + takeEvery( + ReduxActionTypes.UPDATE_DATASOURCE_AUTH_STATE, + updateDatasourceAuthStateSaga, + ), + takeEvery( + ReduxActionTypes.DATASOURCE_DISCARD_ACTION, + datasourceDiscardActionSaga, + ), + takeEvery( + ReduxActionTypes.ADD_AND_FETCH_MOCK_DATASOURCE_STRUCTURE_INIT, + addAndFetchDatasourceStructureSaga, + ), + takeEvery( + ReduxActionTypes.FETCH_DATASOURCES_SUCCESS, + handleFetchDatasourceStructureOnLoad, + ), + takeEvery( + ReduxActionTypes.SOFT_REFRESH_DATASOURCE_STRUCTURE, + handleFetchDatasourceStructureOnLoad, + ), + takeEvery( + ReduxActionTypes.SET_DATASOURCE_EDITOR_MODE, + setDatasourceViewModeSaga, + ), + ]); +} diff --git a/app/client/src/entities/Action/index.ts b/app/client/src/entities/Action/index.ts index 2278643cd8..c9847a076f 100644 --- a/app/client/src/entities/Action/index.ts +++ b/app/client/src/entities/Action/index.ts @@ -15,6 +15,7 @@ export enum PluginType { REMOTE = "REMOTE", AI = "AI", INTERNAL = "INTERNAL", + EXTERNAL_SAAS = "EXTERNAL_SAAS", } export enum PluginPackageName { @@ -260,13 +261,22 @@ export interface ActionViewMode { timeoutInMillisecond?: number; } +export interface ExternalSaasAction extends BaseAction { + pluginType: PluginType.EXTERNAL_SAAS; + // TODO: Fix this the next time the file is edited + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionConfiguration: any; + datasource: StoredDatasource; +} + export type Action = | ApiAction | QueryAction | SaaSAction | RemoteAction | AIAction - | InternalAction; + | InternalAction + | ExternalSaasAction; export enum SlashCommand { NEW_API, diff --git a/app/client/src/entities/Datasource/index.ts b/app/client/src/entities/Datasource/index.ts index 2bb69a96b9..8b9e039520 100644 --- a/app/client/src/entities/Datasource/index.ts +++ b/app/client/src/entities/Datasource/index.ts @@ -140,7 +140,7 @@ export enum DatasourceConnectionMode { export interface DatasourceConfiguration { url: string; - authentication?: DatasourceAuthentication; + authentication?: ExternalSaasDSAuthentication | DatasourceAuthentication; properties?: Property[]; headers?: Property[]; queryParameters?: Property[]; @@ -206,3 +206,13 @@ export enum DatasourceStructureContext { // this does not exist yet, but in case it does in the future. API_EDITOR = "api-editor", } + +export interface ExternalSaasDSAuthentication extends DatasourceAuthentication { + integrationId: string; + credentialId: string; + integrationType: string; +} + +export enum AuthenticationType { + EXTERNAL_SAAS_AUTHENTICATION = "externalSaasAuth", +} diff --git a/app/client/src/entities/JSCollection/index.ts b/app/client/src/entities/JSCollection/index.ts index a01ea37852..07127c8dac 100644 --- a/app/client/src/entities/JSCollection/index.ts +++ b/app/client/src/entities/JSCollection/index.ts @@ -1,4 +1,4 @@ -import type { BaseAction } from "../Action"; +import type { BaseAction } from "../../entities/Action"; import type { PluginType } from "entities/Action"; import type { LayoutOnLoadActionErrors } from "constants/AppsmithActionConstants/ActionConstants"; import type { ActionParentEntityTypeInterface } from "ee/entities/Engine/actionHelpers"; diff --git a/app/client/src/pages/Editor/EntityNavigation/ActionPane/index.ts b/app/client/src/pages/Editor/EntityNavigation/ActionPane/index.ts index da1262ff5d..4946b82811 100644 --- a/app/client/src/pages/Editor/EntityNavigation/ActionPane/index.ts +++ b/app/client/src/pages/Editor/EntityNavigation/ActionPane/index.ts @@ -20,6 +20,7 @@ export default class ActionPaneNavigationFactory { case PluginType.DB: case PluginType.SAAS: case PluginType.REMOTE: + case PluginType.EXTERNAL_SAAS: case PluginType.AI: return new QueryPaneNavigation(entityInfo); default: diff --git a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx b/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx index a16ce56a84..3326d90761 100644 --- a/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx +++ b/app/client/src/pages/Editor/IntegrationEditor/NewApi.tsx @@ -250,7 +250,9 @@ function NewApiScreen(props: Props) { const API_PLUGINS = plugins.filter((p) => !showSaasAPIs ? p.packageName === PluginPackageName.GRAPHQL - : p.type === PluginType.SAAS || p.type === PluginType.REMOTE, + : p.type === PluginType.SAAS || + p.type === PluginType.REMOTE || + p.type === PluginType.EXTERNAL_SAAS, ); return ( diff --git a/app/client/src/sagas/WidgetBlueprintSagas.ts b/app/client/src/sagas/WidgetBlueprintSagas.ts index 6e2cd0c6db..6fa8a986eb 100644 --- a/app/client/src/sagas/WidgetBlueprintSagas.ts +++ b/app/client/src/sagas/WidgetBlueprintSagas.ts @@ -18,7 +18,7 @@ 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"; +import { createOrUpdateDataSourceWithAction } from "../ee/sagas/DatasourcesSagas"; function buildView(view: WidgetBlueprint["view"], widgetId: string) { const children = []; diff --git a/app/client/test/sagas.ts b/app/client/test/sagas.ts index 602f10fbcf..e36db5c0ab 100644 --- a/app/client/test/sagas.ts +++ b/app/client/test/sagas.ts @@ -3,7 +3,7 @@ import userSagas from "ee/sagas/userSagas"; import workspaceSagas from "ee/sagas/WorkspaceSagas"; import { watchActionSagas } from "sagas/ActionSagas"; import layoutUpdateSagas from "sagas/AutoLayoutUpdateSagas"; -import { watchDatasourcesSagas } from "sagas/DatasourcesSagas"; +import { watchDatasourcesSagas } from "ee/sagas/DatasourcesSagas"; import { watchJSActionSagas } from "ee/sagas/JSActionSagas"; import apiPaneSagas from "../src/sagas/ApiPaneSagas"; import applicationSagas from "ee/sagas/ApplicationSagas";