PromucFlow_constructor/app/client/src/sagas/WidgetOperationUtils.ts
Pawan Kumar 91bf527bea
List Widget Phase 2 (#4189)
* update  meta properties + default properties map

* update widget registery

* update get meta property

* update metahoc + widgetfactory + data tree evaluator

* try sending function as string to worker

* revert data tree evaluator update

* pass default props map from dataTreeWidget file

* wip

* save child meta properties

* remove console.log

* save meta and default map in list

* update listwidget

* remove console.log + unused variables

* revert getMetaPropertiesMap function

* fix data tree test

* fix list widget test

* fix entity definition test

* fix overriting of item in updatedItems

* remove todo comments

* fix meta prop issue

* revert making meta properties from undefiend to "" & fix filepicker bug

* fix test case

* change items to listData and updatedItems to items

* remove console.log

* fix test

* extract derived properties to dervied.js

* disabled top, left, right resize handler list widget container

* add test for dervied js

* add test for selectedItem

* fix background color bug on hover

* remove console.log

* fix chart widget inside list widget

* fix checkbox issue + points raised by yogesh

* revert the createImmerReducer usage

* fix parse derived properties

* remove internal props object that fails the test

* fix import typo

* allow bottom resize handler

* fix template height check

* fix template height check

* update template size check

* fix the is visible invalid prop issue

* fix migration of list widget phase 2

* fix migration

* remove unused import

* fix migration

* fix migration

* remove console.log

* hide delete option for container in entity explorer

* fix testcases

* remove unused import

* fix switch widget meta prop

Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain>
Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-06-18 13:12:57 +05:30

227 lines
6.5 KiB
TypeScript

import {
MAIN_CONTAINER_WIDGET_ID,
WidgetTypes,
} from "constants/WidgetConstants";
import { cloneDeep, get, isString, filter, set } from "lodash";
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import { call, select } from "redux-saga/effects";
import { getDynamicBindings } from "utils/DynamicBindingUtils";
import { getWidget } from "./selectors";
/**
* checks if triggerpaths contains property path passed
*
* @param isTriggerProperty
* @param propertyPath
* @param triggerPaths
* @returns
*/
export const doesTriggerPathsContainPropertyPath = (
isTriggerProperty: boolean,
propertyPath: string,
triggerPaths?: string[],
) => {
if (!isTriggerProperty) {
if (
triggerPaths &&
triggerPaths.length &&
triggerPaths.includes(propertyPath)
) {
return true;
}
}
return isTriggerProperty;
};
/**
*
* check if copied widget is being pasted in list widget,
* if yes, change all keys in template of list widget and
* update dynamicBindingPathList of ListWidget
*
* updates in list widget :
* 1. `dynamicBindingPathList`
* 2. `template`
*
* @param widget
* @param widgets
*/
export const handleIfParentIsListWidgetWhilePasting = (
widget: FlattenedWidgetProps,
widgets: { [widgetId: string]: FlattenedWidgetProps },
): { [widgetId: string]: FlattenedWidgetProps } => {
let root = get(widgets, `${widget.parentId}`);
while (root && root.parentId && root.widgetId !== MAIN_CONTAINER_WIDGET_ID) {
if (root.type === WidgetTypes.LIST_WIDGET) {
const listWidget = root;
const currentWidget = cloneDeep(widget);
let template = get(listWidget, "template", {});
const dynamicBindingPathList: any[] = get(
listWidget,
"dynamicBindingPathList",
[],
).slice();
// iterating over each keys of the new createdWidget checking if value contains currentItem
const keys = Object.keys(currentWidget);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
let value = currentWidget[key];
if (isString(value) && value.indexOf("currentItem") > -1) {
const { jsSnippets } = getDynamicBindings(value);
const modifiedAction = jsSnippets.reduce(
(prev: string, next: string) => {
return prev + `${next}`;
},
"",
);
value = `{{${listWidget.widgetName}.listData.map((currentItem) => ${modifiedAction})}}`;
currentWidget[key] = value;
dynamicBindingPathList.push({
key: `template.${currentWidget.widgetName}.${key}`,
});
}
}
template = {
...template,
[currentWidget.widgetName]: currentWidget,
};
// now we have updated `dynamicBindingPathList` and updatedTemplate
// we need to update it the list widget
widgets[listWidget.widgetId] = {
...listWidget,
template,
dynamicBindingPathList,
};
}
root = widgets[root.parentId];
}
return widgets;
};
/**
* this saga handles special cases when pasting the widget
*
* for e.g - when the list widget is being copied, we want to update template of list widget
* with new widgets name
*
* @param widget
* @param widgets
* @param widgetNameMap
* @param newWidgetList
* @returns
*/
export const handleSpecificCasesWhilePasting = (
widget: FlattenedWidgetProps,
widgets: { [widgetId: string]: FlattenedWidgetProps },
widgetNameMap: Record<string, string>,
newWidgetList: FlattenedWidgetProps[],
) => {
// this is the case when whole list widget is copied and pasted
if (widget.type === WidgetTypes.LIST_WIDGET) {
Object.keys(widget.template).map((widgetName) => {
const oldWidgetName = widgetName;
const newWidgetName = widgetNameMap[oldWidgetName];
const newWidget = newWidgetList.find(
(w: any) => w.widgetName === newWidgetName,
);
if (newWidget) {
newWidget.widgetName = newWidgetName;
if (widgetName === oldWidgetName) {
widget.template[newWidgetName] = {
...widget.template[oldWidgetName],
widgetId: newWidget.widgetId,
widgetName: newWidget.widgetName,
};
delete widget.template[oldWidgetName];
}
}
// updating dynamicBindingPath in copied widget if the copied widge thas reference to oldWidgetNames
widget.dynamicBindingPathList = (widget.dynamicBindingPathList || []).map(
(path: any) => {
if (path.key.startsWith(`template.${oldWidgetName}`)) {
return {
key: path.key.replace(
`template.${oldWidgetName}`,
`template.${newWidgetName}`,
),
};
}
return path;
},
);
});
widgets[widget.widgetId] = widget;
} else if (widget.type === WidgetTypes.MODAL_WIDGET) {
// if Modal is being coppied handle all onClose action rename
const oldWidgetName = Object.keys(widgetNameMap).find(
(key) => widgetNameMap[key] === widget.widgetName,
);
// get all the button, icon widgets
const copiedBtnIcnWidgets = filter(
newWidgetList,
(copyWidget) =>
copyWidget.type === "BUTTON_WIDGET" ||
copyWidget.type === "ICON_WIDGET",
);
// replace oldName with new one if any of this widget have onClick action for old modal
copiedBtnIcnWidgets.map((copyWidget) => {
if (copyWidget.onClick) {
const newOnClick = widgets[copyWidget.widgetId].onClick.replace(
oldWidgetName,
widget.widgetName,
);
set(widgets[copyWidget.widgetId], "onClick", newOnClick);
}
});
}
widgets = handleIfParentIsListWidgetWhilePasting(widget, widgets);
return widgets;
};
export function* getWidgetChildren(widgetId: string): any {
const childrenIds: string[] = [];
const widget = yield select(getWidget, 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
if (widget === undefined) {
return [];
}
const { children = [] } = widget;
if (children && children.length) {
for (const childIndex in children) {
if (children.hasOwnProperty(childIndex)) {
const child = children[childIndex];
childrenIds.push(child);
const grandChildren = yield call(getWidgetChildren, child);
if (grandChildren.length) {
childrenIds.push(...grandChildren);
}
}
}
}
return childrenIds;
}