PromucFlow_constructor/app/client/src/sagas/layoutConversionSagas.ts
Rudraprasad Das 6045119054
feat: Shared Package for DSL based operations (#23894)
## 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>
2023-06-26 12:25:55 +05:30

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;
}