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>
This commit is contained in:
Pawan Kumar 2021-07-06 12:24:34 +05:30 committed by GitHub
parent ca87b692bd
commit fa4e42f4c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 }>) {
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) {
const childId = childrenIds[childIndex];
yield put(resetWidgetMetaProperty(childId));
@ -1483,6 +1487,7 @@ function* pasteWidgetSaga() {
parentId: string;
list: WidgetProps[];
}[] = yield getCopiedWidgets();
if (!Array.isArray(copiedWidgetGroups)) {
return;
// to avoid invoking old copied widgets
@ -1492,12 +1497,17 @@ function* pasteWidgetSaga() {
getSelectedWidget,
);
selectedWidget = yield checkIfPastingIntoListWidget(
stateWidgets,
selectedWidget,
copiedWidgetGroups,
);
const pastingIntoWidgetId: string = yield getParentWidgetIdForPasting(
{ ...stateWidgets },
selectedWidget,
);
selectedWidget = yield checkIfPastingIntoListWidget(selectedWidget);
let widgets = { ...stateWidgets };
const newlyCreatedWidgetIds: string[] = [];
const sortedWidgetList = copiedWidgetGroups.sort(

View File

@ -3,6 +3,7 @@ import {
handleIfParentIsListWidgetWhilePasting,
handleSpecificCasesWhilePasting,
doesTriggerPathsContainPropertyPath,
checkIfPastingIntoListWidget,
} from "./WidgetOperationUtils";
describe("WidgetOperationSaga", () => {
@ -384,4 +385,75 @@ describe("WidgetOperationSaga", () => {
"{{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,
FlattenedWidgetProps,
} from "reducers/entityReducers/canvasWidgetsReducer";
import { call, select } from "redux-saga/effects";
import { select } from "redux-saga/effects";
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
@ -203,9 +204,12 @@ export const handleSpecificCasesWhilePasting = (
return widgets;
};
export function* getWidgetChildren(widgetId: string): any {
export function getWidgetChildren(
canvasWidgets: CanvasWidgetsReduxState,
widgetId: string,
): any {
const childrenIds: string[] = [];
const widget = yield select(getWidget, widgetId);
const widget = get(canvasWidgets, widgetId);
// When a form widget tries to resetChildrenMetaProperties
// But one or more of its container like children
// have just been deleted, widget can be undefined
@ -218,7 +222,7 @@ export function* getWidgetChildren(widgetId: string): any {
if (children.hasOwnProperty(childIndex)) {
const child = children[childIndex];
childrenIds.push(child);
const grandChildren = yield call(getWidgetChildren, child);
const grandChildren = getWidgetChildren(canvasWidgets, child);
if (grandChildren.length) {
childrenIds.push(...grandChildren);
}
@ -251,8 +255,11 @@ export const getParentWidgetIdForPasting = function*(
newWidgetParentId = selectedWidget.parentId;
}
}
// Select the selected widget if the widget is container like
if (selectedWidget.children) {
// Select the selected widget if the widget is container like ( excluding list widget )
if (
selectedWidget.children &&
selectedWidget.type !== WidgetTypes.LIST_WIDGET
) {
parentWidget = widgets[selectedWidget.widgetId];
}
}
@ -289,8 +296,14 @@ export const getParentWidgetIdForPasting = function*(
return newWidgetParentId;
};
export const checkIfPastingIntoListWidget = function*(
export const checkIfPastingIntoListWidget = function(
canvasWidgets: CanvasWidgetsReduxState,
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
// which is first children of list widget
@ -299,13 +312,23 @@ export const checkIfPastingIntoListWidget = function*(
selectedWidget.children &&
selectedWidget?.type === WidgetTypes.LIST_WIDGET
) {
const childrenIds: string[] = yield call(
getWidgetChildren,
const childrenIds: string[] = getWidgetChildren(
canvasWidgets,
selectedWidget.children[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;
};