PromucFlow_constructor/app/client/src/sagas/InitSagas.ts

170 lines
5.2 KiB
TypeScript

import { get } from "lodash";
import {
all,
call,
put,
race,
select,
take,
takeEvery,
takeLatest,
} from "redux-saga/effects";
import {
ApplicationPayload,
Page,
ReduxAction,
ReduxActionTypes,
ReduxActionWithoutPayload,
} from "@appsmith/constants/ReduxActionConstants";
import { ERROR_CODES } from "@appsmith/constants/ApiConstants";
import { resetApplicationWidgets, resetPageList } from "actions/pageActions";
import { resetCurrentApplication } from "actions/applicationActions";
import log from "loglevel";
import * as Sentry from "@sentry/react";
import { resetRecentEntities } from "actions/globalSearchActions";
import { resetEditorSuccess } from "actions/initActions";
import {
getCurrentPageId,
getIsEditorInitialized,
selectCurrentApplicationSlug,
} from "selectors/editorSelectors";
import { getIsInitialized as getIsViewerInitialized } from "selectors/appViewSelectors";
import { enableGuidedTour } from "actions/onboardingActions";
import { setPreviewModeAction } from "actions/editorActions";
import AppEngine, {
AppEngineApiError,
AppEnginePayload,
} from "entities/Engine";
import AppEngineFactory from "entities/Engine/factory";
import { ApplicationPagePayload } from "api/ApplicationApi";
import { updateSlugNamesInURL } from "utils/helpers";
export const URL_CHANGE_ACTIONS = [
ReduxActionTypes.CURRENT_APPLICATION_NAME_UPDATE,
ReduxActionTypes.UPDATE_PAGE_SUCCESS,
ReduxActionTypes.UPDATE_APPLICATION_SUCCESS,
];
export type ReduxURLChangeAction = {
type: typeof URL_CHANGE_ACTIONS;
payload: ApplicationPagePayload | ApplicationPayload | Page;
};
export function* failFastApiCalls(
triggerActions: Array<ReduxAction<unknown> | ReduxActionWithoutPayload>,
successActions: string[],
failureActions: string[],
) {
yield all(triggerActions.map((triggerAction) => put(triggerAction)));
const effectRaceResult: { success: boolean; failure: boolean } = yield race({
success: all(successActions.map((successAction) => take(successAction))),
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;
}
export function* startAppEngine(action: ReduxAction<AppEnginePayload>) {
try {
const engine: AppEngine = AppEngineFactory.create(
action.payload.mode,
action.payload.mode,
);
engine.startPerformanceTracking();
yield call(engine.setupEngine, action.payload);
const { applicationId, toLoadPageId } = yield call(
engine.loadAppData,
action.payload,
);
yield call(engine.loadAppURL, toLoadPageId, action.payload.pageId);
yield call(engine.loadAppEntities, toLoadPageId, applicationId);
yield call(engine.loadGit, applicationId);
yield call(engine.completeChore);
engine.stopPerformanceTracking();
} catch (e) {
log.error(e);
if (e instanceof AppEngineApiError) return;
Sentry.captureException(e);
yield put({
type: ReduxActionTypes.SAFE_CRASH_APPSMITH_REQUEST,
payload: {
code: ERROR_CODES.SERVER_ERROR,
},
});
}
}
function* resetEditorSaga() {
yield put(resetCurrentApplication());
yield put(resetPageList());
yield put(resetApplicationWidgets());
yield put(resetRecentEntities());
// End guided tour once user exits editor
yield put(enableGuidedTour(false));
// Reset to edit mode once user exits editor
// Without doing this if the user creates a new app they
// might end up in preview mode if they were in preview mode
// previously
yield put(setPreviewModeAction(false));
yield put(resetEditorSuccess());
}
export function* waitForInit() {
const isEditorInitialised: boolean = yield select(getIsEditorInitialized);
const isViewerInitialized: boolean = yield select(getIsViewerInitialized);
if (!isEditorInitialised && !isViewerInitialized) {
yield take([
ReduxActionTypes.INITIALIZE_EDITOR_SUCCESS,
ReduxActionTypes.INITIALIZE_PAGE_VIEWER_SUCCESS,
]);
}
}
function* updateURLSaga(action: ReduxURLChangeAction) {
yield call(waitForInit);
const currentPageId: string = yield select(getCurrentPageId);
const applicationSlug: string = yield select(selectCurrentApplicationSlug);
const payload = action.payload;
if ("applicationVersion" in payload) {
updateSlugNamesInURL({ applicationSlug: payload.slug });
return;
}
if ("pageId" in payload) {
if (payload.pageId !== currentPageId) return;
updateSlugNamesInURL({
pageSlug: payload.slug,
customSlug: payload.customSlug || "",
applicationSlug,
});
return;
}
if (payload.id !== currentPageId) return;
updateSlugNamesInURL({
pageSlug: payload.slug,
customSlug: payload.customSlug || "",
applicationSlug,
});
}
export default function* watchInitSagas() {
yield all([
takeLatest(ReduxActionTypes.INITIALIZE_EDITOR, startAppEngine),
takeLatest(ReduxActionTypes.INITIALIZE_PAGE_VIEWER, startAppEngine),
takeLatest(ReduxActionTypes.RESET_EDITOR_REQUEST, resetEditorSaga),
takeEvery(URL_CHANGE_ACTIONS, updateURLSaga),
]);
}