diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27119_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27119_Spec.ts new file mode 100644 index 0000000000..ed2067b4d3 --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/Bug27119_Spec.ts @@ -0,0 +1,83 @@ +import { + entityExplorer, + propPane, + draggableWidgets, + agHelper, + deployMode, + locators, + jsEditor, +} from "../../../../support/Objects/ObjectsCore"; + +describe("Reset widget action", () => { + it("Reset widget to default after setValue has been applied", () => { + entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2); + propPane.UpdatePropertyFieldValue("Default value", "John"); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 300, 300); + propPane.EnterJSContext("onClick", `{{Input1.setValue('Hello!')}}`); + propPane.UpdatePropertyFieldValue("Label", "Set value"); + + entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 500, 100); + propPane.EnterJSContext("onClick", `{{resetWidget("Input1")}}`); + propPane.UpdatePropertyFieldValue("Label", "Reset value"); + + deployMode.DeployApp(); + + agHelper.ClickButton("Set value"); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "Hello!", + ); + + agHelper.ClickButton("Reset value"); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "John", + ); + + agHelper.ClearNType( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "Testing", + ); + agHelper.ClickButton("Reset value"); + agHelper.AssertText( + locators._widgetInDeployed(draggableWidgets.INPUT_V2) + " input", + "val", + "John", + ); + }); + it("Reset value is accessible after 'awaiting'", () => { + deployMode.NavigateBacktoEditor(); + agHelper.ClearNType(locators._input, "Meta Text"); + + const JS_OBJECT_BODY = `export default { + async resetInputWithoutAwait () { + resetWidget('Input1') + showAlert(Input1.text) + }, + async resetInputWithAwait () { + await resetWidget('Input1') + showAlert(Input1.text) + } + }`; + + // Create js object + jsEditor.CreateJSObject(JS_OBJECT_BODY, { + paste: true, + completeReplace: true, + toRun: false, + prettify: false, + shouldCreateNewJSObj: true, + }); + agHelper.Sleep(4000); + jsEditor.SelectFunctionDropdown("resetInputWithoutAwait"); + agHelper.ClickButton("Run"); + agHelper.AssertContains("Meta Text"); + + jsEditor.SelectFunctionDropdown("resetInputWithAwait"); + agHelper.ClickButton("Run"); + agHelper.AssertContains("John"); + }); +}); diff --git a/app/client/src/actions/metaActions.ts b/app/client/src/actions/metaActions.ts index 779002e734..d8fda7e68c 100644 --- a/app/client/src/actions/metaActions.ts +++ b/app/client/src/actions/metaActions.ts @@ -55,6 +55,18 @@ export const resetWidgetMetaProperty = ( }); }; +export const resetWidgetMetaUpdates = ( + evalMetaUpdates: EvalMetaUpdates, +): BatchAction => { + return batchAction({ + type: ReduxActionTypes.RESET_WIDGET_META_UPDATES, + payload: { + evalMetaUpdates, + }, + postEvalActions: [{ type: ReduxActionTypes.RESET_WIDGET_META_EVALUATED }], + }); +}; + export const resetChildrenMetaProperty = ( widgetId: string, ): ReduxAction<{ widgetId: string }> => { diff --git a/app/client/src/ce/actions/evaluationActionsList.ts b/app/client/src/ce/actions/evaluationActionsList.ts index 8903308f7f..7c142060d3 100644 --- a/app/client/src/ce/actions/evaluationActionsList.ts +++ b/app/client/src/ce/actions/evaluationActionsList.ts @@ -90,6 +90,7 @@ export const EVALUATE_REDUX_ACTIONS = [ ReduxActionTypes.SET_META_PROP_AND_EVAL, ReduxActionTypes.META_UPDATE_DEBOUNCED_EVAL, ReduxActionTypes.RESET_WIDGET_META, + ReduxActionTypes.RESET_WIDGET_META_UPDATES, // Batches ReduxActionTypes.BATCH_UPDATES_SUCCESS, // App Theme diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx index 86b129f162..edeba59a95 100644 --- a/app/client/src/ce/constants/ReduxActionConstants.tsx +++ b/app/client/src/ce/constants/ReduxActionConstants.tsx @@ -426,6 +426,7 @@ const ActionTypes = { META_UPDATE_DEBOUNCED_EVAL: "META_UPDATE_DEBOUNCED_EVAL", RESET_CHILDREN_WIDGET_META: "RESET_CHILDREN_WIDGET_META", RESET_WIDGET_META: "RESET_WIDGET_META", + RESET_WIDGET_META_UPDATES: "RESET_WIDGET_META_UPDATES", RESET_WIDGET_META_EVALUATED: "RESET_WIDGET_META_EVALUATED", RESET_WIDGETS_META_STATE: "RESET_WIDGETS_META_STATE", UPDATE_WIDGET_NAME_INIT: "UPDATE_WIDGET_NAME_INIT", diff --git a/app/client/src/entities/DataTree/dataTreeWidget.ts b/app/client/src/entities/DataTree/dataTreeWidget.ts index a703614945..7212413591 100644 --- a/app/client/src/entities/DataTree/dataTreeWidget.ts +++ b/app/client/src/entities/DataTree/dataTreeWidget.ts @@ -368,7 +368,6 @@ export const generateDataTreeWidget = ( // overridingMetaProps maps properties that can be overriden by either default values or meta changes to initial values. // initial value is set to metaProps value or defaultMetaProps value. - Object.entries(defaultMetaProps).forEach(([key, value]) => { if (overridingMetaPropsMap[key]) { overridingMetaProps[key] = diff --git a/app/client/src/reducers/entityReducers/metaReducer/index.ts b/app/client/src/reducers/entityReducers/metaReducer/index.ts index e415e6496b..b0486211fa 100644 --- a/app/client/src/reducers/entityReducers/metaReducer/index.ts +++ b/app/client/src/reducers/entityReducers/metaReducer/index.ts @@ -13,7 +13,11 @@ import { } from "@appsmith/constants/ReduxActionConstants"; import produce from "immer"; import type { EvalMetaUpdates } from "@appsmith/workers/common/DataTreeEvaluator/types"; -import { getMetaWidgetResetObj } from "./metaReducerUtils"; +import { + getMetaWidgetResetObj, + getNextMetaStateWithUpdates, + setMetaValuesOnResetFromEval, +} from "./metaReducerUtils"; import type { WidgetEntityConfig } from "@appsmith/entities/DataTree/types"; export type WidgetMetaState = Record; @@ -28,18 +32,7 @@ export const metaReducer = createReducer(initialState, { evalMetaUpdates: EvalMetaUpdates; }>, ) => { - const { evalMetaUpdates } = action.payload; - - if (!evalMetaUpdates.length) return state; - - // if metaObject is updated in dataTree we also update meta values, to keep meta state in sync. - const newMetaState = produce(state, (draftMetaState) => { - evalMetaUpdates.forEach(({ metaPropertyPath, value, widgetId }) => { - set(draftMetaState, [widgetId, ...metaPropertyPath], value); - }); - return draftMetaState; - }); - return newMetaState; + return getNextMetaStateWithUpdates(state, action); }, [ReduxActionTypes.SET_META_PROP]: ( state: MetaState, @@ -132,6 +125,14 @@ export const metaReducer = createReducer(initialState, { } return state; }, + [ReduxActionTypes.RESET_WIDGET_META_UPDATES]: ( + state: MetaState, + action: ReduxAction<{ + evalMetaUpdates: EvalMetaUpdates; + }>, + ) => { + return setMetaValuesOnResetFromEval(state, action); + }, [ReduxActionTypes.RESET_WIDGETS_META_STATE]: ( state: MetaState, action: ReduxAction<{ widgetIdsToClear: string[] }>, diff --git a/app/client/src/reducers/entityReducers/metaReducer/metaReducerUtils.ts b/app/client/src/reducers/entityReducers/metaReducer/metaReducerUtils.ts index fc26ebafca..3f988ac6b9 100644 --- a/app/client/src/reducers/entityReducers/metaReducer/metaReducerUtils.ts +++ b/app/client/src/reducers/entityReducers/metaReducer/metaReducerUtils.ts @@ -4,7 +4,11 @@ import type { PropertyOverrideDependency, } from "@appsmith/entities/DataTree/types"; import { klona } from "klona"; -import type { WidgetMetaState } from "."; +import type { MetaState, WidgetMetaState } from "."; +import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants"; +import type { EvalMetaUpdates } from "@appsmith/workers/common/DataTreeEvaluator/types"; +import produce from "immer"; +import { set, unset } from "lodash"; export function getMetaWidgetResetObj( evaluatedWidget: WidgetEntity | undefined, @@ -30,3 +34,50 @@ export function getMetaWidgetResetObj( } return resetMetaObj; } + +/** + * When resetWidget is called from eval, we update all the meta values and remove those meta values which are undefined + */ +export function setMetaValuesOnResetFromEval( + state: MetaState, + action: ReduxAction<{ + evalMetaUpdates: EvalMetaUpdates; + }>, +) { + const { evalMetaUpdates } = action.payload; + + if (!evalMetaUpdates.length) return state; + + const newMetaState = klona(state); + + evalMetaUpdates.forEach(({ metaPropertyPath, value, widgetId }) => { + if (value === undefined) { + unset(newMetaState, `${widgetId}.${metaPropertyPath.join(".")}`); + } else { + set(newMetaState, [widgetId, ...metaPropertyPath], value); + } + }); + + return newMetaState; +} + +export function getNextMetaStateWithUpdates( + state: MetaState, + action: ReduxAction<{ + evalMetaUpdates: EvalMetaUpdates; + }>, +) { + const { evalMetaUpdates } = action.payload; + + if (!evalMetaUpdates.length) return state; + + // if metaObject is updated in dataTree we also update meta values, to keep meta state in sync. + const newMetaState = produce(state, (draftMetaState) => { + evalMetaUpdates.forEach(({ metaPropertyPath, value, widgetId }) => { + set(draftMetaState, [widgetId, ...metaPropertyPath], value); + }); + return draftMetaState; + }); + + return newMetaState; +} diff --git a/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts b/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts index e71fce0013..08d7c8c1a5 100644 --- a/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts +++ b/app/client/src/sagas/ActionExecution/ResetWidgetActionSaga.ts @@ -1,10 +1,7 @@ import { put, select, take } from "redux-saga/effects"; import { getWidgetByName } from "sagas/selectors"; -import { - resetChildrenMetaProperty, - resetWidgetMetaProperty, -} from "actions/metaActions"; -import AppsmithConsole from "utils/AppsmithConsole"; +import { resetWidgetMetaUpdates } from "actions/metaActions"; + import { ActionValidationError, TriggerFailureError, @@ -12,20 +9,15 @@ import { import { getType, Types } from "utils/TypeHelpers"; import type { FlattenedWidgetProps } from "WidgetProvider/constants"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; -import { getDataTree, getConfigTree } from "selectors/dataTreeSelectors"; -import type { - WidgetEntity, - WidgetEntityConfig, -} from "@appsmith/entities/DataTree/types"; -import type { DataTree, ConfigTree } from "entities/DataTree/dataTreeTypes"; -import { isWidget } from "@appsmith/workers/Evaluation/evaluationUtils"; import type { TResetWidgetDescription } from "workers/Evaluation/fns/resetWidget"; +import AppsmithConsole from "utils/AppsmithConsole"; export default function* resetWidgetActionSaga( action: TResetWidgetDescription, ) { const { payload } = action; - const { widgetName } = payload; + const { metaUpdates, widgetName } = payload; + if (getType(widgetName) !== Types.STRING) { throw new ActionValidationError( "RESET_WIDGET_META_RECURSIVE_BY_NAME", @@ -34,8 +26,6 @@ export default function* resetWidgetActionSaga( getType(widgetName), ); } - const dataTree: DataTree = yield select(getDataTree); - const configTree: ConfigTree = yield select(getConfigTree); const widget: FlattenedWidgetProps | undefined = yield select( getWidgetByName, @@ -44,23 +34,10 @@ export default function* resetWidgetActionSaga( if (!widget) { throw new TriggerFailureError(`Widget ${payload.widgetName} not found`); } - const evaluatedEntity = dataTree[widget.widgetName]; - const evaluatedEntityConfig = configTree[widget.widgetName]; - if (isWidget(evaluatedEntity)) { - yield put( - resetWidgetMetaProperty( - widget.widgetId, - evaluatedEntity as WidgetEntity, - evaluatedEntityConfig as WidgetEntityConfig, - ), - ); - if (payload.resetChildren) { - yield put(resetChildrenMetaProperty(widget.widgetId)); - } - } + + yield put(resetWidgetMetaUpdates(metaUpdates)); yield take(ReduxActionTypes.RESET_WIDGET_META_EVALUATED); - AppsmithConsole.info({ text: `resetWidget('${payload.widgetName}', ${payload.resetChildren}) was triggered`, }); diff --git a/app/client/src/sagas/BatchSagas.tsx b/app/client/src/sagas/BatchSagas.tsx index e915edc358..7ebf778604 100644 --- a/app/client/src/sagas/BatchSagas.tsx +++ b/app/client/src/sagas/BatchSagas.tsx @@ -19,6 +19,10 @@ const BATCH_PRIORITY = { priority: 0, needsSaga: false, }, + [ReduxActionTypes.RESET_WIDGET_META_UPDATES]: { + priority: 0, + needsSaga: false, + }, [ReduxActionTypes.UPDATE_WIDGET_PROPERTY]: { priority: 0, needsSaga: false, diff --git a/app/client/src/sagas/EvaluationsSaga.ts b/app/client/src/sagas/EvaluationsSaga.ts index 50284f1fc2..3dcf99bbd2 100644 --- a/app/client/src/sagas/EvaluationsSaga.ts +++ b/app/client/src/sagas/EvaluationsSaga.ts @@ -22,7 +22,7 @@ import { getDataTree, getUnevaluatedDataTree, } from "selectors/dataTreeSelectors"; -import { getMetaWidgets, getWidgets } from "sagas/selectors"; +import { getMetaWidgets, getWidgets, getWidgetsMeta } from "sagas/selectors"; import type { WidgetTypeConfigMap } from "WidgetProvider/factory"; import WidgetFactory from "WidgetProvider/factory"; import { GracefulWorkerService } from "utils/WorkerUtil"; @@ -260,6 +260,8 @@ export function* evaluateTreeSaga( PerformanceTransactionName.DATA_TREE_EVALUATION, ); const appMode: ReturnType = yield select(getAppMode); + const widgetsMeta: ReturnType = + yield select(getWidgetsMeta); const evalTreeRequestData: EvalTreeRequestData = { unevalTree: unEvalAndConfigTree, @@ -271,6 +273,7 @@ export function* evaluateTreeSaga( forceEvaluation, metaWidgets, appMode, + widgetsMeta, }; const workerResponse: EvalTreeResponseData = yield call( diff --git a/app/client/src/workers/Evaluation/__tests__/Actions.test.ts b/app/client/src/workers/Evaluation/__tests__/Actions.test.ts index ec0cd7bb2e..f91509e0d5 100644 --- a/app/client/src/workers/Evaluation/__tests__/Actions.test.ts +++ b/app/client/src/workers/Evaluation/__tests__/Actions.test.ts @@ -309,7 +309,6 @@ describe("Add functions", () => { it("resetWidget works", () => { const widgetName = "widget1"; const resetChildren = true; - expect(evalContext.resetWidget(widgetName, resetChildren)).resolves.toBe( {}, ); @@ -323,6 +322,7 @@ describe("Add functions", () => { payload: { widgetName, resetChildren, + metaUpdates: [], }, }, eventType: undefined, diff --git a/app/client/src/workers/Evaluation/fns/resetWidget.ts b/app/client/src/workers/Evaluation/fns/resetWidget.ts index 05710f14ee..e2b126a701 100644 --- a/app/client/src/workers/Evaluation/fns/resetWidget.ts +++ b/app/client/src/workers/Evaluation/fns/resetWidget.ts @@ -1,22 +1,284 @@ import { promisify } from "./utils/Promisify"; -function resetWidgetFnDescriptor(widgetName: string, resetChildren = true) { +import type { FlattenedWidgetProps } from "WidgetProvider/constants"; +import { + canvasWidgets, + dataTreeEvaluator, + canvasWidgetsMeta, +} from "../handlers/evalTree"; +import _ from "lodash"; +import type { + WidgetEntityConfig, + WidgetEntity, +} from "@appsmith/entities/DataTree/types"; +import { isWidget } from "@appsmith/workers/Evaluation/evaluationUtils"; +import { klona } from "klona"; +import { getDynamicBindings, isDynamicValue } from "utils/DynamicBindingUtils"; +import evaluateSync from "../evaluate"; +import type { DescendantWidgetMap } from "sagas/WidgetOperationUtils"; +import type { MetaState } from "reducers/entityReducers/metaReducer"; +import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; +import type { EvalMetaUpdates } from "@appsmith/workers/common/DataTreeEvaluator/types"; +import type { DataTree } from "entities/DataTree/dataTreeTypes"; +import { validateAndParseWidgetProperty } from "workers/common/DataTreeEvaluator/validationUtils"; + +function resetWidgetFnDescriptor( + widgetName: string, + resetChildren = true, + metaUpdates: EvalMetaUpdates, +) { return { type: "RESET_WIDGET_META_RECURSIVE_BY_NAME" as const, - payload: { widgetName, resetChildren }, + payload: { widgetName, resetChildren, metaUpdates }, }; } -export type TResetWidgetArgs = Parameters; export type TResetWidgetDescription = ReturnType< typeof resetWidgetFnDescriptor >; export type TResetWidgetActionType = TResetWidgetDescription["type"]; async function resetWidget( - ...args: Parameters + ...args: [widgetName: string, resetChildren: boolean] ) { - return promisify(resetWidgetFnDescriptor)(...args); + const widgetName = args[0]; + const resetChildren = args[1] || true; + const metaUpdates: EvalMetaUpdates = []; + const updatedProperties: string[][] = []; + + resetWidgetMetaProperty( + widgetName, + resetChildren, + metaUpdates, + updatedProperties, + ); + + return promisify(resetWidgetFnDescriptor)( + widgetName, + resetChildren, + metaUpdates, + ); +} + +function resetWidgetMetaProperty( + widgetName: string, + resetChildren = true, + evalMetaUpdates: EvalMetaUpdates, + updatedProperties: string[][], +) { + const widget: FlattenedWidgetProps | undefined = _.find( + Object.values(canvasWidgets || {}), + (widget) => widget.widgetName === widgetName, + ); + + if (!dataTreeEvaluator || !widget) return; + + const evalTree = dataTreeEvaluator.getEvalTree(); + const oldUnEvalTree = dataTreeEvaluator.getOldUnevalTree(); + const configTree = dataTreeEvaluator.getConfigTree(); + const evalProps = dataTreeEvaluator.getEvalProps(); + const evalPathsIdenticalToState = + dataTreeEvaluator.getEvalPathsIdenticalToState(); + + const evaluatedEntity = evalTree[widget.widgetName]; + const evaluatedEntityConfig = configTree[ + widget.widgetName + ] as WidgetEntityConfig; + + if (evaluatedEntity && isWidget(evaluatedEntity)) { + const metaObj = evaluatedEntity.meta; + const currentMetaProperties = Object.keys(metaObj); + const { propertyOverrideDependency } = evaluatedEntityConfig; + + for (const propertyPath of currentMetaProperties) { + const defaultPropertyPath = + propertyOverrideDependency[propertyPath]?.DEFAULT; + if (defaultPropertyPath) { + const unEvalEntity = oldUnEvalTree[widget.widgetName] as WidgetEntity; + const expressionToEvaluate: string = unEvalEntity[defaultPropertyPath]; + + let finalValue: unknown; + if ( + expressionToEvaluate && + typeof expressionToEvaluate === "string" && + isDynamicValue(expressionToEvaluate) + ) { + const { jsSnippets } = getDynamicBindings(expressionToEvaluate); + const { result } = evaluateSync( + jsSnippets[0] || expressionToEvaluate, + evalTree, + false, + {}, + undefined, + configTree, + ); + + finalValue = klona(result); + } else { + finalValue = klona(expressionToEvaluate); + } + + const parsedValue = validateAndParseWidgetProperty({ + fullPropertyPath: `${widget.widgetName}.${defaultPropertyPath}`, + widget: unEvalEntity, + configTree, + evalPropertyValue: finalValue, + unEvalPropertyValue: expressionToEvaluate, + evalProps, + evalPathsIdenticalToState, + }); + + evalMetaUpdates.push({ + widgetId: evaluatedEntity.widgetId, + metaPropertyPath: propertyPath.split("."), + value: parsedValue, + }); + + continue; + } else { + evalMetaUpdates.push({ + widgetId: evaluatedEntity.widgetId, + metaPropertyPath: propertyPath.split("."), + value: undefined, + }); + } + } + + if (resetChildren) { + resetChildrenMetaProperty( + widget.widgetId, + evalTree, + evalMetaUpdates, + updatedProperties, + ); + } + } +} + +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 function getWidgetDescendantToReset( + canvasWidgets: CanvasWidgetsReduxState, + widgetId: string, + evaluatedDataTree: DataTree, + widgetsMeta: MetaState, +): DescendantWidgetMap[] { + const descendantList: DescendantWidgetMap[] = []; + const widget = _.get(canvasWidgets, widgetId); + + 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 WidgetEntity | undefined; + descendantList.push({ + id: childMetaWidgetId, + evaluatedWidget: evaluatedChildWidget, + }); + const grandChildren = getWidgetDescendantToReset( + canvasWidgets, + childMetaWidgetId, + evaluatedDataTree, + sortedWidgetsMeta.otherWidgetsMeta, + ); + if (grandChildren.length) { + descendantList.push(...grandChildren); + } + } + + 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)) { + descendantList.push({ + id: childWidgetId, + evaluatedWidget: childWidget, + }); + const grandChildren = getWidgetDescendantToReset( + canvasWidgets, + childWidgetId, + evaluatedDataTree, + sortedWidgetsMeta.otherWidgetsMeta, + ); + if (grandChildren.length) { + descendantList.push(...grandChildren); + } + } + } + } + } + } + + return descendantList; +} + +function resetChildrenMetaProperty( + parentWidgetId: string, + evaluatedDataTree: DataTree, + evalMetaUpdates: EvalMetaUpdates, + updatedProperties: string[][], +) { + const childrenList = getWidgetDescendantToReset( + canvasWidgets, + parentWidgetId, + evaluatedDataTree, + canvasWidgetsMeta, + ); + + for (const childIndex in childrenList) { + const { evaluatedWidget: childWidget } = childrenList[childIndex]; + + if (!childWidget) continue; + + resetWidgetMetaProperty( + childWidget?.widgetName, + false, + evalMetaUpdates, + updatedProperties, + ); + } } export default resetWidget; diff --git a/app/client/src/workers/Evaluation/fns/utils/Promisify.ts b/app/client/src/workers/Evaluation/fns/utils/Promisify.ts index 8abdd81538..cccd776912 100644 --- a/app/client/src/workers/Evaluation/fns/utils/Promisify.ts +++ b/app/client/src/workers/Evaluation/fns/utils/Promisify.ts @@ -14,6 +14,7 @@ export function promisify

>( return async function (...args: P) { const actionDescription = fnDescriptor(...args); const metaData = ExecutionMetaData.getExecutionMetaData(); + const response = await WorkerMessenger.request({ method: MAIN_THREAD_ACTION.PROCESS_TRIGGER, data: { diff --git a/app/client/src/workers/Evaluation/handlers/evalTree.ts b/app/client/src/workers/Evaluation/handlers/evalTree.ts index 859fc5d8da..5dea32b680 100644 --- a/app/client/src/workers/Evaluation/handlers/evalTree.ts +++ b/app/client/src/workers/Evaluation/handlers/evalTree.ts @@ -27,9 +27,13 @@ import DataStore from "../dataStore"; import type { TransmissionErrorHandler } from "../fns/utils/Messenger"; import { MessageType, sendMessage } from "utils/MessageUtil"; import { startSpansInAnEvaluation } from "UITelemetry/generateWebWorkerTraces"; +import type { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer"; + export let replayMap: Record> | undefined; export let dataTreeEvaluator: DataTreeEvaluator | undefined; export const CANVAS = "canvas"; +export let canvasWidgetsMeta: Record; +export let canvasWidgets: CanvasWidgetsReduxState; export default function (request: EvalWorkerSyncRequest) { const { data } = request; @@ -56,11 +60,15 @@ export default function (request: EvalWorkerSyncRequest) { theme, unevalTree: __unevalTree__, widgets, + widgetsMeta, widgetTypeConfigMap, } = data as EvalTreeRequestData; const unevalTree = __unevalTree__.unEvalTree; configTree = __unevalTree__.configTree as ConfigTree; + canvasWidgets = widgets; + canvasWidgetsMeta = widgetsMeta; + try { if (!dataTreeEvaluator) { isCreateFirstTree = true; diff --git a/app/client/src/workers/Evaluation/types.ts b/app/client/src/workers/Evaluation/types.ts index 3bbe4e89d4..388e0cb5b6 100644 --- a/app/client/src/workers/Evaluation/types.ts +++ b/app/client/src/workers/Evaluation/types.ts @@ -42,6 +42,7 @@ export interface EvalTreeRequestData { forceEvaluation: boolean; metaWidgets: MetaWidgetsReduxState; appMode?: APP_MODE; + widgetsMeta: Record; } export interface EvalTreeResponseData { diff --git a/app/client/src/workers/common/DataTreeEvaluator/index.ts b/app/client/src/workers/common/DataTreeEvaluator/index.ts index 97adcb37af..062dc112db 100644 --- a/app/client/src/workers/common/DataTreeEvaluator/index.ts +++ b/app/client/src/workers/common/DataTreeEvaluator/index.ts @@ -192,6 +192,10 @@ export default class DataTreeEvaluator { return this.evalTree; } + getEvalProps() { + return this.evalProps; + } + setEvalTree(evalTree: DataTree) { this.evalTree = evalTree; } diff --git a/app/client/src/workers/common/DataTreeEvaluator/validationUtils.ts b/app/client/src/workers/common/DataTreeEvaluator/validationUtils.ts index 0e6835b99f..ad6117a90c 100644 --- a/app/client/src/workers/common/DataTreeEvaluator/validationUtils.ts +++ b/app/client/src/workers/common/DataTreeEvaluator/validationUtils.ts @@ -74,6 +74,7 @@ export function validateAndParseWidgetProperty({ evalPathsIdenticalToState: EvalPathsIdenticalToState; }): unknown { const { propertyPath } = getEntityNameAndPropertyPath(fullPropertyPath); + if (isPathDynamicTrigger(widget, propertyPath)) { // TODO find a way to validate triggers return unEvalPropertyValue;