Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
import {
|
|
|
|
|
all,
|
2021-04-22 03:30:09 +00:00
|
|
|
call,
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
put,
|
|
|
|
|
select,
|
|
|
|
|
take,
|
2021-04-22 03:30:09 +00:00
|
|
|
takeEvery,
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
takeLatest,
|
|
|
|
|
} from "redux-saga/effects";
|
2023-02-10 10:41:17 +00:00
|
|
|
import {
|
|
|
|
|
change,
|
|
|
|
|
getFormInitialValues,
|
|
|
|
|
getFormValues,
|
|
|
|
|
initialize,
|
|
|
|
|
} from "redux-form";
|
|
|
|
|
import _, { merge, isEmpty, get, set } from "lodash";
|
2022-09-02 09:16:30 +00:00
|
|
|
import equal from "fast-deep-equal/es6";
|
2019-11-07 09:32:38 +00:00
|
|
|
import {
|
|
|
|
|
ReduxAction,
|
|
|
|
|
ReduxActionErrorTypes,
|
|
|
|
|
ReduxActionTypes,
|
2021-02-11 12:28:06 +00:00
|
|
|
ReduxActionWithCallbacks,
|
2021-04-22 03:30:09 +00:00
|
|
|
ReduxActionWithMeta,
|
|
|
|
|
ReduxFormActionTypes,
|
2022-04-12 10:50:01 +00:00
|
|
|
} from "@appsmith/constants/ReduxActionConstants";
|
2020-04-28 06:52:53 +00:00
|
|
|
import {
|
|
|
|
|
getCurrentApplicationId,
|
|
|
|
|
getCurrentPageId,
|
|
|
|
|
} from "selectors/editorSelectors";
|
2020-05-19 06:10:59 +00:00
|
|
|
import {
|
|
|
|
|
getDatasource,
|
|
|
|
|
getDatasourceDraft,
|
2021-04-22 03:30:09 +00:00
|
|
|
getPluginForm,
|
2021-07-29 08:13:10 +00:00
|
|
|
getGenerateCRUDEnabledPluginMap,
|
2022-01-14 06:31:54 +00:00
|
|
|
getPluginPackageFromDatasourceId,
|
2022-11-30 05:59:45 +00:00
|
|
|
getDatasources,
|
|
|
|
|
getDatasourceActionRouteInfo,
|
2020-05-19 06:10:59 +00:00
|
|
|
} from "selectors/entitiesSelector";
|
2020-06-03 05:40:48 +00:00
|
|
|
import {
|
|
|
|
|
changeDatasource,
|
2020-10-09 13:24:50 +00:00
|
|
|
fetchDatasourceStructure,
|
2022-12-02 03:06:22 +00:00
|
|
|
setDatasourceViewMode,
|
2021-04-19 13:17:27 +00:00
|
|
|
updateDatasourceSuccess,
|
|
|
|
|
UpdateDatasourceSuccessAction,
|
2021-07-29 08:13:10 +00:00
|
|
|
executeDatasourceQueryReduxAction,
|
2022-11-30 05:59:45 +00:00
|
|
|
createTempDatasourceFromForm,
|
|
|
|
|
removeTempDatasource,
|
|
|
|
|
createDatasourceSuccess,
|
2023-02-10 10:41:17 +00:00
|
|
|
resetDefaultKeyValPairFlag,
|
2020-06-03 05:40:48 +00:00
|
|
|
} from "actions/datasourceActions";
|
2022-06-21 13:57:34 +00:00
|
|
|
import { ApiResponse } from "api/ApiResponses";
|
2021-01-12 04:17:28 +00:00
|
|
|
import DatasourcesApi, { CreateDatasourceConfig } from "api/DatasourcesApi";
|
|
|
|
|
import { Datasource } from "entities/Datasource";
|
2020-06-03 05:40:48 +00:00
|
|
|
|
2022-03-25 10:43:26 +00:00
|
|
|
import { INTEGRATION_EDITOR_MODES, INTEGRATION_TABS } from "constants/routes";
|
2020-04-28 06:52:53 +00:00
|
|
|
import history from "utils/history";
|
2021-12-07 09:45:18 +00:00
|
|
|
import {
|
|
|
|
|
API_EDITOR_FORM_NAME,
|
|
|
|
|
DATASOURCE_DB_FORM,
|
|
|
|
|
DATASOURCE_REST_API_FORM,
|
2022-09-02 17:15:08 +00:00
|
|
|
} from "@appsmith/constants/forms";
|
2019-11-13 07:34:59 +00:00
|
|
|
import { validateResponse } from "./ErrorSagas";
|
2020-03-06 04:59:24 +00:00
|
|
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
2020-04-28 06:52:53 +00:00
|
|
|
import { getFormData } from "selectors/formSelectors";
|
2022-06-15 15:37:41 +00:00
|
|
|
import { getCurrentWorkspaceId } from "@appsmith/selectors/workspaceSelectors";
|
2023-01-23 03:50:47 +00:00
|
|
|
import { Toaster, Variant } from "design-system-old";
|
2020-11-23 06:28:15 +00:00
|
|
|
import { getConfigInitialValues } from "components/formControls/utils";
|
2021-08-27 09:25:28 +00:00
|
|
|
import { setActionProperty } from "actions/pluginActionActions";
|
2022-01-14 06:31:54 +00:00
|
|
|
import { authorizeDatasourceWithAppsmithToken } from "api/CloudServicesApi";
|
2021-03-13 14:24:45 +00:00
|
|
|
import {
|
|
|
|
|
createMessage,
|
|
|
|
|
DATASOURCE_CREATE,
|
|
|
|
|
DATASOURCE_DELETE,
|
|
|
|
|
DATASOURCE_UPDATE,
|
|
|
|
|
DATASOURCE_VALID,
|
2022-01-14 06:31:54 +00:00
|
|
|
OAUTH_APPSMITH_TOKEN_NOT_FOUND,
|
|
|
|
|
OAUTH_AUTHORIZATION_APPSMITH_ERROR,
|
|
|
|
|
OAUTH_AUTHORIZATION_FAILED,
|
|
|
|
|
OAUTH_AUTHORIZATION_SUCCESSFUL,
|
2022-02-11 18:08:46 +00:00
|
|
|
} from "@appsmith/constants/messages";
|
2021-04-23 13:50:55 +00:00
|
|
|
import AppsmithConsole from "utils/AppsmithConsole";
|
|
|
|
|
import { ENTITY_TYPE } from "entities/AppsmithConsole";
|
2021-04-22 03:30:09 +00:00
|
|
|
import localStorage from "utils/localStorage";
|
|
|
|
|
import log from "loglevel";
|
2022-03-25 10:43:26 +00:00
|
|
|
import { APPSMITH_TOKEN_STORAGE_KEY } from "pages/Editor/SaaSEditor/constants";
|
2021-03-30 05:29:03 +00:00
|
|
|
import { checkAndGetPluginFormConfigsSaga } from "sagas/PluginSagas";
|
2021-04-22 03:30:09 +00:00
|
|
|
import { PluginType } from "entities/Action";
|
2021-04-23 13:50:55 +00:00
|
|
|
import LOG_TYPE from "entities/AppsmithConsole/logtype";
|
2021-06-15 05:54:14 +00:00
|
|
|
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
2022-08-04 05:40:44 +00:00
|
|
|
import { getQueryParams } from "utils/URLUtils";
|
2022-04-12 10:50:01 +00:00
|
|
|
import { GenerateCRUDEnabledPluginMap } from "api/PluginApi";
|
|
|
|
|
import { getIsGeneratePageInitiator } from "utils/GenerateCrudUtil";
|
2022-06-21 13:57:34 +00:00
|
|
|
import { shouldBeDefined, trimQueryString } from "utils/helpers";
|
2022-01-25 13:56:52 +00:00
|
|
|
import { inGuidedTour } from "selectors/onboardingSelectors";
|
2021-12-07 09:45:18 +00:00
|
|
|
import { updateReplayEntity } from "actions/pageActions";
|
2022-01-14 06:31:54 +00:00
|
|
|
import OAuthApi from "api/OAuthApi";
|
2022-08-24 12:16:32 +00:00
|
|
|
import { AppState } from "@appsmith/reducers";
|
2022-06-15 15:37:41 +00:00
|
|
|
import { getWorkspaceIdForImport } from "selectors/applicationSelectors";
|
2022-03-25 10:43:26 +00:00
|
|
|
import {
|
|
|
|
|
apiEditorIdURL,
|
|
|
|
|
datasourcesEditorIdURL,
|
|
|
|
|
generateTemplateFormURL,
|
|
|
|
|
integrationEditorURL,
|
|
|
|
|
saasEditorDatasourceIdURL,
|
|
|
|
|
} from "RouteBuilder";
|
2022-11-30 05:59:45 +00:00
|
|
|
import {
|
|
|
|
|
DATASOURCE_NAME_DEFAULT_PREFIX,
|
|
|
|
|
TEMP_DATASOURCE_ID,
|
|
|
|
|
} from "constants/Datasource";
|
|
|
|
|
import { getUntitledDatasourceSequence } from "utils/DatasourceSagaUtils";
|
2021-10-18 14:03:44 +00:00
|
|
|
|
2022-03-17 10:28:54 +00:00
|
|
|
function* fetchDatasourcesSaga(
|
2022-06-15 15:37:41 +00:00
|
|
|
action: ReduxAction<{ workspaceId?: string } | undefined>,
|
2022-03-17 10:28:54 +00:00
|
|
|
) {
|
2019-11-13 07:34:59 +00:00
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
let workspaceId: string = yield select(getCurrentWorkspaceId);
|
2022-06-15 15:37:41 +00:00
|
|
|
if (action.payload?.workspaceId) workspaceId = action.payload?.workspaceId;
|
2022-03-17 10:28:54 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource[]> = yield DatasourcesApi.fetchDatasources(
|
2022-06-15 15:37:41 +00:00
|
|
|
workspaceId,
|
2020-06-17 10:19:56 +00:00
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2019-11-13 07:34:59 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.FETCH_DATASOURCES_SUCCESS,
|
|
|
|
|
payload: response.data,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2019-11-07 09:32:38 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.FETCH_DATASOURCES_ERROR,
|
2019-11-13 07:34:59 +00:00
|
|
|
payload: { error },
|
2019-11-07 09:32:38 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 03:46:16 +00:00
|
|
|
function* fetchMockDatasourcesSaga() {
|
|
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse = yield DatasourcesApi.fetchMockDatasources();
|
2021-07-07 03:46:16 +00:00
|
|
|
// not validating the api call here. If the call is unsuccessful it'll be unblocking. And we'll hide the mock DB section.
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.FETCH_MOCK_DATASOURCES_SUCCESS,
|
|
|
|
|
payload: !!response && !!response.data ? response.data : [],
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.FETCH_MOCK_DATASOURCES_ERROR,
|
|
|
|
|
payload: { error },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 08:13:10 +00:00
|
|
|
interface addMockDb
|
|
|
|
|
extends ReduxActionWithCallbacks<
|
2021-07-08 05:59:11 +00:00
|
|
|
{
|
|
|
|
|
name: string;
|
2022-06-15 15:37:41 +00:00
|
|
|
workspaceId: string;
|
2021-07-08 05:59:11 +00:00
|
|
|
pluginId: string;
|
2021-07-08 10:33:41 +00:00
|
|
|
packageName: string;
|
2021-07-08 05:59:11 +00:00
|
|
|
},
|
2021-07-07 03:46:16 +00:00
|
|
|
unknown,
|
|
|
|
|
unknown
|
2021-07-29 08:13:10 +00:00
|
|
|
> {
|
|
|
|
|
extraParams?: any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function* addMockDbToDatasources(actionPayload: addMockDb) {
|
2021-07-07 03:46:16 +00:00
|
|
|
try {
|
2022-06-15 15:37:41 +00:00
|
|
|
const { name, packageName, pluginId, workspaceId } = actionPayload.payload;
|
2021-07-29 08:13:10 +00:00
|
|
|
const { isGeneratePageMode } = actionPayload.extraParams;
|
2022-07-11 04:06:29 +00:00
|
|
|
const pageId: string = yield select(getCurrentPageId);
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse = yield DatasourcesApi.addMockDbToDatasources(
|
2021-07-08 05:59:11 +00:00
|
|
|
name,
|
2022-06-15 15:37:41 +00:00
|
|
|
workspaceId,
|
2021-07-08 05:59:11 +00:00
|
|
|
pluginId,
|
2021-07-08 10:33:41 +00:00
|
|
|
packageName,
|
2021-07-07 03:46:16 +00:00
|
|
|
);
|
2021-07-29 08:13:10 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2021-07-07 03:46:16 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.ADD_MOCK_DATASOURCES_SUCCESS,
|
|
|
|
|
payload: response.data,
|
|
|
|
|
});
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.FETCH_DATASOURCES_INIT,
|
|
|
|
|
});
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.FETCH_PLUGINS_REQUEST,
|
|
|
|
|
});
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: response is of type unknown
|
2021-07-07 03:46:16 +00:00
|
|
|
yield call(checkAndGetPluginFormConfigsSaga, response.data.pluginId);
|
2021-07-29 08:13:10 +00:00
|
|
|
const isGeneratePageInitiator = getIsGeneratePageInitiator(
|
|
|
|
|
isGeneratePageMode,
|
2021-07-07 03:46:16 +00:00
|
|
|
);
|
2022-03-25 10:43:26 +00:00
|
|
|
const isInGuidedTour: boolean = yield select(inGuidedTour);
|
2021-07-29 08:13:10 +00:00
|
|
|
if (isGeneratePageInitiator) {
|
|
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
generateTemplateFormURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
params: {
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: response.data is of type unknown
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourceId: response.data.id,
|
|
|
|
|
},
|
2021-10-18 14:03:44 +00:00
|
|
|
}),
|
2021-07-29 08:13:10 +00:00
|
|
|
);
|
|
|
|
|
} else {
|
2022-01-25 13:56:52 +00:00
|
|
|
if (isInGuidedTour) return;
|
2021-07-29 08:13:10 +00:00
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
integrationEditorURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
selectedTab: INTEGRATION_TABS.ACTIVE,
|
|
|
|
|
params: getQueryParams(),
|
|
|
|
|
}),
|
2021-07-29 08:13:10 +00:00
|
|
|
);
|
|
|
|
|
}
|
2021-07-07 03:46:16 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.ADD_MOCK_DATASOURCES_ERROR,
|
|
|
|
|
payload: { error },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 10:03:56 +00:00
|
|
|
export function* deleteDatasourceSaga(
|
2021-04-22 03:30:09 +00:00
|
|
|
actionPayload: ReduxActionWithCallbacks<{ id: string }, unknown, unknown>,
|
2020-04-29 10:03:56 +00:00
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
const id = actionPayload.payload.id;
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield DatasourcesApi.deleteDatasource(
|
2020-04-29 10:03:56 +00:00
|
|
|
id,
|
|
|
|
|
);
|
2022-07-11 04:06:29 +00:00
|
|
|
const pageId: string = yield select(getCurrentPageId);
|
2020-04-29 10:03:56 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2020-04-29 10:03:56 +00:00
|
|
|
|
|
|
|
|
if (isValidResponse) {
|
2022-06-21 13:57:34 +00:00
|
|
|
const pluginPackageName = shouldBeDefined<string>(
|
|
|
|
|
yield select((state: AppState) =>
|
|
|
|
|
getPluginPackageFromDatasourceId(state, id),
|
|
|
|
|
),
|
|
|
|
|
`Plugin package not found for the given id - ${id}`,
|
2022-01-14 06:31:54 +00:00
|
|
|
);
|
2021-10-18 14:03:44 +00:00
|
|
|
const datasourcePathWithoutQuery = trimQueryString(
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourcesEditorIdURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourceId: id,
|
|
|
|
|
}),
|
2021-10-18 14:03:44 +00:00
|
|
|
);
|
2022-01-14 06:31:54 +00:00
|
|
|
|
|
|
|
|
const saasPathWithoutQuery = trimQueryString(
|
2022-03-25 10:43:26 +00:00
|
|
|
saasEditorDatasourceIdURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-01-14 06:31:54 +00:00
|
|
|
pluginPackageName,
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourceId: id,
|
|
|
|
|
}),
|
2022-01-14 06:31:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
window.location.pathname === datasourcePathWithoutQuery ||
|
|
|
|
|
window.location.pathname === saasPathWithoutQuery
|
|
|
|
|
) {
|
2021-07-07 03:46:16 +00:00
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
integrationEditorURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
selectedTab: INTEGRATION_TABS.NEW,
|
|
|
|
|
params: {
|
|
|
|
|
...getQueryParams(),
|
|
|
|
|
mode: INTEGRATION_EDITOR_MODES.AUTO,
|
|
|
|
|
},
|
|
|
|
|
}),
|
2021-07-07 03:46:16 +00:00
|
|
|
);
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-24 07:01:37 +00:00
|
|
|
Toaster.show({
|
2021-03-13 14:24:45 +00:00
|
|
|
text: createMessage(DATASOURCE_DELETE, response.data.name),
|
2020-11-24 07:01:37 +00:00
|
|
|
variant: Variant.success,
|
2020-04-29 10:03:56 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.DELETE_DATASOURCE_SUCCESS,
|
|
|
|
|
payload: response.data,
|
|
|
|
|
});
|
2020-05-19 06:10:59 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.DELETE_DATASOURCE_DRAFT,
|
|
|
|
|
payload: {
|
|
|
|
|
id: response.data.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.info({
|
|
|
|
|
logType: LOG_TYPE.ENTITY_DELETED,
|
|
|
|
|
text: "Datasource deleted",
|
|
|
|
|
source: {
|
|
|
|
|
id: response.data.id,
|
|
|
|
|
name: response.data.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-22 03:30:09 +00:00
|
|
|
if (actionPayload.onSuccess) {
|
|
|
|
|
yield put(actionPayload.onSuccess);
|
|
|
|
|
}
|
2020-04-29 10:03:56 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2022-06-21 13:57:34 +00:00
|
|
|
const datasource = shouldBeDefined<Datasource>(
|
|
|
|
|
yield select(getDatasource, actionPayload.payload.id),
|
|
|
|
|
`Datasource not found for id - ${actionPayload.payload.id}`,
|
|
|
|
|
);
|
2020-11-24 07:01:37 +00:00
|
|
|
Toaster.show({
|
2022-06-21 13:57:34 +00:00
|
|
|
text: (error as Error).message,
|
2020-11-24 07:01:37 +00:00
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
2020-04-29 10:03:56 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.DELETE_DATASOURCE_ERROR,
|
2020-10-12 13:37:18 +00:00
|
|
|
payload: { error, id: actionPayload.payload.id, show: false },
|
2020-04-29 10:03:56 +00:00
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.error({
|
2022-06-21 13:57:34 +00:00
|
|
|
text: (error as Error).message,
|
2021-04-23 13:50:55 +00:00
|
|
|
source: {
|
|
|
|
|
id: actionPayload.payload.id,
|
2022-06-21 13:57:34 +00:00
|
|
|
name: datasource.name,
|
2021-04-23 13:50:55 +00:00
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-22 03:30:09 +00:00
|
|
|
if (actionPayload.onError) {
|
|
|
|
|
yield put(actionPayload.onError);
|
|
|
|
|
}
|
2020-04-29 10:03:56 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-11 12:28:06 +00:00
|
|
|
function* updateDatasourceSaga(
|
|
|
|
|
actionPayload: ReduxActionWithCallbacks<Datasource, unknown, unknown>,
|
|
|
|
|
) {
|
2020-04-28 06:52:53 +00:00
|
|
|
try {
|
2021-07-29 08:13:10 +00:00
|
|
|
const queryParams = getQueryParams();
|
2020-09-02 06:07:18 +00:00
|
|
|
const datasourcePayload = _.omit(actionPayload.payload, "name");
|
2022-03-17 10:28:54 +00:00
|
|
|
datasourcePayload.isConfigured = true; // when clicking save button, it should be changed as configured
|
feat: gsheet form config changes (#20395)
## Description
As a part of Limiting Google Sheets access project, we are modifying the
UI of datasource configuration form for google sheets datasource as per
[figma
link](https://www.figma.com/file/TcFhqEbAc8ymHTRF5wR1qv/Limited-GSheet-Access?node-id=7%3A8&t=FN3j084OyCErlu67-0)
This PR contains the code changes required for this new flow. Please
check https://github.com/appsmithorg/appsmith/issues/20159 for more
information.
This improvement was suggested in form config for feature flag, I have
created https://github.com/appsmithorg/appsmith/issues/20925 to track
it, will be fixing it.
Steps to test:
1. Create new google sheet datasource, you should see first option in
the dropdown as `Read/Write | Selected Sheets` selected by default.
2. In this case if we click on save and authorise, it should take us to
google accounts page, where we can select the account.
3. Once account is selected, we should land on permissions page, where
we can check the new permission of `See, edit, create, and delete only
the specific Google Drive files you use with this app`, click on allow.
4. This will take us back to datasource config page in appsmith.
5. Other two options in dropdown are for providing Read/Write or Read
only access to all files in google drive. For Read Only option we should
see permissions as before, where as for read/write option we should see
two permissions: `See, edit, create, and delete all of your Google Drive
files` and `https://www.googleapis.com/auth/spreadsheets`.
7. Since this feature is hidden behind feature flag, we would also need
to test the flow for normal user and ensure that current implementation
is working as is without any issues
Fixes #20158 , #20159
> if no issue exists, please create an issue and ask the maintainers
about this first
## Type of change
- New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
- Manual
- Cypress
### Test Plan
> Add Testsmith test cases links that relate to this PR
### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
## Checklist:
### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [x] PR is being merged under a feature flag
### QA activity:
- [ ] Test plan has been approved by relevant developers
- [ ] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test
---------
Co-authored-by: “sneha122” <“sneha@appsmith.com”>
Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2023-02-24 10:12:28 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield DatasourcesApi.updateDatasource(
|
2020-08-26 05:24:44 +00:00
|
|
|
datasourcePayload,
|
|
|
|
|
datasourcePayload.id,
|
2020-04-28 06:52:53 +00:00
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2020-04-28 06:52:53 +00:00
|
|
|
if (isValidResponse) {
|
2020-10-06 15:10:21 +00:00
|
|
|
AnalyticsUtil.logEvent("SAVE_DATA_SOURCE", {
|
|
|
|
|
datasourceName: response.data.name,
|
|
|
|
|
});
|
2020-11-24 07:01:37 +00:00
|
|
|
Toaster.show({
|
2021-03-13 14:24:45 +00:00
|
|
|
text: createMessage(DATASOURCE_UPDATE, response.data.name),
|
2020-11-24 07:01:37 +00:00
|
|
|
variant: Variant.success,
|
2020-04-28 06:52:53 +00:00
|
|
|
});
|
2020-10-09 13:24:50 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const state: AppState = yield select();
|
2020-10-09 13:24:50 +00:00
|
|
|
const expandDatasourceId = state.ui.datasourcePane.expandDatasourceId;
|
|
|
|
|
|
2021-04-19 13:17:27 +00:00
|
|
|
// Dont redirect if action payload has an onSuccess
|
|
|
|
|
yield put(
|
2021-07-29 08:13:10 +00:00
|
|
|
updateDatasourceSuccess(
|
|
|
|
|
response.data,
|
|
|
|
|
!actionPayload.onSuccess,
|
|
|
|
|
queryParams,
|
|
|
|
|
),
|
2021-04-19 13:17:27 +00:00
|
|
|
);
|
2020-05-19 06:10:59 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.DELETE_DATASOURCE_DRAFT,
|
|
|
|
|
payload: {
|
|
|
|
|
id: response.data.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-07-07 03:46:16 +00:00
|
|
|
if (actionPayload.onSuccess) {
|
|
|
|
|
yield put(actionPayload.onSuccess);
|
|
|
|
|
}
|
2022-11-25 05:05:37 +00:00
|
|
|
if (expandDatasourceId === response.data.id) {
|
|
|
|
|
yield put(fetchDatasourceStructure(response.data.id, true));
|
2020-10-09 13:24:50 +00:00
|
|
|
}
|
2022-12-02 03:06:22 +00:00
|
|
|
yield put(setDatasourceViewMode(true));
|
2021-04-23 13:50:55 +00:00
|
|
|
|
|
|
|
|
AppsmithConsole.info({
|
|
|
|
|
text: "Datasource configuration saved",
|
|
|
|
|
source: {
|
|
|
|
|
id: response.data.id,
|
|
|
|
|
name: response.data.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
state: {
|
|
|
|
|
datasourceConfiguration: response.data.datasourceConfiguration,
|
|
|
|
|
},
|
|
|
|
|
});
|
2022-11-30 05:59:45 +00:00
|
|
|
|
|
|
|
|
// updating form initial values to latest data, so that next time when form is opened
|
|
|
|
|
// isDirty will use updated initial values data to compare actual values with
|
|
|
|
|
yield put(initialize(DATASOURCE_DB_FORM, response.data));
|
2020-04-28 06:52:53 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.UPDATE_DATASOURCE_ERROR,
|
|
|
|
|
payload: { error },
|
|
|
|
|
});
|
2021-02-11 12:28:06 +00:00
|
|
|
if (actionPayload.onError) {
|
|
|
|
|
yield put(actionPayload.onError);
|
|
|
|
|
}
|
2020-04-28 06:52:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 03:30:09 +00:00
|
|
|
function* redirectAuthorizationCodeSaga(
|
|
|
|
|
actionPayload: ReduxAction<{
|
|
|
|
|
datasourceId: string;
|
|
|
|
|
pageId: string;
|
|
|
|
|
pluginType: PluginType;
|
|
|
|
|
}>,
|
2021-02-11 12:28:06 +00:00
|
|
|
) {
|
2021-04-22 03:30:09 +00:00
|
|
|
const { datasourceId, pageId, pluginType } = actionPayload.payload;
|
2022-06-15 15:37:41 +00:00
|
|
|
const isImport: string = yield select(getWorkspaceIdForImport);
|
2021-04-22 03:30:09 +00:00
|
|
|
|
|
|
|
|
if (pluginType === PluginType.API) {
|
|
|
|
|
window.location.href = `/api/v1/datasources/${datasourceId}/pages/${pageId}/code`;
|
2022-01-14 06:31:54 +00:00
|
|
|
} else {
|
2021-04-22 03:30:09 +00:00
|
|
|
try {
|
|
|
|
|
// Get an "appsmith token" from the server
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<string> = yield OAuthApi.getAppsmithToken(
|
2021-04-22 03:30:09 +00:00
|
|
|
datasourceId,
|
|
|
|
|
pageId,
|
2022-03-17 10:28:54 +00:00
|
|
|
!!isImport,
|
2021-04-22 03:30:09 +00:00
|
|
|
);
|
2022-01-14 06:31:54 +00:00
|
|
|
|
2021-04-22 03:30:09 +00:00
|
|
|
if (validateResponse(response)) {
|
|
|
|
|
const appsmithToken = response.data;
|
|
|
|
|
// Save the token for later use once we come back from the auth flow
|
|
|
|
|
localStorage.setItem(APPSMITH_TOKEN_STORAGE_KEY, appsmithToken);
|
|
|
|
|
// Redirect to the cloud services to authorise
|
2022-01-14 06:31:54 +00:00
|
|
|
window.location.assign(
|
|
|
|
|
authorizeDatasourceWithAppsmithToken(appsmithToken),
|
|
|
|
|
);
|
2021-04-22 03:30:09 +00:00
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Toaster.show({
|
2022-01-14 06:31:54 +00:00
|
|
|
text: OAUTH_AUTHORIZATION_FAILED,
|
2021-04-22 03:30:09 +00:00
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
log.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* getOAuthAccessTokenSaga(
|
|
|
|
|
actionPayload: ReduxAction<{ datasourceId: string }>,
|
|
|
|
|
) {
|
|
|
|
|
const { datasourceId } = actionPayload.payload;
|
|
|
|
|
// get the saved appsmith token that started the auth request
|
|
|
|
|
const appsmithToken = localStorage.getItem(APPSMITH_TOKEN_STORAGE_KEY);
|
|
|
|
|
if (!appsmithToken) {
|
|
|
|
|
// Error out because auth token should been here
|
2022-01-14 06:31:54 +00:00
|
|
|
log.error(OAUTH_APPSMITH_TOKEN_NOT_FOUND);
|
2021-04-22 03:30:09 +00:00
|
|
|
Toaster.show({
|
2022-01-14 06:31:54 +00:00
|
|
|
text: OAUTH_AUTHORIZATION_APPSMITH_ERROR,
|
2021-04-22 03:30:09 +00:00
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// Get access token for datasource
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield OAuthApi.getAccessToken(
|
|
|
|
|
datasourceId,
|
|
|
|
|
appsmithToken,
|
|
|
|
|
);
|
2021-04-22 03:30:09 +00:00
|
|
|
if (validateResponse(response)) {
|
|
|
|
|
// Update the datasource object
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.UPDATE_DATASOURCE_SUCCESS,
|
|
|
|
|
payload: response.data,
|
|
|
|
|
});
|
|
|
|
|
Toaster.show({
|
2022-01-14 06:31:54 +00:00
|
|
|
text: OAUTH_AUTHORIZATION_SUCCESSFUL,
|
2021-04-22 03:30:09 +00:00
|
|
|
variant: Variant.success,
|
|
|
|
|
});
|
|
|
|
|
// Remove the token because it is supposed to be short lived
|
|
|
|
|
localStorage.removeItem(APPSMITH_TOKEN_STORAGE_KEY);
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Toaster.show({
|
2022-01-14 06:31:54 +00:00
|
|
|
text: OAUTH_AUTHORIZATION_FAILED,
|
2021-04-22 03:30:09 +00:00
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
log.error(e);
|
|
|
|
|
}
|
2021-02-11 12:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
2022-11-30 05:59:45 +00:00
|
|
|
function* updateDatasourceNameSaga(
|
2020-08-26 05:24:44 +00:00
|
|
|
actionPayload: ReduxAction<{ id: string; name: string }>,
|
|
|
|
|
) {
|
|
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield DatasourcesApi.updateDatasource(
|
2020-08-26 05:24:44 +00:00
|
|
|
{
|
|
|
|
|
name: actionPayload.payload.name,
|
|
|
|
|
},
|
|
|
|
|
actionPayload.payload.id,
|
|
|
|
|
);
|
|
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2020-08-26 05:24:44 +00:00
|
|
|
if (isValidResponse) {
|
2022-11-30 05:59:45 +00:00
|
|
|
// update error state of datasourcename
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.UPDATE_DATASOURCE_NAME_SUCCESS,
|
|
|
|
|
payload: { ...response.data },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// update name in the datasource Object as well
|
2020-08-26 05:24:44 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.SAVE_DATASOURCE_NAME_SUCCESS,
|
|
|
|
|
payload: { ...response.data },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
2022-11-30 05:59:45 +00:00
|
|
|
type: ReduxActionErrorTypes.UPDATE_DATASOURCE_NAME_ERROR,
|
2020-08-26 05:24:44 +00:00
|
|
|
payload: { id: actionPayload.payload.id },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function* handleDatasourceNameChangeFailureSaga(
|
|
|
|
|
action: ReduxAction<{ oldName: string }>,
|
|
|
|
|
) {
|
|
|
|
|
yield put(change(DATASOURCE_DB_FORM, "name", action.payload.oldName));
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-28 06:52:53 +00:00
|
|
|
function* testDatasourceSaga(actionPayload: ReduxAction<Datasource>) {
|
2022-06-21 13:57:34 +00:00
|
|
|
let workspaceId: string = yield select(getCurrentWorkspaceId);
|
2022-03-17 10:28:54 +00:00
|
|
|
|
|
|
|
|
// test button within the import modal
|
2022-06-15 15:37:41 +00:00
|
|
|
if (!workspaceId) {
|
|
|
|
|
workspaceId = yield select(getWorkspaceIdForImport);
|
2022-03-17 10:28:54 +00:00
|
|
|
}
|
2020-04-28 06:52:53 +00:00
|
|
|
const { initialValues, values } = yield select(
|
|
|
|
|
getFormData,
|
|
|
|
|
DATASOURCE_DB_FORM,
|
|
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const datasource = shouldBeDefined<Datasource>(
|
|
|
|
|
yield select(getDatasource, actionPayload.payload.id),
|
|
|
|
|
`Datasource not found for id - ${actionPayload.payload.id}`,
|
|
|
|
|
);
|
2020-10-12 13:06:05 +00:00
|
|
|
const payload = {
|
|
|
|
|
...actionPayload.payload,
|
|
|
|
|
id: actionPayload.payload.id as any,
|
|
|
|
|
};
|
2020-04-28 06:52:53 +00:00
|
|
|
|
2023-01-05 12:36:26 +00:00
|
|
|
// when datasource is not yet saved by user, datasource id is temporary
|
|
|
|
|
// for temporary datasource, we do not need to pass datasource id in test api call
|
|
|
|
|
if (!equal(initialValues, values) || datasource?.id === TEMP_DATASOURCE_ID) {
|
2020-04-28 06:52:53 +00:00
|
|
|
delete payload.id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield DatasourcesApi.testDatasource(
|
2020-06-17 10:19:56 +00:00
|
|
|
{
|
|
|
|
|
...payload,
|
2022-06-15 15:37:41 +00:00
|
|
|
workspaceId,
|
2020-06-17 10:19:56 +00:00
|
|
|
},
|
2020-04-28 06:52:53 +00:00
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2021-04-26 12:17:38 +00:00
|
|
|
let messages: Array<string> = [];
|
2020-04-28 06:52:53 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
const responseData = response.data;
|
2021-04-26 12:17:38 +00:00
|
|
|
if (
|
|
|
|
|
(responseData.invalids && responseData.invalids.length) ||
|
|
|
|
|
(responseData.messages && responseData.messages.length)
|
|
|
|
|
) {
|
|
|
|
|
if (responseData.invalids && responseData.invalids.length) {
|
|
|
|
|
Toaster.show({
|
|
|
|
|
text: responseData.invalids[0],
|
|
|
|
|
variant: Variant.danger,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (responseData.messages && responseData.messages.length) {
|
|
|
|
|
messages = responseData.messages;
|
2021-09-06 05:53:21 +00:00
|
|
|
if (responseData.success) {
|
|
|
|
|
Toaster.show({
|
|
|
|
|
text: createMessage(DATASOURCE_VALID, payload.name),
|
|
|
|
|
variant: Variant.success,
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-04-26 12:17:38 +00:00
|
|
|
}
|
2020-10-12 13:37:18 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.TEST_DATASOURCE_ERROR,
|
2021-04-26 12:17:38 +00:00
|
|
|
payload: { show: false, id: datasource.id, messages: messages },
|
2020-10-12 13:37:18 +00:00
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.error({
|
|
|
|
|
text: "Test Connection failed",
|
|
|
|
|
source: {
|
|
|
|
|
id: actionPayload.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
state: {
|
2021-04-26 13:48:13 +00:00
|
|
|
message:
|
|
|
|
|
responseData.invalids && responseData.invalids.length
|
|
|
|
|
? responseData.invalids[0]
|
|
|
|
|
: "",
|
2021-04-23 13:50:55 +00:00
|
|
|
},
|
|
|
|
|
});
|
2020-04-28 06:52:53 +00:00
|
|
|
} else {
|
2020-10-06 15:10:21 +00:00
|
|
|
AnalyticsUtil.logEvent("TEST_DATA_SOURCE_SUCCESS", {
|
|
|
|
|
datasource: payload.name,
|
|
|
|
|
});
|
2020-11-24 07:01:37 +00:00
|
|
|
Toaster.show({
|
2021-03-13 14:24:45 +00:00
|
|
|
text: createMessage(DATASOURCE_VALID, payload.name),
|
2020-11-24 07:01:37 +00:00
|
|
|
variant: Variant.success,
|
2020-04-28 06:52:53 +00:00
|
|
|
});
|
2020-10-12 13:37:18 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.TEST_DATASOURCE_SUCCESS,
|
2021-04-26 12:17:38 +00:00
|
|
|
payload: { show: false, id: datasource.id, messages: [] },
|
2020-10-12 13:37:18 +00:00
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.info({
|
|
|
|
|
text: "Test Connection successful",
|
|
|
|
|
source: {
|
|
|
|
|
id: actionPayload.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
2020-04-28 06:52:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.TEST_DATASOURCE_ERROR,
|
2020-09-24 05:26:06 +00:00
|
|
|
payload: { error, show: false },
|
2020-04-28 06:52:53 +00:00
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.error({
|
|
|
|
|
text: "Test Connection failed",
|
|
|
|
|
source: {
|
|
|
|
|
id: actionPayload.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
state: {
|
|
|
|
|
message: error,
|
|
|
|
|
},
|
|
|
|
|
});
|
2020-04-28 06:52:53 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 05:59:45 +00:00
|
|
|
function* createTempDatasourceFromFormSaga(
|
|
|
|
|
actionPayload: ReduxAction<CreateDatasourceConfig | Datasource>,
|
|
|
|
|
) {
|
|
|
|
|
yield call(checkAndGetPluginFormConfigsSaga, actionPayload.payload.pluginId);
|
|
|
|
|
const formConfig: Record<string, any>[] = yield select(
|
|
|
|
|
getPluginForm,
|
|
|
|
|
actionPayload.payload.pluginId,
|
|
|
|
|
);
|
|
|
|
|
const initialValues: unknown = yield call(getConfigInitialValues, formConfig);
|
|
|
|
|
|
|
|
|
|
const dsList: Datasource[] = yield select(getDatasources);
|
|
|
|
|
const sequence = getUntitledDatasourceSequence(dsList);
|
|
|
|
|
|
|
|
|
|
const initialPayload = {
|
|
|
|
|
id: TEMP_DATASOURCE_ID,
|
|
|
|
|
name: DATASOURCE_NAME_DEFAULT_PREFIX + sequence,
|
|
|
|
|
type: (actionPayload.payload as any).type,
|
|
|
|
|
pluginId: actionPayload.payload.pluginId,
|
|
|
|
|
new: false,
|
|
|
|
|
datasourceConfiguration: {
|
|
|
|
|
properties: [],
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const payload = merge(
|
|
|
|
|
merge(initialPayload, actionPayload.payload),
|
|
|
|
|
initialValues,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
yield put(createDatasourceSuccess(payload as Datasource));
|
|
|
|
|
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.SAVE_DATASOURCE_NAME,
|
|
|
|
|
payload,
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-02 03:06:22 +00:00
|
|
|
yield put(setDatasourceViewMode(false));
|
2022-11-30 05:59:45 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-07 04:44:52 +00:00
|
|
|
function* createDatasourceFromFormSaga(
|
2022-11-30 05:59:45 +00:00
|
|
|
actionPayload: ReduxActionWithCallbacks<Datasource, unknown, unknown>,
|
2020-05-07 04:44:52 +00:00
|
|
|
) {
|
|
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const workspaceId: string = yield select(getCurrentWorkspaceId);
|
2022-11-30 05:59:45 +00:00
|
|
|
const actionRouteInfo: Partial<{
|
|
|
|
|
apiId: string;
|
|
|
|
|
datasourceId: string;
|
|
|
|
|
pageId: string;
|
|
|
|
|
applicationId: string;
|
|
|
|
|
}> = yield select(getDatasourceActionRouteInfo);
|
2021-03-30 05:29:03 +00:00
|
|
|
yield call(
|
|
|
|
|
checkAndGetPluginFormConfigsSaga,
|
|
|
|
|
actionPayload.payload.pluginId,
|
|
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const formConfig: Record<string, any>[] = yield select(
|
2021-03-30 05:29:03 +00:00
|
|
|
getPluginForm,
|
|
|
|
|
actionPayload.payload.pluginId,
|
|
|
|
|
);
|
2020-05-07 04:44:52 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const initialValues: unknown = yield call(
|
|
|
|
|
getConfigInitialValues,
|
|
|
|
|
formConfig,
|
|
|
|
|
);
|
2020-05-07 04:44:52 +00:00
|
|
|
|
2022-11-30 05:59:45 +00:00
|
|
|
const payload = _.omit(merge(initialValues, actionPayload.payload), [
|
|
|
|
|
"id",
|
|
|
|
|
"new",
|
|
|
|
|
"type",
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
payload.isConfigured = true;
|
2020-05-07 04:44:52 +00:00
|
|
|
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse<Datasource> = yield DatasourcesApi.createDatasource(
|
2020-06-17 10:19:56 +00:00
|
|
|
{
|
|
|
|
|
...payload,
|
2022-06-15 15:37:41 +00:00
|
|
|
workspaceId,
|
2020-06-17 10:19:56 +00:00
|
|
|
},
|
2020-05-07 04:44:52 +00:00
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2020-05-07 04:44:52 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.UPDATE_DATASOURCE_REFS,
|
|
|
|
|
payload: response.data,
|
|
|
|
|
});
|
2020-10-12 13:37:18 +00:00
|
|
|
yield put(
|
2022-11-30 05:59:45 +00:00
|
|
|
createDatasourceSuccess(response.data, true, !!actionRouteInfo.apiId),
|
2020-05-07 04:44:52 +00:00
|
|
|
);
|
2022-11-30 05:59:45 +00:00
|
|
|
|
2020-11-24 07:01:37 +00:00
|
|
|
Toaster.show({
|
2021-03-13 14:24:45 +00:00
|
|
|
text: createMessage(DATASOURCE_CREATE, response.data.name),
|
2020-11-24 07:01:37 +00:00
|
|
|
variant: Variant.success,
|
2020-05-07 04:44:52 +00:00
|
|
|
});
|
2022-11-30 05:59:45 +00:00
|
|
|
|
|
|
|
|
if (actionPayload.onSuccess) {
|
|
|
|
|
if (
|
|
|
|
|
(actionPayload.onSuccess.payload as any).datasourceId ===
|
|
|
|
|
TEMP_DATASOURCE_ID
|
|
|
|
|
) {
|
|
|
|
|
(actionPayload.onSuccess.payload as any).datasourceId =
|
|
|
|
|
response.data.id;
|
|
|
|
|
}
|
|
|
|
|
yield put(actionPayload.onSuccess);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.DELETE_DATASOURCE_DRAFT,
|
|
|
|
|
payload: {
|
|
|
|
|
id: TEMP_DATASOURCE_ID,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// for all datasources, except for REST and GraphQL, need to delete temp datasource data
|
|
|
|
|
// as soon as possible, for REST and GraphQL it is getting deleted in APIPaneSagas.ts
|
|
|
|
|
if (!actionRouteInfo.apiId) {
|
|
|
|
|
yield put(removeTempDatasource());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// updating form initial values to latest data, so that next time when form is opened
|
|
|
|
|
// isDirty will use updated initial values data to compare actual values with
|
|
|
|
|
yield put(initialize(DATASOURCE_DB_FORM, response.data));
|
2020-05-07 04:44:52 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.CREATE_DATASOURCE_ERROR,
|
|
|
|
|
payload: { error },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 09:45:18 +00:00
|
|
|
function* changeDatasourceSaga(
|
2022-04-11 11:23:52 +00:00
|
|
|
actionPayload: ReduxAction<{
|
|
|
|
|
datasource: Datasource;
|
|
|
|
|
shouldNotRedirect?: boolean;
|
|
|
|
|
}>,
|
2021-12-07 09:45:18 +00:00
|
|
|
) {
|
2022-04-11 11:23:52 +00:00
|
|
|
const { datasource, shouldNotRedirect } = actionPayload.payload;
|
2021-12-07 09:45:18 +00:00
|
|
|
const { id } = datasource;
|
2022-06-21 13:57:34 +00:00
|
|
|
const draft: Record<string, unknown> = yield select(getDatasourceDraft, id);
|
2022-07-11 04:06:29 +00:00
|
|
|
const pageId: string = yield select(getCurrentPageId);
|
2020-05-19 06:10:59 +00:00
|
|
|
let data;
|
|
|
|
|
if (_.isEmpty(draft)) {
|
2021-12-07 09:45:18 +00:00
|
|
|
data = datasource;
|
2020-05-19 06:10:59 +00:00
|
|
|
} else {
|
|
|
|
|
data = draft;
|
|
|
|
|
}
|
2020-09-24 05:26:06 +00:00
|
|
|
yield put(initialize(DATASOURCE_DB_FORM, _.omit(data, ["name"])));
|
2022-04-11 11:23:52 +00:00
|
|
|
// on reconnect modal, it shouldn't be redirected to datasource edit page
|
|
|
|
|
if (shouldNotRedirect) return;
|
2021-07-07 03:46:16 +00:00
|
|
|
// this redirects to the same route, so checking first.
|
2021-10-18 14:03:44 +00:00
|
|
|
const datasourcePath = trimQueryString(
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourcesEditorIdURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourceId: datasource.id,
|
|
|
|
|
}),
|
2021-10-18 14:03:44 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (history.location.pathname !== datasourcePath)
|
2021-07-07 03:46:16 +00:00
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourcesEditorIdURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
datasourceId: datasource.id,
|
|
|
|
|
params: getQueryParams(),
|
|
|
|
|
}),
|
2021-07-07 03:46:16 +00:00
|
|
|
);
|
2021-12-07 09:45:18 +00:00
|
|
|
yield put(
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: data is of type unknown
|
2021-12-07 09:45:18 +00:00
|
|
|
updateReplayEntity(data.id, _.omit(data, ["name"]), ENTITY_TYPE.DATASOURCE),
|
|
|
|
|
);
|
2020-05-19 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 11:23:52 +00:00
|
|
|
function* switchDatasourceSaga(
|
|
|
|
|
action: ReduxAction<{
|
|
|
|
|
datasourceId: string;
|
|
|
|
|
shouldNotRedirect: boolean;
|
|
|
|
|
}>,
|
|
|
|
|
) {
|
|
|
|
|
const { datasourceId, shouldNotRedirect } = action.payload;
|
2021-12-07 09:45:18 +00:00
|
|
|
const datasource: Datasource = yield select(getDatasource, datasourceId);
|
2021-01-27 06:56:19 +00:00
|
|
|
if (datasource) {
|
2022-04-11 11:23:52 +00:00
|
|
|
yield put(changeDatasource({ datasource, shouldNotRedirect }));
|
2021-01-27 06:56:19 +00:00
|
|
|
}
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-19 06:10:59 +00:00
|
|
|
function* formValueChangeSaga(
|
|
|
|
|
actionPayload: ReduxActionWithMeta<string, { field: string; form: string }>,
|
|
|
|
|
) {
|
2021-05-13 08:35:39 +00:00
|
|
|
const { field, form } = actionPayload.meta;
|
2021-12-07 09:45:18 +00:00
|
|
|
if (form === DATASOURCE_REST_API_FORM) {
|
|
|
|
|
const { values } = yield select(getFormData, DATASOURCE_REST_API_FORM);
|
2021-12-23 17:09:11 +00:00
|
|
|
if (values && values.datasourceId) {
|
|
|
|
|
yield put(
|
|
|
|
|
updateReplayEntity(values.datasourceId, values, ENTITY_TYPE.DATASOURCE),
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-12-07 09:45:18 +00:00
|
|
|
}
|
2020-05-19 06:10:59 +00:00
|
|
|
if (form !== DATASOURCE_DB_FORM) return;
|
2020-08-26 05:24:44 +00:00
|
|
|
if (field === "name") return;
|
2020-05-19 06:10:59 +00:00
|
|
|
yield all([call(updateDraftsSaga)]);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 05:59:45 +00:00
|
|
|
function* updateDraftsSaga() {
|
|
|
|
|
const values: Record<string, unknown> = yield select(
|
|
|
|
|
getFormValues(DATASOURCE_DB_FORM),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!values.id) return;
|
|
|
|
|
const datasource: Datasource | undefined = yield select(
|
|
|
|
|
getDatasource,
|
|
|
|
|
// @ts-expect-error: values is of type unknown
|
|
|
|
|
values.id,
|
|
|
|
|
);
|
|
|
|
|
if (!equal(values, datasource)) {
|
|
|
|
|
// @ts-expect-error: values is of type unknown
|
|
|
|
|
yield put(updateReplayEntity(values.id, values, ENTITY_TYPE.DATASOURCE));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-03 05:40:48 +00:00
|
|
|
function* storeAsDatasourceSaga() {
|
|
|
|
|
const { values } = yield select(getFormData, API_EDITOR_FORM_NAME);
|
2022-06-21 13:57:34 +00:00
|
|
|
const applicationId: string = yield select(getCurrentApplicationId);
|
|
|
|
|
const pageId: string | undefined = yield select(getCurrentPageId);
|
2020-06-20 05:28:10 +00:00
|
|
|
let datasource = _.get(values, "datasource");
|
|
|
|
|
datasource = _.omit(datasource, ["name"]);
|
2021-06-15 05:54:14 +00:00
|
|
|
const originalHeaders = _.get(values, "actionConfiguration.headers", []);
|
|
|
|
|
const [datasourceHeaders, actionHeaders] = _.partition(
|
|
|
|
|
originalHeaders,
|
|
|
|
|
({ key, value }: { key: string; value: string }) => {
|
|
|
|
|
return !(isDynamicValue(key) || isDynamicValue(value));
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
yield put(
|
|
|
|
|
setActionProperty({
|
|
|
|
|
actionId: values.id,
|
|
|
|
|
propertyName: "actionConfiguration.headers",
|
|
|
|
|
value: actionHeaders,
|
|
|
|
|
}),
|
|
|
|
|
);
|
2022-03-08 14:19:02 +00:00
|
|
|
|
|
|
|
|
// Empty Headers getting created so filtering out the empty headers before setting it to datasource
|
|
|
|
|
const filteredDatasourceHeaders = datasourceHeaders.filter(
|
|
|
|
|
(d) => !(d.key === "" && d.key === ""),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
_.set(
|
|
|
|
|
datasource,
|
|
|
|
|
"datasourceConfiguration.headers",
|
|
|
|
|
filteredDatasourceHeaders,
|
|
|
|
|
);
|
2020-06-03 05:40:48 +00:00
|
|
|
|
2022-11-30 05:59:45 +00:00
|
|
|
yield put(createTempDatasourceFromForm(datasource));
|
2022-06-21 13:57:34 +00:00
|
|
|
const createDatasourceSuccessAction: unknown = yield take(
|
2020-06-03 05:40:48 +00:00
|
|
|
ReduxActionTypes.CREATE_DATASOURCE_SUCCESS,
|
|
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: createDatasourceSuccessAction is of type unknown
|
2020-06-03 05:40:48 +00:00
|
|
|
const createdDatasource = createDatasourceSuccessAction.payload;
|
|
|
|
|
|
2020-11-19 11:30:22 +00:00
|
|
|
// Set datasource page to edit mode
|
2022-12-02 03:06:22 +00:00
|
|
|
yield put(setDatasourceViewMode(false));
|
2020-11-19 11:30:22 +00:00
|
|
|
|
2020-06-03 05:40:48 +00:00
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.STORE_AS_DATASOURCE_UPDATE,
|
|
|
|
|
payload: {
|
|
|
|
|
pageId,
|
|
|
|
|
applicationId,
|
|
|
|
|
apiId: values.id,
|
|
|
|
|
datasourceId: createdDatasource.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2021-12-07 09:45:18 +00:00
|
|
|
yield put(changeDatasource({ datasource: createdDatasource }));
|
2020-06-03 05:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
2021-04-19 13:17:27 +00:00
|
|
|
function* updateDatasourceSuccessSaga(action: UpdateDatasourceSuccessAction) {
|
2022-06-21 13:57:34 +00:00
|
|
|
const state: AppState = yield select();
|
2020-06-03 05:40:48 +00:00
|
|
|
const actionRouteInfo = _.get(state, "ui.datasourcePane.actionRouteInfo");
|
2021-07-29 08:13:10 +00:00
|
|
|
const generateCRUDSupportedPlugin: GenerateCRUDEnabledPluginMap = yield select(
|
|
|
|
|
getGenerateCRUDEnabledPluginMap,
|
|
|
|
|
);
|
2022-07-11 04:06:29 +00:00
|
|
|
const pageId: string = yield select(getCurrentPageId);
|
2020-06-03 05:40:48 +00:00
|
|
|
const updatedDatasource = action.payload;
|
|
|
|
|
|
2021-07-29 08:13:10 +00:00
|
|
|
const { queryParams = {} } = action;
|
|
|
|
|
|
|
|
|
|
const isGeneratePageInitiator = getIsGeneratePageInitiator(
|
|
|
|
|
queryParams.isGeneratePageMode,
|
|
|
|
|
);
|
2022-01-14 06:31:54 +00:00
|
|
|
|
2020-06-03 05:40:48 +00:00
|
|
|
if (
|
2021-07-29 08:13:10 +00:00
|
|
|
isGeneratePageInitiator &&
|
|
|
|
|
updatedDatasource.pluginId &&
|
|
|
|
|
generateCRUDSupportedPlugin[updatedDatasource.pluginId]
|
|
|
|
|
) {
|
|
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
generateTemplateFormURL({
|
2022-07-11 04:06:29 +00:00
|
|
|
pageId,
|
2022-03-25 10:43:26 +00:00
|
|
|
params: {
|
|
|
|
|
datasourceId: updatedDatasource.id,
|
|
|
|
|
},
|
2021-10-18 14:03:44 +00:00
|
|
|
}),
|
2021-07-29 08:13:10 +00:00
|
|
|
);
|
|
|
|
|
} else if (
|
2020-06-03 05:40:48 +00:00
|
|
|
actionRouteInfo &&
|
2021-04-19 13:17:27 +00:00
|
|
|
updatedDatasource.id === actionRouteInfo.datasourceId &&
|
|
|
|
|
action.redirect
|
2020-06-03 05:40:48 +00:00
|
|
|
) {
|
2020-11-19 11:30:22 +00:00
|
|
|
history.push(
|
2022-03-25 10:43:26 +00:00
|
|
|
apiEditorIdURL({
|
|
|
|
|
pageId: actionRouteInfo.pageId,
|
|
|
|
|
apiId: actionRouteInfo.apiId,
|
|
|
|
|
}),
|
2020-11-19 11:30:22 +00:00
|
|
|
);
|
2020-06-03 05:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.STORE_AS_DATASOURCE_COMPLETE,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 08:13:10 +00:00
|
|
|
function* fetchDatasourceStructureSaga(
|
|
|
|
|
action: ReduxAction<{ id: string; ignoreCache: boolean }>,
|
|
|
|
|
) {
|
2022-06-21 13:57:34 +00:00
|
|
|
const datasource = shouldBeDefined<Datasource>(
|
|
|
|
|
yield select(getDatasource, action.payload.id),
|
|
|
|
|
`Datasource not found for id - ${action.payload.id}`,
|
|
|
|
|
);
|
|
|
|
|
|
2020-09-21 09:11:42 +00:00
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse = yield DatasourcesApi.fetchDatasourceStructure(
|
2020-09-21 09:11:42 +00:00
|
|
|
action.payload.id,
|
2021-07-29 08:13:10 +00:00
|
|
|
action.payload.ignoreCache,
|
2020-09-21 09:11:42 +00:00
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response, false);
|
2020-09-21 09:11:42 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.FETCH_DATASOURCE_STRUCTURE_SUCCESS,
|
|
|
|
|
payload: {
|
|
|
|
|
data: response.data,
|
|
|
|
|
datasourceId: action.payload.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
|
|
|
|
|
if (isEmpty(response.data)) {
|
|
|
|
|
AppsmithConsole.warning({
|
|
|
|
|
text: "Datasource structure could not be retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
AppsmithConsole.info({
|
|
|
|
|
text: "Datasource structure retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-09-21 09:11:42 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.FETCH_DATASOURCE_STRUCTURE_ERROR,
|
|
|
|
|
payload: {
|
|
|
|
|
error,
|
|
|
|
|
show: false,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.error({
|
|
|
|
|
text: "Datasource structure could not be retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
2020-09-21 09:11:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 03:30:09 +00:00
|
|
|
function* refreshDatasourceStructure(action: ReduxAction<{ id: string }>) {
|
2022-06-21 13:57:34 +00:00
|
|
|
const datasource = shouldBeDefined<Datasource>(
|
|
|
|
|
yield select(getDatasource, action.payload.id),
|
|
|
|
|
`Datasource is not found for it - ${action.payload.id}`,
|
|
|
|
|
);
|
|
|
|
|
|
2020-09-29 04:17:25 +00:00
|
|
|
try {
|
2022-06-21 13:57:34 +00:00
|
|
|
const response: ApiResponse = yield DatasourcesApi.fetchDatasourceStructure(
|
2020-09-29 04:17:25 +00:00
|
|
|
action.payload.id,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2022-06-21 13:57:34 +00:00
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
2020-09-29 04:17:25 +00:00
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.REFRESH_DATASOURCE_STRUCTURE_SUCCESS,
|
|
|
|
|
payload: {
|
|
|
|
|
data: response.data,
|
|
|
|
|
datasourceId: action.payload.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
|
|
|
|
|
if (isEmpty(response.data)) {
|
|
|
|
|
AppsmithConsole.warning({
|
|
|
|
|
text: "Datasource structure could not be retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
AppsmithConsole.info({
|
|
|
|
|
text: "Datasource structure retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-09-29 04:17:25 +00:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.REFRESH_DATASOURCE_STRUCTURE_ERROR,
|
|
|
|
|
payload: {
|
|
|
|
|
error,
|
|
|
|
|
show: false,
|
|
|
|
|
},
|
|
|
|
|
});
|
2021-04-23 13:50:55 +00:00
|
|
|
AppsmithConsole.error({
|
|
|
|
|
text: "Datasource structure could not be retrieved",
|
|
|
|
|
source: {
|
|
|
|
|
id: action.payload.id,
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
type: ENTITY_TYPE.DATASOURCE,
|
|
|
|
|
},
|
|
|
|
|
});
|
2020-09-29 04:17:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-29 08:13:10 +00:00
|
|
|
function* executeDatasourceQuerySaga(
|
2021-08-20 06:57:01 +00:00
|
|
|
action: executeDatasourceQueryReduxAction<any>,
|
2021-07-29 08:13:10 +00:00
|
|
|
) {
|
|
|
|
|
try {
|
feat: Simplified Google Sheets queries (#14869)
* Client changes 1
* add DSL functionality
* Temp commit for refactoring changes
* Do I even know what I'm doing here?
* chore: Second GS layout
* Update: Visibility conditional outputs for schemas
- Added the output from conditional outputs for schema children too
* Update: Entity selector visibility control
- Added logic for controlling visibility of sub components via the JS expressions system
* Update: Passing disabled prop to toggle button
* Update: Passing disabled prop to toggle btn
* Update: Styled component for toggle button
- Added disabled styles based on the disabled prop sent to the toggle form view JSON button
* Update: configProperty role in Entity Selector
- Removed dependance of the configProperty of the entity selector children to it's parent component
* Update: type of placeholder key
- Made placeholder key from form config JSON to accept either string or an object
- Earlier only string was accepted
- This is for pagination component
* Update: Added placeholder control for pagination
* Client changes 1
* add DSL functionality
* Do I even know what I'm doing here?
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design
* fix: updated tooltip component for wrong ui on entity explore
* temp triggers
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design (#12395)
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design
* fix: updated tooltip component for wrong ui on entity explore
* fix: updated tooltip ui, where condition placement, sort by ui
* temp form data access logic
* fix: updated sorting type width ui
* fix: updated ui for spacing, width and text issues
* Update: Type for tooltip of UQI forms
- Added option to send an object to the tooltipText object.
- This allows for composite components like pagination to have tooltips for each sub component
* Update: tooltip for pagination component
- Added handling to parse the tooltip for multiple components.
- This allows for composite components like pagination to have tooltips for each sub component
* Update: Type cast for tooltip component
- Made the content passed to tooltip component as a string only
* Update: Fixed tooltip component CSS
* Update: Dropdown option component
- Added a tooltip wrapper to each option
- This is to show on hover text like disabled state
* fix: updated ẇhere clause broken ui for condition
* Add: functions to check and extract expressions
- Loop through the formConfig and find any keys that have a value that is bindable
- Used pre defined regex to check if value is a moustache binding
* Add: Types for evaluated form configs
- Added types for the form configs to be evaluated and their output post eval
* Add: Flow to run the form config
- Run the form config and update the result to the redux state
* Update: Name of the type for formconfigs
- Updated since it was clashing with a component of the same name
* Add: Function to enforce config type checks
- This is done so that the improper configs can be weeded out and the rest of the form can be shown
* Add: Function to update evaluated config
- Added option to update the config if it's values needed evaluation
* Add: Type check for schema sections
* Update: Error handling for invalid control type
- We were throwing an exception till now, changed it to a warning text
* Add: Exposed tooltip for dropdown option disabled state
* Update: switch to json mode functionality
- Added logic to convert data to a string rather than an object when the first switch to JSON mode happens
* Update: Added key to tooltip for dropdown options
* Trigger API modification
* Add: function to fetch default trigger URL
* Update: Made URL optional in dynamic trigger config
* Update: Dynamic trigger API call
- Made the API call for dynamic triggers have URL as optional field
- Added type check to the response of the API call
* Update: resp type for trigger APIs
* Update: Moved code to utils folder
- Moved functions for UQI form eval processing to utils file
* Update: passing original controltype to JS switch
* Update: config for JSON editor mode
- Updated the config to have different options for JSON mode depending on the original control type
* Update: Connected line numbers flag to config
* Revert: CSS changes for tooltip
* Refactor: Removed consle
* Add: type for the config of dynamic values
* Add: Feature to evaluate config for triggers
* Refactor: fix type check errors
* fix: dropdown ui width with text alignment
* Update: fixed selector for dynamic values
* Update: selector call for fetchDynamicValues
* Add table header index prop for columns selector
* migration partial commit
* migration partial commit
* Refactor: removed unused import
* Update: reused function for checking dynamic value
* Update: removed unused import
* Fix format JSON issues
* Retrieve binding paths from entity selector components
* Fixes 6 remaining issues with UQI implementation
* Fix dropdown issues
* Fix dropdown height issues and fixes triggering of APIs when option is deselected
* Migration changes
* Fix QA generated UQI issues
* Fix projection component height and route change logic
* Fix multi select dropdown placeholder text issue and json stringify issue with switching view types
* Reset entity type value when command value changes
* Test changes
* Review comments
* Moved migrations around
* Corrected import statement
* Added JSON schema migration
* Updated schema version
* perf improvements and filter dropdown options feature
* Fix Code mirror component config for toggleComponentToJson input fields.
* Fix prettier issues
* fix prettier issues
* Fix style issues as a result of the merged conflicts
* Fix failing test case
* Fixed a few other flows (#14225)
* Fixed a few other flows
* Review comments
* Fix generate CRUD, fix evaluation of dynamic bindings and fix various styling issues.
* More fixes (#14367)
* Factor in the root formconfig parent key.
* Fix flickering issues, and evaluatedFormConfig issues
* fix: Teeny bugs (#14455)
* Teeny bugs
* Added previous functionality as is
* Improvements in the way we fetch dynamic values
* Fix stringiification issue and cyclic dependency issues
* Resolve projection component values deletion
* Resolve merge conflicts and fix prettier issues
* fix: Tsc issues
* Fix property pane connection navigation
* updating ee locator
* updating inputfield locator
* dropdown locator update
* Merge conflict not properly resolved.
* Fix s3 spec
* Fix Mongo Spec
* Fix some more tests
* fix: prevent cyclic dependency when switching to js mode (#14668)
* add delete events for change from array to string in diff
* add test to assert absence of cyclic dependency error when switching to js in switchgroup widget
* Assert that evaluation is not disabled when no cyclic dependency happens
* Cypress test preparations for google sheets and form controls
* Fixed a few test errors (#14874)
* Add: unit tests for uqi UI updates
- view type tests
- conditional output extraction
- processing conditional output to handle view/enabled state of the component
* Add: completed isValidFormConfig test
* Update: improved tests for update config
- These tests cover the functionality to update a section config after it's components are done evaluating
* Fix failing cypress tests and cyclic dependency issue
* Fixes some more tests
* Fixed migration of row objects (#14896)
* Bumped the version of design system package
* Update: reverted change to EE selector
* Fix deletion pointer
* Update: selector for js on load spec
- Synced with changes related to ADS dropdown
* Fix mongoDBShoppingCart spec
* Remove comments
* Fix: mongo shopping cart test failures
* fix: mongo shopping cart spec
* Dummy push to retrigger vercel
* fix: mongo shopping cart spec
* Update MongoDBShoppingCart_spec.js
* fix: removed unused click away
* dummy commit
* Update: moved helper functions to separate file
* Add: added tests for saga functions
- Worked on testing for
- extractFetchDynamicValueFormConfigs
- extractQueueOfValuesToBeFetched
* Add if check for queueOfValuesToBeFetched
* Resolve review comments
* Empty-Commit
Co-authored-by: Irongade <adeoluayangade@yahoo.com>
Co-authored-by: Ayush Pahwa <ayush@appsmith.com>
Co-authored-by: Aman Agarwal <aman@appsmith.com>
Co-authored-by: Ayangade Adeoluwa <37867493+Irongade@users.noreply.github.com>
Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
Co-authored-by: Favour Ohanekwu <fohanekwu@gmail.com>
Co-authored-by: Albin <albin@appsmith.com>
2022-07-04 05:43:27 +00:00
|
|
|
// const response: GenericApiResponse<any> = yield DatasourcesApi.executeDatasourceQuery(
|
|
|
|
|
// action.payload,
|
|
|
|
|
// );
|
|
|
|
|
const response: ApiResponse = yield DatasourcesApi.executeGoogleSheetsDatasourceQuery(
|
2021-07-29 08:13:10 +00:00
|
|
|
action.payload,
|
|
|
|
|
);
|
|
|
|
|
const isValidResponse: boolean = yield validateResponse(response);
|
|
|
|
|
if (isValidResponse) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionTypes.EXECUTE_DATASOURCE_QUERY_SUCCESS,
|
|
|
|
|
payload: {
|
feat: Simplified Google Sheets queries (#14869)
* Client changes 1
* add DSL functionality
* Temp commit for refactoring changes
* Do I even know what I'm doing here?
* chore: Second GS layout
* Update: Visibility conditional outputs for schemas
- Added the output from conditional outputs for schema children too
* Update: Entity selector visibility control
- Added logic for controlling visibility of sub components via the JS expressions system
* Update: Passing disabled prop to toggle button
* Update: Passing disabled prop to toggle btn
* Update: Styled component for toggle button
- Added disabled styles based on the disabled prop sent to the toggle form view JSON button
* Update: configProperty role in Entity Selector
- Removed dependance of the configProperty of the entity selector children to it's parent component
* Update: type of placeholder key
- Made placeholder key from form config JSON to accept either string or an object
- Earlier only string was accepted
- This is for pagination component
* Update: Added placeholder control for pagination
* Client changes 1
* add DSL functionality
* Do I even know what I'm doing here?
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design
* fix: updated tooltip component for wrong ui on entity explore
* temp triggers
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design (#12395)
* fix: updated uqi forms ui, clubbed JS switch button to ads, updated tooltip design
* fix: updated tooltip component for wrong ui on entity explore
* fix: updated tooltip ui, where condition placement, sort by ui
* temp form data access logic
* fix: updated sorting type width ui
* fix: updated ui for spacing, width and text issues
* Update: Type for tooltip of UQI forms
- Added option to send an object to the tooltipText object.
- This allows for composite components like pagination to have tooltips for each sub component
* Update: tooltip for pagination component
- Added handling to parse the tooltip for multiple components.
- This allows for composite components like pagination to have tooltips for each sub component
* Update: Type cast for tooltip component
- Made the content passed to tooltip component as a string only
* Update: Fixed tooltip component CSS
* Update: Dropdown option component
- Added a tooltip wrapper to each option
- This is to show on hover text like disabled state
* fix: updated ẇhere clause broken ui for condition
* Add: functions to check and extract expressions
- Loop through the formConfig and find any keys that have a value that is bindable
- Used pre defined regex to check if value is a moustache binding
* Add: Types for evaluated form configs
- Added types for the form configs to be evaluated and their output post eval
* Add: Flow to run the form config
- Run the form config and update the result to the redux state
* Update: Name of the type for formconfigs
- Updated since it was clashing with a component of the same name
* Add: Function to enforce config type checks
- This is done so that the improper configs can be weeded out and the rest of the form can be shown
* Add: Function to update evaluated config
- Added option to update the config if it's values needed evaluation
* Add: Type check for schema sections
* Update: Error handling for invalid control type
- We were throwing an exception till now, changed it to a warning text
* Add: Exposed tooltip for dropdown option disabled state
* Update: switch to json mode functionality
- Added logic to convert data to a string rather than an object when the first switch to JSON mode happens
* Update: Added key to tooltip for dropdown options
* Trigger API modification
* Add: function to fetch default trigger URL
* Update: Made URL optional in dynamic trigger config
* Update: Dynamic trigger API call
- Made the API call for dynamic triggers have URL as optional field
- Added type check to the response of the API call
* Update: resp type for trigger APIs
* Update: Moved code to utils folder
- Moved functions for UQI form eval processing to utils file
* Update: passing original controltype to JS switch
* Update: config for JSON editor mode
- Updated the config to have different options for JSON mode depending on the original control type
* Update: Connected line numbers flag to config
* Revert: CSS changes for tooltip
* Refactor: Removed consle
* Add: type for the config of dynamic values
* Add: Feature to evaluate config for triggers
* Refactor: fix type check errors
* fix: dropdown ui width with text alignment
* Update: fixed selector for dynamic values
* Update: selector call for fetchDynamicValues
* Add table header index prop for columns selector
* migration partial commit
* migration partial commit
* Refactor: removed unused import
* Update: reused function for checking dynamic value
* Update: removed unused import
* Fix format JSON issues
* Retrieve binding paths from entity selector components
* Fixes 6 remaining issues with UQI implementation
* Fix dropdown issues
* Fix dropdown height issues and fixes triggering of APIs when option is deselected
* Migration changes
* Fix QA generated UQI issues
* Fix projection component height and route change logic
* Fix multi select dropdown placeholder text issue and json stringify issue with switching view types
* Reset entity type value when command value changes
* Test changes
* Review comments
* Moved migrations around
* Corrected import statement
* Added JSON schema migration
* Updated schema version
* perf improvements and filter dropdown options feature
* Fix Code mirror component config for toggleComponentToJson input fields.
* Fix prettier issues
* fix prettier issues
* Fix style issues as a result of the merged conflicts
* Fix failing test case
* Fixed a few other flows (#14225)
* Fixed a few other flows
* Review comments
* Fix generate CRUD, fix evaluation of dynamic bindings and fix various styling issues.
* More fixes (#14367)
* Factor in the root formconfig parent key.
* Fix flickering issues, and evaluatedFormConfig issues
* fix: Teeny bugs (#14455)
* Teeny bugs
* Added previous functionality as is
* Improvements in the way we fetch dynamic values
* Fix stringiification issue and cyclic dependency issues
* Resolve projection component values deletion
* Resolve merge conflicts and fix prettier issues
* fix: Tsc issues
* Fix property pane connection navigation
* updating ee locator
* updating inputfield locator
* dropdown locator update
* Merge conflict not properly resolved.
* Fix s3 spec
* Fix Mongo Spec
* Fix some more tests
* fix: prevent cyclic dependency when switching to js mode (#14668)
* add delete events for change from array to string in diff
* add test to assert absence of cyclic dependency error when switching to js in switchgroup widget
* Assert that evaluation is not disabled when no cyclic dependency happens
* Cypress test preparations for google sheets and form controls
* Fixed a few test errors (#14874)
* Add: unit tests for uqi UI updates
- view type tests
- conditional output extraction
- processing conditional output to handle view/enabled state of the component
* Add: completed isValidFormConfig test
* Update: improved tests for update config
- These tests cover the functionality to update a section config after it's components are done evaluating
* Fix failing cypress tests and cyclic dependency issue
* Fixes some more tests
* Fixed migration of row objects (#14896)
* Bumped the version of design system package
* Update: reverted change to EE selector
* Fix deletion pointer
* Update: selector for js on load spec
- Synced with changes related to ADS dropdown
* Fix mongoDBShoppingCart spec
* Remove comments
* Fix: mongo shopping cart test failures
* fix: mongo shopping cart spec
* Dummy push to retrigger vercel
* fix: mongo shopping cart spec
* Update MongoDBShoppingCart_spec.js
* fix: removed unused click away
* dummy commit
* Update: moved helper functions to separate file
* Add: added tests for saga functions
- Worked on testing for
- extractFetchDynamicValueFormConfigs
- extractQueueOfValuesToBeFetched
* Add if check for queueOfValuesToBeFetched
* Resolve review comments
* Empty-Commit
Co-authored-by: Irongade <adeoluayangade@yahoo.com>
Co-authored-by: Ayush Pahwa <ayush@appsmith.com>
Co-authored-by: Aman Agarwal <aman@appsmith.com>
Co-authored-by: Ayangade Adeoluwa <37867493+Irongade@users.noreply.github.com>
Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
Co-authored-by: Favour Ohanekwu <fohanekwu@gmail.com>
Co-authored-by: Albin <albin@appsmith.com>
2022-07-04 05:43:27 +00:00
|
|
|
// @ts-expect-error: we don't know what the response will be
|
|
|
|
|
data: response.data?.trigger,
|
2021-07-29 08:13:10 +00:00
|
|
|
datasourceId: action.payload.datasourceId,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (action.onSuccessCallback) {
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: type mismatch for response
|
2021-07-29 08:13:10 +00:00
|
|
|
action.onSuccessCallback(response);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
yield put({
|
|
|
|
|
type: ReduxActionErrorTypes.EXECUTE_DATASOURCE_QUERY_ERROR,
|
|
|
|
|
payload: {
|
|
|
|
|
error,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (action.onErrorCallback) {
|
2022-06-21 13:57:34 +00:00
|
|
|
// @ts-expect-error: onErrorCallback expects string
|
2021-07-29 08:13:10 +00:00
|
|
|
action.onErrorCallback(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 10:41:17 +00:00
|
|
|
function* initializeFormWithDefaults(
|
|
|
|
|
action: ReduxAction<{ pluginType: string }>,
|
|
|
|
|
) {
|
|
|
|
|
const formName =
|
|
|
|
|
action?.payload?.pluginType === "API"
|
|
|
|
|
? DATASOURCE_REST_API_FORM
|
|
|
|
|
: DATASOURCE_DB_FORM;
|
|
|
|
|
const initialValue: Datasource = yield select(getFormInitialValues(formName));
|
|
|
|
|
const defaultKeyValueArrayConfig: string[] = yield select(
|
|
|
|
|
(state) => state?.ui?.datasourcePane?.defaultKeyValueArrayConfig,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
defaultKeyValueArrayConfig &&
|
|
|
|
|
defaultKeyValueArrayConfig?.length > 0 &&
|
|
|
|
|
!!initialValue
|
|
|
|
|
) {
|
|
|
|
|
const restAPIFormData: Datasource = yield select(
|
|
|
|
|
getFormValues(DATASOURCE_REST_API_FORM),
|
|
|
|
|
);
|
|
|
|
|
const formData: Datasource = yield select(
|
|
|
|
|
getFormValues(DATASOURCE_DB_FORM),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const formDataObj: Datasource =
|
|
|
|
|
action?.payload?.pluginType === "API" ? restAPIFormData : formData;
|
|
|
|
|
for (const prop of defaultKeyValueArrayConfig) {
|
|
|
|
|
const propPath: string[] = prop.split("[*].");
|
|
|
|
|
const newValues = get(formDataObj, propPath[0], []);
|
|
|
|
|
set(initialValue, propPath[0], newValues);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield put(resetDefaultKeyValPairFlag());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-07 09:32:38 +00:00
|
|
|
export function* watchDatasourcesSagas() {
|
|
|
|
|
yield all([
|
|
|
|
|
takeEvery(ReduxActionTypes.FETCH_DATASOURCES_INIT, fetchDatasourcesSaga),
|
2021-07-07 03:46:16 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.FETCH_MOCK_DATASOURCES_INIT,
|
|
|
|
|
fetchMockDatasourcesSaga,
|
|
|
|
|
),
|
|
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.ADD_MOCK_DATASOURCES_INIT,
|
|
|
|
|
addMockDbToDatasources,
|
|
|
|
|
),
|
2020-05-07 04:44:52 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT,
|
|
|
|
|
createDatasourceFromFormSaga,
|
|
|
|
|
),
|
2022-11-30 05:59:45 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.CREATE_TEMP_DATASOURCE_FROM_FORM_SUCCESS,
|
|
|
|
|
createTempDatasourceFromFormSaga,
|
|
|
|
|
),
|
2020-04-28 06:52:53 +00:00
|
|
|
takeEvery(ReduxActionTypes.UPDATE_DATASOURCE_INIT, updateDatasourceSaga),
|
2020-08-26 05:24:44 +00:00
|
|
|
takeEvery(
|
2022-11-30 05:59:45 +00:00
|
|
|
ReduxActionTypes.UPDATE_DATASOURCE_NAME,
|
|
|
|
|
updateDatasourceNameSaga,
|
|
|
|
|
),
|
|
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionErrorTypes.UPDATE_DATASOURCE_NAME_ERROR,
|
2020-08-26 05:24:44 +00:00
|
|
|
handleDatasourceNameChangeFailureSaga,
|
|
|
|
|
),
|
2020-04-28 06:52:53 +00:00
|
|
|
takeEvery(ReduxActionTypes.TEST_DATASOURCE_INIT, testDatasourceSaga),
|
2020-04-29 10:03:56 +00:00
|
|
|
takeEvery(ReduxActionTypes.DELETE_DATASOURCE_INIT, deleteDatasourceSaga),
|
2020-05-19 06:10:59 +00:00
|
|
|
takeEvery(ReduxActionTypes.CHANGE_DATASOURCE, changeDatasourceSaga),
|
Feature/entity browse (#220)
# New Feature: Entity Explorer
- Entities are actions (apis and queries), datasources, pages, and widgets
- With this new feature, all entities in the application will be available
to view in the new entity explorer sidebar
- All existing application features from the api sidebar, query sidebar, datasource sidebar and pages sidebar
now are avialable on the entity explorer sidebar
- Users are now able to quickly switch to any entity in the application from the entity explorer sidebar.
- Users can also search all entities in the application from the new sidebar. Use cmd + f or ctrl + f to focus on the search input
- Users can rename entities from the new sidebar
- Users can also perform contextual actions on these entities like set a page as home page, copy/move actions, delete entity, etc from the context menu available alongside the entities in the sidebar
- Users can view the properties of the entities in the sidebar, as well as copy bindings to use in the application.
2020-08-10 08:52:45 +00:00
|
|
|
takeLatest(ReduxActionTypes.SWITCH_DATASOURCE, switchDatasourceSaga),
|
2020-06-03 05:40:48 +00:00
|
|
|
takeEvery(ReduxActionTypes.STORE_AS_DATASOURCE_INIT, storeAsDatasourceSaga),
|
|
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.UPDATE_DATASOURCE_SUCCESS,
|
|
|
|
|
updateDatasourceSuccessSaga,
|
|
|
|
|
),
|
2021-02-11 12:28:06 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.REDIRECT_AUTHORIZATION_CODE,
|
2021-04-22 03:30:09 +00:00
|
|
|
redirectAuthorizationCodeSaga,
|
|
|
|
|
),
|
2022-01-14 06:31:54 +00:00
|
|
|
takeEvery(ReduxActionTypes.GET_OAUTH_ACCESS_TOKEN, getOAuthAccessTokenSaga),
|
2020-09-21 09:11:42 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.FETCH_DATASOURCE_STRUCTURE_INIT,
|
2021-04-22 03:30:09 +00:00
|
|
|
fetchDatasourceStructureSaga,
|
2020-09-21 09:11:42 +00:00
|
|
|
),
|
2020-09-29 04:17:25 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.REFRESH_DATASOURCE_STRUCTURE_INIT,
|
2021-04-22 03:30:09 +00:00
|
|
|
refreshDatasourceStructure,
|
2020-09-29 04:17:25 +00:00
|
|
|
),
|
2021-07-29 08:13:10 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.EXECUTE_DATASOURCE_QUERY_INIT,
|
|
|
|
|
executeDatasourceQuerySaga,
|
|
|
|
|
),
|
2023-02-10 10:41:17 +00:00
|
|
|
takeEvery(
|
|
|
|
|
ReduxActionTypes.INITIALIZE_DATASOURCE_FORM_WITH_DEFAULTS,
|
|
|
|
|
initializeFormWithDefaults,
|
|
|
|
|
),
|
2021-12-07 09:45:18 +00:00
|
|
|
// Intercepting the redux-form change actionType to update drafts and track change history
|
2020-05-19 06:10:59 +00:00
|
|
|
takeEvery(ReduxFormActionTypes.VALUE_CHANGE, formValueChangeSaga),
|
2021-12-07 09:45:18 +00:00
|
|
|
takeEvery(ReduxFormActionTypes.ARRAY_PUSH, formValueChangeSaga),
|
|
|
|
|
takeEvery(ReduxFormActionTypes.ARRAY_REMOVE, formValueChangeSaga),
|
2019-11-07 09:32:38 +00:00
|
|
|
]);
|
|
|
|
|
}
|