feat: reset meta widgets (#18809)
* Initial commit * reset meta widgets * Annotate code * Rehydrate meta values for meta widgets when dirty * Undo rehydration logic
This commit is contained in:
parent
a2c878e8c7
commit
8ed9d20547
|
|
@ -29,12 +29,12 @@ export const updateWidgetMetaPropAndEval = (
|
|||
|
||||
export type ResetWidgetMetaPayload = {
|
||||
widgetId: string;
|
||||
evaluatedWidget: DataTreeWidget;
|
||||
evaluatedWidget: DataTreeWidget | undefined;
|
||||
};
|
||||
|
||||
export const resetWidgetMetaProperty = (
|
||||
widgetId: string,
|
||||
evaluatedWidget: DataTreeWidget,
|
||||
evaluatedWidget: DataTreeWidget | undefined,
|
||||
): BatchAction<ResetWidgetMetaPayload> => {
|
||||
return batchAction({
|
||||
type: ReduxActionTypes.RESET_WIDGET_META,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from "@appsmith/constants/ReduxActionConstants";
|
||||
import produce from "immer";
|
||||
import { EvalMetaUpdates } from "workers/common/DataTreeEvaluator/types";
|
||||
import { klona } from "klona";
|
||||
import { getMetaWidgetResetObj } from "./metaReducerUtils";
|
||||
|
||||
export type WidgetMetaState = Record<string, unknown>;
|
||||
export type MetaState = Record<string, WidgetMetaState>;
|
||||
|
|
@ -104,25 +104,7 @@ export const metaReducer = createReducer(initialState, {
|
|||
|
||||
if (widgetId in state) {
|
||||
// only reset widgets whose meta properties were changed.
|
||||
// reset widget: sets the meta values to current default values of widget
|
||||
const resetMetaObj: WidgetMetaState = {};
|
||||
|
||||
// evaluatedWidget is widget data inside dataTree, this will have latest default values of widget
|
||||
if (evaluatedWidget) {
|
||||
const { propertyOverrideDependency } = evaluatedWidget;
|
||||
// propertyOverrideDependency has defaultProperty name for each meta property of widget
|
||||
Object.entries(propertyOverrideDependency).map(
|
||||
([propertyName, dependency]) => {
|
||||
const defaultPropertyValue =
|
||||
dependency.DEFAULT && evaluatedWidget[dependency.DEFAULT];
|
||||
if (defaultPropertyValue !== undefined) {
|
||||
// cloning data to avoid mutation
|
||||
resetMetaObj[propertyName] = klona(defaultPropertyValue);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return { ...state, [widgetId]: resetMetaObj };
|
||||
state = { ...state, [widgetId]: getMetaWidgetResetObj(evaluatedWidget) };
|
||||
}
|
||||
return state;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import { DataTreeWidget } from "entities/DataTree/dataTreeFactory";
|
||||
import { klona } from "klona";
|
||||
import { WidgetMetaState } from ".";
|
||||
|
||||
export function getMetaWidgetResetObj(
|
||||
evaluatedWidget: DataTreeWidget | undefined,
|
||||
) {
|
||||
// reset widget: sets the meta values to current default values of widget
|
||||
const resetMetaObj: WidgetMetaState = {};
|
||||
|
||||
// evaluatedWidget is widget data inside dataTree, this will have latest default values of widget
|
||||
if (evaluatedWidget) {
|
||||
const { propertyOverrideDependency } = evaluatedWidget;
|
||||
// propertyOverrideDependency has defaultProperty name for each meta property of widget
|
||||
Object.entries(propertyOverrideDependency).map(
|
||||
([propertyName, dependency]) => {
|
||||
const defaultPropertyValue =
|
||||
dependency.DEFAULT && evaluatedWidget[dependency.DEFAULT];
|
||||
if (defaultPropertyValue !== undefined) {
|
||||
// cloning data to avoid mutation
|
||||
resetMetaObj[propertyName] = klona(defaultPropertyValue);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return resetMetaObj;
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import {
|
|||
CanvasWidgetsReduxState,
|
||||
FlattenedWidgetProps,
|
||||
} from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { getWidget, getWidgets } from "./selectors";
|
||||
import { getWidget, getWidgets, getWidgetsMeta } from "./selectors";
|
||||
import {
|
||||
actionChannel,
|
||||
all,
|
||||
|
|
@ -85,7 +85,7 @@ import {
|
|||
doesTriggerPathsContainPropertyPath,
|
||||
getParentBottomRowAfterAddingWidget,
|
||||
getParentWidgetIdForPasting,
|
||||
getWidgetChildren,
|
||||
getWidgetDescendantToReset,
|
||||
groupWidgetsIntoContainer,
|
||||
handleSpecificCasesWhilePasting,
|
||||
getSelectedWidgetWhenPasting,
|
||||
|
|
@ -144,6 +144,7 @@ import { builderURL } from "RouteBuilder";
|
|||
import history from "utils/history";
|
||||
import { updateMultipleWidgetProperties } from "actions/widgetActions";
|
||||
import { generateAutoHeightLayoutTreeAction } from "actions/autoHeightActions";
|
||||
import { MetaState } from "reducers/entityReducers/metaReducer";
|
||||
|
||||
export function* updateAllChildCanvasHeights(
|
||||
currentContainerLikeWidgetId: string,
|
||||
|
|
@ -814,10 +815,12 @@ function* resetChildrenMetaSaga(action: ReduxAction<{ widgetId: string }>) {
|
|||
const { widgetId: parentWidgetId } = action.payload;
|
||||
const canvasWidgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
||||
const evaluatedDataTree: DataTree = yield select(getDataTree);
|
||||
const childrenList = getWidgetChildren(
|
||||
const widgetsMeta: MetaState = yield select(getWidgetsMeta);
|
||||
const childrenList = getWidgetDescendantToReset(
|
||||
canvasWidgets,
|
||||
parentWidgetId,
|
||||
evaluatedDataTree,
|
||||
widgetsMeta,
|
||||
);
|
||||
|
||||
for (const childIndex in childrenList) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
getWidgetMetaProps,
|
||||
getWidgets,
|
||||
} from "./selectors";
|
||||
import _, { isString, remove } from "lodash";
|
||||
import _, { find, isString, reduce, remove } from "lodash";
|
||||
import {
|
||||
CONTAINER_GRID_PADDING,
|
||||
GridDefaults,
|
||||
|
|
@ -54,6 +54,7 @@ import { getBottomRowAfterReflow } from "utils/reflowHookUtils";
|
|||
import { DataTreeWidget } from "entities/DataTree/dataTreeFactory";
|
||||
import { isWidget } from "workers/Evaluation/evaluationUtils";
|
||||
import { CANVAS_DEFAULT_MIN_HEIGHT_PX } from "constants/AppConstants";
|
||||
import { MetaState } from "reducers/entityReducers/metaReducer";
|
||||
|
||||
export interface CopiedWidgetGroup {
|
||||
widgetId: string;
|
||||
|
|
@ -301,53 +302,114 @@ export function getWidgetChildrenIds(
|
|||
}
|
||||
return childrenIds;
|
||||
}
|
||||
function sortWidgetsMetaByParent(widgetsMeta: MetaState, parentId: string) {
|
||||
return reduce(
|
||||
widgetsMeta,
|
||||
function(
|
||||
result: {
|
||||
childrenWidgetsMeta: MetaState;
|
||||
otherWidgetsMeta: MetaState;
|
||||
},
|
||||
currentWidgetMeta,
|
||||
key,
|
||||
) {
|
||||
return key.startsWith(parentId + "_")
|
||||
? {
|
||||
...result,
|
||||
childrenWidgetsMeta: {
|
||||
...result.childrenWidgetsMeta,
|
||||
[key]: currentWidgetMeta,
|
||||
},
|
||||
}
|
||||
: {
|
||||
...result,
|
||||
otherWidgetsMeta: {
|
||||
...result.otherWidgetsMeta,
|
||||
[key]: currentWidgetMeta,
|
||||
},
|
||||
};
|
||||
},
|
||||
{
|
||||
childrenWidgetsMeta: {},
|
||||
otherWidgetsMeta: {},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export type DescendantWidgetMap = {
|
||||
id: string;
|
||||
// To accomodate metaWidgets which might not be present on the evalTree, evaluatedWidget might be undefined
|
||||
evaluatedWidget: DataTreeWidget | undefined;
|
||||
};
|
||||
|
||||
export type ChildrenWidgetMap = { id: string; evaluatedWidget: DataTreeWidget };
|
||||
/**
|
||||
* getWidgetChildren: It gets all the child widgets of given widget's id with evaluated values
|
||||
*
|
||||
* As part of widget's descendant, we add both children and metaWidgets.
|
||||
* children are assessed from "widget.children"
|
||||
* metaWidgets are assessed from the metaState, since we care about only metawidgets whose values have been changed.
|
||||
* NB: metaWidgets id start with parentId + "_"
|
||||
*/
|
||||
export function getWidgetChildren(
|
||||
export function getWidgetDescendantToReset(
|
||||
canvasWidgets: CanvasWidgetsReduxState,
|
||||
widgetId: string,
|
||||
evaluatedDataTree: DataTree,
|
||||
): ChildrenWidgetMap[] {
|
||||
const childrenList: ChildrenWidgetMap[] = [];
|
||||
widgetsMeta: MetaState,
|
||||
): DescendantWidgetMap[] {
|
||||
const descendantList: DescendantWidgetMap[] = [];
|
||||
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
|
||||
if (widget === undefined) {
|
||||
return [];
|
||||
|
||||
const sortedWidgetsMeta = sortWidgetsMetaByParent(widgetsMeta, widgetId);
|
||||
for (const childMetaWidgetId of Object.keys(
|
||||
sortedWidgetsMeta.childrenWidgetsMeta,
|
||||
)) {
|
||||
const evaluatedChildWidget = find(evaluatedDataTree, function(entity) {
|
||||
return isWidget(entity) && entity.widgetId === childMetaWidgetId;
|
||||
}) as DataTreeWidget | undefined;
|
||||
descendantList.push({
|
||||
id: childMetaWidgetId,
|
||||
evaluatedWidget: evaluatedChildWidget,
|
||||
});
|
||||
const grandChildren = getWidgetDescendantToReset(
|
||||
canvasWidgets,
|
||||
childMetaWidgetId,
|
||||
evaluatedDataTree,
|
||||
sortedWidgetsMeta.otherWidgetsMeta,
|
||||
);
|
||||
if (grandChildren.length) {
|
||||
descendantList.push(...grandChildren);
|
||||
}
|
||||
}
|
||||
|
||||
const { children = [] } = widget;
|
||||
if (children && children.length) {
|
||||
for (const childIndex in children) {
|
||||
if (children.hasOwnProperty(childIndex)) {
|
||||
const childWidgetId = children[childIndex];
|
||||
if (widget) {
|
||||
const { children = [] } = widget;
|
||||
if (children && children.length) {
|
||||
for (const childIndex in children) {
|
||||
if (children.hasOwnProperty(childIndex)) {
|
||||
const childWidgetId = children[childIndex];
|
||||
|
||||
const childCanvasWidget = _.get(canvasWidgets, childWidgetId);
|
||||
const childWidgetName = childCanvasWidget.widgetName;
|
||||
const childWidget = evaluatedDataTree[childWidgetName];
|
||||
if (isWidget(childWidget)) {
|
||||
childrenList.push({
|
||||
id: childWidgetId,
|
||||
evaluatedWidget: childWidget,
|
||||
});
|
||||
const grandChildren = getWidgetChildren(
|
||||
canvasWidgets,
|
||||
childWidgetId,
|
||||
evaluatedDataTree,
|
||||
);
|
||||
if (grandChildren.length) {
|
||||
childrenList.push(...grandChildren);
|
||||
const childCanvasWidget = _.get(canvasWidgets, childWidgetId);
|
||||
const childWidgetName = childCanvasWidget.widgetName;
|
||||
const childWidget = evaluatedDataTree[childWidgetName];
|
||||
if (isWidget(childWidget)) {
|
||||
descendantList.push({
|
||||
id: childWidgetId,
|
||||
evaluatedWidget: childWidget,
|
||||
});
|
||||
const grandChildren = getWidgetDescendantToReset(
|
||||
canvasWidgets,
|
||||
childWidgetId,
|
||||
evaluatedDataTree,
|
||||
sortedWidgetsMeta.otherWidgetsMeta,
|
||||
);
|
||||
if (grandChildren.length) {
|
||||
descendantList.push(...grandChildren);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return childrenList;
|
||||
|
||||
return descendantList;
|
||||
}
|
||||
|
||||
export const getParentWidgetIdForPasting = function*(
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user