Fix: App crash on list widget after copy/paste (#5605)

* fix list widget in list widget bug when pasting

* remove console.log

* add test

Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain>
(cherry picked from commit fa4e42f4c6)
This commit is contained in:
Pawan Kumar 2021-07-06 12:24:34 +05:30 committed by root
parent be05a1bc26
commit df4cfb99ab
3 changed files with 118 additions and 13 deletions

View File

@ -1301,7 +1301,11 @@ const unsetPropertyPath = (obj: Record<string, unknown>, path: string) => {
function* resetChildrenMetaSaga(action: ReduxAction<{ widgetId: string }>) { function* resetChildrenMetaSaga(action: ReduxAction<{ widgetId: string }>) {
const parentWidgetId = action.payload.widgetId; const parentWidgetId = action.payload.widgetId;
const childrenIds: string[] = yield call(getWidgetChildren, parentWidgetId); const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
const childrenIds: string[] = getWidgetChildren(
canvasWidgets,
parentWidgetId,
);
for (const childIndex in childrenIds) { for (const childIndex in childrenIds) {
const childId = childrenIds[childIndex]; const childId = childrenIds[childIndex];
yield put(resetWidgetMetaProperty(childId)); yield put(resetWidgetMetaProperty(childId));
@ -1483,6 +1487,7 @@ function* pasteWidgetSaga() {
parentId: string; parentId: string;
list: WidgetProps[]; list: WidgetProps[];
}[] = yield getCopiedWidgets(); }[] = yield getCopiedWidgets();
if (!Array.isArray(copiedWidgetGroups)) { if (!Array.isArray(copiedWidgetGroups)) {
return; return;
// to avoid invoking old copied widgets // to avoid invoking old copied widgets
@ -1492,12 +1497,17 @@ function* pasteWidgetSaga() {
getSelectedWidget, getSelectedWidget,
); );
selectedWidget = yield checkIfPastingIntoListWidget(
stateWidgets,
selectedWidget,
copiedWidgetGroups,
);
const pastingIntoWidgetId: string = yield getParentWidgetIdForPasting( const pastingIntoWidgetId: string = yield getParentWidgetIdForPasting(
{ ...stateWidgets }, { ...stateWidgets },
selectedWidget, selectedWidget,
); );
selectedWidget = yield checkIfPastingIntoListWidget(selectedWidget);
let widgets = { ...stateWidgets }; let widgets = { ...stateWidgets };
const newlyCreatedWidgetIds: string[] = []; const newlyCreatedWidgetIds: string[] = [];
const sortedWidgetList = copiedWidgetGroups.sort( const sortedWidgetList = copiedWidgetGroups.sort(

View File

@ -3,6 +3,7 @@ import {
handleIfParentIsListWidgetWhilePasting, handleIfParentIsListWidgetWhilePasting,
handleSpecificCasesWhilePasting, handleSpecificCasesWhilePasting,
doesTriggerPathsContainPropertyPath, doesTriggerPathsContainPropertyPath,
checkIfPastingIntoListWidget,
} from "./WidgetOperationUtils"; } from "./WidgetOperationUtils";
describe("WidgetOperationSaga", () => { describe("WidgetOperationSaga", () => {
@ -384,4 +385,75 @@ describe("WidgetOperationSaga", () => {
"{{closeModal('Modal1Copy')}}", "{{closeModal('Modal1Copy')}}",
); );
}); });
it("should returns widgets after executing checkIfPastingIntoListWidget", async () => {
const result = checkIfPastingIntoListWidget(
{
list2: {
widgetId: "list2",
type: "LIST_WIDGET",
widgetName: "List2",
parentId: "0",
renderMode: "CANVAS",
parentColumnSpace: 2,
parentRowSpace: 3,
leftColumn: 2,
rightColumn: 3,
topRow: 1,
bottomRow: 3,
isLoading: false,
listData: [],
version: 16,
disablePropertyPane: false,
template: {},
},
},
{
widgetId: "list2",
type: "LIST_WIDGET",
widgetName: "List2",
parentId: "0",
renderMode: "CANVAS",
parentColumnSpace: 2,
parentRowSpace: 3,
leftColumn: 2,
rightColumn: 3,
topRow: 1,
bottomRow: 3,
isLoading: false,
listData: [],
version: 16,
disablePropertyPane: false,
template: {},
},
[
{
widgetId: "list2",
parentId: "0",
list: [
{
widgetId: "list2",
type: "LIST_WIDGET",
widgetName: "List2",
parentId: "0",
renderMode: "CANVAS",
parentColumnSpace: 2,
parentRowSpace: 3,
leftColumn: 2,
rightColumn: 3,
topRow: 1,
bottomRow: 3,
isLoading: false,
listData: [],
version: 16,
disablePropertyPane: false,
template: {},
},
],
},
],
);
expect(result?.type).toStrictEqual("LIST_WIDGET");
});
}); });

View File

@ -7,9 +7,10 @@ import {
CanvasWidgetsReduxState, CanvasWidgetsReduxState,
FlattenedWidgetProps, FlattenedWidgetProps,
} from "reducers/entityReducers/canvasWidgetsReducer"; } from "reducers/entityReducers/canvasWidgetsReducer";
import { call, select } from "redux-saga/effects"; import { select } from "redux-saga/effects";
import { getDynamicBindings } from "utils/DynamicBindingUtils"; import { getDynamicBindings } from "utils/DynamicBindingUtils";
import { getWidget, getWidgetMetaProps } from "./selectors"; import { WidgetProps } from "widgets/BaseWidget";
import { getWidgetMetaProps } from "./selectors";
/** /**
* checks if triggerpaths contains property path passed * checks if triggerpaths contains property path passed
@ -203,9 +204,12 @@ export const handleSpecificCasesWhilePasting = (
return widgets; return widgets;
}; };
export function* getWidgetChildren(widgetId: string): any { export function getWidgetChildren(
canvasWidgets: CanvasWidgetsReduxState,
widgetId: string,
): any {
const childrenIds: string[] = []; const childrenIds: string[] = [];
const widget = yield select(getWidget, widgetId); const widget = get(canvasWidgets, widgetId);
// When a form widget tries to resetChildrenMetaProperties // When a form widget tries to resetChildrenMetaProperties
// But one or more of its container like children // But one or more of its container like children
// have just been deleted, widget can be undefined // have just been deleted, widget can be undefined
@ -218,7 +222,7 @@ export function* getWidgetChildren(widgetId: string): any {
if (children.hasOwnProperty(childIndex)) { if (children.hasOwnProperty(childIndex)) {
const child = children[childIndex]; const child = children[childIndex];
childrenIds.push(child); childrenIds.push(child);
const grandChildren = yield call(getWidgetChildren, child); const grandChildren = getWidgetChildren(canvasWidgets, child);
if (grandChildren.length) { if (grandChildren.length) {
childrenIds.push(...grandChildren); childrenIds.push(...grandChildren);
} }
@ -251,8 +255,11 @@ export const getParentWidgetIdForPasting = function*(
newWidgetParentId = selectedWidget.parentId; newWidgetParentId = selectedWidget.parentId;
} }
} }
// Select the selected widget if the widget is container like // Select the selected widget if the widget is container like ( excluding list widget )
if (selectedWidget.children) { if (
selectedWidget.children &&
selectedWidget.type !== WidgetTypes.LIST_WIDGET
) {
parentWidget = widgets[selectedWidget.widgetId]; parentWidget = widgets[selectedWidget.widgetId];
} }
} }
@ -289,8 +296,14 @@ export const getParentWidgetIdForPasting = function*(
return newWidgetParentId; return newWidgetParentId;
}; };
export const checkIfPastingIntoListWidget = function*( export const checkIfPastingIntoListWidget = function(
canvasWidgets: CanvasWidgetsReduxState,
selectedWidget: FlattenedWidgetProps | undefined, selectedWidget: FlattenedWidgetProps | undefined,
copiedWidgets: {
widgetId: string;
parentId: string;
list: WidgetProps[];
}[],
) { ) {
// when list widget is selected, if the user is pasting, we want it to be pasted in the template // when list widget is selected, if the user is pasting, we want it to be pasted in the template
// which is first children of list widget // which is first children of list widget
@ -299,13 +312,23 @@ export const checkIfPastingIntoListWidget = function*(
selectedWidget.children && selectedWidget.children &&
selectedWidget?.type === WidgetTypes.LIST_WIDGET selectedWidget?.type === WidgetTypes.LIST_WIDGET
) { ) {
const childrenIds: string[] = yield call( const childrenIds: string[] = getWidgetChildren(
getWidgetChildren, canvasWidgets,
selectedWidget.children[0], selectedWidget.children[0],
); );
const firstChildId = childrenIds[0]; const firstChildId = childrenIds[0];
selectedWidget = yield select(getWidget, firstChildId); // if any copiedWidget is a list widget, we will paste into the parent of list widget
for (let i = 0; i < copiedWidgets.length; i++) {
const copiedWidgetId = copiedWidgets[i].widgetId;
const copiedWidget = canvasWidgets[copiedWidgetId];
if (copiedWidget.type === WidgetTypes.LIST_WIDGET) {
return selectedWidget;
}
}
return get(canvasWidgets, firstChildId);
} }
return selectedWidget; return selectedWidget;
}; };