## Description Splitting DSL into different files when saving into git #### PR fixes following issue(s) Fixes #23763 #### Media #### Type of change - New feature (non-breaking change which adds functionality) ## Testing Manual Testing #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] Jest - [ ] 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 - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] 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 - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Test-plan-implementation#speedbreaker-features-to-consider-for-every-change) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans/_edit#areas-of-interest) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed --------- Co-authored-by: Hetu Nandu <hetunandu@gmail.com>
260 lines
7.5 KiB
TypeScript
260 lines
7.5 KiB
TypeScript
import { setLayoutConversionStateAction } from "actions/autoLayoutActions";
|
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
|
import type { Page } from "@appsmith/constants/ReduxActionConstants";
|
|
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
|
|
import type { AppState } from "@appsmith/reducers";
|
|
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";
|
|
import {
|
|
createSnapshotSaga,
|
|
deleteApplicationSnapshotSaga,
|
|
} from "./SnapshotSagas";
|
|
import * as Sentry from "@sentry/react";
|
|
import log from "loglevel";
|
|
import { saveAllPagesSaga } from "./PageSagas";
|
|
import { updateApplicationLayout } from "@appsmith/actions/applicationActions";
|
|
import {
|
|
getCurrentApplicationId,
|
|
getPageList,
|
|
} from "selectors/editorSelectors";
|
|
import { updateApplicationLayoutType } from "./AutoLayoutUpdateSagas";
|
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
|
import { nestDSL } from "@shared/dsl";
|
|
|
|
/**
|
|
* This method is used to convert from auto-layout to fixed layout
|
|
* @param action
|
|
*/
|
|
function* convertFromAutoToFixedSaga(action: ReduxAction<SupportedLayouts>) {
|
|
let appId = "";
|
|
let snapshotSaveSuccess = false;
|
|
try {
|
|
const pageList: Page[] = yield select(getPageList);
|
|
const pageWidgetsList: PageWidgetsReduxState = yield select(getPageWidgets);
|
|
|
|
appId = yield select(getCurrentApplicationId);
|
|
|
|
const notEmptyApp = isNotEmptyApp(pageWidgetsList);
|
|
|
|
if (notEmptyApp) {
|
|
yield call(createSnapshotSaga);
|
|
}
|
|
|
|
AnalyticsUtil.logEvent("CONVERT_AUTO_TO_FIXED", {
|
|
isNewApp: !notEmptyApp,
|
|
appId,
|
|
});
|
|
snapshotSaveSuccess = true;
|
|
|
|
//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
|
|
for (const page of pageList) {
|
|
const pageId = page?.pageId;
|
|
const { dsl: normalizedDSL, layoutId } = pageWidgetsList[pageId];
|
|
|
|
const fixedLayoutDSL = convertNormalizedDSLToFixed(
|
|
normalizedDSL,
|
|
action.payload,
|
|
);
|
|
|
|
const dsl = nestDSL(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),
|
|
);
|
|
} catch (e: any) {
|
|
let error: Error = e;
|
|
if (error) {
|
|
error.message = `Layout conversion error - while converting from auto-layout to fixed layout: ${error.message}`;
|
|
} else {
|
|
error = new Error(
|
|
"Layout conversion error - while converting from auto-layout to fixed layout",
|
|
);
|
|
}
|
|
|
|
log.error(error);
|
|
|
|
if (snapshotSaveSuccess) {
|
|
yield call(deleteApplicationSnapshotSaga);
|
|
}
|
|
//update conversion form state to error
|
|
yield put(
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_ERROR, error),
|
|
);
|
|
|
|
AnalyticsUtil.logEvent("CONVERSION_FAILURE", {
|
|
flow: "CONVERT_AUTO_TO_FIXED",
|
|
appId,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This method is used to convert from fixed layout to auto-layout
|
|
* @param action
|
|
*/
|
|
function* convertFromFixedToAutoSaga() {
|
|
let appId = "";
|
|
let snapshotSaveSuccess = false;
|
|
try {
|
|
const pageList: Page[] = yield select(getPageList);
|
|
const pageWidgetsList: PageWidgetsReduxState = yield select(getPageWidgets);
|
|
|
|
appId = yield select(getCurrentApplicationId);
|
|
|
|
const notEmptyApp = isNotEmptyApp(pageWidgetsList);
|
|
|
|
if (notEmptyApp) {
|
|
yield call(createSnapshotSaga);
|
|
}
|
|
|
|
AnalyticsUtil.logEvent("CONVERT_FIXED_TO_AUTO", {
|
|
isNewApp: !notEmptyApp,
|
|
appId,
|
|
});
|
|
snapshotSaveSuccess = true;
|
|
|
|
yield put(
|
|
setLayoutConversionStateAction(CONVERSION_STATES.CONVERSION_SPINNER),
|
|
);
|
|
|
|
const pageLayouts = [];
|
|
|
|
for (const page of pageList) {
|
|
const pageId = page?.pageId;
|
|
const { dsl: normalizedDSL, layoutId } = pageWidgetsList[pageId];
|
|
|
|
const fixedDSL = nestDSL(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),
|
|
);
|
|
} catch (e: any) {
|
|
let error: Error = e;
|
|
if (error) {
|
|
error.message = `Layout conversion error - while converting from fixed layout to auto-layout: ${error.message}`;
|
|
} else {
|
|
error = new Error(
|
|
"Layout conversion error - while converting from fixed layout to auto-layout",
|
|
);
|
|
}
|
|
|
|
log.error(error);
|
|
//update conversion form state to error
|
|
if (snapshotSaveSuccess) {
|
|
yield call(deleteApplicationSnapshotSaga);
|
|
}
|
|
yield put(
|
|
setLayoutConversionStateAction(CONVERSION_STATES.COMPLETED_ERROR, error),
|
|
);
|
|
|
|
AnalyticsUtil.logEvent("CONVERSION_FAILURE", {
|
|
flow: "CONVERT_FIXED_TO_AUTO",
|
|
appId,
|
|
});
|
|
}
|
|
}
|
|
|
|
//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
|
|
function isNotEmptyApp(pageWidgetsList: PageWidgetsReduxState) {
|
|
const pageList = Object.values(pageWidgetsList);
|
|
|
|
if (pageList.length !== 1) return true;
|
|
|
|
const { dsl: pageDSL } = pageList[0];
|
|
|
|
return Object.keys(pageDSL).length !== 1;
|
|
}
|