fix: table search text dependency deletion (#11608)
* Replace BindingPaths with ReactivePaths and remove non-bindable property path from bindingPaths to reduce confusion.
This commit is contained in:
parent
68bca33a55
commit
136308fd7c
|
|
@ -1,5 +1,5 @@
|
|||
import { Action, PluginType } from "entities/Action/index";
|
||||
import { getBindingPathsOfAction } from "entities/Action/actionProperties";
|
||||
import { getBindingAndReactivePathsOfAction } from "entities/Action/actionProperties";
|
||||
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||
|
||||
const DEFAULT_ACTION: Action = {
|
||||
|
|
@ -18,12 +18,16 @@ const DEFAULT_ACTION: Action = {
|
|||
organizationId: "",
|
||||
pageId: "",
|
||||
pluginId: "",
|
||||
messages: [],
|
||||
pluginType: PluginType.DB,
|
||||
};
|
||||
|
||||
describe("getBindingPathsOfAction", () => {
|
||||
describe("getReactivePathsOfAction", () => {
|
||||
it("returns default list of no config is sent", () => {
|
||||
const response = getBindingPathsOfAction(DEFAULT_ACTION, undefined);
|
||||
const response = getBindingAndReactivePathsOfAction(
|
||||
DEFAULT_ACTION,
|
||||
undefined,
|
||||
).reactivePaths;
|
||||
expect(response).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -73,7 +77,8 @@ describe("getBindingPathsOfAction", () => {
|
|||
},
|
||||
};
|
||||
|
||||
const response = getBindingPathsOfAction(basicAction, config);
|
||||
const response = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.reactivePaths;
|
||||
expect(response).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -139,7 +144,8 @@ describe("getBindingPathsOfAction", () => {
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const response = getBindingPathsOfAction(basicAction, config);
|
||||
const response = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.reactivePaths;
|
||||
expect(response).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -195,7 +201,8 @@ describe("getBindingPathsOfAction", () => {
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const response = getBindingPathsOfAction(basicAction, config);
|
||||
const response = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.reactivePaths;
|
||||
expect(response).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -205,7 +212,7 @@ describe("getBindingPathsOfAction", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("checks for hidden field and returns bindingPaths accordingly", () => {
|
||||
it("checks for hidden field and returns reactivePaths accordingly", () => {
|
||||
const config = [
|
||||
{
|
||||
sectionName: "",
|
||||
|
|
@ -252,7 +259,8 @@ describe("getBindingPathsOfAction", () => {
|
|||
},
|
||||
};
|
||||
|
||||
const response = getBindingPathsOfAction(basicAction, config);
|
||||
const response = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.reactivePaths;
|
||||
expect(response).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -263,7 +271,8 @@ describe("getBindingPathsOfAction", () => {
|
|||
|
||||
basicAction.actionConfiguration.template.setting = true;
|
||||
|
||||
const response2 = getBindingPathsOfAction(basicAction, config);
|
||||
const response2 = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.reactivePaths;
|
||||
expect(response2).toStrictEqual({
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -272,4 +281,63 @@ describe("getBindingPathsOfAction", () => {
|
|||
"config.body2": EvaluationSubstitutionType.TEMPLATE,
|
||||
});
|
||||
});
|
||||
|
||||
it.only("returns default list of no config is sent", () => {
|
||||
const response = getBindingAndReactivePathsOfAction(
|
||||
DEFAULT_ACTION,
|
||||
undefined,
|
||||
).bindingPaths;
|
||||
expect(response).toStrictEqual({});
|
||||
});
|
||||
|
||||
it.only("returns correct values for basic config", () => {
|
||||
const config = [
|
||||
{
|
||||
sectionName: "",
|
||||
id: 1,
|
||||
children: [
|
||||
{
|
||||
label: "",
|
||||
configProperty: "actionConfiguration.body",
|
||||
controlType: "QUERY_DYNAMIC_TEXT",
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
configProperty: "actionConfiguration.body2",
|
||||
controlType: "QUERY_DYNAMIC_INPUT_TEXT",
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
configProperty: "actionConfiguration.field1",
|
||||
controlType: "QUERY_DYNAMIC_INPUT_TEXT",
|
||||
evaluationSubstitutionType: "SMART_SUBSTITUTE",
|
||||
},
|
||||
{
|
||||
label: "",
|
||||
configProperty: "actionConfiguration.field2",
|
||||
controlType: "QUERY_DYNAMIC_INPUT_TEXT",
|
||||
evaluationSubstitutionType: "PARAMETER",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const basicAction = {
|
||||
...DEFAULT_ACTION,
|
||||
actionConfiguration: {
|
||||
body: "basic action",
|
||||
body2: "another body",
|
||||
field1: "test",
|
||||
field2: "anotherTest",
|
||||
},
|
||||
};
|
||||
|
||||
const response = getBindingAndReactivePathsOfAction(basicAction, config)
|
||||
.bindingPaths;
|
||||
expect(response).toStrictEqual({
|
||||
"config.body": EvaluationSubstitutionType.TEMPLATE,
|
||||
"config.body2": EvaluationSubstitutionType.TEMPLATE,
|
||||
"config.field1": EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
"config.field2": EvaluationSubstitutionType.PARAMETER,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,9 +12,15 @@ import {
|
|||
WhereClauseSubComponent,
|
||||
allowedControlTypes,
|
||||
} from "components/formControls/utils";
|
||||
import formControlTypes from "utils/formControl/formControlTypes";
|
||||
|
||||
const dynamicFields = ["QUERY_DYNAMIC_TEXT", "QUERY_DYNAMIC_INPUT_TEXT"];
|
||||
const dynamicFields = [
|
||||
formControlTypes.QUERY_DYNAMIC_TEXT,
|
||||
formControlTypes.QUERY_DYNAMIC_INPUT_TEXT,
|
||||
];
|
||||
|
||||
type ReactivePaths = Record<string, EvaluationSubstitutionType>;
|
||||
type BindingPaths = ReactivePaths;
|
||||
const getCorrectEvaluationSubstitutionType = (substitutionType?: string) => {
|
||||
if (substitutionType) {
|
||||
if (substitutionType === EvaluationSubstitutionType.SMART_SUBSTITUTE) {
|
||||
|
|
@ -26,20 +32,25 @@ const getCorrectEvaluationSubstitutionType = (substitutionType?: string) => {
|
|||
return EvaluationSubstitutionType.TEMPLATE;
|
||||
};
|
||||
|
||||
export const getBindingPathsOfAction = (
|
||||
export const getBindingAndReactivePathsOfAction = (
|
||||
action: Action,
|
||||
formConfig?: any[],
|
||||
): Record<string, EvaluationSubstitutionType> => {
|
||||
const bindingPaths: Record<string, EvaluationSubstitutionType> = {
|
||||
): { reactivePaths: ReactivePaths; bindingPaths: BindingPaths } => {
|
||||
let reactivePaths: ReactivePaths = {
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
datasourceUrl: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
const bindingPaths: BindingPaths = {};
|
||||
if (!formConfig) {
|
||||
return {
|
||||
...bindingPaths,
|
||||
reactivePaths = {
|
||||
...reactivePaths,
|
||||
config: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
return {
|
||||
reactivePaths,
|
||||
bindingPaths,
|
||||
};
|
||||
}
|
||||
const recursiveFindBindingPaths = (formConfig: any) => {
|
||||
if (formConfig.children) {
|
||||
|
|
@ -61,7 +72,7 @@ export const getBindingPathsOfAction = (
|
|||
bindingPaths[configPath] = getCorrectEvaluationSubstitutionType(
|
||||
alternateViewTypeInputConfig.evaluationSubstitutionType,
|
||||
);
|
||||
} else if (formConfig.controlType === "ARRAY_FIELD") {
|
||||
} else if (formConfig.controlType === formControlTypes.ARRAY_FIELD) {
|
||||
let actionValue = _.get(action, formConfig.configProperty);
|
||||
if (Array.isArray(actionValue)) {
|
||||
actionValue = actionValue.filter((val) => val);
|
||||
|
|
@ -81,7 +92,7 @@ export const getBindingPathsOfAction = (
|
|||
});
|
||||
}
|
||||
}
|
||||
} else if (formConfig.controlType === "WHERE_CLAUSE") {
|
||||
} else if (formConfig.controlType === formControlTypes.WHERE_CLAUSE) {
|
||||
const recursiveFindBindingPathsForWhereClause = (
|
||||
newConfigPath: string,
|
||||
actionValue: any,
|
||||
|
|
@ -138,7 +149,7 @@ export const getBindingPathsOfAction = (
|
|||
recursiveFindBindingPathsForWhereClause(childrenPath, value);
|
||||
});
|
||||
}
|
||||
} else if (formConfig.controlType === "PAGINATION") {
|
||||
} else if (formConfig.controlType === formControlTypes.PAGINATION) {
|
||||
const limitPath = getBindingOrConfigPathsForPaginationControl(
|
||||
PaginationSubComponent.Offset,
|
||||
configPath,
|
||||
|
|
@ -153,7 +164,7 @@ export const getBindingPathsOfAction = (
|
|||
bindingPaths[offsetPath] = getCorrectEvaluationSubstitutionType(
|
||||
formConfig.evaluationSubstitutionType,
|
||||
);
|
||||
} else if (formConfig.controlType === "SORTING") {
|
||||
} else if (formConfig.controlType === formControlTypes.SORTING) {
|
||||
const actionValue = _.get(action, formConfig.configProperty);
|
||||
if (Array.isArray(actionValue)) {
|
||||
actionValue.forEach((fieldConfig: any, index: number) => {
|
||||
|
|
@ -175,7 +186,7 @@ export const getBindingPathsOfAction = (
|
|||
);
|
||||
});
|
||||
}
|
||||
} else if (formConfig.controlType === "ENTITY_SELECTOR") {
|
||||
} else if (formConfig.controlType === formControlTypes.ENTITY_SELECTOR) {
|
||||
if (Array.isArray(formConfig.schema)) {
|
||||
formConfig.schema.forEach((schemaField: any, index: number) => {
|
||||
if (allowedControlTypes.includes(schemaField.controlType)) {
|
||||
|
|
@ -193,7 +204,11 @@ export const getBindingPathsOfAction = (
|
|||
}
|
||||
};
|
||||
formConfig.forEach(recursiveFindBindingPaths);
|
||||
return bindingPaths;
|
||||
reactivePaths = {
|
||||
...reactivePaths,
|
||||
...bindingPaths,
|
||||
};
|
||||
return { reactivePaths, bindingPaths };
|
||||
};
|
||||
|
||||
export const getBindingOrConfigPathsForSortingControl = (
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { DependencyMap, DynamicPath } from "utils/DynamicBindingUtils";
|
|||
import { DataTreeAction, ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
||||
import { ActionData } from "reducers/entityReducers/actionsReducer";
|
||||
import {
|
||||
getBindingPathsOfAction,
|
||||
getBindingAndReactivePathsOfAction,
|
||||
getDataTreeActionConfigPath,
|
||||
} from "entities/Action/actionProperties";
|
||||
|
||||
|
|
@ -38,6 +38,11 @@ export const generateDataTreeAction = (
|
|||
getDataTreeActionConfigPath,
|
||||
);
|
||||
});
|
||||
|
||||
const { bindingPaths, reactivePaths } = getBindingAndReactivePathsOfAction(
|
||||
action.config,
|
||||
editorConfig,
|
||||
);
|
||||
return {
|
||||
run: {},
|
||||
clear: {},
|
||||
|
|
@ -55,7 +60,8 @@ export const generateDataTreeAction = (
|
|||
},
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
isLoading: action.isLoading,
|
||||
bindingPaths: getBindingPathsOfAction(action.config, editorConfig),
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
dependencyMap,
|
||||
logBlackList: {},
|
||||
datasourceUrl,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ export interface DataTreeAction
|
|||
| Record<string, unknown>;
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION;
|
||||
dependencyMap: DependencyMap;
|
||||
logBlackList: Record<string, true>;
|
||||
|
|
@ -75,6 +76,7 @@ export interface DataTreeJSAction {
|
|||
meta: Record<string, MetaArgs>;
|
||||
dynamicBindingPathList: DynamicPath[];
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
reactivePaths: Record<string, EvaluationSubstitutionType>;
|
||||
variables: Array<string>;
|
||||
dependencyMap: DependencyMap;
|
||||
}
|
||||
|
|
@ -106,6 +108,7 @@ export type PropertyOverrideDependency = Record<
|
|||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import { JSCollectionData } from "reducers/entityReducers/jsActionsReducer";
|
|||
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||
import { DependencyMap } from "utils/DynamicBindingUtils";
|
||||
|
||||
const reg = /this\./g;
|
||||
|
||||
export const generateDataTreeJSAction = (
|
||||
js: JSCollectionData,
|
||||
): DataTreeJSAction => {
|
||||
|
|
@ -17,7 +19,7 @@ export const generateDataTreeJSAction = (
|
|||
const variables = js.config.variables;
|
||||
const listVariables: Array<string> = [];
|
||||
dynamicBindingPathList.push({ key: "body" });
|
||||
const reg = /this\./g;
|
||||
|
||||
const removeThisReference = js.config.body.replace(reg, `${js.config.name}.`);
|
||||
bindingPaths["body"] = EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
|
||||
|
|
@ -56,7 +58,8 @@ export const generateDataTreeJSAction = (
|
|||
ENTITY_TYPE: ENTITY_TYPE.JSACTION,
|
||||
body: removeThisReference,
|
||||
meta: meta,
|
||||
bindingPaths: bindingPaths,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -196,19 +196,24 @@ describe("generateDataTreeWidget", () => {
|
|||
isDirty: true,
|
||||
});
|
||||
|
||||
const bindingPaths = {
|
||||
defaultText: EvaluationSubstitutionType.TEMPLATE,
|
||||
placeholderText: EvaluationSubstitutionType.TEMPLATE,
|
||||
regex: EvaluationSubstitutionType.TEMPLATE,
|
||||
resetOnSubmit: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isRequired: EvaluationSubstitutionType.TEMPLATE,
|
||||
isDisabled: EvaluationSubstitutionType.TEMPLATE,
|
||||
errorMessage: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
|
||||
const expected: DataTreeWidget = {
|
||||
bindingPaths: {
|
||||
defaultText: EvaluationSubstitutionType.TEMPLATE,
|
||||
errorMessage: EvaluationSubstitutionType.TEMPLATE,
|
||||
bindingPaths,
|
||||
reactivePaths: {
|
||||
...bindingPaths,
|
||||
isDirty: EvaluationSubstitutionType.TEMPLATE,
|
||||
isDisabled: EvaluationSubstitutionType.TEMPLATE,
|
||||
isFocused: EvaluationSubstitutionType.TEMPLATE,
|
||||
isRequired: EvaluationSubstitutionType.TEMPLATE,
|
||||
isValid: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
placeholderText: EvaluationSubstitutionType.TEMPLATE,
|
||||
regex: EvaluationSubstitutionType.TEMPLATE,
|
||||
resetOnSubmit: EvaluationSubstitutionType.TEMPLATE,
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
value: EvaluationSubstitutionType.TEMPLATE,
|
||||
"meta.text": EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export const generateDataTreeWidget = (
|
|||
|
||||
const {
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
triggerPaths,
|
||||
validationPaths,
|
||||
} = getAllPathsFromPropertyConfig(widget, propertyPaneConfigs, {
|
||||
|
|
@ -152,6 +153,7 @@ export const generateDataTreeWidget = (
|
|||
propertyOverrideDependency,
|
||||
overridingPropertyPaths,
|
||||
bindingPaths,
|
||||
reactivePaths,
|
||||
triggerPaths,
|
||||
validationPaths,
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
|
|
|
|||
|
|
@ -117,8 +117,61 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
};
|
||||
const config = tablePropertyPaneConfig;
|
||||
|
||||
const bindingPaths = {
|
||||
tableData: EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
defaultSearchText: EvaluationSubstitutionType.TEMPLATE,
|
||||
defaultSelectedRow: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isSortable: EvaluationSubstitutionType.TEMPLATE,
|
||||
animateLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
primaryColumnId: EvaluationSubstitutionType.TEMPLATE,
|
||||
compactMode: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisibleDownload: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisibleFilters: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisiblePagination: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisibleSearch: EvaluationSubstitutionType.TEMPLATE,
|
||||
delimiter: EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.computedValue": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.horizontalAlignment":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.verticalAlignment":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.textSize": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.fontStyle": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.textColor": EvaluationSubstitutionType.TEMPLATE,
|
||||
// "primaryColumns.name.isVisible": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.name.isCellVisible": EvaluationSubstitutionType.TEMPLATE,
|
||||
|
||||
"primaryColumns.name.cellBackground": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.inputFormat":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.outputFormat":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.computedValue":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.isCellVisible":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.horizontalAlignment":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.verticalAlignment":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.textSize": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.fontStyle": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.textColor": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.createdAt.cellBackground":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonLabel": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonColor": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.isDisabled": EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonVariant":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.isCellVisible":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
const expected = {
|
||||
bindingPaths: {
|
||||
bindingPaths,
|
||||
reactivePaths: {
|
||||
...bindingPaths,
|
||||
selectedRow: EvaluationSubstitutionType.TEMPLATE,
|
||||
selectedRows: EvaluationSubstitutionType.TEMPLATE,
|
||||
tableData: EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
|
|
@ -171,8 +224,6 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonLabel":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonVariant":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.buttonColor":
|
||||
EvaluationSubstitutionType.TEMPLATE,
|
||||
"primaryColumns.status.isDisabled": EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -508,18 +559,21 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
};
|
||||
const config = chartPorpertyConfig;
|
||||
|
||||
const bindingPaths = {
|
||||
chartType: EvaluationSubstitutionType.TEMPLATE,
|
||||
chartName: EvaluationSubstitutionType.TEMPLATE,
|
||||
"chartData.random-id.seriesName": EvaluationSubstitutionType.TEMPLATE,
|
||||
"chartData.random-id.data": EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
xAxisName: EvaluationSubstitutionType.TEMPLATE,
|
||||
yAxisName: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
animateLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
setAdaptiveYMin: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
bindingPaths: {
|
||||
chartType: EvaluationSubstitutionType.TEMPLATE,
|
||||
chartName: EvaluationSubstitutionType.TEMPLATE,
|
||||
"chartData.random-id.seriesName": EvaluationSubstitutionType.TEMPLATE,
|
||||
"chartData.random-id.data": EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
xAxisName: EvaluationSubstitutionType.TEMPLATE,
|
||||
yAxisName: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
animateLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
setAdaptiveYMin: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
bindingPaths,
|
||||
reactivePaths: { ...bindingPaths },
|
||||
triggerPaths: {
|
||||
onDataPointClick: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,10 +10,21 @@ import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
|||
/**
|
||||
* @typedef {Object} Paths
|
||||
* @property {Object} configBindingPaths - The Binding Path
|
||||
* @property {Object} configReactivePaths - The Dynamic Property Path
|
||||
* @property {Object} configTriggerPaths - The Trigger Path
|
||||
* @property {Object} configValidationPaths - The Validation Path
|
||||
*/
|
||||
|
||||
/**
|
||||
* All widget's property or paths where user can write javaScript bindings using mustache syntax are called bindingPaths.
|
||||
* Widget's meta and derived paths aren't binding paths as user can't add or remove binding for those value.
|
||||
*/
|
||||
type BindingPaths = Record<string, EvaluationSubstitutionType>;
|
||||
/**
|
||||
* Binding paths and non-binding paths of widget/action together form reactivePaths.
|
||||
*/
|
||||
type ReactivePaths = Record<string, EvaluationSubstitutionType>;
|
||||
|
||||
/**
|
||||
* This function gets the binding validation and trigger paths from a config
|
||||
* @param config
|
||||
|
|
@ -24,14 +35,14 @@ const checkPathsInConfig = (
|
|||
config: any,
|
||||
path: string,
|
||||
): {
|
||||
configBindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
configBindingPaths: BindingPaths;
|
||||
configReactivePaths: ReactivePaths;
|
||||
configTriggerPaths: Record<string, true>;
|
||||
configValidationPaths: Record<string, ValidationConfig>;
|
||||
} => {
|
||||
const configBindingPaths: Record<string, EvaluationSubstitutionType> = {};
|
||||
const configBindingPaths: BindingPaths = {};
|
||||
const configTriggerPaths: Record<string, true> = {};
|
||||
const configValidationPaths: Record<any, ValidationConfig> = {};
|
||||
|
||||
// Purely a Binding Path
|
||||
if (config.isBindProperty && !config.isTriggerProperty) {
|
||||
configBindingPaths[path] =
|
||||
|
|
@ -42,7 +53,12 @@ const checkPathsInConfig = (
|
|||
} else if (config.isBindProperty && config.isTriggerProperty) {
|
||||
configTriggerPaths[path] = true;
|
||||
}
|
||||
return { configBindingPaths, configTriggerPaths, configValidationPaths };
|
||||
return {
|
||||
configBindingPaths,
|
||||
configReactivePaths: configBindingPaths, // All bindingPaths are reactivePaths.
|
||||
configTriggerPaths,
|
||||
configValidationPaths,
|
||||
};
|
||||
};
|
||||
|
||||
// "originalWidget" param here always contains the complete widget props
|
||||
|
|
@ -55,7 +71,9 @@ const childHasPanelConfig = (
|
|||
) => {
|
||||
const panelPropertyPath = config.propertyName;
|
||||
const widgetPanelPropertyValues = get(widget, panelPropertyPath);
|
||||
let bindingPaths: Record<string, EvaluationSubstitutionType> = {};
|
||||
|
||||
let bindingPaths: BindingPaths = {};
|
||||
let reactivePaths: ReactivePaths = {};
|
||||
let triggerPaths: Record<string, true> = {};
|
||||
let validationPaths: Record<any, ValidationConfig> = {};
|
||||
if (widgetPanelPropertyValues) {
|
||||
|
|
@ -86,13 +104,21 @@ const childHasPanelConfig = (
|
|||
if (!isControlHidden) {
|
||||
const {
|
||||
configBindingPaths,
|
||||
configReactivePaths,
|
||||
configTriggerPaths,
|
||||
configValidationPaths,
|
||||
} = checkPathsInConfig(
|
||||
panelColumnControlConfig,
|
||||
panelPropertyConfigPath,
|
||||
);
|
||||
bindingPaths = { ...configBindingPaths, ...bindingPaths };
|
||||
bindingPaths = {
|
||||
...configBindingPaths,
|
||||
...bindingPaths,
|
||||
};
|
||||
reactivePaths = {
|
||||
...configReactivePaths,
|
||||
...reactivePaths,
|
||||
};
|
||||
triggerPaths = { ...configTriggerPaths, ...triggerPaths };
|
||||
validationPaths = {
|
||||
...configValidationPaths,
|
||||
|
|
@ -102,6 +128,7 @@ const childHasPanelConfig = (
|
|||
if (panelColumnControlConfig.panelConfig) {
|
||||
const {
|
||||
bindingPaths: panelBindingPaths,
|
||||
reactivePaths: panelReactivePaths,
|
||||
triggerPaths: panelTriggerPaths,
|
||||
validationPaths: panelValidationPaths,
|
||||
} = childHasPanelConfig(
|
||||
|
|
@ -110,7 +137,14 @@ const childHasPanelConfig = (
|
|||
panelPropertyConfigPath,
|
||||
originalWidget,
|
||||
);
|
||||
bindingPaths = { ...panelBindingPaths, ...bindingPaths };
|
||||
bindingPaths = {
|
||||
...panelBindingPaths,
|
||||
...bindingPaths,
|
||||
};
|
||||
reactivePaths = {
|
||||
...panelReactivePaths,
|
||||
...reactivePaths,
|
||||
};
|
||||
triggerPaths = { ...panelTriggerPaths, ...triggerPaths };
|
||||
validationPaths = {
|
||||
...panelValidationPaths,
|
||||
|
|
@ -126,7 +160,7 @@ const childHasPanelConfig = (
|
|||
);
|
||||
}
|
||||
|
||||
return { bindingPaths, triggerPaths, validationPaths };
|
||||
return { reactivePaths, triggerPaths, validationPaths, bindingPaths };
|
||||
};
|
||||
|
||||
export const getAllPathsFromPropertyConfig = (
|
||||
|
|
@ -134,15 +168,16 @@ export const getAllPathsFromPropertyConfig = (
|
|||
widgetConfig: readonly PropertyPaneConfig[],
|
||||
defaultProperties: Record<string, any>,
|
||||
): {
|
||||
bindingPaths: Record<string, EvaluationSubstitutionType>;
|
||||
bindingPaths: BindingPaths;
|
||||
reactivePaths: ReactivePaths;
|
||||
triggerPaths: Record<string, true>;
|
||||
validationPaths: Record<string, ValidationConfig>;
|
||||
} => {
|
||||
let bindingPaths: Record<string, EvaluationSubstitutionType> = {};
|
||||
Object.keys(defaultProperties).forEach(
|
||||
(property) =>
|
||||
(bindingPaths[property] = EvaluationSubstitutionType.TEMPLATE),
|
||||
);
|
||||
let bindingPaths: BindingPaths = {};
|
||||
let reactivePaths: ReactivePaths = {};
|
||||
Object.keys(defaultProperties).forEach((property) => {
|
||||
reactivePaths[property] = EvaluationSubstitutionType.TEMPLATE;
|
||||
});
|
||||
let triggerPaths: Record<string, true> = {};
|
||||
let validationPaths: Record<any, ValidationConfig> = {};
|
||||
|
||||
|
|
@ -158,11 +193,19 @@ export const getAllPathsFromPropertyConfig = (
|
|||
const path = controlConfig.propertyName;
|
||||
const {
|
||||
configBindingPaths,
|
||||
configReactivePaths,
|
||||
configTriggerPaths,
|
||||
configValidationPaths,
|
||||
} = checkPathsInConfig(controlConfig, path);
|
||||
bindingPaths = {
|
||||
...bindingPaths,
|
||||
...configBindingPaths,
|
||||
};
|
||||
// Update default path configs with the ones in the property config
|
||||
bindingPaths = { ...bindingPaths, ...configBindingPaths };
|
||||
reactivePaths = {
|
||||
...reactivePaths,
|
||||
...configReactivePaths,
|
||||
};
|
||||
triggerPaths = { ...triggerPaths, ...configTriggerPaths };
|
||||
validationPaths = { ...validationPaths, ...configValidationPaths };
|
||||
}
|
||||
|
|
@ -174,7 +217,14 @@ export const getAllPathsFromPropertyConfig = (
|
|||
basePath,
|
||||
widget,
|
||||
);
|
||||
bindingPaths = { ...bindingPaths, ...resultingPaths.bindingPaths };
|
||||
bindingPaths = {
|
||||
...bindingPaths,
|
||||
...resultingPaths.bindingPaths,
|
||||
};
|
||||
reactivePaths = {
|
||||
...reactivePaths,
|
||||
...resultingPaths.reactivePaths,
|
||||
};
|
||||
triggerPaths = { ...triggerPaths, ...resultingPaths.triggerPaths };
|
||||
validationPaths = {
|
||||
...validationPaths,
|
||||
|
|
@ -195,13 +245,21 @@ export const getAllPathsFromPropertyConfig = (
|
|||
const childArrayPropertyPath = `${objectIndexPropertyPath}.${childPropertyConfig.propertyName}`;
|
||||
const {
|
||||
configBindingPaths,
|
||||
configReactivePaths,
|
||||
configTriggerPaths,
|
||||
configValidationPaths,
|
||||
} = checkPathsInConfig(
|
||||
childPropertyConfig,
|
||||
childArrayPropertyPath,
|
||||
);
|
||||
bindingPaths = { ...bindingPaths, ...configBindingPaths };
|
||||
bindingPaths = {
|
||||
...bindingPaths,
|
||||
...configBindingPaths,
|
||||
};
|
||||
reactivePaths = {
|
||||
...reactivePaths,
|
||||
...configReactivePaths,
|
||||
};
|
||||
triggerPaths = { ...triggerPaths, ...configTriggerPaths };
|
||||
validationPaths = {
|
||||
...validationPaths,
|
||||
|
|
@ -215,7 +273,7 @@ export const getAllPathsFromPropertyConfig = (
|
|||
}
|
||||
});
|
||||
|
||||
return { bindingPaths, triggerPaths, validationPaths };
|
||||
return { reactivePaths, triggerPaths, validationPaths, bindingPaths };
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "components/formControls/utils";
|
||||
import { useSelector, shallowEqual } from "react-redux";
|
||||
import { getFormValues } from "redux-form";
|
||||
import FormControlFactory from "utils/FormControlFactory";
|
||||
import FormControlFactory from "utils/formControl/FormControlFactory";
|
||||
|
||||
import { AppState } from "reducers";
|
||||
import { Action } from "entities/Action";
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ const createLoadingWidget = (
|
|||
type: WidgetTypes.SKELETON_WIDGET,
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
logBlackList: {},
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import AnalyticsUtil from "./AnalyticsUtil";
|
||||
import FormControlRegistry from "./FormControlRegistry";
|
||||
import FormControlRegistry from "./formControl/FormControlRegistry";
|
||||
import { Property } from "api/ActionAPI";
|
||||
import _ from "lodash";
|
||||
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Action, PluginType } from "entities/Action";
|
||||
import _ from "lodash";
|
||||
import { getPropertyPath } from "./DynamicBindingUtils";
|
||||
import {
|
||||
EVAL_VALUE_PATH,
|
||||
getDynamicBindingsChangesSaga,
|
||||
|
|
@ -156,6 +157,23 @@ describe("DynamicBindingPathlist", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("getPropertyPath function", () => {
|
||||
it("test getPropertyPath", () => {
|
||||
const testCases = [
|
||||
["Table1.searchText", "searchText"],
|
||||
["Table1.selectedRow", "selectedRow"],
|
||||
["Table1.meta.searchText", "meta.searchText"],
|
||||
["Table1", "Table1"],
|
||||
["Table1.", ""],
|
||||
];
|
||||
|
||||
testCases.forEach(([input, expectedResult]) => {
|
||||
const actualResult = getPropertyPath(input);
|
||||
expect(actualResult).toStrictEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getNestedEvalPath", () => {
|
||||
it("returns valid nested path", () => {
|
||||
const actualUnpopulatedNestedPath = getEvalValuePath(
|
||||
|
|
|
|||
|
|
@ -239,6 +239,15 @@ export const isPathADynamicBinding = (
|
|||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Get property path from full property path
|
||||
* Input: "Table1.meta.searchText" => Output: "meta.searchText"
|
||||
* @param {string} fullPropertyPath
|
||||
* @return {*}
|
||||
*/
|
||||
export const getPropertyPath = (fullPropertyPath: string) => {
|
||||
return fullPropertyPath.substring(fullPropertyPath.indexOf(".") + 1);
|
||||
};
|
||||
|
||||
export const getWidgetDynamicTriggerPathList = (
|
||||
widget: WidgetProps,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const JS_object_tree: DataTreeJSAction = {
|
|||
meta: {},
|
||||
dynamicBindingPathList: [],
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
variables: [],
|
||||
dependencyMap: {},
|
||||
};
|
||||
|
|
@ -26,6 +27,7 @@ const JS_object_tree: DataTreeJSAction = {
|
|||
const Select_tree: DataTreeWidget = {
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
logBlackList: {},
|
||||
|
|
@ -58,6 +60,7 @@ const Query_tree: DataTreeAction = {
|
|||
clear: {},
|
||||
dynamicBindingPathList: [],
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
dependencyMap: {},
|
||||
logBlackList: {},
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ describe("dataTreeTypeDefCreator", () => {
|
|||
bindingPaths: {
|
||||
defaultText: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
reactivePaths: {
|
||||
defaultText: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
triggerPaths: {
|
||||
onTextChange: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -45,50 +45,54 @@ import SortingControl, {
|
|||
import EntitySelectorControl, {
|
||||
EntitySelectorControlProps,
|
||||
} from "components/formControls/EntitySelectorControl";
|
||||
import formControlTypes from "./formControlTypes";
|
||||
|
||||
/**
|
||||
* NOTE: If you are adding a component that uses FormControl
|
||||
* then add logic for creating bindingPaths in recursiveFindBindingPaths() at entities/Action/actionProperties.ts
|
||||
* then add logic for creating reactivePaths in recursiveFindReactivePaths() at entities/Action/actionProperties.ts
|
||||
*/
|
||||
class FormControlRegistry {
|
||||
static registerFormControlBuilders() {
|
||||
FormControlFactory.registerControlBuilder("INPUT_TEXT", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.INPUT_TEXT, {
|
||||
buildPropertyControl(controlProps: InputControlProps): JSX.Element {
|
||||
return <InputTextControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("FIXED_KEY_INPUT", {
|
||||
buildPropertyControl(
|
||||
controlProps: FixedKeyInputControlProps,
|
||||
): JSX.Element {
|
||||
//TODO: may not be in use
|
||||
return <FixedKeyInputControl {...controlProps} />;
|
||||
FormControlFactory.registerControlBuilder(
|
||||
formControlTypes.FIXED_KEY_INPUT,
|
||||
{
|
||||
buildPropertyControl(
|
||||
controlProps: FixedKeyInputControlProps,
|
||||
): JSX.Element {
|
||||
//TODO: may not be in use
|
||||
return <FixedKeyInputControl {...controlProps} />;
|
||||
},
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("DROP_DOWN", {
|
||||
);
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.DROP_DOWN, {
|
||||
buildPropertyControl(controlProps: DropDownControlProps): JSX.Element {
|
||||
return <DropDownControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("SWITCH", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.SWITCH, {
|
||||
buildPropertyControl(controlProps: SwitchControlProps): JSX.Element {
|
||||
return <SwitchControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("KEYVALUE_ARRAY", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.KEYVALUE_ARRAY, {
|
||||
buildPropertyControl(
|
||||
controlProps: KeyValueArrayControlProps,
|
||||
): JSX.Element {
|
||||
return <KeyValueArrayControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("FILE_PICKER", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.FILE_PICKER, {
|
||||
buildPropertyControl(controlProps: FilePickerControlProps): JSX.Element {
|
||||
//used by redshift datasource
|
||||
return <FilePickerControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("KEY_VAL_INPUT", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.KEY_VAL_INPUT, {
|
||||
//TODO: may not be in use, replace it with KeyValueArrayControl
|
||||
buildPropertyControl(
|
||||
controlProps: KeyValueInputControlProps,
|
||||
|
|
@ -96,58 +100,67 @@ class FormControlRegistry {
|
|||
return <KeyValueInputControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("QUERY_DYNAMIC_TEXT", {
|
||||
buildPropertyControl(controlProps: DynamicTextFieldProps): JSX.Element {
|
||||
return <DynamicTextControl {...controlProps} />;
|
||||
FormControlFactory.registerControlBuilder(
|
||||
formControlTypes.QUERY_DYNAMIC_TEXT,
|
||||
{
|
||||
buildPropertyControl(controlProps: DynamicTextFieldProps): JSX.Element {
|
||||
return <DynamicTextControl {...controlProps} />;
|
||||
},
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("QUERY_DYNAMIC_INPUT_TEXT", {
|
||||
buildPropertyControl(
|
||||
controlProps: DynamicInputControlProps,
|
||||
): JSX.Element {
|
||||
return <DynamicInputTextControl {...controlProps} />;
|
||||
);
|
||||
FormControlFactory.registerControlBuilder(
|
||||
formControlTypes.QUERY_DYNAMIC_INPUT_TEXT,
|
||||
{
|
||||
buildPropertyControl(
|
||||
controlProps: DynamicInputControlProps,
|
||||
): JSX.Element {
|
||||
return <DynamicInputTextControl {...controlProps} />;
|
||||
},
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("CHECKBOX", {
|
||||
);
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.CHECKBOX, {
|
||||
buildPropertyControl(controlProps: CheckboxControlProps): JSX.Element {
|
||||
//used in API datasource form only
|
||||
return <CheckboxControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("NUMBER_INPUT", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.NUMBER_INPUT, {
|
||||
buildPropertyControl(controlProps: InputControlProps): JSX.Element {
|
||||
return <InputTextControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("ARRAY_FIELD", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.ARRAY_FIELD, {
|
||||
buildPropertyControl(controlProps: FieldArrayControlProps): JSX.Element {
|
||||
return <FieldArrayControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("WHERE_CLAUSE", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.WHERE_CLAUSE, {
|
||||
buildPropertyControl(controlProps: WhereClauseControlProps): JSX.Element {
|
||||
return <WhereClauseControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("ENTITY_SELECTOR", {
|
||||
buildPropertyControl(
|
||||
controlProps: EntitySelectorControlProps,
|
||||
): JSX.Element {
|
||||
return <EntitySelectorControl {...controlProps} />;
|
||||
FormControlFactory.registerControlBuilder(
|
||||
formControlTypes.ENTITY_SELECTOR,
|
||||
{
|
||||
buildPropertyControl(
|
||||
controlProps: EntitySelectorControlProps,
|
||||
): JSX.Element {
|
||||
return <EntitySelectorControl {...controlProps} />;
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
FormControlFactory.registerControlBuilder("PAGINATION", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.PAGINATION, {
|
||||
buildPropertyControl(controlProps: PaginationControlProps): JSX.Element {
|
||||
return <PaginationControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("SORTING", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.SORTING, {
|
||||
buildPropertyControl(controlProps: SortingControlProps): JSX.Element {
|
||||
return <SortingControl {...controlProps} />;
|
||||
},
|
||||
});
|
||||
FormControlFactory.registerControlBuilder("PROJECTION", {
|
||||
FormControlFactory.registerControlBuilder(formControlTypes.PROJECTION, {
|
||||
buildPropertyControl(controlProps: DropDownControlProps): JSX.Element {
|
||||
return (
|
||||
<DropDownControl
|
||||
19
app/client/src/utils/formControl/formControlTypes.ts
Normal file
19
app/client/src/utils/formControl/formControlTypes.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
export default {
|
||||
INPUT_TEXT: "INPUT_TEXT",
|
||||
FIXED_KEY_INPUT: "FIXED_KEY_INPUT",
|
||||
DROP_DOWN: "DROP_DOWN",
|
||||
SWITCH: "SWITCH",
|
||||
KEYVALUE_ARRAY: "KEYVALUE_ARRAY",
|
||||
FILE_PICKER: "FILE_PICKER",
|
||||
KEY_VAL_INPUT: "KEY_VAL_INPUT",
|
||||
QUERY_DYNAMIC_TEXT: "QUERY_DYNAMIC_TEXT",
|
||||
QUERY_DYNAMIC_INPUT_TEXT: "QUERY_DYNAMIC_INPUT_TEXT",
|
||||
CHECKBOX: "CHECKBOX",
|
||||
NUMBER_INPUT: "NUMBER_INPUT",
|
||||
ARRAY_FIELD: "ARRAY_FIELD",
|
||||
WHERE_CLAUSE: "WHERE_CLAUSE",
|
||||
ENTITY_SELECTOR: "ENTITY_SELECTOR",
|
||||
PAGINATION: "PAGINATION",
|
||||
SORTING: "SORTING",
|
||||
PROJECTION: "PROJECTION",
|
||||
};
|
||||
|
|
@ -20,3 +20,16 @@ export const mapTree = (tree: Tree, callback: (tree: Tree) => Tree) => {
|
|||
}
|
||||
return { ...mapped };
|
||||
};
|
||||
|
||||
/**
|
||||
* This function sorts the object's value which is array of string.
|
||||
*
|
||||
* @param {Record<string, Array<string>>} data
|
||||
* @return {*}
|
||||
*/
|
||||
export const sortObjectWithArray = (data: Record<string, Array<string>>) => {
|
||||
Object.entries(data).map(([key, value]) => {
|
||||
data[key] = value.sort();
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ describe("Add functions", () => {
|
|||
dynamicBindingPathList: [],
|
||||
name: "action1",
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
isLoading: false,
|
||||
run: {},
|
||||
clear: {},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
getEntityDynamicBindingPathList,
|
||||
getEvalErrorPath,
|
||||
getEvalValuePath,
|
||||
getPropertyPath,
|
||||
isChildPropertyPath,
|
||||
isPathADynamicBinding,
|
||||
isPathADynamicTrigger,
|
||||
|
|
@ -76,7 +77,7 @@ import { JSUpdate } from "utils/JSPaneUtils";
|
|||
import {
|
||||
addWidgetPropertyDependencies,
|
||||
overrideWidgetProperties,
|
||||
} from "./evaluationUtils";
|
||||
} from "../evaluationUtils";
|
||||
import {
|
||||
ActionValidationConfigMap,
|
||||
ValidationConfig,
|
||||
|
|
@ -292,19 +293,21 @@ export default class DataTreeEvaluator {
|
|||
translateDiffEventToDataTreeDiffEvent(diff, localUnEvalTree),
|
||||
),
|
||||
);
|
||||
this.logs.push({ differences, translatedDiffs });
|
||||
this.logs.push({
|
||||
differences,
|
||||
translatedDiffs,
|
||||
});
|
||||
const diffCheckTimeStop = performance.now();
|
||||
// Check if dependencies have changed
|
||||
const updateDependenciesStart = performance.now();
|
||||
|
||||
this.logs.push({ differences: clone(differences), translatedDiffs });
|
||||
|
||||
// Find all the paths that have changed as part of the difference and update the
|
||||
// global dependency map if an existing dynamic binding has now become legal
|
||||
const {
|
||||
dependenciesOfRemovedPaths,
|
||||
removedPaths,
|
||||
} = this.updateDependencyMap(translatedDiffs, localUnEvalTree);
|
||||
|
||||
const updateDependenciesStop = performance.now();
|
||||
|
||||
this.applyDifferencesToEvalTree(differences);
|
||||
|
|
@ -560,8 +563,8 @@ export default class DataTreeEvaluator {
|
|||
}
|
||||
if (isJSAction(entity)) {
|
||||
// making functions dependent on their function body entities
|
||||
if (entity.bindingPaths) {
|
||||
Object.keys(entity.bindingPaths).forEach((propertyPath) => {
|
||||
if (entity.reactivePaths) {
|
||||
Object.keys(entity.reactivePaths).forEach((propertyPath) => {
|
||||
const existingDeps =
|
||||
dependencies[`${entityName}.${propertyPath}`] || [];
|
||||
const unevalPropValue = _.get(entity, propertyPath).toString();
|
||||
|
|
@ -613,14 +616,14 @@ export default class DataTreeEvaluator {
|
|||
fullPropertyPath,
|
||||
);
|
||||
|
||||
const isABindingPath =
|
||||
const isADynamicBindingPath =
|
||||
(isAction(entity) || isWidget(entity) || isJSAction(entity)) &&
|
||||
isPathADynamicBinding(entity, propertyPath);
|
||||
const isATriggerPath =
|
||||
isWidget(entity) && isPathADynamicTrigger(entity, propertyPath);
|
||||
let evalPropertyValue;
|
||||
const requiresEval =
|
||||
isABindingPath &&
|
||||
isADynamicBindingPath &&
|
||||
!isATriggerPath &&
|
||||
(isDynamicValue(unEvalPropertyValue) || isJSAction(entity));
|
||||
if (propertyPath) {
|
||||
|
|
@ -628,7 +631,7 @@ export default class DataTreeEvaluator {
|
|||
}
|
||||
if (requiresEval) {
|
||||
const evaluationSubstitutionType =
|
||||
entity.bindingPaths[propertyPath] ||
|
||||
entity.reactivePaths[propertyPath] ||
|
||||
EvaluationSubstitutionType.TEMPLATE;
|
||||
|
||||
const contextData: EvaluateContext = {};
|
||||
|
|
@ -1330,14 +1333,12 @@ export default class DataTreeEvaluator {
|
|||
| DataTreeWidget
|
||||
| DataTreeJSAction;
|
||||
const fullPropertyPath = dataTreeDiff.payload.propertyPath;
|
||||
const entityPropertyPath = fullPropertyPath.substring(
|
||||
fullPropertyPath.indexOf(".") + 1,
|
||||
);
|
||||
const isABindingPath = isPathADynamicBinding(
|
||||
const entityPropertyPath = getPropertyPath(fullPropertyPath);
|
||||
const isADynamicBindingPath = isPathADynamicBinding(
|
||||
entity,
|
||||
entityPropertyPath,
|
||||
);
|
||||
if (isABindingPath) {
|
||||
if (isADynamicBindingPath) {
|
||||
didUpdateDependencyMap = true;
|
||||
|
||||
const { jsSnippets } = getDynamicBindings(
|
||||
|
|
@ -1381,11 +1382,12 @@ export default class DataTreeEvaluator {
|
|||
}
|
||||
}
|
||||
}
|
||||
// If the whole binding was removed then the value
|
||||
// at this path would be "".
|
||||
// In this case if the path exists in the dependency map
|
||||
// remove it.
|
||||
else if (fullPropertyPath in this.dependencyMap) {
|
||||
// If the whole binding was removed, then the value at this path would be a string without any bindings.
|
||||
// In this case, if the path exists in the dependency map and is a bindingPath, then remove it.
|
||||
else if (
|
||||
entity.bindingPaths[entityPropertyPath] &&
|
||||
fullPropertyPath in this.dependencyMap
|
||||
) {
|
||||
didUpdateDependencyMap = true;
|
||||
delete this.dependencyMap[fullPropertyPath];
|
||||
}
|
||||
|
|
@ -1501,7 +1503,7 @@ export default class DataTreeEvaluator {
|
|||
);
|
||||
}
|
||||
const parentPropertyPath = convertPathToString(d.path);
|
||||
Object.keys(entity.bindingPaths).forEach((relativePath) => {
|
||||
Object.keys(entity.reactivePaths).forEach((relativePath) => {
|
||||
const childPropertyPath = `${entityName}.${relativePath}`;
|
||||
// Check if relative path has dynamic binding
|
||||
if (
|
||||
|
|
@ -1,10 +1,27 @@
|
|||
import DataTreeEvaluator from "./DataTreeEvaluator";
|
||||
import DataTreeEvaluator from "../DataTreeEvaluator";
|
||||
import { unEvalTree } from "./mockUnEvalTree";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { DataTreeDiff } from "workers/evaluationUtils";
|
||||
import { ALL_WIDGETS_AND_CONFIG } from "utils/WidgetRegistry";
|
||||
|
||||
const widgetConfigMap = {};
|
||||
ALL_WIDGETS_AND_CONFIG.map(([, config]) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
if (config.type && config.properties) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
widgetConfigMap[config.type] = {
|
||||
defaultProperties: config.properties.default,
|
||||
derivedProperties: config.properties.derived,
|
||||
metaProperties: config.properties.meta,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const dataTreeEvaluator = new DataTreeEvaluator(widgetConfigMap);
|
||||
|
||||
describe("DataTreeEvaluator", () => {
|
||||
let dataTreeEvaluator: DataTreeEvaluator;
|
||||
beforeAll(() => {
|
||||
dataTreeEvaluator = new DataTreeEvaluator({});
|
||||
});
|
||||
describe("evaluateActionBindings", () => {
|
||||
it("handles this.params.property", () => {
|
||||
const result = dataTreeEvaluator.evaluateActionBindings(
|
||||
|
|
@ -106,4 +123,67 @@ describe("DataTreeEvaluator", () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("test updateDependencyMap", () => {
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
dataTreeEvaluator.createFirstTree(unEvalTree as DataTree);
|
||||
});
|
||||
|
||||
it("initial dependencyMap computation", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
dataTreeEvaluator.updateDataTree(unEvalTree as DataTree);
|
||||
|
||||
expect(dataTreeEvaluator.dependencyMap).toStrictEqual({
|
||||
"Button2.text": ["Button1.text"],
|
||||
Button2: ["Button2.text"],
|
||||
Button1: ["Button1.text"],
|
||||
});
|
||||
});
|
||||
|
||||
it(`When empty binding is modified from {{Button1.text}} to {{""}}`, () => {
|
||||
const translatedDiffs = [
|
||||
{
|
||||
payload: {
|
||||
propertyPath: "Button2.text",
|
||||
value: '{{""}}',
|
||||
},
|
||||
event: "EDIT",
|
||||
},
|
||||
];
|
||||
dataTreeEvaluator.updateDependencyMap(
|
||||
translatedDiffs as Array<DataTreeDiff>,
|
||||
dataTreeEvaluator.oldUnEvalTree,
|
||||
);
|
||||
|
||||
expect(dataTreeEvaluator.dependencyMap).toStrictEqual({
|
||||
"Button2.text": [],
|
||||
Button2: ["Button2.text"],
|
||||
Button1: ["Button1.text"],
|
||||
});
|
||||
});
|
||||
|
||||
it(`When binding is removed`, () => {
|
||||
const translatedDiffs = [
|
||||
{
|
||||
payload: {
|
||||
propertyPath: "Button2.text",
|
||||
value: "abc",
|
||||
},
|
||||
event: "EDIT",
|
||||
},
|
||||
];
|
||||
dataTreeEvaluator.updateDependencyMap(
|
||||
translatedDiffs as Array<DataTreeDiff>,
|
||||
dataTreeEvaluator.oldUnEvalTree,
|
||||
);
|
||||
|
||||
expect(dataTreeEvaluator.dependencyMap).toStrictEqual({
|
||||
Button2: ["Button2.text"],
|
||||
Button1: ["Button1.text"],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
293
app/client/src/workers/DataTreeEvaluator/test/mockUnEvalTree.ts
Normal file
293
app/client/src/workers/DataTreeEvaluator/test/mockUnEvalTree.ts
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
export const unEvalTree = {
|
||||
MainContainer: {
|
||||
widgetName: "MainContainer",
|
||||
backgroundColor: "none",
|
||||
rightColumn: 2220,
|
||||
snapColumns: 64,
|
||||
detachFromLayout: true,
|
||||
widgetId: "0",
|
||||
topRow: 0,
|
||||
bottomRow: 640,
|
||||
containerStyle: "none",
|
||||
snapRows: 113,
|
||||
parentRowSpace: 1,
|
||||
type: "CANVAS_WIDGET",
|
||||
canExtend: true,
|
||||
version: 52,
|
||||
minHeight: 620,
|
||||
parentColumnSpace: 1,
|
||||
dynamicBindingPathList: [],
|
||||
leftColumn: 0,
|
||||
children: ["j9dpft2lpu", "l0yem4eh6l"],
|
||||
defaultProps: {},
|
||||
defaultMetaProps: [],
|
||||
logBlackList: {},
|
||||
meta: {},
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
privateWidgets: {},
|
||||
},
|
||||
Button1: {
|
||||
widgetName: "Button1",
|
||||
buttonColor: "#03B365",
|
||||
displayName: "Button",
|
||||
iconSVG: "/static/media/icon.cca02633.svg",
|
||||
topRow: 15,
|
||||
bottomRow: 19,
|
||||
parentRowSpace: 10,
|
||||
type: "BUTTON_WIDGET",
|
||||
hideCard: false,
|
||||
animateLoading: true,
|
||||
parentColumnSpace: 26.421875,
|
||||
dynamicTriggerPathList: [],
|
||||
leftColumn: 20,
|
||||
dynamicBindingPathList: [],
|
||||
text: "button1",
|
||||
isDisabled: false,
|
||||
key: "r6h8y6dc8i",
|
||||
rightColumn: 36,
|
||||
isDefaultClickDisabled: true,
|
||||
widgetId: "j9dpft2lpu",
|
||||
isVisible: true,
|
||||
recaptchaType: "V3",
|
||||
version: 1,
|
||||
parentId: "0",
|
||||
renderMode: "CANVAS",
|
||||
isLoading: false,
|
||||
buttonVariant: "PRIMARY",
|
||||
placement: "CENTER",
|
||||
defaultProps: {},
|
||||
defaultMetaProps: ["recaptchaToken"],
|
||||
logBlackList: {},
|
||||
meta: {},
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
reactivePaths: {
|
||||
recaptchaToken: "TEMPLATE",
|
||||
text: "TEMPLATE",
|
||||
tooltip: "TEMPLATE",
|
||||
googleRecaptchaKey: "TEMPLATE",
|
||||
recaptchaType: "TEMPLATE",
|
||||
isVisible: "TEMPLATE",
|
||||
isDisabled: "TEMPLATE",
|
||||
animateLoading: "TEMPLATE",
|
||||
buttonVariant: "TEMPLATE",
|
||||
placement: "TEMPLATE",
|
||||
},
|
||||
triggerPaths: {
|
||||
onClick: true,
|
||||
},
|
||||
validationPaths: {
|
||||
text: {
|
||||
type: "TEXT",
|
||||
},
|
||||
tooltip: {
|
||||
type: "TEXT",
|
||||
},
|
||||
googleRecaptchaKey: {
|
||||
type: "TEXT",
|
||||
},
|
||||
recaptchaType: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["V3", "V2"],
|
||||
default: "V3",
|
||||
},
|
||||
},
|
||||
isVisible: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
isDisabled: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
animateLoading: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
buttonVariant: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["PRIMARY", "SECONDARY", "TERTIARY"],
|
||||
default: "PRIMARY",
|
||||
},
|
||||
},
|
||||
placement: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["START", "BETWEEN", "CENTER"],
|
||||
default: "CENTER",
|
||||
},
|
||||
},
|
||||
},
|
||||
ENTITY_TYPE: "WIDGET",
|
||||
privateWidgets: {},
|
||||
},
|
||||
Button2: {
|
||||
widgetName: "Button2",
|
||||
buttonColor: "#03B365",
|
||||
displayName: "Button",
|
||||
iconSVG: "/static/media/icon.cca02633.svg",
|
||||
topRow: 25,
|
||||
bottomRow: 29,
|
||||
parentRowSpace: 10,
|
||||
type: "BUTTON_WIDGET",
|
||||
hideCard: false,
|
||||
animateLoading: true,
|
||||
parentColumnSpace: 26.421875,
|
||||
dynamicTriggerPathList: [],
|
||||
leftColumn: 20,
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "text",
|
||||
},
|
||||
],
|
||||
text: "{{Button1.text}}",
|
||||
isDisabled: false,
|
||||
key: "r6h8y6dc8i",
|
||||
rightColumn: 36,
|
||||
isDefaultClickDisabled: true,
|
||||
widgetId: "l0yem4eh6l",
|
||||
isVisible: true,
|
||||
recaptchaType: "V3",
|
||||
version: 1,
|
||||
parentId: "0",
|
||||
renderMode: "CANVAS",
|
||||
isLoading: false,
|
||||
buttonVariant: "PRIMARY",
|
||||
placement: "CENTER",
|
||||
defaultProps: {},
|
||||
defaultMetaProps: ["recaptchaToken"],
|
||||
logBlackList: {},
|
||||
meta: {},
|
||||
propertyOverrideDependency: {},
|
||||
overridingPropertyPaths: {},
|
||||
reactivePaths: {
|
||||
recaptchaToken: "TEMPLATE",
|
||||
text: "TEMPLATE",
|
||||
tooltip: "TEMPLATE",
|
||||
googleRecaptchaKey: "TEMPLATE",
|
||||
recaptchaType: "TEMPLATE",
|
||||
isVisible: "TEMPLATE",
|
||||
isDisabled: "TEMPLATE",
|
||||
animateLoading: "TEMPLATE",
|
||||
buttonVariant: "TEMPLATE",
|
||||
placement: "TEMPLATE",
|
||||
},
|
||||
triggerPaths: {
|
||||
onClick: true,
|
||||
},
|
||||
validationPaths: {
|
||||
text: {
|
||||
type: "TEXT",
|
||||
},
|
||||
tooltip: {
|
||||
type: "TEXT",
|
||||
},
|
||||
googleRecaptchaKey: {
|
||||
type: "TEXT",
|
||||
},
|
||||
recaptchaType: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["V3", "V2"],
|
||||
default: "V3",
|
||||
},
|
||||
},
|
||||
isVisible: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
isDisabled: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
animateLoading: {
|
||||
type: "BOOLEAN",
|
||||
},
|
||||
buttonVariant: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["PRIMARY", "SECONDARY", "TERTIARY"],
|
||||
default: "PRIMARY",
|
||||
},
|
||||
},
|
||||
placement: {
|
||||
type: "TEXT",
|
||||
params: {
|
||||
allowedValues: ["START", "BETWEEN", "CENTER"],
|
||||
default: "CENTER",
|
||||
},
|
||||
},
|
||||
},
|
||||
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",
|
||||
organizationIds: [
|
||||
"6218a61972ccd9145ec78c57",
|
||||
"621913df0276eb01d22fec44",
|
||||
"60caf8edb1e47a1315f0c48f",
|
||||
"609114fe05c4d35a9f6cbbf2",
|
||||
],
|
||||
username: "rathod@appsmith.com",
|
||||
name: "Rishabh",
|
||||
commentOnboardingState: "RESOLVED",
|
||||
role: "engineer",
|
||||
useCase: "personal project",
|
||||
enableTelemetry: false,
|
||||
emptyInstance: false,
|
||||
accountNonExpired: true,
|
||||
accountNonLocked: true,
|
||||
credentialsNonExpired: true,
|
||||
isAnonymous: false,
|
||||
isEnabled: true,
|
||||
isSuperUser: false,
|
||||
isConfigurable: true,
|
||||
},
|
||||
URL: {
|
||||
fullPath:
|
||||
"https://dev.appsmith.com/applications/6200d1a2b5bfc0392b959cab/pages/6220c268c48234070f8ac65a/edit?a=b",
|
||||
host: "dev.appsmith.com",
|
||||
hostname: "dev.appsmith.com",
|
||||
queryParams: {
|
||||
a: "b",
|
||||
},
|
||||
protocol: "https:",
|
||||
pathname:
|
||||
"/applications/6200d1a2b5bfc0392b959cab/pages/6220c268c48234070f8ac65a/edit",
|
||||
port: "",
|
||||
hash: "",
|
||||
},
|
||||
store: {
|
||||
textColor: "#DF7E65",
|
||||
},
|
||||
geolocation: {
|
||||
canBeRequested: true,
|
||||
},
|
||||
mode: "EDIT",
|
||||
ENTITY_TYPE: "APPSMITH",
|
||||
},
|
||||
};
|
||||
|
|
@ -27,6 +27,7 @@ describe("evaluateSync", () => {
|
|||
text: "value",
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
logBlackList: {},
|
||||
|
|
|
|||
|
|
@ -7,23 +7,11 @@ import {
|
|||
import { WidgetTypeConfigMap } from "utils/WidgetFactory";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import { PluginType } from "entities/Action";
|
||||
import DataTreeEvaluator from "workers/DataTreeEvaluator";
|
||||
import DataTreeEvaluator from "workers/DataTreeEvaluator/DataTreeEvaluator";
|
||||
import { ValidationTypes } from "constants/WidgetValidation";
|
||||
import WidgetFactory from "utils/WidgetFactory";
|
||||
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
|
||||
|
||||
/**
|
||||
* This function sorts the object's value which is array of string.
|
||||
*
|
||||
* @param {Record<string, Array<string>>} data
|
||||
* @return {*}
|
||||
*/
|
||||
const sortObject = (data: Record<string, Array<string>>) => {
|
||||
Object.entries(data).map(([key, value]) => {
|
||||
data[key] = value.sort();
|
||||
});
|
||||
return data;
|
||||
};
|
||||
import { sortObjectWithArray } from "../utils/treeUtils";
|
||||
|
||||
const WIDGET_CONFIG_MAP: WidgetTypeConfigMap = {
|
||||
CONTAINER_WIDGET: {
|
||||
|
|
@ -230,6 +218,7 @@ const BASE_WIDGET: DataTreeWidget = {
|
|||
parentId: "0",
|
||||
version: 1,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
|
|
@ -254,7 +243,8 @@ const BASE_ACTION: DataTreeAction = {
|
|||
data: {},
|
||||
responseMeta: { isExecutionSuccess: false },
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
bindingPaths: {
|
||||
bindingPaths: {},
|
||||
reactivePaths: {
|
||||
isLoading: EvaluationSubstitutionType.TEMPLATE,
|
||||
data: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
|
|
@ -334,7 +324,7 @@ describe("DataTreeEvaluator", () => {
|
|||
defaultText: "Default value",
|
||||
widgetName: "Input1",
|
||||
type: "INPUT_WIDGET_V2",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
defaultText: EvaluationSubstitutionType.TEMPLATE,
|
||||
isValid: EvaluationSubstitutionType.TEMPLATE,
|
||||
value: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -406,7 +396,7 @@ describe("DataTreeEvaluator", () => {
|
|||
text: "{{Table1.selectedRow.test}}",
|
||||
dynamicBindingPathList: [{ key: "text" }],
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -424,7 +414,7 @@ describe("DataTreeEvaluator", () => {
|
|||
|
||||
expect(evaluation).toHaveProperty("Text2.text", "Label");
|
||||
expect(evaluation).toHaveProperty("Text3.text", "Label");
|
||||
expect(sortObject(dependencyMap)).toStrictEqual(dependencyMap);
|
||||
expect(sortObjectWithArray(dependencyMap)).toStrictEqual(dependencyMap);
|
||||
});
|
||||
|
||||
it("Evaluates a value change in update run", () => {
|
||||
|
|
@ -455,7 +445,9 @@ describe("DataTreeEvaluator", () => {
|
|||
expect(dataTree).toHaveProperty("Text2.text", "Label");
|
||||
expect(dataTree).toHaveProperty("Text3.text", "Label 3");
|
||||
|
||||
expect(sortObject(updatedDependencyMap)).toStrictEqual(dependencyMap);
|
||||
expect(sortObjectWithArray(updatedDependencyMap)).toStrictEqual(
|
||||
dependencyMap,
|
||||
);
|
||||
});
|
||||
|
||||
it("Overrides with default value", () => {
|
||||
|
|
@ -470,6 +462,13 @@ describe("DataTreeEvaluator", () => {
|
|||
});
|
||||
|
||||
it("Evaluates for value changes in nested diff paths", () => {
|
||||
const bindingPaths = {
|
||||
options: EvaluationSubstitutionType.TEMPLATE,
|
||||
defaultOptionValue: EvaluationSubstitutionType.TEMPLATE,
|
||||
isRequired: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isDisabled: EvaluationSubstitutionType.TEMPLATE,
|
||||
};
|
||||
const updatedUnEvalTree = {
|
||||
...unEvalTree,
|
||||
Dropdown2: {
|
||||
|
|
@ -485,12 +484,9 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
],
|
||||
type: "SELECT_WIDGET",
|
||||
bindingPaths: {
|
||||
options: EvaluationSubstitutionType.TEMPLATE,
|
||||
defaultOptionValue: EvaluationSubstitutionType.TEMPLATE,
|
||||
isRequired: EvaluationSubstitutionType.TEMPLATE,
|
||||
isVisible: EvaluationSubstitutionType.TEMPLATE,
|
||||
isDisabled: EvaluationSubstitutionType.TEMPLATE,
|
||||
bindingPaths,
|
||||
reactivePaths: {
|
||||
...bindingPaths,
|
||||
isValid: EvaluationSubstitutionType.TEMPLATE,
|
||||
selectedOption: EvaluationSubstitutionType.TEMPLATE,
|
||||
selectedOptionValue: EvaluationSubstitutionType.TEMPLATE,
|
||||
|
|
@ -533,7 +529,7 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
]);
|
||||
|
||||
expect(sortObject(updatedDependencyMap)).toStrictEqual({
|
||||
expect(sortObjectWithArray(updatedDependencyMap)).toStrictEqual({
|
||||
Api1: ["Api1.data"],
|
||||
...dependencyMap,
|
||||
"Table1.tableData": ["Api1.data", "Text1.text"],
|
||||
|
|
@ -579,7 +575,7 @@ describe("DataTreeEvaluator", () => {
|
|||
},
|
||||
]);
|
||||
expect(dataTree).toHaveProperty("Text4.text", "Hey");
|
||||
expect(sortObject(updatedDependencyMap)).toStrictEqual({
|
||||
expect(sortObjectWithArray(updatedDependencyMap)).toStrictEqual({
|
||||
Api1: ["Api1.data"],
|
||||
...dependencyMap,
|
||||
"Table1.tableData": ["Api1.data", "Text1.text"],
|
||||
|
|
@ -599,8 +595,8 @@ describe("DataTreeEvaluator", () => {
|
|||
dependencyMap: {
|
||||
"config.body": ["config.pluginSpecifiedTemplates[0].value"],
|
||||
},
|
||||
bindingPaths: {
|
||||
...BASE_ACTION.bindingPaths,
|
||||
reactivePaths: {
|
||||
...BASE_ACTION.reactivePaths,
|
||||
"config.body": EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
config: {
|
||||
|
|
@ -646,8 +642,8 @@ describe("DataTreeEvaluator", () => {
|
|||
...updatedTree2,
|
||||
Api2: {
|
||||
...updatedTree2.Api2,
|
||||
bindingPaths: {
|
||||
...updatedTree2.Api2.bindingPaths,
|
||||
reactivePaths: {
|
||||
...updatedTree2.Api2.reactivePaths,
|
||||
"config.body": EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
},
|
||||
config: {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
removeFunctions,
|
||||
validateWidgetProperty,
|
||||
} from "./evaluationUtils";
|
||||
import DataTreeEvaluator from "workers/DataTreeEvaluator";
|
||||
import DataTreeEvaluator from "workers/DataTreeEvaluator/DataTreeEvaluator";
|
||||
import ReplayEntity from "entities/Replay";
|
||||
import evaluate, {
|
||||
evaluateAsync,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ const BASE_WIDGET: DataTreeWidget = {
|
|||
parentId: "0",
|
||||
version: 1,
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
triggerPaths: {},
|
||||
validationPaths: {},
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
|
|
@ -55,7 +56,7 @@ const testDataTree: Record<string, DataTreeWidget> = {
|
|||
widgetName: "Text1",
|
||||
text: "Label",
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -68,7 +69,7 @@ const testDataTree: Record<string, DataTreeWidget> = {
|
|||
text: "{{Text1.text}}",
|
||||
dynamicBindingPathList: [{ key: "text" }],
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -81,7 +82,7 @@ const testDataTree: Record<string, DataTreeWidget> = {
|
|||
text: "{{Text1.text}}",
|
||||
dynamicBindingPathList: [{ key: "text" }],
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -94,7 +95,7 @@ const testDataTree: Record<string, DataTreeWidget> = {
|
|||
text: "{{Text1.text}}",
|
||||
dynamicBindingPathList: [{ key: "text" }],
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -198,7 +199,7 @@ describe("privateWidgets", () => {
|
|||
widgetName: "Text1",
|
||||
text: "Label",
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
@ -212,7 +213,7 @@ describe("privateWidgets", () => {
|
|||
text: "{{Text1.text}}",
|
||||
dynamicBindingPathList: [{ key: "text" }],
|
||||
type: "TEXT_WIDGET",
|
||||
bindingPaths: {
|
||||
reactivePaths: {
|
||||
text: EvaluationSubstitutionType.TEMPLATE,
|
||||
},
|
||||
validationPaths: {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export function getEntityNameAndPropertyPath(
|
|||
|
||||
//these paths are not required to go through evaluate tree as these are internal properties
|
||||
const ignorePathsForEvalRegex =
|
||||
".(bindingPaths|triggerPaths|validationPaths|dynamicBindingPathList)";
|
||||
".(reactivePaths|bindingPaths|triggerPaths|validationPaths|dynamicBindingPathList)";
|
||||
|
||||
//match if paths are part of ignorePathsForEvalRegex
|
||||
const isUninterestingChangeForDependencyUpdate = (path: string) => {
|
||||
|
|
@ -602,7 +602,7 @@ export const isDynamicLeaf = (unEvalTree: DataTree, propertyPath: string) => {
|
|||
return false;
|
||||
const relativePropertyPath = convertPathToString(propPathEls);
|
||||
return (
|
||||
relativePropertyPath in entity.bindingPaths ||
|
||||
relativePropertyPath in entity.reactivePaths ||
|
||||
(isWidget(entity) && relativePropertyPath in entity.triggerPaths)
|
||||
);
|
||||
};
|
||||
|
|
@ -642,14 +642,15 @@ export const updateJSCollectionInDataTree = (
|
|||
);
|
||||
}
|
||||
} else {
|
||||
const bindingPaths = jsCollection.bindingPaths;
|
||||
bindingPaths[action.name] = EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
bindingPaths[`${action.name}.data`] =
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
reactivePaths[action.name] =
|
||||
EvaluationSubstitutionType.SMART_SUBSTITUTE;
|
||||
reactivePaths[`${action.name}.data`] =
|
||||
EvaluationSubstitutionType.TEMPLATE;
|
||||
_.set(
|
||||
modifiedDataTree,
|
||||
`${jsCollection.name}.bindingPaths`,
|
||||
bindingPaths,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
const dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
dynamicBindingPathList.push({ key: action.name });
|
||||
|
|
@ -697,12 +698,12 @@ export const updateJSCollectionInDataTree = (
|
|||
(js: ParsedJSSubAction) => js.name === preAction,
|
||||
);
|
||||
if (!existed) {
|
||||
const bindingPaths = jsCollection.bindingPaths;
|
||||
delete bindingPaths[preAction];
|
||||
const reactivePaths = jsCollection.reactivePaths;
|
||||
delete reactivePaths[preAction];
|
||||
_.set(
|
||||
modifiedDataTree,
|
||||
`${jsCollection.name}.bindingPaths`,
|
||||
bindingPaths,
|
||||
`${jsCollection.name}.reactivePaths`,
|
||||
reactivePaths,
|
||||
);
|
||||
let dynamicBindingPathList = jsCollection.dynamicBindingPathList;
|
||||
dynamicBindingPathList = dynamicBindingPathList.filter(
|
||||
|
|
@ -796,12 +797,12 @@ export const removeFunctionsAndVariableJSCollection = (
|
|||
}
|
||||
//remove functions
|
||||
let dynamicBindingPathList = entity.dynamicBindingPathList;
|
||||
const bindingPaths = entity.bindingPaths;
|
||||
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 bindingPaths[actionName];
|
||||
delete reactivePaths[actionName];
|
||||
delete meta[actionName];
|
||||
delete modifiedDataTree[`${entity.name}`][`${actionName}`];
|
||||
dynamicBindingPathList = dynamicBindingPathList.filter(
|
||||
|
|
@ -809,7 +810,7 @@ export const removeFunctionsAndVariableJSCollection = (
|
|||
);
|
||||
dependencyMap = dependencyMap.filter((item: any) => item !== actionName);
|
||||
}
|
||||
_.set(modifiedDataTree, `${entity.name}.bindingPaths`, bindingPaths);
|
||||
_.set(modifiedDataTree, `${entity.name}.reactivePaths`, reactivePaths);
|
||||
_.set(
|
||||
modifiedDataTree,
|
||||
`${entity.name}.dynamicBindingPathList`,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user