2023-04-07 13:51:35 +00:00
|
|
|
import { setLayoutConversionStateAction } from "actions/autoLayoutActions";
|
|
|
|
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
2023-05-08 09:56:41 +00:00
|
|
|
import type { Page } from "@appsmith/constants/ReduxActionConstants";
|
2023-04-07 13:51:35 +00:00
|
|
|
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
|
|
|
|
import type { AppState } from "@appsmith/reducers";
|
|
|
|
|
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
|
|
|
|
import CanvasWidgetsNormalizer from "normalizers/CanvasWidgetsNormalizer";
|
|
|
|
|
import { AppPositioningTypes } from "reducers/entityReducers/pageListReducer";
|
|
|
|
|
import type { SupportedLayouts } from "reducers/entityReducers/pageListReducer";
|
|
|
|
|
import { CONVERSION_STATES } from "reducers/uiReducers/layoutConversionReducer";
|
|
|
|
|
import type { PageWidgetsReduxState } from "reducers/uiReducers/pageWidgetsReducer";
|
|
|
|
|
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
|
|
|
|
import { getPageWidgets } from "selectors/entitiesSelector";
|
|
|
|
|
import { convertNormalizedDSLToFixed } from "utils/DSLConversions/autoToFixedLayout";
|
|
|
|
|
import convertToAutoLayout from "utils/DSLConversions/fixedToAutoLayout";
|
|
|
|
|
import type { DSLWidget } from "widgets/constants";
|
2023-05-03 04:26:52 +00:00
|
|
|
import {
|
|
|
|
|
createSnapshotSaga,
|
|
|
|
|
deleteApplicationSnapshotSaga,
|
|
|
|
|
} from "./SnapshotSagas";
|
2023-04-07 13:51:35 +00:00
|
|
|
import * as Sentry from "@sentry/react";
|
|
|
|
|
import log from "loglevel";
|
|
|
|
|
import { saveAllPagesSaga } from "./PageSagas";
|
|
|
|
|
import { updateApplicationLayout } from "@appsmith/actions/applicationActions";
|
2023-05-08 09:56:41 +00:00
|
|
|
import {
|
|
|
|
|
getCurrentApplicationId,
|
|
|
|
|
getPageList,
|
|
|
|
|
} from "selectors/editorSelectors";
|
2023-04-07 13:51:35 +00:00
|
|
|
import { updateApplicationLayoutType } from "./AutoLayoutUpdateSagas";
|
2023-05-07 05:10:03 +00:00
|
|
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
2023-04-07 13:51:35 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This method is used to convert from Auto layout to Fixed layout
|
|
|
|
|
* @param action
|
|
|
|
|
*/
|
|
|
|
|
function* convertFromAutoToFixedSaga(action: ReduxAction<SupportedLayouts>) {
|
2023-05-07 05:10:03 +00:00
|
|
|
let appId = "";
|
2023-05-03 04:26:52 +00:00
|
|
|
let snapshotSaveSuccess = false;
|
2023-04-07 13:51:35 +00:00
|
|
|
try {
|
2023-05-08 09:56:41 +00:00
|
|
|
const pageList: Page[] = yield select(getPageList);
|
2023-04-07 13:51:35 +00:00
|
|
|
const pageWidgetsList: PageWidgetsReduxState = yield select(getPageWidgets);
|
|
|
|
|
|
2023-05-08 09:56:41 +00:00
|
|
|
appId = yield select(getCurrentApplicationId);
|
|
|
|
|
|
2023-05-07 05:10:03 +00:00
|
|
|
const notEmptyApp = isNotEmptyApp(pageWidgetsList);
|
|
|
|
|
|
|
|
|
|
if (notEmptyApp) {
|
2023-04-07 13:51:35 +00:00
|
|
|
yield call(createSnapshotSaga);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 05:10:03 +00:00
|
|
|
AnalyticsUtil.logEvent("CONVERT_AUTO_TO_FIXED", {
|
|
|
|
|
isNewApp: !notEmptyApp,
|
|
|
|
|
});
|
2023-05-03 04:26:52 +00:00
|
|
|
snapshotSaveSuccess = true;
|
|
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
//Set conversion form to indicated conversion loading state
|
|
|
|
|
yield put(
|
|
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.CONVERSION_SPINNER),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const pageLayouts = [];
|
|
|
|
|
|
|
|
|
|
//Convert all the pages into Fixed layout by iterating over the list
|
2023-05-08 09:56:41 +00:00
|
|
|
for (const page of pageList) {
|
|
|
|
|
const pageId = page?.pageId;
|
|
|
|
|
const { dsl: normalizedDSL, layoutId } = pageWidgetsList[pageId];
|
2023-04-07 13:51:35 +00:00
|
|
|
|
|
|
|
|
const fixedLayoutDSL = convertNormalizedDSLToFixed(
|
|
|
|
|
normalizedDSL,
|
|
|
|
|
action.payload,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const dsl: DSLWidget = CanvasWidgetsNormalizer.denormalize(
|
|
|
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
{ canvasWidgets: fixedLayoutDSL },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
pageLayouts.push({
|
|
|
|
|
pageId,
|
|
|
|
|
layoutId,
|
|
|
|
|
layout: {
|
|
|
|
|
dsl,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield call(saveAllPagesSaga, pageLayouts);
|
|
|
|
|
//Set type of fixed layout
|
|
|
|
|
yield call(setLayoutTypePostConversion, action.payload);
|
|
|
|
|
yield call(updateApplicationLayoutType, AppPositioningTypes.FIXED);
|
|
|
|
|
//update conversion form state to success
|
|
|
|
|
yield put(
|
|
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_SUCCESS),
|
|
|
|
|
);
|
2023-05-07 05:10:03 +00:00
|
|
|
} catch (e: any) {
|
|
|
|
|
let error: Error = e;
|
|
|
|
|
if (error) {
|
|
|
|
|
error.message = `Layout Conversion Error - while Converting from Auto to Fixed Layout: ${error.message}`;
|
|
|
|
|
} else {
|
|
|
|
|
error = new Error(
|
|
|
|
|
"Layout Conversion Error - while Converting from Auto to Fixed Layout",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.error(error);
|
2023-05-03 04:26:52 +00:00
|
|
|
|
|
|
|
|
if (snapshotSaveSuccess) {
|
|
|
|
|
yield call(deleteApplicationSnapshotSaga);
|
|
|
|
|
}
|
2023-04-07 13:51:35 +00:00
|
|
|
//update conversion form state to error
|
|
|
|
|
yield put(
|
2023-05-07 05:10:03 +00:00
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_ERROR, error),
|
2023-04-07 13:51:35 +00:00
|
|
|
);
|
2023-05-07 05:10:03 +00:00
|
|
|
|
|
|
|
|
AnalyticsUtil.logEvent("CONVERSION_FAILURE", {
|
|
|
|
|
flow: "CONVERT_AUTO_TO_FIXED",
|
|
|
|
|
appId,
|
|
|
|
|
});
|
2023-04-07 13:51:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This method is used to convert from Fixed layout to Auto layout
|
|
|
|
|
* @param action
|
|
|
|
|
*/
|
|
|
|
|
function* convertFromFixedToAutoSaga() {
|
2023-05-07 05:10:03 +00:00
|
|
|
let appId = "";
|
2023-05-03 04:26:52 +00:00
|
|
|
let snapshotSaveSuccess = false;
|
2023-04-07 13:51:35 +00:00
|
|
|
try {
|
2023-05-08 09:56:41 +00:00
|
|
|
const pageList: Page[] = yield select(getPageList);
|
2023-04-07 13:51:35 +00:00
|
|
|
const pageWidgetsList: PageWidgetsReduxState = yield select(getPageWidgets);
|
|
|
|
|
|
2023-05-08 09:56:41 +00:00
|
|
|
appId = yield select(getCurrentApplicationId);
|
|
|
|
|
|
2023-05-07 05:10:03 +00:00
|
|
|
const notEmptyApp = isNotEmptyApp(pageWidgetsList);
|
|
|
|
|
|
|
|
|
|
if (notEmptyApp) {
|
2023-04-07 13:51:35 +00:00
|
|
|
yield call(createSnapshotSaga);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 05:10:03 +00:00
|
|
|
AnalyticsUtil.logEvent("CONVERT_FIXED_TO_AUTO", {
|
|
|
|
|
isNewApp: !notEmptyApp,
|
|
|
|
|
appId,
|
|
|
|
|
});
|
2023-05-03 04:26:52 +00:00
|
|
|
snapshotSaveSuccess = true;
|
|
|
|
|
|
2023-04-07 13:51:35 +00:00
|
|
|
yield put(
|
|
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.CONVERSION_SPINNER),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const pageLayouts = [];
|
|
|
|
|
|
2023-05-08 09:56:41 +00:00
|
|
|
for (const page of pageList) {
|
|
|
|
|
const pageId = page?.pageId;
|
|
|
|
|
const { dsl: normalizedDSL, layoutId } = pageWidgetsList[pageId];
|
2023-04-07 13:51:35 +00:00
|
|
|
|
|
|
|
|
const fixedDSL: DSLWidget = CanvasWidgetsNormalizer.denormalize(
|
|
|
|
|
MAIN_CONTAINER_WIDGET_ID,
|
|
|
|
|
{ canvasWidgets: normalizedDSL },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const dsl: DSLWidget = convertToAutoLayout(fixedDSL);
|
|
|
|
|
|
|
|
|
|
pageLayouts.push({
|
|
|
|
|
pageId,
|
|
|
|
|
layoutId,
|
|
|
|
|
layout: {
|
|
|
|
|
dsl,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield call(saveAllPagesSaga, pageLayouts);
|
|
|
|
|
yield call(updateApplicationLayoutType, AppPositioningTypes.AUTO);
|
|
|
|
|
//update conversion form state to success
|
|
|
|
|
yield put(
|
|
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_SUCCESS),
|
|
|
|
|
);
|
2023-05-07 05:10:03 +00:00
|
|
|
} catch (e: any) {
|
|
|
|
|
let error: Error = e;
|
|
|
|
|
if (error) {
|
|
|
|
|
error.message = `Layout Conversion Error - while Converting from Fixed to Auto Layout: ${error.message}`;
|
|
|
|
|
} else {
|
|
|
|
|
error = new Error(
|
|
|
|
|
"Layout Conversion Error - while Converting from Fixed to Auto Layout",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.error(error);
|
2023-04-07 13:51:35 +00:00
|
|
|
//update conversion form state to error
|
2023-05-03 04:26:52 +00:00
|
|
|
if (snapshotSaveSuccess) {
|
|
|
|
|
yield call(deleteApplicationSnapshotSaga);
|
|
|
|
|
}
|
2023-04-07 13:51:35 +00:00
|
|
|
yield put(
|
2023-05-07 05:10:03 +00:00
|
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_ERROR, error),
|
2023-04-07 13:51:35 +00:00
|
|
|
);
|
2023-05-07 05:10:03 +00:00
|
|
|
|
|
|
|
|
AnalyticsUtil.logEvent("CONVERSION_FAILURE", {
|
|
|
|
|
flow: "CONVERT_FIXED_TO_AUTO",
|
|
|
|
|
appId,
|
|
|
|
|
});
|
2023-04-07 13:51:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Saga to log conversion sentry error when user reports it
|
|
|
|
|
function* logLayoutConversionErrorSaga() {
|
|
|
|
|
try {
|
|
|
|
|
const error: Error = yield select(
|
|
|
|
|
(state: AppState) => state.ui.layoutConversion.conversionError,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
yield call(Sentry.captureException, error);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set layout type of Application based on user selection while converting
|
|
|
|
|
* @param selectedLayoutType
|
|
|
|
|
*/
|
|
|
|
|
function* setLayoutTypePostConversion(selectedLayoutType: SupportedLayouts) {
|
|
|
|
|
let convertToLayoutType: SupportedLayouts = selectedLayoutType;
|
|
|
|
|
const applicationId: string = yield select(getCurrentApplicationId);
|
|
|
|
|
|
|
|
|
|
if (selectedLayoutType === "DESKTOP") {
|
|
|
|
|
convertToLayoutType = "FLUID";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield put(
|
|
|
|
|
updateApplicationLayout(applicationId, {
|
|
|
|
|
appLayout: {
|
|
|
|
|
type: convertToLayoutType,
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function* layoutConversionSagas() {
|
|
|
|
|
yield all([
|
|
|
|
|
takeLatest(
|
|
|
|
|
ReduxActionTypes.CONVERT_AUTO_TO_FIXED,
|
|
|
|
|
convertFromAutoToFixedSaga,
|
|
|
|
|
),
|
|
|
|
|
takeLatest(
|
|
|
|
|
ReduxActionTypes.CONVERT_FIXED_TO_AUTO,
|
|
|
|
|
convertFromFixedToAutoSaga,
|
|
|
|
|
),
|
|
|
|
|
takeLatest(
|
|
|
|
|
ReduxActionTypes.LOG_LAYOUT_CONVERSION_ERROR,
|
|
|
|
|
logLayoutConversionErrorSaga,
|
|
|
|
|
),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Function returns boolean, SnapShot should not be saved for a single empty canvas
|
2023-05-07 05:10:03 +00:00
|
|
|
function isNotEmptyApp(pageWidgetsList: PageWidgetsReduxState) {
|
2023-04-07 13:51:35 +00:00
|
|
|
const pageList = Object.values(pageWidgetsList);
|
|
|
|
|
|
|
|
|
|
if (pageList.length !== 1) return true;
|
|
|
|
|
|
|
|
|
|
const { dsl: pageDSL } = pageList[0];
|
|
|
|
|
|
|
|
|
|
return Object.keys(pageDSL).length !== 1;
|
|
|
|
|
}
|