PromucFlow_constructor/app/client/src/sagas/PluginSagas.ts
Valera Melnikov c42e0317de
fix: change appsmith alias (#35349)
In order to unify package names, we decided to use `@appsmith` prefix as
a marker to indicate that packages belong to our codebase and that these
packages are developed internally. So that we can use this prefix, we
need to rename the alias of the same name. But since `@appsmith` is
currently being used as an alias for `ee` folder, we have to rename the
alias as the first step.

Related discussion
https://theappsmith.slack.com/archives/CPG2ZTXEY/p1722516279126329

EE PR — https://github.com/appsmithorg/appsmith-ee/pull/4801

## 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/10267368821>
> Commit: 2b00af2d257e4d4304db0a80072afef7513de6be
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=10267368821&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Tue, 06 Aug 2024 14:24:22 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No
2024-08-06 17:52:22 +03:00

309 lines
10 KiB
TypeScript

import { all, takeEvery, call, put, select } from "redux-saga/effects";
import type { ReduxAction } from "ee/constants/ReduxActionConstants";
import {
ReduxActionTypes,
ReduxActionErrorTypes,
} from "ee/constants/ReduxActionConstants";
import type { DefaultPlugin, PluginFormPayload } from "api/PluginApi";
import PluginsApi from "api/PluginApi";
import { validateResponse } from "sagas/ErrorSagas";
import { getCurrentWorkspaceId } from "ee/selectors/selectedWorkspaceSelectors";
import {
getActions,
getDatasources,
getPlugin,
getPluginForm,
getPlugins,
} from "ee/selectors/entitiesSelector";
import type { Datasource } from "entities/Datasource";
import type { Plugin } from "api/PluginApi";
import {
fetchPluginFormConfigsSuccess,
fetchPluginFormConfigSuccess,
fetchPluginFormConfigError,
} from "actions/pluginActions";
import {
defaultActionDependenciesConfig,
defaultActionEditorConfigs,
defaultActionSettings,
defaultDatasourceFormButtonConfig,
} from "constants/AppsmithActionConstants/ActionConstants";
import type { ApiResponse } from "api/ApiResponses";
import PluginApi from "api/PluginApi";
import log from "loglevel";
import {
getAppsmithAIPlugin,
getGraphQLPlugin,
PluginType,
} from "entities/Action";
import type {
FormEditorConfigs,
FormSettingsConfigs,
FormDependencyConfigs,
FormDatasourceButtonConfigs,
} from "utils/DynamicBindingUtils";
import type { ActionDataState } from "ee/reducers/entityReducers/actionsReducer";
import { getFromServerWhenNoPrefetchedResult } from "./helper";
function* fetchPluginsSaga(
action: ReduxAction<
{ workspaceId?: string; plugins?: ApiResponse<Plugin[]> } | undefined
>,
) {
try {
const plugins = action.payload?.plugins;
let workspaceId: string = yield select(getCurrentWorkspaceId);
if (action.payload?.workspaceId) workspaceId = action.payload?.workspaceId;
if (!workspaceId) {
throw Error("Workspace id does not exist");
}
const pluginsResponse: ApiResponse<Plugin[]> = yield call(
getFromServerWhenNoPrefetchedResult,
plugins,
() => call(PluginsApi.fetchPlugins, workspaceId),
);
const isValid: boolean = yield validateResponse(pluginsResponse);
if (isValid) {
yield put({
type: ReduxActionTypes.FETCH_PLUGINS_SUCCESS,
payload: pluginsResponse.data,
});
}
} catch (error) {
yield put({
type: ReduxActionErrorTypes.FETCH_PLUGINS_ERROR,
payload: { error },
});
}
}
function* fetchPluginFormConfigsSaga(action?: {
payload?: { pluginFormConfigs?: ApiResponse<PluginFormPayload[]> };
}) {
const pluginFormConfigs = action?.payload?.pluginFormConfigs;
try {
const datasources: Datasource[] = yield select(getDatasources);
const plugins: Plugin[] = yield select(getPlugins);
// Add plugins of all the datasources of their workspace
const pluginIdFormsToFetch = new Set(
datasources.map((datasource) => datasource.pluginId),
);
// Add the api plugin id by default as API, JS, Graphql can exists without datasource
const apiPlugin = plugins.find((plugin) => plugin.type === PluginType.API);
const jsPlugin = plugins.find((plugin) => plugin.type === PluginType.JS);
const graphqlPlugin = getGraphQLPlugin(plugins);
const appsmithAIPlugin = getAppsmithAIPlugin(plugins);
if (apiPlugin) {
pluginIdFormsToFetch.add(apiPlugin.id);
}
if (graphqlPlugin) {
pluginIdFormsToFetch.add(graphqlPlugin.id);
}
if (appsmithAIPlugin) {
pluginIdFormsToFetch.add(appsmithAIPlugin.id);
}
const actions: ActionDataState = yield select(getActions);
const actionPluginIds = actions.map((action) => action.config.pluginId);
for (const pluginId of actionPluginIds) {
pluginIdFormsToFetch.add(pluginId);
}
const pluginCalls = [...pluginIdFormsToFetch].map((id) =>
call(
getFromServerWhenNoPrefetchedResult,
// Set the data if it exists in the prefetched data
// This is to avoid making a call to the server for the data
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
pluginFormConfigs?.data?.[id as any]
? {
...pluginFormConfigs,
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: pluginFormConfigs?.data?.[id as any],
}
: undefined,
// If the data does not exist in the prefetched data, make a call to the server
() => call(PluginsApi.fetchFormConfig, id),
),
);
const pluginFormResponses: ApiResponse<PluginFormPayload>[] =
yield all(pluginCalls);
const pluginFormData: PluginFormPayload[] = [];
for (let i = 0; i < pluginFormResponses.length; i++) {
const response = pluginFormResponses[i];
yield validateResponse(response);
pluginFormData.push(response.data);
}
if (jsPlugin) {
pluginIdFormsToFetch.add(jsPlugin.id);
}
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const formConfigs: Record<string, any[]> = {};
const editorConfigs: FormEditorConfigs = {};
const settingConfigs: FormSettingsConfigs = {};
const dependencies: FormDependencyConfigs = {};
const datasourceFormButtonConfigs: FormDatasourceButtonConfigs = {};
Array.from(pluginIdFormsToFetch).forEach((pluginId, index) => {
const plugin = plugins.find((plugin) => plugin.id === pluginId);
if (plugin && plugin.type === PluginType.JS) {
settingConfigs[pluginId] = defaultActionSettings[plugin.type];
editorConfigs[pluginId] = defaultActionEditorConfigs[plugin.type];
formConfigs[pluginId] = [];
dependencies[pluginId] = defaultActionDependenciesConfig[plugin.type];
} else {
// Datasource form always use server's copy
if (!!pluginFormData[index]) {
formConfigs[pluginId] = pluginFormData[index].form;
// Action editor form if not available use default
if (plugin && !pluginFormData[index].editor) {
editorConfigs[pluginId] = defaultActionEditorConfigs[plugin.type];
} else {
editorConfigs[pluginId] = pluginFormData[index].editor;
}
// Action settings form if not available use default
if (plugin && !pluginFormData[index].setting) {
settingConfigs[pluginId] = defaultActionSettings[plugin.type];
} else {
settingConfigs[pluginId] = pluginFormData[index].setting;
}
// Action dependencies config if not available use default
if (plugin && !pluginFormData[index].dependencies) {
dependencies[pluginId] =
defaultActionDependenciesConfig[plugin.type];
} else {
dependencies[pluginId] = pluginFormData[index].dependencies;
}
// Datasource form buttons config if not available use default
if (plugin && !pluginFormData[index].formButton) {
datasourceFormButtonConfigs[pluginId] =
defaultDatasourceFormButtonConfig[plugin.type];
} else {
datasourceFormButtonConfigs[pluginId] =
pluginFormData[index].formButton;
}
}
}
});
yield put(
fetchPluginFormConfigsSuccess({
formConfigs,
editorConfigs,
settingConfigs,
dependencies,
datasourceFormButtonConfigs,
}),
);
} catch (error) {
yield put({
type: ReduxActionErrorTypes.FETCH_PLUGIN_FORM_CONFIGS_ERROR,
payload: { error },
});
}
}
export function* checkAndGetPluginFormConfigsSaga(pluginId: string) {
try {
const plugin: Plugin = yield select(getPlugin, pluginId);
const formConfig: Record<string, unknown> = yield select(
getPluginForm,
pluginId,
);
if (!formConfig) {
const formConfigResponse: ApiResponse<PluginFormPayload> =
yield PluginApi.fetchFormConfig(pluginId);
yield validateResponse(formConfigResponse);
if (!formConfigResponse.data.setting) {
formConfigResponse.data.setting = defaultActionSettings[plugin.type];
}
if (!formConfigResponse.data.editor) {
formConfigResponse.data.editor =
defaultActionEditorConfigs[plugin.type];
}
if (!formConfigResponse.data.dependencies) {
formConfigResponse.data.dependencies =
defaultActionDependenciesConfig[plugin.type];
}
if (!formConfigResponse.data.formButton) {
formConfigResponse.data.formButton =
defaultDatasourceFormButtonConfig[plugin.type];
}
yield put(
fetchPluginFormConfigSuccess({
id: pluginId,
...formConfigResponse.data,
}),
);
}
} catch (e) {
log.error("Failed to get plugin form");
yield put(
fetchPluginFormConfigError({
id: pluginId,
}),
);
}
}
interface GetPluginFormConfigParams {
id: string;
type: string;
}
function* getPluginFormConfig({ id }: GetPluginFormConfigParams) {
yield call(checkAndGetPluginFormConfigsSaga, id);
}
function* getDefaultPluginsSaga() {
try {
const response: ApiResponse<DefaultPlugin> = yield call(
PluginsApi.fetchDefaultPlugins,
);
const isValid: boolean = yield validateResponse(response);
if (isValid) {
yield put({
type: ReduxActionTypes.GET_DEFAULT_PLUGINS_SUCCESS,
payload: response.data,
});
}
} catch (error) {
yield put({
type: ReduxActionErrorTypes.GET_DEFAULT_PLUGINS_ERROR,
payload: {
error,
},
});
}
}
function* root() {
yield all([
takeEvery(ReduxActionTypes.FETCH_PLUGINS_REQUEST, fetchPluginsSaga),
takeEvery(
ReduxActionTypes.FETCH_PLUGIN_FORM_CONFIGS_REQUEST,
fetchPluginFormConfigsSaga,
),
takeEvery(
ReduxActionTypes.GET_PLUGIN_FORM_CONFIG_INIT,
getPluginFormConfig,
),
takeEvery(
ReduxActionTypes.GET_DEFAULT_PLUGINS_REQUEST,
getDefaultPluginsSaga,
),
]);
}
export default root;