PromucFlow_constructor/app/client/src/sagas/InitSagas.ts
2021-05-20 17:33:08 +05:30

297 lines
8.7 KiB
TypeScript

import { get } from "lodash";
import {
all,
call,
put,
race,
select,
take,
takeLatest,
} from "redux-saga/effects";
import {
InitializeEditorPayload,
ReduxAction,
ReduxActionErrorTypes,
ReduxActionTypes,
ReduxActionWithoutPayload,
} from "constants/ReduxActionConstants";
import { ERROR_CODES } from "constants/ApiConstants";
import {
fetchPage,
fetchPageList,
fetchPublishedPage,
setAppMode,
updateAppPersistentStore,
} from "actions/pageActions";
import { fetchDatasources } from "actions/datasourceActions";
import { fetchPluginFormConfigs, fetchPlugins } from "actions/pluginActions";
import { fetchActions, fetchActionsForView } from "actions/actionActions";
import { fetchApplication } from "actions/applicationActions";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getCurrentApplication } from "selectors/applicationSelectors";
import { APP_MODE } from "reducers/entityReducers/appReducer";
import { getPersistentAppStore } from "constants/AppConstants";
import { getDefaultPageId } from "./selectors";
import { populatePageDSLsSaga } from "./PageSagas";
import log from "loglevel";
import * as Sentry from "@sentry/react";
import {
resetRecentEntities,
restoreRecentEntitiesRequest,
} from "actions/globalSearchActions";
import { resetEditorSuccess } from "actions/initActions";
import { initCommentThreads } from "actions/commentActions";
import PerformanceTracker, {
PerformanceTransactionName,
} from "utils/PerformanceTracker";
import { executePageLoadActions } from "actions/widgetActions";
import { getIsEditorInitialized } from "selectors/editorSelectors";
import { getIsInitialized as getIsViewerInitialized } from "selectors/appViewSelectors";
import { resetDebuggerState } from "actions/debuggerActions";
function* failFastApiCalls(
triggerActions: Array<ReduxAction<unknown> | ReduxActionWithoutPayload>,
successActions: string[],
failureActions: string[],
) {
const triggerEffects = [];
for (const triggerAction of triggerActions) {
triggerEffects.push(put(triggerAction));
}
const successEffects = [];
for (const successAction of successActions) {
successEffects.push(take(successAction));
}
yield all(triggerEffects);
const effectRaceResult = yield race({
success: all(successEffects),
failure: take(failureActions),
});
if (effectRaceResult.failure) {
yield put({
type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST,
payload: {
code: get(
effectRaceResult,
"failure.payload.error.code",
ERROR_CODES.SERVER_ERROR,
),
},
});
return false;
}
return true;
}
function* initializeEditorSaga(
initializeEditorAction: ReduxAction<InitializeEditorPayload>,
) {
const { applicationId, pageId } = initializeEditorAction.payload;
try {
PerformanceTracker.startAsyncTracking(
PerformanceTransactionName.INIT_EDIT_APP,
);
yield put(setAppMode(APP_MODE.EDIT));
yield put(updateAppPersistentStore(getPersistentAppStore(applicationId)));
yield put({ type: ReduxActionTypes.START_EVALUATION });
const applicationAndLayoutCalls = yield failFastApiCalls(
[
fetchPageList(applicationId, APP_MODE.EDIT),
fetchPage(pageId),
fetchApplication(applicationId, APP_MODE.EDIT),
],
[
ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS,
ReduxActionTypes.FETCH_PAGE_SUCCESS,
ReduxActionTypes.FETCH_APPLICATION_SUCCESS,
],
[
ReduxActionErrorTypes.FETCH_PAGE_LIST_ERROR,
ReduxActionErrorTypes.FETCH_PAGE_ERROR,
ReduxActionErrorTypes.FETCH_APPLICATION_ERROR,
],
);
if (!applicationAndLayoutCalls) return;
const pluginsAndDatasourcesCalls = yield failFastApiCalls(
[fetchPlugins(), fetchDatasources()],
[
ReduxActionTypes.FETCH_PLUGINS_SUCCESS,
ReduxActionTypes.FETCH_DATASOURCES_SUCCESS,
],
[
ReduxActionErrorTypes.FETCH_PLUGINS_ERROR,
ReduxActionErrorTypes.FETCH_DATASOURCES_ERROR,
],
);
if (!pluginsAndDatasourcesCalls) return;
const pluginFormCall = yield failFastApiCalls(
[fetchPluginFormConfigs()],
[ReduxActionTypes.FETCH_PLUGIN_FORM_CONFIGS_SUCCESS],
[ReduxActionErrorTypes.FETCH_PLUGIN_FORM_CONFIGS_ERROR],
);
if (!pluginFormCall) return;
const actionsCall = yield failFastApiCalls(
[fetchActions(applicationId, [executePageLoadActions()])],
[ReduxActionTypes.FETCH_ACTIONS_SUCCESS],
[ReduxActionErrorTypes.FETCH_ACTIONS_ERROR],
);
if (!actionsCall) return;
const currentApplication = yield select(getCurrentApplication);
const appName = currentApplication ? currentApplication.name : "";
const appId = currentApplication ? currentApplication.id : "";
yield put(restoreRecentEntitiesRequest(applicationId));
AnalyticsUtil.logEvent("EDITOR_OPEN", {
appId: appId,
appName: appName,
});
// todo remove (for dev)
yield put(initCommentThreads());
yield put({
type: ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS,
});
PerformanceTracker.stopAsyncTracking(
PerformanceTransactionName.INIT_EDIT_APP,
);
} catch (e) {
log.error(e);
Sentry.captureException(e);
yield put({
type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST,
payload: {
code: ERROR_CODES.SERVER_ERROR,
},
});
return;
}
yield call(populatePageDSLsSaga);
}
export function* initializeAppViewerSaga(
action: ReduxAction<{ applicationId: string; pageId: string }>,
) {
const { applicationId, pageId } = action.payload;
PerformanceTracker.startAsyncTracking(
PerformanceTransactionName.INIT_VIEW_APP,
);
yield put(setAppMode(APP_MODE.PUBLISHED));
yield put(updateAppPersistentStore(getPersistentAppStore(applicationId)));
yield put({ type: ReduxActionTypes.START_EVALUATION });
yield all([
// TODO (hetu) Remove spl view call for fetch actions
put(fetchActionsForView(applicationId)),
put(fetchPageList(applicationId, APP_MODE.PUBLISHED)),
put(fetchApplication(applicationId, APP_MODE.PUBLISHED)),
]);
const resultOfPrimaryCalls = yield race({
success: all([
take(ReduxActionTypes.FETCH_ACTIONS_VIEW_MODE_SUCCESS),
take(ReduxActionTypes.FETCH_PAGE_LIST_SUCCESS),
take(ReduxActionTypes.FETCH_APPLICATION_SUCCESS),
]),
failure: take([
ReduxActionErrorTypes.FETCH_ACTIONS_VIEW_MODE_ERROR,
ReduxActionErrorTypes.FETCH_PAGE_LIST_ERROR,
ReduxActionErrorTypes.FETCH_APPLICATION_ERROR,
]),
});
if (resultOfPrimaryCalls.failure) {
yield put({
type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST,
payload: {
code: get(
resultOfPrimaryCalls,
"failure.payload.error.code",
ERROR_CODES.SERVER_ERROR,
),
},
});
return;
}
const defaultPageId = yield select(getDefaultPageId);
const toLoadPageId = pageId || defaultPageId;
if (toLoadPageId) {
yield put(fetchPublishedPage(toLoadPageId, true));
const resultOfFetchPage = yield race({
success: take(ReduxActionTypes.FETCH_PUBLISHED_PAGE_SUCCESS),
failure: take(ReduxActionErrorTypes.FETCH_PUBLISHED_PAGE_ERROR),
});
if (resultOfFetchPage.failure) {
yield put({
type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST,
payload: {
code: get(
resultOfFetchPage,
"failure.payload.error.code",
ERROR_CODES.SERVER_ERROR,
),
},
});
return;
}
yield put(setAppMode(APP_MODE.PUBLISHED));
// todo remove (for dev)
yield put(initCommentThreads());
yield put({
type: ReduxActionTypes.INITIALIZE_PAGE_VIEWER_SUCCESS,
});
PerformanceTracker.stopAsyncTracking(
PerformanceTransactionName.INIT_VIEW_APP,
);
if ("serviceWorker" in navigator) {
yield put({
type: ReduxActionTypes.FETCH_ALL_PUBLISHED_PAGES,
});
}
}
}
function* resetEditorSaga() {
yield put(resetEditorSuccess());
yield put(resetRecentEntities());
yield put(resetDebuggerState());
}
export function* waitForInit() {
const isEditorInitialised = yield select(getIsEditorInitialized);
const isViewerInitialized = yield select(getIsViewerInitialized);
if (!isEditorInitialised && !isViewerInitialized) {
yield take([
ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS,
ReduxActionTypes.INITIALIZE_PAGE_VIEWER_SUCCESS,
]);
}
}
export default function* watchInitSagas() {
yield all([
takeLatest(ReduxActionTypes.INITIALIZE_EDITOR, initializeEditorSaga),
takeLatest(
ReduxActionTypes.INITIALIZE_PAGE_VIEWER,
initializeAppViewerSaga,
),
takeLatest(ReduxActionTypes.RESET_EDITOR_REQUEST, resetEditorSaga),
]);
}