chore: perf data tree shrink (#18361)
trimming dataTree object size by removing configs to make evaluation faster.
This commit is contained in:
parent
ced3b413c3
commit
c440343586
|
|
@ -167,3 +167,17 @@ export const WidgetHeightLimits = {
|
|||
MIN_HEIGHT_IN_ROWS: 4,
|
||||
MIN_CANVAS_HEIGHT_IN_ROWS: 10,
|
||||
};
|
||||
|
||||
export const WIDGET_PROPS_TO_SKIP_FROM_EVAL = {
|
||||
children: true,
|
||||
parentId: true,
|
||||
renderMode: true,
|
||||
detachFromLayout: true,
|
||||
noContainerOffset: false,
|
||||
hideCard: true,
|
||||
isDeprecated: true,
|
||||
searchTags: true,
|
||||
iconSVG: true,
|
||||
version: true,
|
||||
displayName: true,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import { DependencyMap, DynamicPath } from "utils/DynamicBindingUtils";
|
||||
import { DataTreeAction, ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
||||
import {
|
||||
ENTITY_TYPE,
|
||||
UnEvalTreeAction,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { ActionData } from "reducers/entityReducers/actionsReducer";
|
||||
import {
|
||||
getBindingAndReactivePathsOfAction,
|
||||
|
|
@ -10,7 +13,7 @@ export const generateDataTreeAction = (
|
|||
action: ActionData,
|
||||
editorConfig: any[],
|
||||
dependencyConfig: DependencyMap = {},
|
||||
): DataTreeAction => {
|
||||
): UnEvalTreeAction => {
|
||||
let dynamicBindingPathList: DynamicPath[] = [];
|
||||
let datasourceUrl = "";
|
||||
|
||||
|
|
@ -45,26 +48,30 @@ export const generateDataTreeAction = (
|
|||
);
|
||||
|
||||
return {
|
||||
actionId: action.config.id,
|
||||
run: {},
|
||||
clear: {},
|
||||
actionId: action.config.id,
|
||||
name: action.config.name,
|
||||
pluginId: action.config.pluginId,
|
||||
pluginType: action.config.pluginType,
|
||||
config: action.config.actionConfiguration,
|
||||
dynamicBindingPathList,
|
||||
data: action.data ? action.data.body : undefined,
|
||||
isLoading: action.isLoading,
|
||||
responseMeta: {
|
||||
statusCode: action.data?.statusCode,
|
||||
isExecutionSuccess: action.data?.isExecutionSuccess || false,
|
||||
headers: action.data?.headers,
|
||||
},
|
||||
config: action.config.actionConfiguration,
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
isLoading: action.isLoading,
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
dependencyMap,
|
||||
logBlackList: {},
|
||||
datasourceUrl,
|
||||
__config__: {
|
||||
actionId: action.config.id,
|
||||
name: action.config.name,
|
||||
pluginId: action.config.pluginId,
|
||||
pluginType: action.config.pluginType,
|
||||
dynamicBindingPathList,
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
dependencyMap,
|
||||
logBlackList: {},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,126 +1,60 @@
|
|||
import {
|
||||
ActionDataState,
|
||||
ActionDataWithMeta,
|
||||
} from "reducers/entityReducers/actionsReducer";
|
||||
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
||||
import { WidgetProps } from "widgets/BaseWidget";
|
||||
import { ActionResponse } from "api/ActionAPI";
|
||||
import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { MetaState } from "reducers/entityReducers/metaReducer";
|
||||
import { Page } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { ActionConfig, PluginType } from "entities/Action";
|
||||
import { AppDataState } from "reducers/entityReducers/appReducer";
|
||||
import { DependencyMap, DynamicPath } from "utils/DynamicBindingUtils";
|
||||
import { DependencyMap } from "utils/DynamicBindingUtils";
|
||||
import { generateDataTreeAction } from "entities/DataTree/dataTreeAction";
|
||||
import { generateDataTreeJSAction } from "entities/DataTree/dataTreeJSAction";
|
||||
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
|
||||
import { JSCollectionDataState } from "reducers/entityReducers/jsActionsReducer";
|
||||
import { ValidationConfig } from "constants/PropertyControlConstants";
|
||||
import { Variable } from "entities/JSCollection";
|
||||
import {
|
||||
ActionDescription,
|
||||
ClearPluginActionDescription,
|
||||
RunPluginActionDescription,
|
||||
} from "entities/DataTree/actionTriggers";
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { PluginId } from "api/PluginApi";
|
||||
import log from "loglevel";
|
||||
import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer";
|
||||
import {
|
||||
ActionDispatcher,
|
||||
ActionEntityConfig,
|
||||
ActionEntityEvalTree,
|
||||
ENTITY_TYPE,
|
||||
JSActionEntityConfig,
|
||||
JSActionEvalTree,
|
||||
WidgetConfig,
|
||||
EvaluationSubstitutionType,
|
||||
} from "./types";
|
||||
|
||||
export type ActionDispatcher = (
|
||||
...args: any[]
|
||||
) => Promise<unknown> | ActionDescription;
|
||||
|
||||
export enum ENTITY_TYPE {
|
||||
ACTION = "ACTION",
|
||||
WIDGET = "WIDGET",
|
||||
APPSMITH = "APPSMITH",
|
||||
JSACTION = "JSACTION",
|
||||
export interface UnEvalTreeAction extends ActionEntityEvalTree {
|
||||
__config__: ActionEntityConfig;
|
||||
}
|
||||
|
||||
export enum EvaluationSubstitutionType {
|
||||
TEMPLATE = "TEMPLATE",
|
||||
PARAMETER = "PARAMETER",
|
||||
SMART_SUBSTITUTE = "SMART_SUBSTITUTE",
|
||||
}
|
||||
|
||||
// Private widgets do not get evaluated
|
||||
// For example, for widget Button1 in a List widget List1, List1.template.Button1.text gets evaluated,
|
||||
// so there is no need to evaluate Button1.text
|
||||
export type PrivateWidgets = Record<string, true>;
|
||||
|
||||
export interface DataTreeAction
|
||||
extends Omit<ActionDataWithMeta, "data" | "config"> {
|
||||
data: ActionResponse["body"];
|
||||
actionId: string;
|
||||
config: Partial<ActionConfig>;
|
||||
pluginType: PluginType;
|
||||
pluginId: PluginId;
|
||||
name: string;
|
||||
run: ActionDispatcher | RunPluginActionDescription | Record<string, unknown>;
|
||||
clear:
|
||||
| ActionDispatcher
|
||||
| ClearPluginActionDescription
|
||||
| Record<string, unknown>;
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
dependencyMap: DependencyMap;
|
||||
logBlackList: Record<string, true>;
|
||||
datasourceUrl: string;
|
||||
extends ActionEntityEvalTree,
|
||||
ActionEntityConfig {}
|
||||
|
||||
export interface UnEvalTreeJSAction extends JSActionEvalTree {
|
||||
__config__: JSActionEntityConfig;
|
||||
}
|
||||
|
||||
export interface DataTreeJSAction {
|
||||
pluginType: PluginType.JS;
|
||||
name: string;
|
||||
ENTITY_TYPE: ENTITY_TYPE.JSACTION;
|
||||
body: string;
|
||||
[propName: string]: any;
|
||||
meta: Record<string, MetaArgs>;
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
variables: Array<string>;
|
||||
dependencyMap: DependencyMap;
|
||||
export type DataTreeJSAction = JSActionEvalTree & JSActionEntityConfig;
|
||||
|
||||
export interface WidgetEntityConfig
|
||||
extends Partial<WidgetProps>,
|
||||
Omit<WidgetConfigProps, "widgetName" | "rows" | "columns">,
|
||||
WidgetConfig {
|
||||
defaultMetaProps: Array<string>;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface MetaArgs {
|
||||
arguments: Variable[];
|
||||
isAsync: boolean;
|
||||
confirmBeforeExecute: boolean;
|
||||
}
|
||||
/**
|
||||
* Map of overriding property as key and overridden property as values
|
||||
*/
|
||||
export type OverridingPropertyPaths = Record<string, string[]>;
|
||||
|
||||
export enum OverridingPropertyType {
|
||||
META = "META",
|
||||
DEFAULT = "DEFAULT",
|
||||
}
|
||||
/**
|
||||
* Map of property name as key and value as object with defaultPropertyName and metaPropertyName which it depends on.
|
||||
*/
|
||||
export type PropertyOverrideDependency = Record<
|
||||
string,
|
||||
{
|
||||
DEFAULT: string | undefined;
|
||||
META: string | undefined;
|
||||
}
|
||||
>;
|
||||
|
||||
export interface DataTreeWidget extends WidgetProps {
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
triggerPaths: Record<string, boolean>;
|
||||
validationPaths: Record<string, ValidationConfig>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET;
|
||||
logBlackList: Record<string, true>;
|
||||
propertyOverrideDependency: PropertyOverrideDependency;
|
||||
overridingPropertyPaths: OverridingPropertyPaths;
|
||||
privateWidgets: PrivateWidgets;
|
||||
export interface WidgetEvalTree extends WidgetProps {
|
||||
meta: Record<string, unknown>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET;
|
||||
}
|
||||
|
||||
export interface UnEvalTreeWidget extends WidgetEvalTree {
|
||||
__config__: WidgetEntityConfig;
|
||||
}
|
||||
|
||||
export interface DataTreeWidget extends WidgetEvalTree, WidgetConfig {}
|
||||
|
||||
export interface DataTreeAppsmith extends Omit<AppDataState, "store"> {
|
||||
ENTITY_TYPE: ENTITY_TYPE.APPSMITH;
|
||||
store: Record<string, unknown>;
|
||||
|
|
@ -138,6 +72,20 @@ export type DataTree = {
|
|||
[entityName: string]: DataTreeEntity;
|
||||
};
|
||||
|
||||
export type UnEvalTreeEntityObject =
|
||||
| UnEvalTreeAction
|
||||
| UnEvalTreeJSAction
|
||||
| UnEvalTreeWidget;
|
||||
|
||||
export type UnEvalTreeEntity =
|
||||
| UnEvalTreeEntityObject
|
||||
| DataTreeAppsmith
|
||||
| Page[];
|
||||
|
||||
export type UnEvalTree = {
|
||||
[entityName: string]: UnEvalTreeEntity;
|
||||
};
|
||||
|
||||
type DataTreeSeed = {
|
||||
actions: ActionDataState;
|
||||
editorConfigs: Record<string, any[]>;
|
||||
|
|
@ -150,6 +98,12 @@ type DataTreeSeed = {
|
|||
theme: AppTheme["properties"];
|
||||
};
|
||||
|
||||
export type DataTreeEntityConfig =
|
||||
| WidgetEntityConfig
|
||||
| ActionEntityConfig
|
||||
| JSActionEntityConfig
|
||||
| DataTreeAppsmith;
|
||||
|
||||
export class DataTreeFactory {
|
||||
static create({
|
||||
actions,
|
||||
|
|
@ -161,8 +115,8 @@ export class DataTreeFactory {
|
|||
theme,
|
||||
widgets,
|
||||
widgetsMeta,
|
||||
}: DataTreeSeed): DataTree {
|
||||
const dataTree: DataTree = {};
|
||||
}: DataTreeSeed): UnEvalTree {
|
||||
const dataTree: UnEvalTree = {};
|
||||
const start = performance.now();
|
||||
const startActions = performance.now();
|
||||
|
||||
|
|
@ -195,6 +149,7 @@ export class DataTreeFactory {
|
|||
const endWidgets = performance.now();
|
||||
|
||||
dataTree.pageList = pageList;
|
||||
|
||||
dataTree.appsmith = {
|
||||
...appData,
|
||||
// combine both persistent and transient state with the transient state
|
||||
|
|
@ -217,3 +172,5 @@ export class DataTreeFactory {
|
|||
return dataTree;
|
||||
}
|
||||
}
|
||||
|
||||
export { ENTITY_TYPE, EvaluationSubstitutionType };
|
||||
|
|
|
|||
|
|
@ -136,52 +136,10 @@ describe("generateDataTreeJSAction", () => {
|
|||
const expected = {
|
||||
myVar1: [],
|
||||
myVar2: {},
|
||||
name: "JSObject2",
|
||||
actionId: "1234",
|
||||
pluginType: "JS",
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
body:
|
||||
"export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t},\n\tmyFun2: async () => {\n\t\t//use async-await or promises\n\t}\n}",
|
||||
meta: {
|
||||
myFun2: {
|
||||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "body",
|
||||
},
|
||||
{
|
||||
key: "myVar1",
|
||||
},
|
||||
{
|
||||
key: "myVar2",
|
||||
},
|
||||
{
|
||||
key: "myFun2",
|
||||
},
|
||||
{
|
||||
key: "myFun1",
|
||||
},
|
||||
],
|
||||
variables: ["myVar1", "myVar2"],
|
||||
dependencyMap: {
|
||||
body: ["myFun2", "myFun1"],
|
||||
},
|
||||
|
||||
myFun2: {
|
||||
data: {
|
||||
users: [{ id: 1, name: "John" }],
|
||||
|
|
@ -190,12 +148,59 @@ describe("generateDataTreeJSAction", () => {
|
|||
myFun1: {
|
||||
data: {},
|
||||
},
|
||||
reactivePaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
__config__: {
|
||||
name: "JSObject2",
|
||||
actionId: "1234",
|
||||
pluginType: "JS",
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
|
||||
meta: {
|
||||
myFun2: {
|
||||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "body",
|
||||
},
|
||||
{
|
||||
key: "myVar1",
|
||||
},
|
||||
{
|
||||
key: "myVar2",
|
||||
},
|
||||
{
|
||||
key: "myFun2",
|
||||
},
|
||||
{
|
||||
key: "myFun1",
|
||||
},
|
||||
],
|
||||
variables: ["myVar1", "myVar2"],
|
||||
dependencyMap: {
|
||||
body: ["myFun2", "myFun1"],
|
||||
},
|
||||
reactivePaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = generateDataTreeJSAction(jsCollection);
|
||||
|
|
@ -335,52 +340,63 @@ describe("generateDataTreeJSAction", () => {
|
|||
const expected = {
|
||||
myVar1: [],
|
||||
myVar2: {},
|
||||
name: "JSObject2",
|
||||
actionId: "1234",
|
||||
pluginType: "JS",
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
body:
|
||||
"export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1: () => {\n\t\t//write code here\n\t return JSObject2.myFun2},\n\tmyFun2: async () => {\n\t\t//use async-await or promises\n\t}\n}",
|
||||
meta: {
|
||||
myFun2: {
|
||||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
__config__: {
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
meta: {
|
||||
myFun2: {
|
||||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
},
|
||||
myFun1: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
bindingPaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "body",
|
||||
},
|
||||
{
|
||||
key: "myVar1",
|
||||
},
|
||||
{
|
||||
key: "myVar2",
|
||||
},
|
||||
{
|
||||
key: "myFun2",
|
||||
},
|
||||
{
|
||||
key: "myFun1",
|
||||
},
|
||||
],
|
||||
variables: ["myVar1", "myVar2"],
|
||||
dependencyMap: {
|
||||
body: ["myFun2", "myFun1"],
|
||||
},
|
||||
name: "JSObject2",
|
||||
actionId: "1234",
|
||||
pluginType: "JS",
|
||||
reactivePaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
},
|
||||
bindingPaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "body",
|
||||
},
|
||||
{
|
||||
key: "myVar1",
|
||||
},
|
||||
{
|
||||
key: "myVar2",
|
||||
},
|
||||
{
|
||||
key: "myFun2",
|
||||
},
|
||||
{
|
||||
key: "myFun1",
|
||||
},
|
||||
],
|
||||
variables: ["myVar1", "myVar2"],
|
||||
dependencyMap: {
|
||||
body: ["myFun2", "myFun1"],
|
||||
},
|
||||
|
||||
myFun2: {
|
||||
data: {
|
||||
users: [{ id: 1, name: "John" }],
|
||||
|
|
@ -389,13 +405,6 @@ describe("generateDataTreeJSAction", () => {
|
|||
myFun1: {
|
||||
data: {},
|
||||
},
|
||||
reactivePaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
myFun1: "SMART_SUBSTITUTE",
|
||||
myFun2: "SMART_SUBSTITUTE",
|
||||
myVar1: "SMART_SUBSTITUTE",
|
||||
myVar2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
};
|
||||
|
||||
const result = generateDataTreeJSAction(jsCollection);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
import {
|
||||
DataTreeJSAction,
|
||||
ENTITY_TYPE,
|
||||
MetaArgs,
|
||||
UnEvalTreeJSAction,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
import { JSCollectionData } from "reducers/entityReducers/jsActionsReducer";
|
||||
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||
import { DependencyMap } from "utils/DynamicBindingUtils";
|
||||
import { MetaArgs } from "./types";
|
||||
|
||||
const reg = /this\./g;
|
||||
|
||||
export const generateDataTreeJSAction = (
|
||||
js: JSCollectionData,
|
||||
): DataTreeJSAction => {
|
||||
): UnEvalTreeJSAction => {
|
||||
const meta: Record<string, MetaArgs> = {};
|
||||
const dynamicBindingPathList = [];
|
||||
const bindingPaths: Record<string, EvaluationSubstitutionType> = {};
|
||||
|
|
@ -54,17 +55,20 @@ export const generateDataTreeJSAction = (
|
|||
}
|
||||
return {
|
||||
...variableList,
|
||||
name: js.config.name,
|
||||
actionId: js.config.id,
|
||||
pluginType: js.config.pluginType,
|
||||
ENTITY_TYPE: ENTITY_TYPE.JSACTION,
|
||||
body: removeThisReference,
|
||||
meta: meta,
|
||||
bindingPaths: bindingPaths, // As all js object function referred to as action is user javascript code, we add them as binding paths.
|
||||
reactivePaths: { ...bindingPaths },
|
||||
dynamicBindingPathList: dynamicBindingPathList,
|
||||
variables: listVariables,
|
||||
dependencyMap: dependencyMap,
|
||||
...actionsData,
|
||||
body: removeThisReference,
|
||||
ENTITY_TYPE: ENTITY_TYPE.JSACTION,
|
||||
__config__: {
|
||||
meta: meta,
|
||||
name: js.config.name,
|
||||
actionId: js.config.id,
|
||||
pluginType: js.config.pluginType,
|
||||
ENTITY_TYPE: ENTITY_TYPE.JSACTION,
|
||||
bindingPaths: bindingPaths, // As all js object function referred to as action is user javascript code, we add them as binding paths.
|
||||
reactivePaths: { ...bindingPaths },
|
||||
dynamicBindingPathList: dynamicBindingPathList,
|
||||
variables: listVariables,
|
||||
dependencyMap: dependencyMap,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
|
||||
import {
|
||||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
EvaluationSubstitutionType,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import WidgetFactory from "utils/WidgetFactory";
|
||||
|
||||
import { ValidationTypes } from "constants/WidgetValidation";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
|
||||
// const WidgetTypes = WidgetFactory.widgetTypes;
|
||||
|
||||
|
|
@ -207,51 +206,62 @@ describe("generateDataTreeWidget", () => {
|
|||
errorMessage: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
|
||||
const expected: DataTreeWidget = {
|
||||
bindingPaths,
|
||||
reactivePaths: {
|
||||
...bindingPaths,
|
||||
isDirty: EvaluationSubstitutionType.TEMPLATE,
|
||||
isFocused: EvaluationSubstitutionType.TEMPLATE,
|
||||
isValid: EvaluationSubstitutionType.TEMPLATE,
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
value: EvaluationSubstitutionType.TEMPLATE,
|
||||
"meta.text": EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
meta: {
|
||||
text: "Tester",
|
||||
isDirty: true,
|
||||
deepObj: {
|
||||
level1: {
|
||||
metaValue: 10,
|
||||
const expected = {
|
||||
__config__: {
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
bindingPaths,
|
||||
reactivePaths: {
|
||||
...bindingPaths,
|
||||
isDirty: EvaluationSubstitutionType.TEMPLATE,
|
||||
isFocused: EvaluationSubstitutionType.TEMPLATE,
|
||||
isValid: EvaluationSubstitutionType.TEMPLATE,
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
value: EvaluationSubstitutionType.TEMPLATE,
|
||||
"meta.text": EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
|
||||
triggerPaths: {
|
||||
onSubmit: true,
|
||||
onTextChanged: true,
|
||||
},
|
||||
type: "INPUT_WIDGET_V2",
|
||||
validationPaths: {
|
||||
defaultText: { type: ValidationTypes.TEXT },
|
||||
errorMessage: { type: ValidationTypes.TEXT },
|
||||
isDisabled: { type: ValidationTypes.BOOLEAN },
|
||||
isRequired: { type: ValidationTypes.BOOLEAN },
|
||||
isVisible: { type: ValidationTypes.BOOLEAN },
|
||||
placeholderText: { type: ValidationTypes.TEXT },
|
||||
regex: { type: ValidationTypes.REGEX },
|
||||
resetOnSubmit: { type: ValidationTypes.BOOLEAN },
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "isValid",
|
||||
},
|
||||
{
|
||||
key: "value",
|
||||
},
|
||||
],
|
||||
logBlackList: {
|
||||
isValid: true,
|
||||
value: true,
|
||||
},
|
||||
propertyOverrideDependency: {
|
||||
text: {
|
||||
DEFAULT: "defaultText",
|
||||
META: "meta.text",
|
||||
},
|
||||
},
|
||||
},
|
||||
triggerPaths: {
|
||||
onSubmit: true,
|
||||
onTextChanged: true,
|
||||
},
|
||||
validationPaths: {
|
||||
defaultText: { type: ValidationTypes.TEXT },
|
||||
errorMessage: { type: ValidationTypes.TEXT },
|
||||
isDisabled: { type: ValidationTypes.BOOLEAN },
|
||||
isRequired: { type: ValidationTypes.BOOLEAN },
|
||||
isVisible: { type: ValidationTypes.BOOLEAN },
|
||||
placeholderText: { type: ValidationTypes.TEXT },
|
||||
regex: { type: ValidationTypes.REGEX },
|
||||
resetOnSubmit: { type: ValidationTypes.BOOLEAN },
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "isValid",
|
||||
defaultMetaProps: ["text", "isDirty", "isFocused"],
|
||||
defaultProps: {
|
||||
text: "defaultText",
|
||||
},
|
||||
{
|
||||
key: "value",
|
||||
overridingPropertyPaths: {
|
||||
defaultText: ["text", "meta.text"],
|
||||
"meta.text": ["text"],
|
||||
},
|
||||
],
|
||||
logBlackList: {
|
||||
isValid: true,
|
||||
value: true,
|
||||
privateWidgets: {},
|
||||
},
|
||||
value: "{{Input1.text}}",
|
||||
isDirty: true,
|
||||
|
|
@ -263,35 +273,28 @@ describe("generateDataTreeWidget", () => {
|
|||
leftColumn: 0,
|
||||
parentColumnSpace: 0,
|
||||
parentRowSpace: 0,
|
||||
propertyOverrideDependency: {
|
||||
text: {
|
||||
DEFAULT: "defaultText",
|
||||
META: "meta.text",
|
||||
},
|
||||
},
|
||||
renderMode: RenderModes.CANVAS,
|
||||
rightColumn: 0,
|
||||
topRow: 0,
|
||||
type: "INPUT_WIDGET_V2",
|
||||
renderMode: RenderModes.CANVAS,
|
||||
version: 0,
|
||||
topRow: 0,
|
||||
widgetId: "123",
|
||||
widgetName: "Input1",
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
defaultText: "",
|
||||
defaultMetaProps: ["text", "isDirty", "isFocused"],
|
||||
defaultProps: {
|
||||
text: "defaultText",
|
||||
},
|
||||
overridingPropertyPaths: {
|
||||
defaultText: ["text", "meta.text"],
|
||||
"meta.text": ["text"],
|
||||
},
|
||||
privateWidgets: {},
|
||||
deepObj: {
|
||||
level1: {
|
||||
metaValue: 10,
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
text: "Tester",
|
||||
isDirty: true,
|
||||
deepObj: {
|
||||
level1: {
|
||||
metaValue: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = generateDataTreeWidget(widget, widgetMetaProps);
|
||||
|
|
|
|||
|
|
@ -2,15 +2,22 @@ import { getAllPathsFromPropertyConfig } from "entities/Widget/utils";
|
|||
import _ from "lodash";
|
||||
import memoize from "micro-memoize";
|
||||
import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { getEntityDynamicBindingPathList } from "utils/DynamicBindingUtils";
|
||||
import {
|
||||
DynamicPath,
|
||||
getEntityDynamicBindingPathList,
|
||||
} from "utils/DynamicBindingUtils";
|
||||
import WidgetFactory from "utils/WidgetFactory";
|
||||
import {
|
||||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
WidgetEntityConfig,
|
||||
UnEvalTreeWidget,
|
||||
} from "./dataTreeFactory";
|
||||
import {
|
||||
OverridingPropertyPaths,
|
||||
OverridingPropertyType,
|
||||
PropertyOverrideDependency,
|
||||
} from "./dataTreeFactory";
|
||||
} from "./types";
|
||||
|
||||
import { setOverridingProperty } from "./utils";
|
||||
|
||||
// We are splitting generateDataTreeWidget into two parts to memoize better as the widget doesn't change very often.
|
||||
|
|
@ -19,9 +26,10 @@ import { setOverridingProperty } from "./utils";
|
|||
const generateDataTreeWidgetWithoutMeta = (
|
||||
widget: FlattenedWidgetProps,
|
||||
): {
|
||||
dataTreeWidgetWithoutMetaProps: DataTreeWidget;
|
||||
dataTreeWidgetWithoutMetaProps: UnEvalTreeWidget;
|
||||
overridingMetaPropsMap: Record<string, boolean>;
|
||||
defaultMetaProps: Record<string, unknown>;
|
||||
entityConfig: WidgetEntityConfig;
|
||||
} => {
|
||||
const derivedProps: any = {};
|
||||
const blockedDerivedProps: Record<string, true> = {};
|
||||
|
|
@ -130,14 +138,38 @@ const generateDataTreeWidgetWithoutMeta = (
|
|||
*
|
||||
* Therefore spread is replaced with "merge" which merges objects recursively.
|
||||
*/
|
||||
|
||||
const widgetPathsToOmit = [
|
||||
"dynamicBindingPathList",
|
||||
"dynamicPropertyPathList",
|
||||
"dynamicTriggerPathList",
|
||||
"privateWidgets",
|
||||
"type",
|
||||
];
|
||||
|
||||
const dataTreeWidgetWithoutMetaProps = _.merge(
|
||||
{},
|
||||
widget,
|
||||
unInitializedDefaultProps,
|
||||
// defaultMetaProps,
|
||||
// widgetMetaProps,
|
||||
derivedProps,
|
||||
{
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
},
|
||||
_.omit(widget, widgetPathsToOmit),
|
||||
unInitializedDefaultProps,
|
||||
derivedProps,
|
||||
);
|
||||
|
||||
const dynamicPathsList: {
|
||||
dynamicPropertyPathList?: DynamicPath[];
|
||||
dynamicTriggerPathList?: DynamicPath[];
|
||||
} = {};
|
||||
if (widget.dynamicPropertyPathList)
|
||||
dynamicPathsList.dynamicPropertyPathList = widget.dynamicPropertyPathList;
|
||||
if (widget.dynamicTriggerPathList)
|
||||
dynamicPathsList.dynamicTriggerPathList = widget.dynamicTriggerPathList;
|
||||
|
||||
return {
|
||||
dataTreeWidgetWithoutMetaProps,
|
||||
overridingMetaPropsMap,
|
||||
defaultMetaProps,
|
||||
entityConfig: {
|
||||
defaultProps,
|
||||
defaultMetaProps: Object.keys(defaultMetaProps),
|
||||
dynamicBindingPathList,
|
||||
|
|
@ -145,9 +177,6 @@ const generateDataTreeWidgetWithoutMeta = (
|
|||
...widget.logBlackList,
|
||||
...blockedDerivedProps,
|
||||
},
|
||||
meta: {}, // this will be overridden by meta value calculated in generateDataTreeWidget
|
||||
propertyOverrideDependency,
|
||||
overridingPropertyPaths,
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
triggerPaths,
|
||||
|
|
@ -156,31 +185,20 @@ const generateDataTreeWidgetWithoutMeta = (
|
|||
privateWidgets: {
|
||||
...widget.privateWidgets,
|
||||
},
|
||||
propertyOverrideDependency,
|
||||
overridingPropertyPaths,
|
||||
type: widget.type,
|
||||
...dynamicPathsList,
|
||||
},
|
||||
);
|
||||
return {
|
||||
dataTreeWidgetWithoutMetaProps,
|
||||
overridingMetaPropsMap,
|
||||
defaultMetaProps,
|
||||
};
|
||||
};
|
||||
|
||||
// @todo set the max size dynamically based on number of widgets. (widgets.length)
|
||||
// Remove the debug statements in July 2022
|
||||
|
||||
const generateDataTreeWidgetWithoutMetaMemoized = memoize(
|
||||
generateDataTreeWidgetWithoutMeta,
|
||||
{
|
||||
maxSize: 1000,
|
||||
// onCacheHit: (cache, options) => {
|
||||
// console.log("####### cache was hit: ", cache.keys.length);
|
||||
// },
|
||||
// onCacheAdd: (cache, options) => {
|
||||
// console.log(
|
||||
// "####### cache was missed ",
|
||||
// cache.keys.length,
|
||||
// cache.keys[0][0].widgetName,
|
||||
// );
|
||||
// },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -191,6 +209,7 @@ export const generateDataTreeWidget = (
|
|||
const {
|
||||
dataTreeWidgetWithoutMetaProps: dataTreeWidget,
|
||||
defaultMetaProps,
|
||||
entityConfig,
|
||||
overridingMetaPropsMap,
|
||||
} = generateDataTreeWidgetWithoutMetaMemoized(widget);
|
||||
const overridingMetaProps: Record<string, unknown> = {};
|
||||
|
|
@ -215,5 +234,7 @@ export const generateDataTreeWidget = (
|
|||
});
|
||||
|
||||
dataTreeWidget["meta"] = meta;
|
||||
dataTreeWidget["__config__"] = entityConfig;
|
||||
|
||||
return dataTreeWidget;
|
||||
};
|
||||
|
|
|
|||
126
app/client/src/entities/DataTree/types.ts
Normal file
126
app/client/src/entities/DataTree/types.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import { ActionResponse } from "api/ActionAPI";
|
||||
import { PluginId } from "api/PluginApi";
|
||||
import { ValidationConfig } from "constants/PropertyControlConstants";
|
||||
import { ActionConfig, PluginType } from "entities/Action";
|
||||
import {
|
||||
ActionDescription,
|
||||
ClearPluginActionDescription,
|
||||
RunPluginActionDescription,
|
||||
} from "entities/DataTree/actionTriggers";
|
||||
import { Variable } from "entities/JSCollection";
|
||||
import { DependencyMap, DynamicPath } from "utils/DynamicBindingUtils";
|
||||
|
||||
export type ActionDispatcher = (
|
||||
...args: any[]
|
||||
) => Promise<unknown> | ActionDescription;
|
||||
|
||||
export enum ENTITY_TYPE {
|
||||
ACTION = "ACTION",
|
||||
WIDGET = "WIDGET",
|
||||
APPSMITH = "APPSMITH",
|
||||
JSACTION = "JSACTION",
|
||||
}
|
||||
|
||||
export enum EvaluationSubstitutionType {
|
||||
TEMPLATE = "TEMPLATE",
|
||||
PARAMETER = "PARAMETER",
|
||||
SMART_SUBSTITUTE = "SMART_SUBSTITUTE",
|
||||
}
|
||||
|
||||
// Action entity types
|
||||
export interface ActionEntityEvalTree {
|
||||
actionId: string;
|
||||
isLoading: boolean;
|
||||
data: ActionResponse["body"];
|
||||
run: ActionDispatcher | RunPluginActionDescription | Record<string, unknown>;
|
||||
clear:
|
||||
| ActionDispatcher
|
||||
| ClearPluginActionDescription
|
||||
| Record<string, unknown>;
|
||||
responseMeta: {
|
||||
statusCode?: string;
|
||||
isExecutionSuccess: boolean;
|
||||
headers?: unknown;
|
||||
};
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
config: Partial<ActionConfig>;
|
||||
datasourceUrl: string;
|
||||
}
|
||||
|
||||
export interface ActionEntityConfig {
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
dependencyMap: DependencyMap;
|
||||
logBlackList: Record<string, true>;
|
||||
pluginType: PluginType;
|
||||
pluginId: PluginId;
|
||||
actionId: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// JSAction (JSObject) entity Types
|
||||
|
||||
export interface MetaArgs {
|
||||
arguments: Variable[];
|
||||
isAsync: boolean;
|
||||
confirmBeforeExecute: boolean;
|
||||
}
|
||||
|
||||
export interface JSActionEntityConfig {
|
||||
meta: Record<string, MetaArgs>;
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
variables: Array<string>;
|
||||
dependencyMap: DependencyMap;
|
||||
pluginType: PluginType.JS;
|
||||
name: string;
|
||||
ENTITY_TYPE: ENTITY_TYPE.JSACTION;
|
||||
actionId: string;
|
||||
}
|
||||
|
||||
export interface JSActionEvalTree {
|
||||
[propName: string]: any;
|
||||
body: string;
|
||||
}
|
||||
|
||||
// Widget entity Types
|
||||
|
||||
// Private widgets do not get evaluated
|
||||
// For example, for widget Button1 in a List widget List1, List1.template.Button1.text gets evaluated,
|
||||
// so there is no need to evaluate Button1.text
|
||||
export type PrivateWidgets = Record<string, true>;
|
||||
|
||||
/**
|
||||
* Map of overriding property as key and overridden property as values
|
||||
*/
|
||||
export type OverridingPropertyPaths = Record<string, string[]>;
|
||||
|
||||
export enum OverridingPropertyType {
|
||||
META = "META",
|
||||
DEFAULT = "DEFAULT",
|
||||
}
|
||||
/**
|
||||
* Map of property name as key and value as object with defaultPropertyName and metaPropertyName which it depends on.
|
||||
*/
|
||||
export type PropertyOverrideDependency = Record<
|
||||
string,
|
||||
{
|
||||
DEFAULT: string | undefined;
|
||||
META: string | undefined;
|
||||
}
|
||||
>;
|
||||
|
||||
export type WidgetConfig = {
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
triggerPaths: Record<string, boolean>;
|
||||
validationPaths: Record<string, ValidationConfig>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET;
|
||||
logBlackList: Record<string, true>;
|
||||
propertyOverrideDependency: PropertyOverrideDependency;
|
||||
overridingPropertyPaths: OverridingPropertyPaths;
|
||||
privateWidgets: PrivateWidgets;
|
||||
};
|
||||
|
|
@ -2,7 +2,7 @@ import {
|
|||
PropertyOverrideDependency,
|
||||
OverridingPropertyPaths,
|
||||
OverridingPropertyType,
|
||||
} from "./dataTreeFactory";
|
||||
} from "./types";
|
||||
|
||||
type SetOverridingPropertyParams = {
|
||||
key: string;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,11 @@ import { FormEvalActionPayload } from "./FormEvaluationSaga";
|
|||
import { getSelectedAppTheme } from "selectors/appThemingSelectors";
|
||||
import { updateMetaState } from "actions/metaActions";
|
||||
import { getAllActionValidationConfig } from "selectors/entitiesSelector";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import {
|
||||
DataTree,
|
||||
UnEvalTree,
|
||||
UnEvalTreeWidget,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { ActionValidationConfigMap } from "constants/PropertyControlConstants";
|
||||
|
|
@ -125,7 +129,7 @@ function* evaluateTreeSaga(
|
|||
const allActionValidationConfig: {
|
||||
[actionId: string]: ActionValidationConfigMap;
|
||||
} = yield select(getAllActionValidationConfig);
|
||||
const unevalTree: DataTree = yield select(getUnevaluatedDataTree);
|
||||
const unevalTree: UnEvalTree = yield select(getUnevaluatedDataTree);
|
||||
const widgets: CanvasWidgetsReduxState = yield select(getWidgets);
|
||||
const theme: AppTheme = yield select(getSelectedAppTheme);
|
||||
const appMode: APP_MODE | undefined = yield select(getAppMode);
|
||||
|
|
@ -270,7 +274,7 @@ export function* evaluateAndExecuteDynamicTrigger(
|
|||
evalWorker.duplexRequest,
|
||||
EVAL_WORKER_ACTIONS.EVAL_TRIGGER,
|
||||
{
|
||||
dataTree: unEvalTree,
|
||||
unEvalTree,
|
||||
dynamicTrigger,
|
||||
callbackData,
|
||||
globalContext,
|
||||
|
|
@ -383,7 +387,6 @@ export function* executeDynamicTriggerRequest(
|
|||
if (requestData.type === EVAL_WORKER_ACTIONS.LINT_TREE) {
|
||||
yield spawn(lintTreeSaga, {
|
||||
pathsToLint: requestData.lintOrder,
|
||||
jsUpdates: requestData.jsUpdates,
|
||||
unevalTree: requestData.unevalTree,
|
||||
});
|
||||
}
|
||||
|
|
@ -526,9 +529,9 @@ export function* validateProperty(
|
|||
value: any,
|
||||
props: WidgetProps,
|
||||
) {
|
||||
const unevalTree: DataTree = yield select(getUnevaluatedDataTree);
|
||||
// @ts-expect-error: We have a typeMismatch for validationPaths
|
||||
const validation = unevalTree[props.widgetName].validationPaths[property];
|
||||
const unevalTree: UnEvalTree = yield select(getUnevaluatedDataTree);
|
||||
const entity = unevalTree[props.widgetName] as UnEvalTreeWidget;
|
||||
const validation = entity?.__config__.validationPaths[property];
|
||||
const response: unknown = yield call(
|
||||
evalWorker.request,
|
||||
EVAL_WORKER_ACTIONS.VALIDATE_PROPERTY,
|
||||
|
|
@ -539,7 +542,6 @@ export function* validateProperty(
|
|||
validation,
|
||||
},
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { APP_MODE } from "entities/App";
|
|||
import { call, put, select } from "redux-saga/effects";
|
||||
import { getAppMode } from "selectors/entitiesSelector";
|
||||
import { GracefulWorkerService } from "utils/WorkerUtil";
|
||||
import { getUpdatedLocalUnEvalTreeAfterJSUpdates } from "workers/Evaluation/JSObject";
|
||||
import {
|
||||
LintTreeRequest,
|
||||
LintTreeResponse,
|
||||
|
|
@ -20,7 +19,6 @@ export const lintWorker = new GracefulWorkerService(
|
|||
);
|
||||
|
||||
export function* lintTreeSaga({
|
||||
jsUpdates,
|
||||
pathsToLint,
|
||||
unevalTree,
|
||||
}: LintTreeSagaRequestData) {
|
||||
|
|
@ -28,14 +26,9 @@ export function* lintTreeSaga({
|
|||
const appMode: APP_MODE = yield select(getAppMode);
|
||||
if (appMode !== APP_MODE.EDIT) return;
|
||||
|
||||
const updatedUnevalTree = getUpdatedLocalUnEvalTreeAfterJSUpdates(
|
||||
jsUpdates,
|
||||
unevalTree,
|
||||
);
|
||||
const lintTreeRequestData: LintTreeRequest = {
|
||||
jsUpdates,
|
||||
pathsToLint,
|
||||
unevalTree: updatedUnevalTree,
|
||||
unevalTree,
|
||||
};
|
||||
|
||||
const { errors }: LintTreeResponse = yield call(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
PLATFORM_ERROR,
|
||||
Severity,
|
||||
} from "entities/AppsmithConsole";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { DataTree, UnEvalTree } from "entities/DataTree/dataTreeFactory";
|
||||
import {
|
||||
DataTreeDiff,
|
||||
DataTreeDiffEvent,
|
||||
|
|
@ -281,7 +281,7 @@ export function* evalErrorHandler(
|
|||
}
|
||||
|
||||
export function* logSuccessfulBindings(
|
||||
unEvalTree: DataTree,
|
||||
unEvalTree: UnEvalTree,
|
||||
dataTree: DataTree,
|
||||
evaluationOrder: string[],
|
||||
isCreateFirstTree: boolean,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@ import {
|
|||
FlattenedWidgetProps,
|
||||
} from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
import { WidgetProps } from "widgets/BaseWidget";
|
||||
import _ from "lodash";
|
||||
import { WidgetType } from "constants/WidgetConstants";
|
||||
import _, { omit } from "lodash";
|
||||
import {
|
||||
WidgetType,
|
||||
WIDGET_PROPS_TO_SKIP_FROM_EVAL,
|
||||
} from "constants/WidgetConstants";
|
||||
import { ActionData } from "reducers/entityReducers/actionsReducer";
|
||||
import { Page } from "@appsmith/constants/ReduxActionConstants";
|
||||
import { getActions, getPlugins } from "selectors/entitiesSelector";
|
||||
|
|
@ -16,6 +19,17 @@ export const getWidgets = (state: AppState): CanvasWidgetsReduxState => {
|
|||
return state.entities.canvasWidgets;
|
||||
};
|
||||
|
||||
export const getWidgetsForEval = createSelector(getWidgets, (widgets) => {
|
||||
const widgetForEval: CanvasWidgetsReduxState = {};
|
||||
for (const key of Object.keys(widgets)) {
|
||||
widgetForEval[key] = omit(
|
||||
widgets[key],
|
||||
Object.keys(WIDGET_PROPS_TO_SKIP_FROM_EVAL),
|
||||
) as FlattenedWidgetProps;
|
||||
}
|
||||
return widgetForEval;
|
||||
});
|
||||
|
||||
export const getWidgetsMeta = (state: AppState) => state.entities.meta;
|
||||
|
||||
export const getWidgetMetaProps = createSelector(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
DataTreeFactory,
|
||||
DataTreeWidget,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { getWidgets, getWidgetsMeta } from "sagas/selectors";
|
||||
import { getWidgetsForEval, getWidgetsMeta } from "sagas/selectors";
|
||||
import "url-search-params-polyfill";
|
||||
import { getPageList } from "./appViewSelectors";
|
||||
import { AppState } from "@appsmith/reducers";
|
||||
|
|
@ -23,7 +23,7 @@ import { EvaluationError, getEvalErrorPath } from "utils/DynamicBindingUtils";
|
|||
export const getUnevaluatedDataTree = createSelector(
|
||||
getActionsForCurrentPage,
|
||||
getJSCollectionsForCurrentPage,
|
||||
getWidgets,
|
||||
getWidgetsForEval,
|
||||
getWidgetsMeta,
|
||||
getPageList,
|
||||
getAppData,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ import { migrateCheckboxGroupWidgetInlineProperty } from "./migrations/CheckboxG
|
|||
import { migrateMapWidgetIsClickedMarkerCentered } from "./migrations/MapWidget";
|
||||
import { DSLWidget } from "widgets/constants";
|
||||
import { migrateRecaptchaType } from "./migrations/ButtonWidgetMigrations";
|
||||
import { PrivateWidgets } from "entities/DataTree/dataTreeFactory";
|
||||
import { PrivateWidgets } from "entities/DataTree/types";
|
||||
import { migrateStylingPropertiesForTheming } from "./migrations/ThemingMigrations";
|
||||
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const JS_object_tree: DataTreeJSAction = {
|
|||
reactivePaths: {},
|
||||
variables: [],
|
||||
dependencyMap: {},
|
||||
actionId: "",
|
||||
};
|
||||
|
||||
// @ts-expect-error: meta property not provided
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import { entityDefinitions } from "utils/autocomplete/EntityDefinitions";
|
|||
|
||||
describe("dataTreeTypeDefCreator", () => {
|
||||
it("creates the right def for a widget", () => {
|
||||
// @ts-expect-error: meta property not provided
|
||||
const dataTreeEntity: DataTreeWidget = {
|
||||
widgetId: "yolo",
|
||||
widgetName: "Input1",
|
||||
|
|
@ -44,6 +43,7 @@ describe("dataTreeTypeDefCreator", () => {
|
|||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
privateWidgets: {},
|
||||
meta: {},
|
||||
};
|
||||
const { def, entityInfo } = dataTreeTypeDefCreator(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -557,25 +557,6 @@ export interface WidgetPositionProps extends WidgetRowCols {
|
|||
noContainerOffset?: boolean; // This won't offset the child in parent
|
||||
}
|
||||
|
||||
export const WIDGET_STATIC_PROPS = {
|
||||
leftColumn: true,
|
||||
rightColumn: true,
|
||||
topRow: true,
|
||||
bottomRow: true,
|
||||
minHeight: true,
|
||||
parentColumnSpace: true,
|
||||
parentRowSpace: true,
|
||||
children: true,
|
||||
type: true,
|
||||
widgetId: true,
|
||||
widgetName: true,
|
||||
parentId: true,
|
||||
renderMode: true,
|
||||
detachFromLayout: true,
|
||||
noContainerOffset: false,
|
||||
height: false,
|
||||
};
|
||||
|
||||
export const WIDGET_DISPLAY_PROPS = {
|
||||
isVisible: true,
|
||||
isLoading: true,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import { ValidationTypes } from "constants/WidgetValidation";
|
|||
import derivedProperties from "./parseDerivedProperties";
|
||||
import { DSLWidget } from "widgets/constants";
|
||||
import { entityDefinitions } from "utils/autocomplete/EntityDefinitions";
|
||||
import { PrivateWidgets } from "entities/DataTree/dataTreeFactory";
|
||||
import { PrivateWidgets } from "entities/DataTree/types";
|
||||
import equal from "fast-deep-equal/es6";
|
||||
import { klona } from "klona/lite";
|
||||
import { Stylesheet } from "entities/AppTheming";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
functionsList.push(action);
|
||||
});
|
||||
|
||||
const oldConfig = Object.getPrototypeOf(jsCollection) as DataTreeJSAction;
|
||||
|
||||
if (parsedBody.actions && parsedBody.actions.length > 0) {
|
||||
for (let i = 0; i < parsedBody.actions.length; i++) {
|
||||
const action = parsedBody.actions[i];
|
||||
|
|
@ -52,37 +54,26 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
);
|
||||
}
|
||||
} else {
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
const reactivePaths = oldConfig.reactivePaths;
|
||||
|
||||
reactivePaths[action.name] =
|
||||
EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
reactivePaths[`${action.name}.data`] =
|
||||
EvaluationSubstitutionType.TEMPLATE;
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
const dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
|
||||
const dynamicBindingPathList = oldConfig.dynamicBindingPathList;
|
||||
dynamicBindingPathList.push({ key: action.name });
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dynamicBindingPathList`,
|
||||
dynamicBindingPathList,
|
||||
);
|
||||
const dependencyMap = jsCollection.dependencyMap;
|
||||
|
||||
const dependencyMap = oldConfig.dependencyMap;
|
||||
dependencyMap["body"].push(action.name);
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dependencyMap`,
|
||||
dependencyMap,
|
||||
);
|
||||
const meta = jsCollection.meta;
|
||||
|
||||
const meta = oldConfig.meta;
|
||||
meta[action.name] = {
|
||||
arguments: action.arguments,
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
};
|
||||
set(modifiedUnEvalTree, `${jsCollection.name}.meta`, meta);
|
||||
|
||||
const data = get(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.${action.name}.data`,
|
||||
|
|
@ -108,37 +99,23 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
(js: ParsedJSSubAction) => js.name === oldActionName,
|
||||
);
|
||||
if (!existed) {
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
const reactivePaths = oldConfig.reactivePaths;
|
||||
delete reactivePaths[oldActionName];
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
let dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
dynamicBindingPathList = dynamicBindingPathList.filter(
|
||||
|
||||
oldConfig.dynamicBindingPathList = oldConfig.dynamicBindingPathList.filter(
|
||||
(path) => path["key"] !== oldActionName,
|
||||
);
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dynamicBindingPathList`,
|
||||
dynamicBindingPathList,
|
||||
);
|
||||
const dependencyMap = jsCollection.dependencyMap["body"];
|
||||
|
||||
const dependencyMap = oldConfig.dependencyMap["body"];
|
||||
const removeIndex = dependencyMap.indexOf(oldActionName);
|
||||
if (removeIndex > -1) {
|
||||
const updatedDMap = dependencyMap.filter(
|
||||
oldConfig.dependencyMap["body"] = dependencyMap.filter(
|
||||
(item) => item !== oldActionName,
|
||||
);
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dependencyMap.body`,
|
||||
updatedDMap,
|
||||
);
|
||||
}
|
||||
const meta = jsCollection.meta;
|
||||
const meta = oldConfig.meta;
|
||||
delete meta[oldActionName];
|
||||
set(modifiedUnEvalTree, `${jsCollection.name}.meta`, meta);
|
||||
|
||||
unset(modifiedUnEvalTree[jsCollection.name], oldActionName);
|
||||
unset(modifiedUnEvalTree[jsCollection.name], `${oldActionName}.data`);
|
||||
}
|
||||
|
|
@ -163,21 +140,12 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
}
|
||||
} else {
|
||||
varList.push(newVar.name);
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
const reactivePaths = oldConfig.reactivePaths;
|
||||
reactivePaths[newVar.name] =
|
||||
EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
const dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
|
||||
const dynamicBindingPathList = oldConfig.dynamicBindingPathList;
|
||||
dynamicBindingPathList.push({ key: newVar.name });
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dynamicBindingPathList`,
|
||||
dynamicBindingPathList,
|
||||
);
|
||||
|
||||
set(modifiedUnEvalTree, `${jsCollection.name}.variables`, varList);
|
||||
set(
|
||||
|
|
@ -194,23 +162,12 @@ export const updateJSCollectionInUnEvalTree = (
|
|||
(item) => item.name === varListItem,
|
||||
);
|
||||
if (!existsInParsed) {
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
const reactivePaths = oldConfig.reactivePaths;
|
||||
delete reactivePaths[varListItem];
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
|
||||
let dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
dynamicBindingPathList = dynamicBindingPathList.filter(
|
||||
oldConfig.dynamicBindingPathList = oldConfig.dynamicBindingPathList.filter(
|
||||
(path) => path["key"] !== varListItem,
|
||||
);
|
||||
set(
|
||||
modifiedUnEvalTree,
|
||||
`${jsCollection.name}.dynamicBindingPathList`,
|
||||
dynamicBindingPathList,
|
||||
);
|
||||
|
||||
newVarList = newVarList.filter((item) => item !== varListItem);
|
||||
unset(modifiedUnEvalTree[jsCollection.name], varListItem);
|
||||
|
|
@ -234,6 +191,7 @@ export const removeFunctionsAndVariableJSCollection = (
|
|||
unEvalTree: DataTree,
|
||||
entity: DataTreeJSAction,
|
||||
) => {
|
||||
const oldConfig = Object.getPrototypeOf(entity) as DataTreeJSAction;
|
||||
const modifiedDataTree: DataTree = unEvalTree;
|
||||
const functionsList: Array<string> = [];
|
||||
Object.keys(entity.meta).forEach((action) => {
|
||||
|
|
@ -247,28 +205,25 @@ export const removeFunctionsAndVariableJSCollection = (
|
|||
unset(modifiedDataTree[entity.name], varName);
|
||||
}
|
||||
//remove functions
|
||||
let dynamicBindingPathList = entity.dynamicBindingPathList;
|
||||
|
||||
const reactivePaths = entity.reactivePaths;
|
||||
const meta = entity.meta;
|
||||
let dependencyMap = entity.dependencyMap["body"];
|
||||
|
||||
for (let i = 0; i < functionsList.length; i++) {
|
||||
const actionName = functionsList[i];
|
||||
delete reactivePaths[actionName];
|
||||
delete meta[actionName];
|
||||
unset(modifiedDataTree[entity.name], actionName);
|
||||
dynamicBindingPathList = dynamicBindingPathList.filter(
|
||||
|
||||
oldConfig.dynamicBindingPathList = oldConfig.dynamicBindingPathList.filter(
|
||||
(path: any) => path["key"] !== actionName,
|
||||
);
|
||||
dependencyMap = dependencyMap.filter((item: any) => item !== actionName);
|
||||
|
||||
entity.dependencyMap["body"] = entity.dependencyMap["body"].filter(
|
||||
(item: any) => item !== actionName,
|
||||
);
|
||||
}
|
||||
set(modifiedDataTree, `${entity.name}.reactivePaths`, reactivePaths);
|
||||
set(
|
||||
modifiedDataTree,
|
||||
`${entity.name}.dynamicBindingPathList`,
|
||||
dynamicBindingPathList,
|
||||
);
|
||||
set(modifiedDataTree, `${entity.name}.dependencyMap.body`, dependencyMap);
|
||||
set(modifiedDataTree, `${entity.name}.meta`, meta);
|
||||
|
||||
return modifiedDataTree;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,444 @@
|
|||
import {
|
||||
UnEvalTree,
|
||||
UnEvalTreeAction,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import {
|
||||
createNewEntity,
|
||||
createUnEvalTreeForEval,
|
||||
makeEntityConfigsAsObjProperties,
|
||||
} from "../dataTreeUtils";
|
||||
|
||||
const unevalTreeFromMainThread = {
|
||||
Api2: {
|
||||
actionId: "6380b1003a20d922b774eb75",
|
||||
run: {},
|
||||
clear: {},
|
||||
isLoading: false,
|
||||
responseMeta: {
|
||||
isExecutionSuccess: false,
|
||||
},
|
||||
config: {},
|
||||
ENTITY_TYPE: "ACTION",
|
||||
datasourceUrl: "https://www.facebook.com",
|
||||
__config__: {
|
||||
actionId: "6380b1003a20d922b774eb75",
|
||||
name: "Api2",
|
||||
pluginId: "5ca385dc81b37f0004b4db85",
|
||||
pluginType: "API",
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "config.path",
|
||||
},
|
||||
],
|
||||
ENTITY_TYPE: "ACTION",
|
||||
bindingPaths: {
|
||||
"config.path": "TEMPLATE",
|
||||
"config.body": "SMART_SUBSTITUTE",
|
||||
"config.pluginSpecifiedTemplates[1].value": "SMART_SUBSTITUTE",
|
||||
},
|
||||
reactivePaths: {
|
||||
data: "TEMPLATE",
|
||||
isLoading: "TEMPLATE",
|
||||
datasourceUrl: "TEMPLATE",
|
||||
"config.path": "TEMPLATE",
|
||||
"config.body": "SMART_SUBSTITUTE",
|
||||
"config.pluginSpecifiedTemplates[1].value": "SMART_SUBSTITUTE",
|
||||
"config.pluginSpecifiedTemplates[2].value.limitBased.limit.value":
|
||||
"SMART_SUBSTITUTE",
|
||||
},
|
||||
dependencyMap: {
|
||||
"config.body": ["config.pluginSpecifiedTemplates[0].value"],
|
||||
},
|
||||
logBlackList: {},
|
||||
},
|
||||
},
|
||||
JSObject1: {
|
||||
newFunction: {
|
||||
data: {},
|
||||
},
|
||||
storeTest2: {
|
||||
data: {},
|
||||
},
|
||||
body:
|
||||
"export default {\n\tstoreTest2: () => {\n\t\tlet values = [\n\t\t\t\t\tstoreValue('val1', 'number 1'),\n\t\t\t\t\tstoreValue('val2', 'number 2'),\n\t\t\t\t\tstoreValue('val3', 'number 3'),\n\t\t\t\t\tstoreValue('val4', 'number 4')\n\t\t\t\t];\n\t\treturn Promise.all(values)\n\t\t\t.then(() => {\n\t\t\tshowAlert(JSON.stringify(appsmith.store))\n\t\t})\n\t\t\t.catch((err) => {\n\t\t\treturn showAlert('Could not store values in store ' + err.toString());\n\t\t})\n\t},\n\tnewFunction: function() {\n\t\tJSObject1.storeTest()\n\t}\n}",
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
__config__: {
|
||||
meta: {
|
||||
newFunction: {
|
||||
arguments: [],
|
||||
isAsync: false,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
storeTest2: {
|
||||
arguments: [],
|
||||
isAsync: true,
|
||||
confirmBeforeExecute: false,
|
||||
},
|
||||
},
|
||||
name: "JSObject1",
|
||||
actionId: "637cda3b2f8e175c6f5269d5",
|
||||
pluginType: "JS",
|
||||
ENTITY_TYPE: "JSACTION",
|
||||
bindingPaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
newFunction: "SMART_SUBSTITUTE",
|
||||
storeTest2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
reactivePaths: {
|
||||
body: "SMART_SUBSTITUTE",
|
||||
newFunction: "SMART_SUBSTITUTE",
|
||||
storeTest2: "SMART_SUBSTITUTE",
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "body",
|
||||
},
|
||||
{
|
||||
key: "newFunction",
|
||||
},
|
||||
{
|
||||
key: "storeTest2",
|
||||
},
|
||||
],
|
||||
variables: [],
|
||||
dependencyMap: {
|
||||
body: ["newFunction", "storeTest2"],
|
||||
},
|
||||
},
|
||||
},
|
||||
MainContainer: {
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
widgetName: "MainContainer",
|
||||
backgroundColor: "none",
|
||||
rightColumn: 1224,
|
||||
snapColumns: 64,
|
||||
widgetId: "0",
|
||||
topRow: 0,
|
||||
bottomRow: 1240,
|
||||
containerStyle: "none",
|
||||
snapRows: 124,
|
||||
parentRowSpace: 1,
|
||||
canExtend: true,
|
||||
minHeight: 1250,
|
||||
parentColumnSpace: 1,
|
||||
leftColumn: 0,
|
||||
meta: {},
|
||||
__config__: {
|
||||
defaultProps: {},
|
||||
defaultMetaProps: [],
|
||||
dynamicBindingPathList: [],
|
||||
logBlackList: {},
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
privateWidgets: {},
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
type: "CANVAS_WIDGET",
|
||||
},
|
||||
},
|
||||
Button2: {
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
resetFormOnClick: false,
|
||||
boxShadow: "none",
|
||||
widgetName: "Button2",
|
||||
buttonColor: "{{appsmith.theme.colors.primaryColor}}",
|
||||
topRow: 3,
|
||||
bottomRow: 7,
|
||||
parentRowSpace: 10,
|
||||
animateLoading: true,
|
||||
parentColumnSpace: 34.5,
|
||||
leftColumn: 31,
|
||||
text: "test",
|
||||
isDisabled: false,
|
||||
key: "oypcoe6gx4",
|
||||
rightColumn: 47,
|
||||
isDefaultClickDisabled: true,
|
||||
widgetId: "vxpz4ta27g",
|
||||
isVisible: true,
|
||||
recaptchaType: "V3",
|
||||
isLoading: false,
|
||||
disabledWhenInvalid: false,
|
||||
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
buttonVariant: "PRIMARY",
|
||||
placement: "CENTER",
|
||||
meta: {},
|
||||
__config__: {
|
||||
defaultProps: {},
|
||||
defaultMetaProps: ["recaptchaToken"],
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "buttonColor",
|
||||
},
|
||||
{
|
||||
key: "borderRadius",
|
||||
},
|
||||
],
|
||||
logBlackList: {},
|
||||
bindingPaths: {
|
||||
text: "TEMPLATE",
|
||||
tooltip: "TEMPLATE",
|
||||
isVisible: "TEMPLATE",
|
||||
isDisabled: "TEMPLATE",
|
||||
animateLoading: "TEMPLATE",
|
||||
googleRecaptchaKey: "TEMPLATE",
|
||||
recaptchaType: "TEMPLATE",
|
||||
disabledWhenInvalid: "TEMPLATE",
|
||||
resetFormOnClick: "TEMPLATE",
|
||||
buttonVariant: "TEMPLATE",
|
||||
iconName: "TEMPLATE",
|
||||
placement: "TEMPLATE",
|
||||
buttonColor: "TEMPLATE",
|
||||
borderRadius: "TEMPLATE",
|
||||
boxShadow: "TEMPLATE",
|
||||
},
|
||||
reactivePaths: {
|
||||
recaptchaToken: "TEMPLATE",
|
||||
buttonColor: "TEMPLATE",
|
||||
borderRadius: "TEMPLATE",
|
||||
text: "TEMPLATE",
|
||||
tooltip: "TEMPLATE",
|
||||
isVisible: "TEMPLATE",
|
||||
isDisabled: "TEMPLATE",
|
||||
animateLoading: "TEMPLATE",
|
||||
googleRecaptchaKey: "TEMPLATE",
|
||||
recaptchaType: "TEMPLATE",
|
||||
disabledWhenInvalid: "TEMPLATE",
|
||||
resetFormOnClick: "TEMPLATE",
|
||||
buttonVariant: "TEMPLATE",
|
||||
iconName: "TEMPLATE",
|
||||
placement: "TEMPLATE",
|
||||
boxShadow: "TEMPLATE",
|
||||
},
|
||||
triggerPaths: {
|
||||
onClick: true,
|
||||
},
|
||||
validationPaths: {
|
||||
text: {
|
||||
type: "TEXT",
|
||||
},
|
||||
tooltip: {
|
||||
type: "TEXT",
|
||||
},
|
||||
isVisible: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
isDisabled: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
animateLoading: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
googleRecaptchaKey: {
|
||||
type: "TEXT",
|
||||
},
|
||||
recaptchaType: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["V3", "V2"],
|
||||
default: "V3",
|
||||
},
|
||||
},
|
||||
disabledWhenInvalid: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
resetFormOnClick: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
buttonVariant: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["PRIMARY", "SECONDARY", "TERTIARY"],
|
||||
default: "PRIMARY",
|
||||
},
|
||||
},
|
||||
iconName: {
|
||||
type: "TEXT",
|
||||
},
|
||||
placement: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["START", "BETWEEN", "CENTER"],
|
||||
default: "CENTER",
|
||||
},
|
||||
},
|
||||
buttonColor: {
|
||||
type: "TEXT",
|
||||
},
|
||||
borderRadius: {
|
||||
type: "TEXT",
|
||||
},
|
||||
boxShadow: {
|
||||
type: "TEXT",
|
||||
},
|
||||
},
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
privateWidgets: {},
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
type: "BUTTON_WIDGET",
|
||||
dynamicTriggerPathList: [],
|
||||
},
|
||||
},
|
||||
pageList: [
|
||||
{
|
||||
pageName: "Page1",
|
||||
pageId: "63349fb5d39f215f89b8245e",
|
||||
isDefault: false,
|
||||
isHidden: false,
|
||||
slug: "page1",
|
||||
},
|
||||
{
|
||||
pageName: "Page2",
|
||||
pageId: "637cc6b4a3664a7fe679b7b0",
|
||||
isDefault: true,
|
||||
isHidden: false,
|
||||
slug: "page2",
|
||||
},
|
||||
],
|
||||
appsmith: {
|
||||
user: {
|
||||
email: "someuser@appsmith.com",
|
||||
username: "someuser@appsmith.com",
|
||||
name: "Some name",
|
||||
enableTelemetry: true,
|
||||
emptyInstance: false,
|
||||
accountNonExpired: true,
|
||||
accountNonLocked: true,
|
||||
credentialsNonExpired: true,
|
||||
isAnonymous: false,
|
||||
isEnabled: true,
|
||||
isSuperUser: false,
|
||||
isConfigurable: true,
|
||||
},
|
||||
URL: {
|
||||
fullPath: "",
|
||||
host: "dev.appsmith.com",
|
||||
hostname: "dev.appsmith.com",
|
||||
queryParams: {},
|
||||
protocol: "https:",
|
||||
pathname: "",
|
||||
port: "",
|
||||
hash: "",
|
||||
},
|
||||
store: {
|
||||
val1: "number 1",
|
||||
val2: "number 2",
|
||||
},
|
||||
geolocation: {
|
||||
canBeRequested: true,
|
||||
currentPosition: {},
|
||||
},
|
||||
mode: "EDIT",
|
||||
theme: {
|
||||
colors: {
|
||||
primaryColor: "#553DE9",
|
||||
backgroundColor: "#F6F6F6",
|
||||
},
|
||||
borderRadius: {
|
||||
appBorderRadius: "0.375rem",
|
||||
},
|
||||
boxShadow: {
|
||||
appBoxShadow:
|
||||
"0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)",
|
||||
},
|
||||
fontFamily: {
|
||||
appFont: "Nunito Sans",
|
||||
},
|
||||
},
|
||||
ENTITY_TYPE: "APPSMITH",
|
||||
},
|
||||
};
|
||||
|
||||
describe("7. Test util methods", () => {
|
||||
it("1. createUnEvalTree method", () => {
|
||||
const unEvalTreeForEval = createUnEvalTreeForEval(
|
||||
(unevalTreeFromMainThread as unknown) as UnEvalTree,
|
||||
);
|
||||
// Action config
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Api2.dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.Api2.__config__.dynamicBindingPathList,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Api2.bindingPaths",
|
||||
unevalTreeFromMainThread.Api2.__config__.bindingPaths,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Api2.reactivePaths",
|
||||
unevalTreeFromMainThread.Api2.__config__.reactivePaths,
|
||||
);
|
||||
|
||||
// widget config
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Button2.dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.Button2.__config__.dynamicBindingPathList,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Button2.bindingPaths",
|
||||
unevalTreeFromMainThread.Button2.__config__.bindingPaths,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"Button2.reactivePaths",
|
||||
unevalTreeFromMainThread.Button2.__config__.reactivePaths,
|
||||
);
|
||||
|
||||
// appsmith object config
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"appsmith",
|
||||
unevalTreeFromMainThread.appsmith,
|
||||
);
|
||||
|
||||
// JSObject config
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"JSObject1.dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.JSObject1.__config__.dynamicBindingPathList,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"JSObject1.bindingPaths",
|
||||
unevalTreeFromMainThread.JSObject1.__config__.bindingPaths,
|
||||
);
|
||||
expect(unEvalTreeForEval).toHaveProperty(
|
||||
"JSObject1.reactivePaths",
|
||||
unevalTreeFromMainThread.JSObject1.__config__.reactivePaths,
|
||||
);
|
||||
});
|
||||
|
||||
it("2. createNewEntity method", () => {
|
||||
const actionForEval = createNewEntity(
|
||||
(unevalTreeFromMainThread.Api2 as unknown) as UnEvalTreeAction,
|
||||
);
|
||||
// Action config
|
||||
expect(actionForEval).toHaveProperty(
|
||||
"dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.Api2.__config__.dynamicBindingPathList,
|
||||
);
|
||||
expect(actionForEval).not.toHaveProperty("__config__");
|
||||
|
||||
const widgetForEval = createNewEntity(
|
||||
(unevalTreeFromMainThread.Button2 as unknown) as UnEvalTreeAction,
|
||||
);
|
||||
// widget config
|
||||
expect(widgetForEval).toHaveProperty(
|
||||
"dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.Button2.__config__.dynamicBindingPathList,
|
||||
);
|
||||
expect(widgetForEval).not.toHaveProperty("__config__");
|
||||
});
|
||||
|
||||
it("3. makeDataTreeEntityConfigAsProperty method", () => {
|
||||
const unEvalTreeForEval = createUnEvalTreeForEval(
|
||||
(unevalTreeFromMainThread as unknown) as UnEvalTree,
|
||||
);
|
||||
const dataTree = makeEntityConfigsAsObjProperties(unEvalTreeForEval);
|
||||
|
||||
expect(dataTree.Api2).not.toHaveProperty("__config__");
|
||||
|
||||
expect(dataTree.Api2).toHaveProperty(
|
||||
"dynamicBindingPathList",
|
||||
unevalTreeFromMainThread.Api2.__config__.dynamicBindingPathList,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -11,7 +11,6 @@ import {
|
|||
import { RenderModes } from "constants/WidgetConstants";
|
||||
|
||||
describe("evaluateSync", () => {
|
||||
// @ts-expect-error: meta property not provided
|
||||
const widget: DataTreeWidget = {
|
||||
bottomRow: 0,
|
||||
isLoading: false,
|
||||
|
|
@ -35,6 +34,7 @@ describe("evaluateSync", () => {
|
|||
overridingPropertyPaths: {},
|
||||
privateWidgets: {},
|
||||
propertyOverrideDependency: {},
|
||||
meta: {},
|
||||
};
|
||||
const dataTree: DataTree = {
|
||||
Input1: widget,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import {
|
|||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
EvaluationSubstitutionType,
|
||||
UnEvalTree,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { WidgetTypeConfigMap } from "utils/WidgetFactory";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
|
|
@ -12,6 +13,7 @@ import { ValidationTypes } from "constants/WidgetValidation";
|
|||
import WidgetFactory from "utils/WidgetFactory";
|
||||
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
|
||||
import { sortObjectWithArray } from "../../../utils/treeUtils";
|
||||
import { createUnEvalTreeForEval } from "../dataTreeUtils";
|
||||
|
||||
const WIDGET_CONFIG_MAP: WidgetTypeConfigMap = {
|
||||
CONTAINER_WIDGET: {
|
||||
|
|
@ -217,8 +219,7 @@ const WIDGET_CONFIG_MAP: WidgetTypeConfigMap = {
|
|||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error: meta is required
|
||||
const BASE_WIDGET: DataTreeWidget = {
|
||||
const BASE_WIDGET = ({
|
||||
logBlackList: {},
|
||||
widgetId: "randomID",
|
||||
widgetName: "randomWidgetName",
|
||||
|
|
@ -233,15 +234,9 @@ const BASE_WIDGET: DataTreeWidget = {
|
|||
type: "SKELETON_WIDGET",
|
||||
parentId: "0",
|
||||
version: 1,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
privateWidgets: {},
|
||||
};
|
||||
meta: {},
|
||||
} as unknown) as DataTreeWidget;
|
||||
|
||||
export const BASE_ACTION: DataTreeAction = {
|
||||
clear: {},
|
||||
|
|
@ -350,7 +345,7 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
{},
|
||||
);
|
||||
const unEvalTree: Record<string, DataTreeWidget> = {
|
||||
const unEvalTree: UnEvalTree = {
|
||||
Text1: generateDataTreeWidget(
|
||||
{
|
||||
...BASE_WIDGET,
|
||||
|
|
@ -424,7 +419,7 @@ describe("DataTreeEvaluator", () => {
|
|||
),
|
||||
};
|
||||
const evaluator = new DataTreeEvaluator(WIDGET_CONFIG_MAP);
|
||||
evaluator.setupFirstTree(unEvalTree);
|
||||
evaluator.setupFirstTree(createUnEvalTreeForEval(unEvalTree));
|
||||
evaluator.evalAndValidateFirstTree();
|
||||
it("Evaluates a binding in first run", () => {
|
||||
const evaluation = evaluator.evalTree;
|
||||
|
|
@ -446,7 +441,8 @@ describe("DataTreeEvaluator", () => {
|
|||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
const dataTree = evaluator.evalTree;
|
||||
expect(dataTree).toHaveProperty("Text2.text", "Hey there");
|
||||
|
|
@ -464,7 +460,7 @@ describe("DataTreeEvaluator", () => {
|
|||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
|
||||
const dataTree = evaluator.evalTree;
|
||||
|
|
@ -482,10 +478,11 @@ describe("DataTreeEvaluator", () => {
|
|||
...unEvalTree,
|
||||
Input1,
|
||||
};
|
||||
|
||||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
const dataTree = evaluator.evalTree;
|
||||
expect(dataTree).toHaveProperty("Input1.text", "Default value");
|
||||
|
|
@ -499,7 +496,7 @@ describe("DataTreeEvaluator", () => {
|
|||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isDisabled: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
const updatedUnEvalTree = {
|
||||
const updatedUnEvalTree = ({
|
||||
...unEvalTree,
|
||||
Dropdown2: {
|
||||
...BASE_WIDGET,
|
||||
|
|
@ -522,19 +519,21 @@ describe("DataTreeEvaluator", () => {
|
|||
selectedOptionValue: EvaluationSubstitutionType.TEMPLATE,
|
||||
selectedOptionLabel: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
propertyOverrideDependency: {},
|
||||
validationPaths: {},
|
||||
},
|
||||
};
|
||||
} as unknown) as UnEvalTree;
|
||||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
const dataTree = evaluator.evalTree;
|
||||
expect(dataTree).toHaveProperty("Dropdown2.options.0.label", "newValue");
|
||||
});
|
||||
|
||||
it("Adds an entity with a complicated binding", () => {
|
||||
const updatedUnEvalTree = {
|
||||
const updatedUnEvalTree = ({
|
||||
...unEvalTree,
|
||||
Api1: {
|
||||
...BASE_ACTION,
|
||||
|
|
@ -548,11 +547,11 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
} as unknown) as UnEvalTree;
|
||||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
const dataTree = evaluator.evalTree;
|
||||
const updatedDependencyMap = evaluator.dependencyMap;
|
||||
|
|
@ -576,7 +575,7 @@ describe("DataTreeEvaluator", () => {
|
|||
});
|
||||
|
||||
it("Selects a row", () => {
|
||||
const updatedUnEvalTree = {
|
||||
const updatedUnEvalTree = ({
|
||||
...unEvalTree,
|
||||
Table1: {
|
||||
...unEvalTree.Table1,
|
||||
|
|
@ -598,11 +597,11 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
} as unknown) as UnEvalTree;
|
||||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedUnEvalTree);
|
||||
} = evaluator.setupUpdateTree(createUnEvalTreeForEval(updatedUnEvalTree));
|
||||
evaluator.evalAndValidateSubTree(evalOrder, nonDynamicFieldValidationOrder);
|
||||
const dataTree = evaluator.evalTree;
|
||||
const updatedDependencyMap = evaluator.dependencyMap;
|
||||
|
|
@ -629,7 +628,7 @@ describe("DataTreeEvaluator", () => {
|
|||
const updatedTree1 = {
|
||||
...unEvalTree,
|
||||
Text1: {
|
||||
...BASE_WIDGET,
|
||||
...unEvalTree.Text1,
|
||||
text: "Test",
|
||||
},
|
||||
Api2: {
|
||||
|
|
@ -655,7 +654,9 @@ describe("DataTreeEvaluator", () => {
|
|||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder: nonDynamicFieldValidationOrder2,
|
||||
} = evaluator.setupUpdateTree(updatedTree1);
|
||||
} = evaluator.setupUpdateTree(
|
||||
createUnEvalTreeForEval((updatedTree1 as unknown) as UnEvalTree),
|
||||
);
|
||||
evaluator.evalAndValidateSubTree(
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder2,
|
||||
|
|
@ -682,7 +683,9 @@ describe("DataTreeEvaluator", () => {
|
|||
const {
|
||||
evalOrder: newEvalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = evaluator.setupUpdateTree(updatedTree2);
|
||||
} = evaluator.setupUpdateTree(
|
||||
createUnEvalTreeForEval((updatedTree2 as unknown) as UnEvalTree),
|
||||
);
|
||||
evaluator.evalAndValidateSubTree(
|
||||
newEvalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
|
|
@ -715,7 +718,9 @@ describe("DataTreeEvaluator", () => {
|
|||
const {
|
||||
evalOrder: newEvalOrder2,
|
||||
nonDynamicFieldValidationOrder: nonDynamicFieldValidationOrder3,
|
||||
} = evaluator.setupUpdateTree(updatedTree3);
|
||||
} = evaluator.setupUpdateTree(
|
||||
createUnEvalTreeForEval((updatedTree3 as unknown) as UnEvalTree),
|
||||
);
|
||||
evaluator.evalAndValidateSubTree(
|
||||
newEvalOrder2,
|
||||
nonDynamicFieldValidationOrder3,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import {
|
|||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
EvaluationSubstitutionType,
|
||||
PrivateWidgets,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { PrivateWidgets } from "entities/DataTree/types";
|
||||
import {
|
||||
DataTreeDiff,
|
||||
DataTreeDiffEvent,
|
||||
|
|
@ -30,6 +30,8 @@ import InputWidget, {
|
|||
CONFIG as InputWidgetV2Config,
|
||||
} from "widgets/InputWidgetV2";
|
||||
import { registerWidget } from "utils/WidgetRegisterHelpers";
|
||||
import { WidgetConfiguration } from "widgets/constants";
|
||||
import { createNewEntity } from "../dataTreeUtils";
|
||||
|
||||
// to check if logWarn was called.
|
||||
// use jest.unmock, if the mock needs to be removed.
|
||||
|
|
@ -137,8 +139,8 @@ const testDataTree: Record<string, DataTreeWidget> = {
|
|||
},
|
||||
};
|
||||
|
||||
describe("Correctly handle paths", () => {
|
||||
it("getsAllPaths", () => {
|
||||
describe("1. Correctly handle paths", () => {
|
||||
it("1. getsAllPaths", () => {
|
||||
const myTree = {
|
||||
WidgetName: {
|
||||
1: "yo",
|
||||
|
|
@ -177,8 +179,8 @@ describe("Correctly handle paths", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("privateWidgets", () => {
|
||||
it("correctly checks if path is a PrivateEntityPath", () => {
|
||||
describe("2. privateWidgets", () => {
|
||||
it("1. correctly checks if path is a PrivateEntityPath", () => {
|
||||
const privateWidgets: PrivateWidgets = {
|
||||
Button1: true,
|
||||
Image1: true,
|
||||
|
|
@ -196,7 +198,7 @@ describe("privateWidgets", () => {
|
|||
expect(isPrivateEntityPath(privateWidgets, "Image2.data")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("Returns list of all privateWidgets", () => {
|
||||
it("2. Returns list of all privateWidgets", () => {
|
||||
const expectedPrivateWidgetsList = {
|
||||
Text2: true,
|
||||
Text3: true,
|
||||
|
|
@ -209,7 +211,7 @@ describe("privateWidgets", () => {
|
|||
expect(expectedPrivateWidgetsList).toStrictEqual(actualPrivateWidgetsList);
|
||||
});
|
||||
|
||||
it("Returns data tree without privateWidgets", () => {
|
||||
it("3. Returns data tree without privateWidgets", () => {
|
||||
const expectedDataTreeWithoutPrivateWidgets: Record<
|
||||
string,
|
||||
DataTreeWidget
|
||||
|
|
@ -274,8 +276,8 @@ describe("privateWidgets", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("makeParentsDependOnChildren", () => {
|
||||
it("makes parent properties depend on child properties", () => {
|
||||
describe("3. makeParentsDependOnChildren", () => {
|
||||
it("1. makes parent properties depend on child properties", () => {
|
||||
let depMap: DependencyMap = {
|
||||
Widget1: [],
|
||||
"Widget1.defaultText": [],
|
||||
|
|
@ -294,7 +296,7 @@ describe("makeParentsDependOnChildren", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("logs warning for child properties not listed in allKeys", () => {
|
||||
it("2. logs warning for child properties not listed in allKeys", () => {
|
||||
const depMap: DependencyMap = {
|
||||
Widget1: [],
|
||||
"Widget1.defaultText": [],
|
||||
|
|
@ -310,8 +312,8 @@ describe("makeParentsDependOnChildren", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("translateDiffEvent", () => {
|
||||
it("noop when diff path does not exist", () => {
|
||||
describe("4. translateDiffEvent", () => {
|
||||
it("1. noop when diff path does not exist", () => {
|
||||
const noDiffPath: Diff<any, any> = {
|
||||
kind: "E",
|
||||
lhs: undefined,
|
||||
|
|
@ -326,7 +328,7 @@ describe("translateDiffEvent", () => {
|
|||
event: DataTreeDiffEvent.NOOP,
|
||||
});
|
||||
});
|
||||
it("translates new and delete events", () => {
|
||||
it("2. translates new and delete events", () => {
|
||||
const diffs: Diff<any, any>[] = [
|
||||
{
|
||||
kind: "N",
|
||||
|
|
@ -397,7 +399,7 @@ describe("translateDiffEvent", () => {
|
|||
expect(expectedTranslations).toStrictEqual(actualTranslations);
|
||||
});
|
||||
|
||||
it("properly categorises the edit events", () => {
|
||||
it("3. properly categorises the edit events", () => {
|
||||
const diffs: Diff<any, any>[] = [
|
||||
{
|
||||
kind: "E",
|
||||
|
|
@ -423,7 +425,7 @@ describe("translateDiffEvent", () => {
|
|||
expect(expectedTranslations).toStrictEqual(actualTranslations);
|
||||
});
|
||||
|
||||
it("handles JsObject function renaming", () => {
|
||||
it("4. handles JsObject function renaming", () => {
|
||||
// cyclic dependency case
|
||||
const lhs = new String("() => {}");
|
||||
_.set(lhs, "data", {});
|
||||
|
|
@ -465,7 +467,7 @@ describe("translateDiffEvent", () => {
|
|||
expect(expectedTranslations).toStrictEqual(actualTranslations);
|
||||
});
|
||||
|
||||
it("lists array accessors when object is replaced by an array", () => {
|
||||
it("5. lists array accessors when object is replaced by an array", () => {
|
||||
const diffs: Diff<any, any>[] = [
|
||||
{
|
||||
kind: "E",
|
||||
|
|
@ -497,7 +499,7 @@ describe("translateDiffEvent", () => {
|
|||
expect(expectedTranslations).toStrictEqual(actualTranslations);
|
||||
});
|
||||
|
||||
it("lists array accessors when array is replaced by an object", () => {
|
||||
it("6. lists array accessors when array is replaced by an object", () => {
|
||||
const diffs: Diff<any, any>[] = [
|
||||
{
|
||||
kind: "E",
|
||||
|
|
@ -529,7 +531,7 @@ describe("translateDiffEvent", () => {
|
|||
expect(expectedTranslations).toStrictEqual(actualTranslations);
|
||||
});
|
||||
|
||||
it("deletes member expressions when Array changes to string", () => {
|
||||
it("7. deletes member expressions when Array changes to string", () => {
|
||||
const diffs: Diff<any, any>[] = [
|
||||
{
|
||||
kind: "E",
|
||||
|
|
@ -569,10 +571,13 @@ describe("translateDiffEvent", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("overrideWidgetProperties", () => {
|
||||
describe("5. overrideWidgetProperties", () => {
|
||||
beforeAll(() => {
|
||||
registerWidget(TableWidget, TableWidgetConfig);
|
||||
registerWidget(InputWidget, InputWidgetV2Config);
|
||||
registerWidget(
|
||||
InputWidget,
|
||||
(InputWidgetV2Config as unknown) as WidgetConfiguration,
|
||||
);
|
||||
});
|
||||
|
||||
describe("1. Input widget ", () => {
|
||||
|
|
@ -596,7 +601,7 @@ describe("overrideWidgetProperties", () => {
|
|||
},
|
||||
{},
|
||||
);
|
||||
currentTree["Input1"] = inputWidgetDataTree;
|
||||
currentTree["Input1"] = createNewEntity(inputWidgetDataTree);
|
||||
});
|
||||
// When default text is re-evaluated it will override values of meta.text and text in InputWidget
|
||||
it("1. defaultText updating meta.text and text", () => {
|
||||
|
|
@ -673,7 +678,7 @@ describe("overrideWidgetProperties", () => {
|
|||
},
|
||||
{},
|
||||
);
|
||||
currentTree["Table1"] = tableWidgetDataTree;
|
||||
currentTree["Table1"] = createNewEntity(tableWidgetDataTree);
|
||||
});
|
||||
// When default defaultSelectedRow is re-evaluated it will override values of meta.selectedRowIndices, selectedRowIndices, meta.selectedRowIndex & selectedRowIndex.
|
||||
it("1. On change of defaultSelectedRow ", () => {
|
||||
|
|
@ -730,7 +735,7 @@ describe("overrideWidgetProperties", () => {
|
|||
});
|
||||
|
||||
//A set of test cases to evaluate the logic for finding a given value's datatype
|
||||
describe("Evaluated Datatype of a given value", () => {
|
||||
describe("6. Evaluated Datatype of a given value", () => {
|
||||
it("1. Numeric datatypes", () => {
|
||||
expect(findDatatype(37)).toBe("number");
|
||||
expect(findDatatype(3.14)).toBe("number");
|
||||
|
|
|
|||
54
app/client/src/workers/Evaluation/dataTreeUtils.ts
Normal file
54
app/client/src/workers/Evaluation/dataTreeUtils.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import {
|
||||
DataTree,
|
||||
DataTreeEntity,
|
||||
UnEvalTree,
|
||||
UnEvalTreeEntityObject,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
/**
|
||||
* This method accept an entity object as input and if it has __config__ property than it moves the __config__ to object's prototype
|
||||
*/
|
||||
export function createNewEntity(entity: UnEvalTreeEntityObject) {
|
||||
if (!entity || !entity.hasOwnProperty("__config__")) return entity;
|
||||
const { __config__, ...rest } = entity;
|
||||
const newObj = Object.create(__config__);
|
||||
Object.assign(newObj, rest) as DataTreeEntity;
|
||||
return newObj;
|
||||
}
|
||||
/**
|
||||
* This method takes unevaltree received from mainThread as input and return a new unEvalTree with each entity config moved to entity object's prototype.
|
||||
* Moving configs to prototype skips it from diffing, cloning and getAllPaths calculation.
|
||||
* Refer: https://github.com/appsmithorg/appsmith/pull/18361 to know more
|
||||
*/
|
||||
export function createUnEvalTreeForEval(unevalTree: UnEvalTree) {
|
||||
const newUnEvalTree: DataTree = {};
|
||||
|
||||
for (const entityName of Object.keys(unevalTree)) {
|
||||
const entity = unevalTree[entityName];
|
||||
newUnEvalTree[entityName] = createNewEntity(
|
||||
entity as UnEvalTreeEntityObject,
|
||||
);
|
||||
}
|
||||
|
||||
return newUnEvalTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loops through each entity object of dataTree and sets the entity config from prototype as object properties.
|
||||
* This is done to send back dataTree in the format expected by mainThread.
|
||||
*/
|
||||
export function makeEntityConfigsAsObjProperties(
|
||||
dataTree: DataTree,
|
||||
option = {} as { sanitizeDataTree: boolean },
|
||||
) {
|
||||
const { sanitizeDataTree = true } = option;
|
||||
const newDataTree: DataTree = {};
|
||||
for (const entityName of Object.keys(dataTree)) {
|
||||
const entityConfig = Object.getPrototypeOf(dataTree[entityName]) || {};
|
||||
const entity = dataTree[entityName];
|
||||
newDataTree[entityName] = { ...entityConfig, ...entity };
|
||||
}
|
||||
return sanitizeDataTree
|
||||
? JSON.parse(JSON.stringify(newDataTree))
|
||||
: newDataTree;
|
||||
}
|
||||
|
|
@ -170,13 +170,10 @@ export const createGlobalData = (args: createGlobalDataArgs) => {
|
|||
context?.eventType,
|
||||
);
|
||||
///// Adding Data tree with functions
|
||||
Object.keys(dataTreeWithFunctions).forEach((datum) => {
|
||||
GLOBAL_DATA[datum] = dataTreeWithFunctions[datum];
|
||||
});
|
||||
Object.assign(GLOBAL_DATA, dataTreeWithFunctions);
|
||||
} else {
|
||||
Object.keys(dataTree).forEach((datum) => {
|
||||
GLOBAL_DATA[datum] = dataTree[datum];
|
||||
});
|
||||
// Object.assign removes prototypes of the entity object making sure configs are not shown to user.
|
||||
Object.assign(GLOBAL_DATA, dataTree);
|
||||
}
|
||||
if (!isEmpty(resolvedFunctions)) {
|
||||
Object.keys(resolvedFunctions).forEach((datum: any) => {
|
||||
|
|
@ -187,8 +184,7 @@ export const createGlobalData = (args: createGlobalDataArgs) => {
|
|||
const data = dataTreeKey[key]?.data;
|
||||
//do not remove we will be investigating this
|
||||
//const isAsync = dataTreeKey?.meta[key]?.isAsync || false;
|
||||
//const confirmBeforeExecute =
|
||||
dataTreeKey?.meta[key]?.confirmBeforeExecute || false;
|
||||
//const confirmBeforeExecute = dataTreeKey?.meta[key]?.confirmBeforeExecute || false;
|
||||
dataTreeKey[key] = resolvedObject[key];
|
||||
// if (isAsync && confirmBeforeExecute) {
|
||||
// dataTreeKey[key] = confirmationPromise.bind(
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ import evaluate, {
|
|||
import { JSUpdate } from "utils/JSPaneUtils";
|
||||
import { validateWidgetProperty } from "workers/common/DataTreeEvaluator/validationUtils";
|
||||
import { initiateLinting } from "workers/Linting/utils";
|
||||
import {
|
||||
createUnEvalTreeForEval,
|
||||
makeEntityConfigsAsObjProperties,
|
||||
} from "./dataTreeUtils";
|
||||
|
||||
const CANVAS = "canvas";
|
||||
|
||||
|
|
@ -111,19 +115,22 @@ function eventRequestHandler({
|
|||
case EVAL_WORKER_ACTIONS.EVAL_TRIGGER: {
|
||||
const {
|
||||
callbackData,
|
||||
dataTree,
|
||||
dynamicTrigger,
|
||||
eventType,
|
||||
globalContext,
|
||||
triggerMeta,
|
||||
unEvalTree: __unEvalTree__,
|
||||
} = requestData;
|
||||
if (!dataTreeEvaluator) {
|
||||
return { triggers: [], errors: [] };
|
||||
}
|
||||
|
||||
const unEvalTree = createUnEvalTreeForEval(__unEvalTree__);
|
||||
|
||||
const {
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
} = dataTreeEvaluator.setupUpdateTree(dataTree);
|
||||
} = dataTreeEvaluator.setupUpdateTree(unEvalTree);
|
||||
dataTreeEvaluator.evalAndValidateSubTree(
|
||||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
|
|
@ -238,10 +245,13 @@ function eventRequestHandler({
|
|||
requiresLinting,
|
||||
shouldReplay,
|
||||
theme,
|
||||
unevalTree,
|
||||
unevalTree: __unevalTree__,
|
||||
widgets,
|
||||
widgetTypeConfigMap,
|
||||
} = requestData as EvalTreeRequestData;
|
||||
|
||||
const unevalTree = createUnEvalTreeForEval(__unevalTree__);
|
||||
|
||||
try {
|
||||
if (!dataTreeEvaluator) {
|
||||
isCreateFirstTree = true;
|
||||
|
|
@ -251,6 +261,7 @@ function eventRequestHandler({
|
|||
widgetTypeConfigMap,
|
||||
allActionValidationConfig,
|
||||
);
|
||||
|
||||
const setupFirstTreeResponse = dataTreeEvaluator.setupFirstTree(
|
||||
unevalTree,
|
||||
);
|
||||
|
|
@ -260,14 +271,16 @@ function eventRequestHandler({
|
|||
|
||||
initiateLinting(
|
||||
lintOrder,
|
||||
jsUpdates,
|
||||
dataTreeEvaluator.oldUnEvalTree,
|
||||
makeEntityConfigsAsObjProperties(dataTreeEvaluator.oldUnEvalTree, {
|
||||
sanitizeDataTree: false,
|
||||
}),
|
||||
requiresLinting,
|
||||
);
|
||||
|
||||
const dataTreeResponse = dataTreeEvaluator.evalAndValidateFirstTree();
|
||||
dataTree = dataTreeResponse.evalTree;
|
||||
dataTree = dataTree && JSON.parse(JSON.stringify(dataTree));
|
||||
dataTree = makeEntityConfigsAsObjProperties(
|
||||
dataTreeResponse.evalTree,
|
||||
);
|
||||
} else if (dataTreeEvaluator.hasCyclicalDependency) {
|
||||
if (dataTreeEvaluator && !isEmpty(allActionValidationConfig)) {
|
||||
//allActionValidationConfigs may not be set in dataTreeEvaluatior. Therefore, set it explicitly via setter method
|
||||
|
|
@ -297,14 +310,16 @@ function eventRequestHandler({
|
|||
|
||||
initiateLinting(
|
||||
lintOrder,
|
||||
jsUpdates,
|
||||
dataTreeEvaluator.oldUnEvalTree,
|
||||
makeEntityConfigsAsObjProperties(dataTreeEvaluator.oldUnEvalTree, {
|
||||
sanitizeDataTree: false,
|
||||
}),
|
||||
requiresLinting,
|
||||
);
|
||||
|
||||
const dataTreeResponse = dataTreeEvaluator.evalAndValidateFirstTree();
|
||||
dataTree = dataTreeResponse.evalTree;
|
||||
dataTree = dataTree && JSON.parse(JSON.stringify(dataTree));
|
||||
dataTree = makeEntityConfigsAsObjProperties(
|
||||
dataTreeResponse.evalTree,
|
||||
);
|
||||
} else {
|
||||
if (dataTreeEvaluator && !isEmpty(allActionValidationConfig)) {
|
||||
dataTreeEvaluator.setAllActionValidationConfig(
|
||||
|
|
@ -325,8 +340,9 @@ function eventRequestHandler({
|
|||
|
||||
initiateLinting(
|
||||
lintOrder,
|
||||
jsUpdates,
|
||||
dataTreeEvaluator.oldUnEvalTree,
|
||||
makeEntityConfigsAsObjProperties(dataTreeEvaluator.oldUnEvalTree, {
|
||||
sanitizeDataTree: false,
|
||||
}),
|
||||
requiresLinting,
|
||||
);
|
||||
nonDynamicFieldValidationOrder =
|
||||
|
|
@ -335,7 +351,9 @@ function eventRequestHandler({
|
|||
evalOrder,
|
||||
nonDynamicFieldValidationOrder,
|
||||
);
|
||||
dataTree = JSON.parse(JSON.stringify(dataTreeEvaluator.evalTree));
|
||||
dataTree = makeEntityConfigsAsObjProperties(
|
||||
dataTreeEvaluator.evalTree,
|
||||
);
|
||||
evalMetaUpdates = JSON.parse(
|
||||
JSON.stringify(updateResponse.evalMetaUpdates),
|
||||
);
|
||||
|
|
@ -366,7 +384,12 @@ function eventRequestHandler({
|
|||
});
|
||||
console.error(error);
|
||||
}
|
||||
dataTree = getSafeToRenderDataTree(unevalTree, widgetTypeConfigMap);
|
||||
|
||||
dataTree = getSafeToRenderDataTree(
|
||||
makeEntityConfigsAsObjProperties(unevalTree),
|
||||
widgetTypeConfigMap,
|
||||
);
|
||||
|
||||
unEvalUpdates = [];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import {
|
|||
DataTreeWidget,
|
||||
ENTITY_TYPE,
|
||||
DataTreeJSAction,
|
||||
PrivateWidgets,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
import _, { get, set } from "lodash";
|
||||
import { WidgetTypeConfigMap } from "utils/WidgetFactory";
|
||||
import { PluginType } from "entities/Action";
|
||||
|
|
@ -27,6 +27,7 @@ import { EvalMetaUpdates } from "../common/DataTreeEvaluator/types";
|
|||
import { isObject } from "lodash";
|
||||
import { DataTreeObjectEntity } from "entities/DataTree/dataTreeFactory";
|
||||
import { validateWidgetProperty } from "workers/common/DataTreeEvaluator/validationUtils";
|
||||
import { PrivateWidgets } from "entities/DataTree/types";
|
||||
|
||||
// Dropdown1.options[1].value -> Dropdown1.options[1]
|
||||
// Dropdown1.options[1] -> Dropdown1.options
|
||||
|
|
@ -496,8 +497,8 @@ export const getAllPaths = (
|
|||
const tempKey = curKey ? `${curKey}[${i}]` : `${i}`;
|
||||
getAllPaths(records[i], tempKey, result);
|
||||
}
|
||||
} else if (typeof records === "object") {
|
||||
for (const key in records) {
|
||||
} else if (typeof records === "object" && records) {
|
||||
for (const key of Object.keys(records)) {
|
||||
const tempKey = curKey ? `${curKey}.${key}` : `${key}`;
|
||||
getAllPaths(records[key], tempKey, result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ActionValidationConfigMap } from "constants/PropertyControlConstants";
|
||||
import { UserLogObject } from "entities/AppsmithConsole";
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { DataTree, UnEvalTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { CanvasWidgetsReduxState } from "reducers/entityReducers/canvasWidgetsReducer";
|
||||
|
||||
import {
|
||||
|
|
@ -19,7 +19,7 @@ export type EvalWorkerRequest = WorkerRequest<any, EVAL_WORKER_ACTIONS>;
|
|||
export type EvalWorkerResponse = EvalTreeResponseData | boolean | unknown;
|
||||
|
||||
export interface EvalTreeRequestData {
|
||||
unevalTree: DataTree;
|
||||
unevalTree: UnEvalTree;
|
||||
widgetTypeConfigMap: WidgetTypeConfigMap;
|
||||
widgets: CanvasWidgetsReduxState;
|
||||
theme: AppTheme;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { LintErrors } from "reducers/lintingReducers/lintErrorsReducers";
|
||||
import { JSUpdate } from "utils/JSPaneUtils";
|
||||
import { WorkerRequest } from "workers/common/types";
|
||||
|
||||
export enum LINT_WORKER_ACTIONS {
|
||||
|
|
@ -14,7 +13,6 @@ export interface LintTreeResponse {
|
|||
export interface LintTreeRequest {
|
||||
pathsToLint: string[];
|
||||
unevalTree: DataTree;
|
||||
jsUpdates: Record<string, JSUpdate>;
|
||||
}
|
||||
|
||||
export type LintWorkerRequest = WorkerRequest<
|
||||
|
|
@ -24,6 +22,5 @@ export type LintWorkerRequest = WorkerRequest<
|
|||
|
||||
export type LintTreeSagaRequestData = {
|
||||
pathsToLint: string[];
|
||||
jsUpdates: Record<string, JSUpdate>;
|
||||
unevalTree: DataTree;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ import {
|
|||
isWidget,
|
||||
} from "workers/Evaluation/evaluationUtils";
|
||||
import { LintErrors } from "reducers/lintingReducers/lintErrorsReducers";
|
||||
import { JSUpdate } from "utils/JSPaneUtils";
|
||||
import { Severity } from "entities/AppsmithConsole";
|
||||
|
||||
export function getlintErrorsFromTree(
|
||||
|
|
@ -461,7 +460,6 @@ function getInvalidPropertyErrorsFromScript(
|
|||
|
||||
export function initiateLinting(
|
||||
lintOrder: string[],
|
||||
jsUpdates: Record<string, JSUpdate>,
|
||||
unevalTree: DataTree,
|
||||
requiresLinting: boolean,
|
||||
) {
|
||||
|
|
@ -470,7 +468,6 @@ export function initiateLinting(
|
|||
promisified: true,
|
||||
responseData: {
|
||||
lintOrder,
|
||||
jsUpdates,
|
||||
unevalTree,
|
||||
type: EVAL_WORKER_ACTIONS.LINT_TREE,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import {
|
|||
DataTreeJSAction,
|
||||
DataTreeWidget,
|
||||
EvaluationSubstitutionType,
|
||||
PrivateWidgets,
|
||||
} from "entities/DataTree/dataTreeFactory";
|
||||
import { PrivateWidgets } from "entities/DataTree/types";
|
||||
import {
|
||||
addDependantsOfNestedPropertyPaths,
|
||||
addErrorToEntityProperty,
|
||||
|
|
@ -39,6 +39,7 @@ import {
|
|||
trimDependantChangePaths,
|
||||
overrideWidgetProperties,
|
||||
getAllPaths,
|
||||
isValidEntity,
|
||||
} from "workers/Evaluation/evaluationUtils";
|
||||
import {
|
||||
difference,
|
||||
|
|
@ -415,7 +416,7 @@ export default class DataTreeEvaluator {
|
|||
});
|
||||
const updateDependencyEndTime = performance.now();
|
||||
|
||||
this.applyDifferencesToEvalTree(differences);
|
||||
this.applyDifferencesToEvalTree({ differences, localUnEvalTree });
|
||||
|
||||
const calculateSortOrderStartTime = performance.now();
|
||||
const subTreeSortOrder: string[] = this.calculateSubTreeSortOrder(
|
||||
|
|
@ -1158,11 +1159,36 @@ export default class DataTreeEvaluator {
|
|||
}
|
||||
}
|
||||
|
||||
applyDifferencesToEvalTree(differences: Diff<any, any>[]) {
|
||||
/**
|
||||
* Update the entity config set as prototype according to latest unEvalTree changes else code would consume stale configs.
|
||||
*
|
||||
* Example scenario: On addition of a JS binding to widget, it's dynamicBindingPathList changes and needs to be updated.
|
||||
*/
|
||||
updateConfigForModifiedEntity(unEvalTree: DataTree, entityName: string) {
|
||||
const unEvalEntity = unEvalTree[entityName];
|
||||
// skip entity if entity is not present in the evalTree or is not a valid entity
|
||||
if (!this.evalTree[entityName] || !isValidEntity(this.evalTree[entityName]))
|
||||
return;
|
||||
const entityConfig = Object.getPrototypeOf(unEvalEntity);
|
||||
const newEntityObject = Object.create(entityConfig);
|
||||
this.evalTree[entityName] = Object.assign(newEntityObject, {
|
||||
...this.evalTree[entityName],
|
||||
});
|
||||
}
|
||||
|
||||
applyDifferencesToEvalTree({
|
||||
differences,
|
||||
localUnEvalTree,
|
||||
}: {
|
||||
differences: Diff<any, any>[];
|
||||
localUnEvalTree: DataTree;
|
||||
}) {
|
||||
for (const d of differences) {
|
||||
if (!Array.isArray(d.path) || d.path.length === 0) continue; // Null check for typescript
|
||||
// Apply the changes into the evalTree so that it gets the latest changes
|
||||
applyChange(this.evalTree, undefined, d);
|
||||
const { entityName } = getEntityNameAndPropertyPath(d.path.join("."));
|
||||
this.updateConfigForModifiedEntity(localUnEvalTree, entityName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,26 +232,6 @@ export const unEvalTree = {
|
|||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
privateWidgets: {},
|
||||
},
|
||||
pageList: [
|
||||
{
|
||||
pageName: "Page1",
|
||||
pageId: "6200d1a2b5bfc0392b959cae",
|
||||
isDefault: true,
|
||||
isHidden: false,
|
||||
},
|
||||
{
|
||||
pageName: "Page2",
|
||||
pageId: "621e22cf2b75295c1c165fa6",
|
||||
isDefault: false,
|
||||
isHidden: false,
|
||||
},
|
||||
{
|
||||
pageName: "Page3",
|
||||
pageId: "6220c268c48234070f8ac65a",
|
||||
isDefault: false,
|
||||
isHidden: false,
|
||||
},
|
||||
],
|
||||
appsmith: {
|
||||
user: {
|
||||
email: "rathod@appsmith.com",
|
||||
|
|
@ -505,15 +485,6 @@ export const asyncTagUnevalTree: DataTree = {
|
|||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
privateWidgets: {},
|
||||
} as unknown) as DataTreeWidget,
|
||||
pageList: [
|
||||
{
|
||||
pageName: "Page1",
|
||||
pageId: "6272179d8a368d6f1efcd0d2",
|
||||
isDefault: true,
|
||||
isHidden: false,
|
||||
slug: "page1",
|
||||
},
|
||||
],
|
||||
appsmith: ({
|
||||
user: {
|
||||
email: "anand@appsmith.com",
|
||||
|
|
@ -1126,16 +1097,6 @@ export const lintingUnEvalTree = {
|
|||
ENTITY_TYPE: "WIDGET",
|
||||
privateWidgets: {},
|
||||
},
|
||||
pageList: [
|
||||
{
|
||||
pageName: "Page1",
|
||||
pageId: "62bf3730174c17103179d18c",
|
||||
isDefault: true,
|
||||
isHidden: false,
|
||||
slug: "page1",
|
||||
latest: false,
|
||||
},
|
||||
],
|
||||
appsmith: {
|
||||
user: {
|
||||
email: "favour@appsmith.com",
|
||||
|
|
|
|||
|
|
@ -109,59 +109,55 @@ export function validateActionProperty(
|
|||
|
||||
export function getValidatedTree(tree: DataTree) {
|
||||
return Object.keys(tree).reduce((tree, entityKey: string) => {
|
||||
const entity = tree[entityKey] as DataTreeWidget;
|
||||
if (!isWidget(entity)) {
|
||||
const parsedEntity = tree[entityKey];
|
||||
if (!isWidget(parsedEntity)) {
|
||||
return tree;
|
||||
}
|
||||
const parsedEntity = { ...entity };
|
||||
Object.entries(entity.validationPaths).forEach(([property, validation]) => {
|
||||
const value = get(entity, property);
|
||||
// Pass it through parse
|
||||
const { isValid, messages, parsed, transformed } = validateWidgetProperty(
|
||||
validation,
|
||||
value,
|
||||
entity,
|
||||
property,
|
||||
);
|
||||
set(parsedEntity, property, parsed);
|
||||
const evaluatedValue = isValid
|
||||
? parsed
|
||||
: isUndefined(transformed)
|
||||
? value
|
||||
: transformed;
|
||||
const safeEvaluatedValue = removeFunctions(evaluatedValue);
|
||||
set(
|
||||
parsedEntity,
|
||||
getEvalValuePath(`${entityKey}.${property}`, {
|
||||
isPopulated: false,
|
||||
fullPath: false,
|
||||
}),
|
||||
safeEvaluatedValue,
|
||||
);
|
||||
if (!isValid) {
|
||||
const evalErrors: EvaluationError[] =
|
||||
messages?.map((message) => ({
|
||||
errorType: PropertyEvaluationErrorType.VALIDATION,
|
||||
errorMessage: message,
|
||||
severity: Severity.ERROR,
|
||||
raw: value,
|
||||
})) ?? [];
|
||||
addErrorToEntityProperty(
|
||||
evalErrors,
|
||||
tree,
|
||||
getEvalErrorPath(`${entityKey}.${property}`, {
|
||||
|
||||
Object.entries(parsedEntity.validationPaths).forEach(
|
||||
([property, validation]) => {
|
||||
const value = get(parsedEntity, property);
|
||||
// Pass it through parse
|
||||
const {
|
||||
isValid,
|
||||
messages,
|
||||
parsed,
|
||||
transformed,
|
||||
} = validateWidgetProperty(validation, value, parsedEntity, property);
|
||||
set(parsedEntity, property, parsed);
|
||||
const evaluatedValue = isValid
|
||||
? parsed
|
||||
: isUndefined(transformed)
|
||||
? value
|
||||
: transformed;
|
||||
const safeEvaluatedValue = removeFunctions(evaluatedValue);
|
||||
set(
|
||||
parsedEntity,
|
||||
getEvalValuePath(`${entityKey}.${property}`, {
|
||||
isPopulated: false,
|
||||
fullPath: false,
|
||||
}),
|
||||
safeEvaluatedValue,
|
||||
);
|
||||
}
|
||||
// else {
|
||||
// resetValidationErrorsForEntityProperty(
|
||||
// tree,
|
||||
// `${entityKey}.${property}`,
|
||||
// );
|
||||
// }
|
||||
});
|
||||
if (!isValid) {
|
||||
const evalErrors: EvaluationError[] =
|
||||
messages?.map((message) => ({
|
||||
errorType: PropertyEvaluationErrorType.VALIDATION,
|
||||
errorMessage: message,
|
||||
severity: Severity.ERROR,
|
||||
raw: value,
|
||||
})) ?? [];
|
||||
addErrorToEntityProperty(
|
||||
evalErrors,
|
||||
tree,
|
||||
getEvalErrorPath(`${entityKey}.${property}`, {
|
||||
isPopulated: false,
|
||||
fullPath: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
return { ...tree, [entityKey]: parsedEntity };
|
||||
}, tree);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user