feat: widget property setters (#23441)

## Description


- This PR adds setter methods to update widget property
programmatically.

Example:-

`Input1.setText("setter methods are cool!");`

Docs link : 
https://docs.appsmith.com/reference/widgets
For any selected widget check the `Methods` section

#### PR fixes following issue(s)
Fixes 


#### Type of change

- New feature (non-breaking change which adds functionality)

## Testing
>
#### How Has This Been Tested?
- [x] Manual
- [x] Jest
- [x] Cypress
>
>
#### Test Plan
https://github.com/appsmithorg/TestSmith/issues/2409

#### Issues raised during DP testing
- [x] [Errors are not logged in the
debugger](https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1564017346)
separate GitHub issue
https://github.com/appsmithorg/appsmith/issues/24609
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1564155545
( `setVisibility("false")` )
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1580525843
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1576582825
- Blocker for testing
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1577956441
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1577930108
- Not a issue (lint error query)
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1593471791
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1591440488
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1586747864
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1596738201
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1598541537
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1611413076
- [x]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1612621567
- [ ]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1619654507
- [ ]
https://github.com/appsmithorg/appsmith/pull/23441#issuecomment-1621256722

>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Test-plan-implementation#speedbreaker-features-to-consider-for-every-change)
have been covered
- [x] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans/_edit#areas-of-interest)
- [x] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed

---------

Co-authored-by: Rishabh Rathod <rishabh.rathod@appsmith.com>
This commit is contained in:
Druthi Polisetty 2023-07-08 19:37:26 +05:30 committed by GitHub
parent 00c5c6857e
commit 2fc20cfe8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
141 changed files with 2337 additions and 144 deletions

View File

@ -0,0 +1,56 @@
import {
entityExplorer,
jsEditor,
agHelper,
draggableWidgets,
locators,
propPane,
} from "../../../../support/Objects/ObjectsCore";
const jsObjectBody = `export default {
myVar1: [],
myVar2: {},
myFun1(){
},
myFun2: async () => {
//use async-await or promises
}
}`;
describe("Autocomplete tests for setters", () => {
it("1. Check if setters are present in autocomplete for widgets in JsObject", () => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 200, 200);
jsEditor.CreateJSObject(jsObjectBody, {
paste: true,
completeReplace: true,
toRun: false,
shouldCreateNewJSObj: true,
prettify: false,
});
agHelper.GetNClick(jsEditor._lineinJsEditor(5));
agHelper.TypeText(locators._codeMirrorTextArea, "Button1");
agHelper.GetElementsNAssertTextPresence(
locators._hints,
"Button1.setColor()",
);
//For table widget
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 500, 300);
entityExplorer.SelectEntityByName("JSObject1");
agHelper.GetNClick(jsEditor._lineinJsEditor(5));
agHelper.RemoveCharsNType(locators._codeMirrorTextArea, 7, "Table1.set");
agHelper.GetElementsNAssertTextPresence(locators._hints, "setData()");
});
it("2. Check if setters are present in autocomplete for widgets in property Pane", () => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.INPUT_V2, 200, 600);
entityExplorer.SelectEntityByName("Button1");
propPane.EnterJSContext("onClick", "{{Input1.set", true, false);
agHelper.GetElementsNAssertTextPresence(locators._hints, "setDisabled()");
});
});

View File

@ -61,13 +61,13 @@ describe("Autocomplete using slash command and mustache tests", function () {
cy.get(dynamicInputLocators.hints).should("exist");
// validates all autocomplete functions on entering {{}} in onClick field
cy.get(`${dynamicInputLocators.hints} li`)
.eq(1)
.eq(7)
.should("have.text", "storeValue()");
cy.get(`${dynamicInputLocators.hints} li`)
.eq(2)
.eq(8)
.should("have.text", "showAlert()");
cy.get(`${dynamicInputLocators.hints} li`)
.eq(3)
.eq(9)
.should("have.text", "navigateTo()");
});
});

View File

@ -0,0 +1,185 @@
import {
PROPERTY_SELECTOR,
WIDGET,
getWidgetSelector,
} from "../../../../locators/WidgetLocators";
import {
entityExplorer,
jsEditor,
agHelper,
locators,
propPane,
} from "../../../../support/Objects/ObjectsCore";
const setterMethodsToTest = [
{
name: "setVisibility",
property: "isVisible",
widget: WIDGET.INPUT_V2,
actionBinding: "{{Input1.setVisibility(false)}}",
valueBinding: "{{Input1.isVisible}}",
expectedValue: "false",
},
{
name: "setDisabled",
property: "isDisabled",
widget: WIDGET.INPUT_V2,
actionBinding: "{{Input1.setDisabled(false)}}",
valueBinding: "{{Input1.isDisabled}}",
expectedValue: "false",
},
{
name: "setRequired",
property: "isRequired",
widget: WIDGET.INPUT_V2,
actionBinding: "{{Input1.setRequired(false)}}",
valueBinding: "{{Input1.isRequired}}",
expectedValue: "false",
},
{
name: "setURL",
property: "url",
widget: WIDGET.AUDIO,
actionBinding:
"{{Audio1.setURL('https://www.youtube.com/watch?v=JGwWNGJdvx8')}}",
valueBinding: "{{Audio1.url}}",
expectedValue: "https://www.youtube.com/watch?v=JGwWNGJdvx8",
},
{
name: "setPlaying",
property: "playing",
widget: WIDGET.AUDIO,
actionBinding: "{{Audio1.setPlaying(true)}}",
valueBinding: "{{Audio1.playing}}",
expectedValue: "true",
},
{
name: "setSelectedRowIndex",
property: "selectedRowIndex",
widget: WIDGET.TABLE,
actionBinding: "{{Table1.setSelectedRowIndex(1)}}",
valueBinding: "{{Table1.selectedRowIndex}}",
expectedValue: "1",
},
{
name: "setSelectedOption",
property: "selectedOptionLabel",
widget: WIDGET.SELECT,
actionBinding: "{{Select1.setSelectedOption('BLUE')}}",
valueBinding: "{{Select1.selectedOptionLabel}}",
expectedValue: "Blue",
},
{
name: "setProgress",
property: "progress",
widget: WIDGET.PROGRESS,
actionBinding: "{{Progress1.setProgress(50)}}",
valueBinding: "{{Progress1.progress}}",
expectedValue: "50",
},
{
name: "setText",
property: "text",
widget: WIDGET.TEXT,
actionBinding: "{{Text1.setText('Hello World')}}",
valueBinding: "{{Text1.text}}",
expectedValue: "Hello World",
},
{
name: "setValue",
property: "text",
widget: WIDGET.INPUT_V2,
actionBinding: "{{Input1.setValue('Hello World')}}",
valueBinding: "{{Input1.text}}",
expectedValue: "Hello World",
},
{
name: "setData",
property: "tableData",
widget: WIDGET.TABLE,
actionBinding: "{{Table1.setData([{name: 'test'}])}}",
valueBinding: "{{JSON.stringify(Table1.tableData)}}",
expectedValue: '[{"name":"test"}]',
},
];
Object.values(setterMethodsToTest).forEach(
(
{ actionBinding, expectedValue, name, property, valueBinding, widget },
index,
) => {
describe(`${index + 1}. ${name} method test`, () => {
it(`1. DragDrop widget & Label/Text widgets and Verify the updated value`, () => {
entityExplorer.DragDropWidgetNVerify(widget, 300, 200);
entityExplorer.DragDropWidgetNVerify(WIDGET.BUTTON, 700, 200);
propPane.EnterJSContext(
PROPERTY_SELECTOR.onClickFieldName,
actionBinding,
);
entityExplorer.DragDropWidgetNVerify(WIDGET.TEXT, 700, 400);
propPane.UpdatePropertyFieldValue(
PROPERTY_SELECTOR.TextFieldName,
valueBinding,
);
agHelper.GetNClick(getWidgetSelector(WIDGET.BUTTON));
agHelper.GetText(getWidgetSelector(WIDGET.TEXT)).then(($label) => {
expect($label).to.eq(expectedValue);
});
});
afterEach("Delete all the widgets on canvas", () => {
agHelper.GetNClick(locators._widgetInCanvas(widget));
agHelper.PressDelete();
agHelper.GetNClick(getWidgetSelector(WIDGET.BUTTON));
agHelper.AssertContains("is not defined"); // Since widget is removed & Button is still holding its reference
agHelper.PressDelete();
agHelper.GetNClick(getWidgetSelector(WIDGET.TEXT)).click();
agHelper.GetNClick(propPane._deleteWidget);
});
});
},
);
describe("Linting warning for setter methods", function () {
it("Lint error when setter is used in a data field", function () {
entityExplorer.DragDropWidgetNVerify(WIDGET.BUTTON, 200, 200);
agHelper.GetNClick(getWidgetSelector(WIDGET.BUTTON));
propPane.TypeTextIntoField("Label", "{{Button1.setLabel('Hello')}}");
//Mouse hover to exact warning message
agHelper.HoverElement(locators._lintErrorElement);
agHelper.AssertContains("Data fields cannot execute async code");
//Create a JS object
jsEditor.CreateJSObject(
`export default {
myFun1: () => {
Button1.setLabel('Hello');
},
}`,
{
paste: true,
completeReplace: true,
toRun: false,
shouldCreateNewJSObj: true,
prettify: false,
},
);
//Add myFun1 to onClick
entityExplorer.SelectEntityByName("Button1");
propPane.TypeTextIntoField("Label", "{{JSObject1.myFun1()}}");
agHelper.AssertContains(
"Found an action invocation during evaluation. Data fields cannot execute actions.",
);
});
});

View File

@ -35,6 +35,7 @@ export const WIDGET = {
RANGE_SLIDER: "rangesliderwidget",
IFRAME: "iframewidget",
DIVIDER: "dividerwidget",
PROGRESS: "progresswidget",
MODAL: "modalwidget",
FORM: "formwidget",
ICONBUTTON: "iconbuttonwidget",

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/ban-types */
import set from "lodash/set";
import type { DataTree } from "entities/DataTree/dataTreeFactory";
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeFactory";
import type { EvalContext } from "workers/Evaluation/evaluate";
import type { EvaluationVersion } from "@appsmith/api/ApplicationApi";
import { addFn } from "workers/Evaluation/fns/utils/fnGuard";
@ -11,6 +11,8 @@ import {
} from "@appsmith/workers/Evaluation/fns";
import { getEntityForEvalContext } from "workers/Evaluation/getEntityForContext";
import { klona } from "klona/full";
import { isEmpty } from "lodash";
import setters from "workers/Evaluation/setters";
declare global {
/** All identifiers added to the worker global scope should also
* be included in the DEDICATED_WORKER_GLOBAL_SCOPE_IDENTIFIERS in
@ -38,8 +40,10 @@ export const addDataTreeToContext = (args: {
dataTree: Readonly<DataTree>;
removeEntityFunctions?: boolean;
isTriggerBased: boolean;
configTree: ConfigTree;
}) => {
const {
configTree,
dataTree,
EVAL_CONTEXT,
isTriggerBased,
@ -48,15 +52,39 @@ export const addDataTreeToContext = (args: {
const dataTreeEntries = Object.entries(dataTree);
const entityFunctionCollection: Record<string, Record<string, Function>> = {};
if (isTriggerBased && !removeEntityFunctions) setters.clear();
for (const [entityName, entity] of dataTreeEntries) {
EVAL_CONTEXT[entityName] = getEntityForEvalContext(entity, entityName);
if (!removeEntityFunctions && !isTriggerBased) continue;
// when we evaluate data field and removeEntityFunctions is true then we skip adding entity function to evalContext
const skipEntityFunctions = !removeEntityFunctions && !isTriggerBased;
if (skipEntityFunctions) continue;
for (const entityFn of entityFns) {
if (!entityFn.qualifier(entity)) continue;
const func = entityFn.fn(entity, entityName);
const fullPath = `${entityFn.path || `${entityName}.${entityFn.name}`}`;
set(entityFunctionCollection, fullPath, func);
}
// Don't add entity function ( setter method ) to evalContext if removeEntityFunctions is true
if (removeEntityFunctions) continue;
const entityConfig = configTree[entityName];
const entityMethodMap = setters.getEntitySettersFromConfig(
entityConfig,
entityName,
entity,
);
if (isEmpty(entityMethodMap)) continue;
EVAL_CONTEXT[entityName] = Object.assign(
{},
dataTree[entityName],
entityMethodMap,
);
}
if (removeEntityFunctions)
@ -71,7 +99,11 @@ export const addDataTreeToContext = (args: {
for (const [entityName, funcObj] of Object.entries(
entityFunctionCollection,
)) {
EVAL_CONTEXT[entityName] = Object.assign({}, dataTree[entityName], funcObj);
EVAL_CONTEXT[entityName] = Object.assign(
{},
EVAL_CONTEXT[entityName],
funcObj,
);
}
};
@ -81,7 +113,10 @@ export const addPlatformFunctionsToEvalContext = (context: any) => {
}
};
export const getAllAsyncFunctions = (dataTree: DataTree) => {
export const getAllAsyncFunctions = (
dataTree: DataTree,
configTree: ConfigTree,
) => {
const asyncFunctionNameMap: Record<string, true> = {};
const dataTreeEntries = Object.entries(dataTree);
for (const [entityName, entity] of dataTreeEntries) {
@ -90,6 +125,19 @@ export const getAllAsyncFunctions = (dataTree: DataTree) => {
const fullPath = `${entityFn.path || `${entityName}.${entityFn.name}`}`;
asyncFunctionNameMap[fullPath] = true;
}
const entityConfig = configTree[entityName];
const entityMethodMap = setters.getEntitySettersFromConfig(
entityConfig,
entityName,
entity,
);
if (isEmpty(entityMethodMap)) continue;
for (const methodName of Object.keys(entityMethodMap)) {
asyncFunctionNameMap[`${entityName}.${methodName}`] = true;
}
}
for (const platformFn of getPlatformFunctions(self.$cloudHosting)) {
asyncFunctionNameMap[platformFn.name] = true;

View File

@ -783,6 +783,8 @@ export const overrideWidgetProperties = (params: {
evalMetaUpdates: EvalMetaUpdates;
fullPropertyPath: string;
isNewWidget: boolean;
shouldUpdateGlobalContext?: boolean;
overriddenProperties?: string[];
}) => {
const {
configTree,
@ -791,7 +793,9 @@ export const overrideWidgetProperties = (params: {
evalMetaUpdates,
fullPropertyPath,
isNewWidget,
overriddenProperties,
propertyPath,
shouldUpdateGlobalContext,
value,
} = params;
const clonedValue = klona(value);
@ -813,9 +817,14 @@ export const overrideWidgetProperties = (params: {
if (pathsNotToOverride.includes(overriddenPropertyPath)) return;
_.set(
currentTree,
[entity.widgetName, ...overriddenPropertyPathArray],
[entityName, ...overriddenPropertyPathArray],
clonedValue,
);
if (shouldUpdateGlobalContext) {
_.set(self, [entityName, ...overriddenPropertyPathArray], clonedValue);
}
overriddenProperties?.push(overriddenPropertyPath);
// evalMetaUpdates has all updates from property which overrides meta values.
if (
propertyPath.split(".")[0] !== "meta" &&
@ -844,10 +853,14 @@ export const overrideWidgetProperties = (params: {
const propertyPathArray = propertyPath.split(".");
_.set(
currentTree,
[entity.widgetName, ...propertyPathArray],
[entityName, ...propertyPathArray],
clonedDefaultValue,
);
if (shouldUpdateGlobalContext) {
_.set(self, [entityName, ...propertyPathArray], clonedDefaultValue);
}
return {
overwriteParsedValue: true,
newValue: clonedDefaultValue,

View File

@ -9,7 +9,7 @@ import { zIndexLayers } from "constants/CanvasEditorConstants";
import { objectCollapseAnalytics, textSelectAnalytics } from "./Analytics";
import { Divider } from "design-system";
import { useSelector } from "react-redux";
import { getDataTree } from "selectors/dataTreeSelectors";
import { getConfigTree, getDataTree } from "selectors/dataTreeSelectors";
import { filterInternalProperties } from "utils/FilterInternalProperties";
import { getJSCollections } from "selectors/entitiesSelector";
@ -54,6 +54,7 @@ export function PeekOverlayPopUpContent(
const CONTAINER_MAX_HEIGHT_PX = 252;
const dataWrapperRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const dataTree = useSelector(getDataTree);
const configTree = useSelector(getConfigTree);
const jsActions = useSelector(getJSCollections);
const filteredData = filterInternalProperties(
@ -61,6 +62,7 @@ export function PeekOverlayPopUpContent(
dataTree[props.objectName],
jsActions,
dataTree,
configTree,
);
// Because getPropertyData can return a function

View File

@ -75,3 +75,13 @@ export type AppTheme = {
};
};
};
export type SetterConfig = {
__setters: {
[key: string]: {
path: string;
type: string;
disabled?: string;
};
};
};

View File

@ -57,6 +57,7 @@ export interface WidgetEntityConfig
WidgetConfig {
defaultMetaProps: Array<string>;
type: string;
__setters?: Record<string, any>;
}
export interface AppsmithEntity extends Omit<AppDataState, "store"> {

View File

@ -1,5 +1,8 @@
import type { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import { generateDataTreeWidget } from "entities/DataTree/dataTreeWidget";
import {
generateDataTreeWidget,
getSetterConfig,
} from "entities/DataTree/dataTreeWidget";
import {
ENTITY_TYPE,
EvaluationSubstitutionType,
@ -305,4 +308,310 @@ describe("generateDataTreeWidget", () => {
expect(result.unEvalEntity).toStrictEqual(expectedData);
expect(result.configEntity).toStrictEqual(expectedConfig);
});
it("generates setterConfig with the dynamic data", () => {
// Input widget
const inputWidget: FlattenedWidgetProps = {
bottomRow: 0,
isLoading: false,
leftColumn: 0,
parentColumnSpace: 0,
parentRowSpace: 0,
renderMode: RenderModes.CANVAS,
rightColumn: 0,
topRow: 0,
type: "INPUT_WIDGET_V2",
version: 0,
widgetId: "123",
widgetName: "Input1",
defaultText: "",
deepObj: {
level1: {
value: 10,
},
},
};
const inputSetterConfig: Record<string, any> = {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultText",
type: "string",
},
},
};
const expectedInputData = {
__setters: {
setVisibility: {
path: "Input1.isVisible",
type: "boolean",
},
setDisabled: {
path: "Input1.isDisabled",
type: "boolean",
},
setRequired: {
path: "Input1.isRequired",
type: "boolean",
},
setValue: {
path: "Input1.defaultText",
type: "string",
},
},
};
const inputResult = getSetterConfig(inputSetterConfig, inputWidget);
expect(inputResult).toStrictEqual(expectedInputData);
//Json form widget
const jsonFormWidget: FlattenedWidgetProps = {
bottomRow: 0,
isLoading: false,
leftColumn: 0,
parentColumnSpace: 0,
parentRowSpace: 0,
renderMode: RenderModes.CANVAS,
rightColumn: 0,
topRow: 0,
type: "FORM_WIDGET",
version: 0,
widgetId: "123",
widgetName: "Form1",
defaultText: "",
deepObj: {
level1: {
value: 10,
},
},
};
const jsonFormSetterConfig: Record<string, any> = {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setData: {
path: "sourceData",
type: "object",
},
},
};
const expectedJsonFormData = {
__setters: {
setVisibility: {
path: "Form1.isVisible",
type: "boolean",
},
setData: {
path: "Form1.sourceData",
type: "object",
},
},
};
const jsonFormResult = getSetterConfig(
jsonFormSetterConfig,
jsonFormWidget,
);
expect(jsonFormResult).toStrictEqual(expectedJsonFormData);
// Table widget
const tableWidget: FlattenedWidgetProps = {
bottomRow: 0,
isLoading: false,
leftColumn: 0,
parentColumnSpace: 0,
parentRowSpace: 0,
renderMode: RenderModes.CANVAS,
rightColumn: 0,
topRow: 0,
type: "TABLE_WIDGET",
version: 0,
widgetId: "123",
widgetName: "Table1",
defaultText: "",
deepObj: {
level1: {
value: 10,
},
},
primaryColumns: {
step: {
index: 0,
width: 150,
id: "step",
horizontalAlignment: "LEFT",
verticalAlignment: "CENTER",
columnType: "text",
textSize: "PARAGRAPH",
enableFilter: true,
enableSort: true,
isVisible: true,
isCellVisible: true,
isDerived: false,
label: "step",
computedValue:
"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.step))}}",
},
task: {
index: 1,
width: 150,
id: "task",
horizontalAlignment: "LEFT",
verticalAlignment: "CENTER",
columnType: "text",
textSize: "PARAGRAPH",
enableFilter: true,
enableSort: true,
isVisible: true,
isCellVisible: true,
isDerived: false,
label: "task",
computedValue:
"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.task))}}",
},
status: {
index: 2,
width: 150,
id: "status",
horizontalAlignment: "LEFT",
verticalAlignment: "CENTER",
columnType: "text",
textSize: "PARAGRAPH",
enableFilter: true,
enableSort: true,
isVisible: true,
isCellVisible: true,
isDerived: false,
label: "status",
computedValue:
"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.status))}}",
},
action: {
index: 3,
width: 150,
id: "action",
horizontalAlignment: "LEFT",
verticalAlignment: "CENTER",
columnType: "button",
textSize: "PARAGRAPH",
enableFilter: true,
enableSort: true,
isVisible: true,
isCellVisible: true,
isDisabled: false,
isDerived: false,
label: "action",
onClick:
"{{currentRow.step === '#1' ? showAlert('Done', 'success') : currentRow.step === '#2' ? navigateTo('https://docs.appsmith.com/core-concepts/connecting-to-data-sources/querying-a-database',undefined,'NEW_WINDOW') : navigateTo('https://docs.appsmith.com/core-concepts/displaying-data-read/display-data-tables',undefined,'NEW_WINDOW')}}",
computedValue:
"{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.action))}}",
},
},
};
const tableSetterConfig: Record<string, any> = {
__setters: {
setVisibility: {
path: "isVisible",
type: "string",
},
setSelectedRowIndex: {
path: "defaultSelectedRowIndex",
type: "number",
disabled: "return options.entity.multiRowSelection",
},
setSelectedRowIndices: {
path: "defaultSelectedRowIndices",
type: "array",
disabled: "return !options.entity.multiRowSelection",
},
setData: {
path: "tableData",
type: "object",
},
},
text: {
__setters: {
setIsRequired: {
path: "primaryColumns.$columnId.isRequired",
type: "boolean",
},
},
},
button: {
__setters: {
setIsRequired: {
path: "primaryColumns.$columnId.isRequired",
type: "boolean",
},
},
},
pathToSetters: [
{ path: "primaryColumns.$columnId", property: "columnType" },
],
};
const expectedTableData = {
__setters: {
setVisibility: {
path: "Table1.isVisible",
type: "string",
},
setSelectedRowIndex: {
path: "Table1.defaultSelectedRowIndex",
type: "number",
disabled: "return options.entity.multiRowSelection",
},
setSelectedRowIndices: {
path: "Table1.defaultSelectedRowIndices",
type: "array",
disabled: "return !options.entity.multiRowSelection",
},
setData: {
path: "Table1.tableData",
type: "object",
},
"primaryColumns.action.setIsRequired": {
path: "Table1.primaryColumns.action.isRequired",
type: "boolean",
},
"primaryColumns.status.setIsRequired": {
path: "Table1.primaryColumns.status.isRequired",
type: "boolean",
},
"primaryColumns.step.setIsRequired": {
path: "Table1.primaryColumns.step.isRequired",
type: "boolean",
},
"primaryColumns.task.setIsRequired": {
path: "Table1.primaryColumns.task.isRequired",
type: "boolean",
},
},
};
const tableResult = getSetterConfig(tableSetterConfig, tableWidget);
expect(tableResult).toStrictEqual(expectedTableData);
});
});

View File

@ -1,5 +1,5 @@
import { getAllPathsFromPropertyConfig } from "entities/Widget/utils";
import _, { isEmpty } from "lodash";
import _, { get, isEmpty } from "lodash";
import memoize from "micro-memoize";
import type { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
import type { DynamicPath } from "utils/DynamicBindingUtils";
@ -14,6 +14,140 @@ import type {
import { OverridingPropertyType } from "./types";
import { setOverridingProperty } from "./utils";
import { error } from "loglevel";
/**
*
* Example of setterConfig
*
* {
WIDGET: {
TABLE_WIDGET_V2: {
__setters: {
setIsRequired: {
path: "isRequired"
},
},
"text": {
__setters:{
setIsRequired: {
path: "primaryColumns.$columnId.isRequired"
}
}
}
pathToSetters: [{ path: "primaryColumns.$columnId", property: "columnType" }]
}
}
}
columnId = action
Expected output
{
Table2: {
isRequired: true,
__setters: {
setIsRequired: {
path: "Table2.isRequired"
},
"primaryColumns.action.setIsRequired": {
path: "Table2.primaryColumns.action.isRequired"
}
},
}
}
*/
export function getSetterConfig(
setterConfig: Record<string, any>,
widget: FlattenedWidgetProps,
) {
const modifiedSetterConfig: Record<string, any> = {};
try {
if (setterConfig.__setters) {
modifiedSetterConfig.__setters = {};
for (const setterMethodName of Object.keys(setterConfig.__setters)) {
const staticConfigSetter = setterConfig.__setters[setterMethodName];
modifiedSetterConfig.__setters[setterMethodName] = {
path: `${widget.widgetName}.${staticConfigSetter.path}`,
type: staticConfigSetter.type,
};
if (staticConfigSetter.disabled) {
modifiedSetterConfig.__setters[setterMethodName].disabled =
staticConfigSetter.disabled;
}
}
}
if (!setterConfig.pathToSetters || !setterConfig.pathToSetters.length)
return modifiedSetterConfig;
const pathToSetters = setterConfig.pathToSetters;
//pathToSetters = [{ path: "primaryColumns.$columnId", property: "columnType" }]
for (const { path, property } of pathToSetters) {
const pathArray = path.split(".");
const placeHolder = pathArray[pathArray.length - 1];
if (placeHolder[0] !== "$") continue;
//pathToParentObj = primaryColumns
const pathToParentObj = pathArray.slice(0, -1).join(".");
const accessors = Object.keys(get(widget, pathToParentObj));
//accessors = action, step, status, task
for (const accesskey of accessors) {
const fullPath = pathToParentObj + "." + accesskey;
const accessorObject = get(widget, fullPath);
//propertyType = text, button etc
const propertyType = accessorObject[property];
if (!propertyType) continue;
// "text": {
// __setters:{
// setIsRequired: {
// path: "primaryColumns.$columnId.isRequired"
// }
// }
// }
const accessorSetterConfig = setterConfig[propertyType];
if (!accessorSetterConfig) continue;
const accessorSettersMap = accessorSetterConfig.__setters;
if (!accessorSettersMap) continue;
const entries = Object.entries(accessorSettersMap) as [
string,
Record<string, unknown>,
][];
for (const [setterName, setterBody] of entries) {
//path = primaryColumns.action.isRequired
const path = (setterBody as any).path.replace(placeHolder, accesskey);
const setterPathArray = path.split(".");
setterPathArray.pop();
setterPathArray.push(setterName);
//setterPath = primaryColumns.action.setIsRequired
const setterPath = setterPathArray.join(".");
modifiedSetterConfig.__setters[setterPath] = {
path: `${widget.widgetName}.${path}`, //Table2.primaryColumns.action.isRequired
type: setterBody.type,
};
}
}
}
} catch (e) {
error("Error while generating setter config", e);
}
return modifiedSetterConfig;
}
// We are splitting generateDataTreeWidget into two parts to memoize better as the widget doesn't change very often.
// Widget changes only when dynamicBindingPathList changes.
@ -139,6 +273,11 @@ const generateDataTreeWidgetWithoutMeta = (
"type",
];
const setterConfig = getSetterConfig(
WidgetFactory.getWidgetSetterConfig(widget.type),
widget,
);
const dataTreeWidgetWithoutMetaProps = _.merge(
{
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
@ -181,6 +320,7 @@ const generateDataTreeWidgetWithoutMeta = (
overridingPropertyPaths,
type: widget.type,
...dynamicPathsList,
...setterConfig,
},
};
};
@ -208,6 +348,7 @@ export const generateDataTreeWidget = (
// overridingMetaProps maps properties that can be overriden by either default values or meta changes to initial values.
// initial value is set to metaProps value or defaultMetaProps value.
Object.entries(defaultMetaProps).forEach(([key, value]) => {
if (overridingMetaPropsMap[key]) {
overridingMetaProps[key] =

View File

@ -39,7 +39,7 @@ export interface ActionEntity {
datasourceUrl: string;
}
export interface ActionEntityConfig {
export interface ActionEntityConfig extends EntityConfig {
dynamicBindingPathList: DynamicPath[];
bindingPaths: Record<string, EvaluationSubstitutionType>;
reactivePaths: Record<string, EvaluationSubstitutionType>;
@ -60,7 +60,7 @@ export interface MetaArgs {
confirmBeforeExecute: boolean;
}
export interface JSActionEntityConfig {
export interface JSActionEntityConfig extends EntityConfig {
meta: Record<string, MetaArgs>;
dynamicBindingPathList: DynamicPath[];
bindingPaths: Record<string, EvaluationSubstitutionType>;
@ -109,7 +109,7 @@ export type PropertyOverrideDependency = Record<
Partial<overrideDependency>
>;
export type WidgetConfig = {
export interface WidgetConfig extends EntityConfig {
bindingPaths: Record<string, EvaluationSubstitutionType>;
reactivePaths: Record<string, EvaluationSubstitutionType>;
triggerPaths: Record<string, boolean>;
@ -119,4 +119,12 @@ export type WidgetConfig = {
propertyOverrideDependency: PropertyOverrideDependency;
overridingPropertyPaths: OverridingPropertyPaths;
privateWidgets: PrivateWidgets;
};
}
export interface EntityConfig {
__setters?: Record<string, unknown>;
bindingPaths?: Record<string, EvaluationSubstitutionType>;
reactivePaths?: Record<string, EvaluationSubstitutionType>;
validationPaths?: Record<string, ValidationConfig>;
dynamicBindingPathList?: DynamicPath[];
}

View File

@ -154,6 +154,7 @@ export function EntityProperties() {
break;
case ENTITY_TYPE.ACTION:
config = (entityDefinitions.ACTION as any)(entity as any);
if (config) {
entityProperties = Object.keys(config)
.filter((k) => k.indexOf("!") === -1)
@ -200,9 +201,12 @@ export function EntityProperties() {
}
if (isFunction(config)) config = config(entity);
const settersConfig =
WidgetFactory.getWidgetSetterConfig(type)?.__setters;
entityProperties = Object.keys(config)
.filter((k) => k.indexOf("!") === -1)
.filter((k) => settersConfig && !settersConfig[k])
.map((widgetProperty) => {
return {
propertyName: widgetProperty,

View File

@ -74,7 +74,7 @@ export const CUSTOM_LINT_ERRORS: Record<
entity: unknown,
isJsObject: boolean,
) =>
isEntityFunction(entity, propertyName)
isEntityFunction(entity, propertyName, entityName)
? asyncActionInSyncFieldLintMessage(isJsObject)
: `"${propertyName}" doesn't exist in ${entityName}`,

View File

@ -1,18 +1,24 @@
import type { DataTree } from "entities/DataTree/dataTreeFactory";
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeFactory";
import { isEmpty } from "lodash";
import type { EvalContext } from "workers/Evaluation/evaluate";
import getEvaluationContext from "./utils/getEvaluationContext";
import { getEvaluationContext } from "./utils/getEvaluationContext";
class GlobalData {
globalDataWithFunctions: EvalContext = {};
globalDataWithoutFunctions: EvalContext = {};
unevalTree: DataTree = {};
configTree: ConfigTree = {};
cloudHosting = false;
initialize(unevalTree: DataTree, cloudHosting: boolean) {
initialize(
unevalTree: DataTree,
configTree: ConfigTree,
cloudHosting: boolean,
) {
this.globalDataWithFunctions = {};
this.globalDataWithoutFunctions = {};
this.unevalTree = unevalTree;
this.configTree = configTree;
this.cloudHosting = cloudHosting;
}
@ -22,6 +28,7 @@ class GlobalData {
if (isEmpty(this.globalDataWithFunctions)) {
this.globalDataWithFunctions = getEvaluationContext(
this.unevalTree,
this.configTree,
this.cloudHosting,
{
withFunctions: true,
@ -33,6 +40,7 @@ class GlobalData {
if (isEmpty(this.globalDataWithoutFunctions)) {
this.globalDataWithoutFunctions = getEvaluationContext(
this.unevalTree,
this.configTree,
this.cloudHosting,
{
withFunctions: false,

View File

@ -8,6 +8,7 @@ import lintTriggerPath from "./utils/lintTriggerPath";
import lintJSObjectBody from "./utils/lintJSObjectBody";
import sortLintingPathsByType from "./utils/sortLintingPathsByType";
import lintJSObjectProperty from "./utils/lintJSObjectProperty";
import setters from "workers/Evaluation/setters";
import type {
getLintErrorsFromTreeProps,
getLintErrorsFromTreeResponse,
@ -23,7 +24,10 @@ export function getLintErrorsFromTree({
}: getLintErrorsFromTreeProps): getLintErrorsFromTreeResponse {
const lintTreeErrors: LintErrorsStore = {};
const lintedJSPaths = new Set<string>();
globalData.initialize(unEvalTree, cloudHosting);
setters.init(configTree, unEvalTree);
globalData.initialize(unEvalTree, configTree, cloudHosting);
const { bindingPaths, jsObjectPaths, triggerPaths } = sortLintingPathsByType(
pathsToLint,
unEvalTree,

View File

@ -1,22 +1,25 @@
import type { DataTree } from "entities/DataTree/dataTreeFactory";
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeFactory";
import { createEvaluationContext } from "workers/Evaluation/evaluate";
import { getActionTriggerFunctionNames } from "@appsmith/workers/Evaluation/fns";
export default function getEvaluationContext(
export function getEvaluationContext(
unevalTree: DataTree,
configTree: ConfigTree,
cloudHosting: boolean,
options: { withFunctions: boolean },
) {
if (!options.withFunctions)
return createEvaluationContext({
dataTree: unevalTree,
configTree,
isTriggerBased: false,
removeEntityFunctions: true,
});
const evalContext = createEvaluationContext({
dataTree: unevalTree,
isTriggerBased: false,
configTree,
isTriggerBased: true,
removeEntityFunctions: false,
});

View File

@ -1,12 +1,17 @@
import type { DataTreeEntity } from "entities/DataTree/dataTreeFactory";
import { isDataTreeEntity } from "@appsmith/workers/Evaluation/evaluationUtils";
import { entityFns } from "@appsmith/workers/Evaluation/fns";
import setters from "workers/Evaluation/setters";
export default function isEntityFunction(
entity: unknown,
propertyName: string,
entityName: string,
) {
if (!isDataTreeEntity(entity)) return false;
if (setters.has(entityName, propertyName)) return true;
return entityFns.find((entityFn) => {
const entityFnpropertyName = entityFn.path
? entityFn.path.split(".")[1]

View File

@ -172,6 +172,7 @@ export function* handleEvalWorkerMessage(message: TMessage<any>) {
});
break;
}
case MAIN_THREAD_ACTION.PROCESS_JS_VAR_MUTATION_EVENTS: {
const jsVarMutatedEvents: JSVarMutatedEvents = data;
yield call(logJSVarMutationEvent, jsVarMutatedEvents);

View File

@ -1,15 +1,25 @@
import type {
ConfigTree,
DataTree,
WidgetEntity,
WidgetEntityConfig,
} from "entities/DataTree/dataTreeFactory";
import type { EntityDefinitionsOptions } from "@appsmith/utils/autocomplete/EntityDefinitions";
import type { DataTree, WidgetEntity } from "entities/DataTree/dataTreeFactory";
import { isFunction } from "lodash";
import type { Def } from "tern";
import WidgetFactory from "utils/WidgetFactory";
import { addSettersToDefinitions } from "utils/autocomplete/dataTreeTypeDefCreator";
export const getWidgetChildrenPeekData = (
widgetName: string,
widgetType: string,
dataTree: DataTree,
configTree: ConfigTree,
) => {
const peekData: Record<string, unknown> = {};
const dataTreeWidget: WidgetEntity = dataTree[widgetName] as WidgetEntity;
const widgetConfig = configTree[widgetName];
if (widgetType !== "FORM_WIDGET" && dataTreeWidget) {
const type: Exclude<
EntityDefinitionsOptions,
@ -21,12 +31,32 @@ export const getWidgetChildrenPeekData = (
let config: any = WidgetFactory.getAutocompleteDefinitions(type);
if (config) {
if (isFunction(config)) config = config(dataTreeWidget);
// Need to add this in order to add the setters to the definitions which will appear in the peekOverlay
addSettersToDefinitions(
config as Def,
dataTreeWidget,
configTree[widgetName] as WidgetEntityConfig,
);
const widgetProps = Object.keys(config).filter(
(k) => k.indexOf("!") === -1,
);
widgetProps.forEach((prop) => {
const data = dataTreeWidget[prop];
let setterNames: string[] = [];
if (widgetConfig.__setters) {
setterNames = Object.keys(widgetConfig.__setters);
}
if (setterNames.includes(prop)) {
// eslint-disable-next-line @typescript-eslint/no-empty-function
peekData[prop] = function () {}; // tern inference required here
} else {
peekData[prop] = data;
}
});
}
}

View File

@ -1,5 +1,6 @@
import { getActionChildrenPeekData } from "./Action";
import type {
ConfigTree,
DataTree,
DataTreeEntity,
} from "entities/DataTree/dataTreeFactory";
@ -21,6 +22,7 @@ export const filterInternalProperties = (
dataTreeEntity: DataTreeEntity,
jsActions: JSCollectionDataState,
dataTree: DataTree,
configTree: ConfigTree,
) => {
if (!dataTreeEntity) return;
if (isActionEntity(dataTreeEntity)) {
@ -35,8 +37,12 @@ export const filterInternalProperties = (
? getJsActionPeekData(jsAction, dataTree)?.peekData
: dataTreeEntity;
} else if (isWidgetEntity(dataTreeEntity)) {
return getWidgetChildrenPeekData(objectName, dataTreeEntity.type, dataTree)
?.peekData;
return getWidgetChildrenPeekData(
objectName,
dataTreeEntity.type,
dataTree,
configTree,
)?.peekData;
}
return dataTreeEntity;
};

View File

@ -70,6 +70,7 @@ class WidgetFactory {
static stylesheetConfigMap: Map<WidgetType, Stylesheet> = new Map();
static autocompleteDefinitions: Map<WidgetType, AutocompletionDefinitions> =
new Map();
static setterConfig: Map<WidgetType, Record<string, any>> = new Map();
static widgetConfigMap: Map<
WidgetType,
@ -99,6 +100,7 @@ class WidgetFactory {
stylesheetConfig?: Stylesheet,
autocompleteDefinitions?: AutocompletionDefinitions,
autoLayoutConfig?: AutoLayoutConfig,
setterConfig?: Record<string, any>,
) {
if (!this.widgetTypes[widgetType]) {
this.widgetTypes[widgetType] = widgetType;
@ -115,6 +117,7 @@ class WidgetFactory {
this.stylesheetConfigMap.set(widgetType, stylesheetConfig);
autocompleteDefinitions &&
this.autocompleteDefinitions.set(widgetType, autocompleteDefinitions);
setterConfig && this.setterConfig.set(widgetType, setterConfig);
if (Array.isArray(propertyPaneConfig) && propertyPaneConfig.length > 0) {
const enhancedPropertyPaneConfig = enhancePropertyPaneConfig(
@ -375,12 +378,22 @@ class WidgetFactory {
type: WidgetType,
): AutocompletionDefinitions | undefined {
const autocompleteDefinition = this.autocompleteDefinitions.get(type);
if (!autocompleteDefinition) {
log.error("Widget autocomplete properties not defined: ", type);
}
return autocompleteDefinition;
}
static getWidgetSetterConfig(type: WidgetType): Record<string, any> {
const map = this.setterConfig.get(type);
if (!map) {
return {};
}
return map;
}
static getLoadingProperties(type: WidgetType): Array<RegExp> | undefined {
return this.loadingProperties.get(type);
}

View File

@ -66,6 +66,7 @@ export const registerWidget = (
config.properties.stylesheetConfig,
config.properties.autocompleteDefinitions,
config.autoLayout,
config.properties.setterConfig,
);
configureWidget(config);

View File

@ -121,6 +121,7 @@ export class GracefulWorkerService {
yield this.ready(true);
if (!this._Worker) return;
const messageType = MessageType.RESPONSE;
sendMessage.call(this._Worker, {
body: {
data,

View File

@ -1,4 +1,9 @@
import type { ConfigTree, DataTree } from "entities/DataTree/dataTreeFactory";
import type {
ConfigTree,
DataTree,
DataTreeEntity,
WidgetEntityConfig,
} from "entities/DataTree/dataTreeFactory";
import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
import { uniqueId, isFunction, isObject } from "lodash";
import { entityDefinitions } from "@appsmith/utils/autocomplete/EntityDefinitions";
@ -18,6 +23,7 @@ export type ExtraDef = Record<string, Def | string>;
import type { JSActionEntityConfig } from "entities/DataTree/types";
import type { Variable } from "entities/JSCollection";
import WidgetFactory from "utils/WidgetFactory";
import { shouldAddSetter } from "workers/Evaluation/evaluate";
// Def names are encoded with information about the entity
// This so that we have more info about them
@ -45,12 +51,22 @@ export const dataTreeTypeDefCreator = (
WidgetFactory.getAutocompleteDefinitions(widgetType);
if (autocompleteDefinitions) {
const entityConfig = configTree[entityName] as WidgetEntityConfig;
if (isFunction(autocompleteDefinitions)) {
def[entityName] = autocompleteDefinitions(entity, extraDefsToDefine);
def[entityName] = autocompleteDefinitions(
entity,
extraDefsToDefine,
entityConfig,
);
} else {
def[entityName] = autocompleteDefinitions;
}
addSettersToDefinitions(def[entityName] as Def, entity, entityConfig);
flattenDef(def, entityName);
entityMap.set(entityName, {
type: ENTITY_TYPE.WIDGET,
subType: widgetType,
@ -218,3 +234,24 @@ export function generateJSFunctionTypeDef(
data: generateTypeDef(jsData[fullFunctionName], extraDefs),
};
}
export function addSettersToDefinitions(
definitions: Def,
entity: DataTreeEntity,
entityConfig?: WidgetEntityConfig,
) {
if (entityConfig && entityConfig.__setters) {
const setters = Object.keys(entityConfig.__setters);
setters.forEach((setterName: string) => {
const setter = entityConfig.__setters?.[setterName];
const setterType = entityConfig.__setters?.[setterName].type;
if (shouldAddSetter(setter, entity)) {
definitions[
setterName
] = `fn(value:${setterType}) -> +Promise[:t=[!0.<i>.:t]]`;
}
});
}
}

View File

@ -31,6 +31,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
widgetSize: [

View File

@ -3,7 +3,7 @@ import React from "react";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { createBlobUrl } from "utils/AppsmithUtils";
import type { DerivedPropertiesMap } from "utils/WidgetFactory";
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
@ -236,6 +236,21 @@ class AudioRecorderWidget extends BaseWidget<
}
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const {
blobURL,

View File

@ -29,6 +29,7 @@ export const CONFIG = {
meta: Widget.getMetaPropertiesMap(),
config: Widget.getPropertyPaneConfig(),
contentConfig: Widget.getPropertyPaneContentConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -11,6 +11,7 @@ import BaseWidget from "../../BaseWidget";
import type { AutocompletionDefinitions } from "widgets/constants";
import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
import type { SetterConfig } from "entities/AppTheming";
const AudioComponent = lazy(() => retryPromise(() => import("../component")));
@ -32,6 +33,25 @@ class AudioWidget extends BaseWidget<AudioWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setURL: {
path: "url",
type: "string",
},
setPlaying: {
path: "autoPlay",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -177,6 +177,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
};

View File

@ -4,7 +4,7 @@ import type { ButtonPlacement, ButtonVariant } from "components/constants";
import { ButtonPlacementTypes, ButtonVariantTypes } from "components/constants";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { get } from "lodash";
import React from "react";
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
@ -577,6 +577,21 @@ class ButtonGroupWidget extends BaseWidget<
}
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const { componentWidth } = this.getComponentDimensions();
const minPopoverWidth = MinimumPopupRows * this.props.parentColumnSpace;

View File

@ -42,6 +42,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -14,7 +14,7 @@ import type { ExecutionResult } from "constants/AppsmithActionConstants/ActionCo
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import React from "react";
import type { DerivedPropertiesMap } from "utils/WidgetFactory";
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
@ -444,6 +444,29 @@ class ButtonWidget extends BaseWidget<ButtonWidgetProps, ButtonWidgetState> {
}
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setLabel: {
path: "text",
type: "string",
},
setColor: {
path: "buttonColor",
type: "string",
},
},
};
}
getPageView() {
const disabled =
this.props.disabledWhenInvalid &&

View File

@ -30,6 +30,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
widgetSize: [

View File

@ -9,7 +9,7 @@ import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
import BaseWidget from "widgets/BaseWidget";
import { FileDataTypes } from "widgets/constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import CameraComponent from "../component";
import type { CameraMode } from "../constants";
import { CameraModeTypes, MediaCaptureStatusTypes } from "../constants";
@ -224,6 +224,21 @@ class CameraWidget extends BaseWidget<CameraWidgetProps, WidgetState> {
return "CAMERA_WIDGET";
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const {
bottomRow,

View File

@ -46,6 +46,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -8,7 +8,7 @@ import contentConfig from "./propertyConfig/contentConfig";
import styleConfig from "./propertyConfig/styleConfig";
import type { SliderComponentProps } from "../../NumberSliderWidget/component/Slider";
import SliderComponent from "../../NumberSliderWidget/component/Slider";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -61,6 +61,25 @@ class CategorySliderWidget extends BaseWidget<
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setValue: {
path: "defaultOptionValue",
type: "number",
},
},
};
}
componentDidUpdate(prevProps: CategorySliderWidgetProps) {
/**
* If you change the defaultOptionValue from the propertyPane

View File

@ -46,6 +46,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -7,7 +7,7 @@ import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { TextSize, WidgetType } from "constants/WidgetConstants";
import type { ValidationResponse } from "constants/WidgetValidation";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { compact, xor } from "lodash";
import { default as React } from "react";
@ -529,6 +529,29 @@ class CheckboxGroupWidget extends BaseWidget<
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setSelectedOptions: {
path: "defaultSelectedValues",
type: "array",
},
},
};
}
getPageView() {
return (
<CheckboxGroupComponent

View File

@ -42,6 +42,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -2,7 +2,7 @@ import { LabelPosition } from "components/constants";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import React from "react";
import { isAutoLayout } from "utils/autoLayout/flexWidgetUtils";
import type { DerivedPropertiesMap } from "utils/WidgetFactory";
@ -314,6 +314,29 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultCheckedState",
type: "boolean",
},
},
};
}
getPageView() {
return (
<CheckboxComponent

View File

@ -36,6 +36,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
contentConfig: Widget.getPropertyPaneContentConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -7,7 +7,7 @@ import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import contentConfig from "./propertyConfig/contentConfig";
import styleConfig from "./propertyConfig/styleConfig";
import type { CodeScannerWidgetProps } from "../constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
class CodeScannerWidget extends BaseWidget<
@ -18,6 +18,21 @@ class CodeScannerWidget extends BaseWidget<
return contentConfig;
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisable: {
path: "isDisabled",
type: "boolean",
},
},
};
}
static getPropertyPaneStyleConfig() {
return styleConfig;
}

View File

@ -89,6 +89,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
};

View File

@ -13,7 +13,7 @@ import { ValidationTypes } from "constants/WidgetValidation";
import { compact, map, sortBy } from "lodash";
import WidgetsMultiSelectBox from "pages/Editor/WidgetsMultiSelectBox";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { Positioning } from "utils/autoLayout/constants";
import { getSnappedGrid } from "sagas/WidgetOperationUtils";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
@ -46,6 +46,17 @@ export class ContainerWidget extends BaseWidget<
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -43,6 +43,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -34,7 +34,7 @@ import {
isAutoHeightEnabledForWidget,
DefaultAutocompleteDefinitions,
} from "widgets/WidgetUtils";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { NumberInputStepButtonPosition } from "widgets/BaseInputWidget/constants";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -72,12 +72,20 @@ export function defaultValueValidation(
};
}
if (_.isBoolean(value) || _.isUndefined(value) || _.isNull(value)) {
return {
isValid: false,
parsed: value,
messages: [NUMBER_ERROR_MESSAGE],
};
}
let parsed: any = Number(value);
let isValid, messages;
if (_.isString(value) && value.trim() === "") {
/*
* When value is emtpy string
* When value is empty string
*/
isValid = true;
messages = [EMPTY_ERROR_MESSAGE];
@ -163,6 +171,30 @@ class CurrencyInputWidget extends BaseInputWidget<
},
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultText",
type: "string",
},
},
};
}
static getPropertyPaneContentConfig() {
return mergeWidgetConfig(
[

View File

@ -27,6 +27,7 @@ export const CONFIG = {
default: Widget.getDefaultPropertiesMap(),
meta: Widget.getMetaPropertiesMap(),
config: Widget.getPropertyPaneConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
};

View File

@ -12,6 +12,7 @@ import type { DatePickerType } from "../constants";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
import type { SetterConfig } from "entities/AppTheming";
function defaultDateValidation(
value: unknown,
@ -395,6 +396,29 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultDate",
type: "string",
},
},
};
}
getPageView() {
return (
<DatePickerComponent

View File

@ -56,6 +56,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -11,7 +11,7 @@ import type { DerivedPropertiesMap } from "utils/WidgetFactory";
import { Alignment } from "@blueprintjs/core";
import { LabelPosition } from "components/constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
import {
isAutoHeightEnabledForWidget,
@ -58,6 +58,29 @@ class DatePickerWidget extends BaseWidget<DatePickerWidget2Props, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultDate",
type: "string",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -33,6 +33,7 @@ export const CONFIG = {
config: Widget.getPropertyPaneConfig(),
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -8,6 +8,7 @@ import { ValidationTypes } from "constants/WidgetValidation";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
import { isAutoLayout } from "utils/autoLayout/flexWidgetUtils";
import type { SetterConfig } from "entities/AppTheming";
class DividerWidget extends BaseWidget<DividerWidgetProps, WidgetState> {
static getAutocompleteDefinitions(): AutocompletionDefinitions {
@ -24,6 +25,17 @@ class DividerWidget extends BaseWidget<DividerWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -29,6 +29,7 @@ export const CONFIG = {
meta: Widget.getMetaPropertiesMap(),
config: Widget.getPropertyPaneConfig(),
contentConfig: Widget.getPropertyPaneContentConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -7,6 +7,7 @@ import BaseWidget from "widgets/BaseWidget";
import DocumentViewerComponent from "../component";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
import type { SetterConfig } from "entities/AppTheming";
export function documentUrlValidation(value: unknown): ValidationResponse {
// applied validations if value exist
@ -134,6 +135,21 @@ class DocumentViewerWidget extends BaseWidget<
];
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setURL: {
path: "docUrl",
type: "string",
},
},
};
}
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return {
"!doc": "Document viewer widget is used to show documents on a page",

View File

@ -40,6 +40,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -12,7 +12,7 @@ import { Colors } from "constants/Colors";
import type { WidgetType } from "constants/WidgetConstants";
import { FILE_SIZE_LIMIT_FOR_BLOBS } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { klona } from "klona";
import _, { findIndex } from "lodash";
@ -822,6 +822,21 @@ class FilePickerWidget extends BaseWidget<
this.state.uppy.close();
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
return (
<>

View File

@ -32,6 +32,7 @@ export const CONFIG = {
default: Widget.getDefaultPropertiesMap(),
meta: Widget.getMetaPropertiesMap(),
config: Widget.getPropertyPaneConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
};

View File

@ -19,6 +19,7 @@ import log from "loglevel";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
import type { SetterConfig } from "entities/AppTheming";
class FilePickerWidget extends BaseWidget<
FilePickerWidgetProps,
@ -471,6 +472,21 @@ class FilePickerWidget extends BaseWidget<
this.state.uppy.close();
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
return (
<FilePickerComponent

View File

@ -246,6 +246,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
widgetSize: [

View File

@ -12,6 +12,7 @@ import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { ExtraDef } from "utils/autocomplete/dataTreeTypeDefCreator";
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
import type { AutocompletionDefinitions } from "widgets/constants";
import type { SetterConfig } from "entities/AppTheming";
class FormWidget extends ContainerWidget {
checkInvalidChildren = (children: WidgetProps[]): boolean => {
@ -143,6 +144,17 @@ class FormWidget extends ContainerWidget {
});
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "string",
},
},
};
}
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return { positioning: Positioning.Fixed };
}

View File

@ -32,6 +32,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -10,7 +10,7 @@ import BaseWidget from "widgets/BaseWidget";
import { IconNames } from "@blueprintjs/icons";
import type { ButtonVariant } from "components/constants";
import { ButtonVariantTypes } from "components/constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import IconButtonComponent from "../component";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -214,6 +214,21 @@ class IconButtonWidget extends BaseWidget<IconButtonWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const {
borderRadius,

View File

@ -34,6 +34,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -1,6 +1,6 @@
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import React from "react";
import type { WidgetState } from "widgets/BaseWidget";
import BaseWidget from "widgets/BaseWidget";
@ -22,6 +22,22 @@ class IframeWidget extends BaseWidget<IframeWidgetProps, WidgetState> {
messageMetadata: generateTypeDef(widget.messageMetadata),
});
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setURL: {
path: "source",
type: "string",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -168,6 +168,7 @@ class ImageComponent extends React.Component<
render() {
const { imageUrl, maxZoomLevel } = this.props;
const { imageError, imageRotation } = this.state;
const zoomActive =
maxZoomLevel !== undefined && maxZoomLevel > 1 && !this.isPanning;

View File

@ -29,6 +29,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -7,7 +7,7 @@ import ImageComponent from "../component";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import type { DerivedPropertiesMap } from "utils/WidgetFactory";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -28,6 +28,21 @@ class ImageWidget extends BaseWidget<ImageWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setImage: {
path: "image",
type: "string",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -38,6 +38,7 @@ export const CONFIG = {
config: Widget.getPropertyPaneConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
};

View File

@ -29,7 +29,7 @@ import {
getLocale,
} from "../component/utilities";
import { LabelPosition } from "components/constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { checkInputTypeTextByProps } from "widgets/BaseInputWidget/utils";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -127,7 +127,7 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
}
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return {
const definitions = {
"!doc":
"An input text field is used to capture a users textual input such as their names, numbers, emails etc. Inputs are used in forms and can have custom validations.",
"!url": "https://docs.appsmith.com/widget-reference/input",
@ -148,6 +148,8 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
"!doc": "Selected country code for Currency type input",
},
};
return definitions;
}
static getPropertyPaneConfig() {
@ -763,6 +765,29 @@ class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultText",
type: "string",
},
},
};
}
onValueChange = (value: string) => {
this.props.updateWidgetMetaProperty("text", value, {
triggerPropertyName: "onTextChanged",

View File

@ -41,6 +41,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -26,8 +26,8 @@ import {
InputTypes,
NumberInputStepButtonPosition,
} from "widgets/BaseInputWidget/constants";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { getParsedText, isInputTypeEmailOrPassword } from "./Utilities";
import type { Stylesheet } from "entities/AppTheming";
import {
isAutoHeightEnabledForWidget,
DefaultAutocompleteDefinitions,
@ -59,14 +59,20 @@ export function defaultValueValidation(
}
const { inputType } = props;
if (_.isBoolean(value) || _.isNil(value) || _.isUndefined(value)) {
return {
isValid: false,
parsed: value,
messages: [STRING_ERROR_MESSAGE],
};
}
let parsed;
switch (inputType) {
case "NUMBER":
if (_.isNil(value)) {
parsed = null;
} else {
parsed = Number(value);
}
let isValid, messages;
if (_.isString(value) && value.trim() === "") {
@ -262,7 +268,7 @@ function InputTypeUpdateHook(
class InputWidget extends BaseInputWidget<InputWidgetProps, WidgetState> {
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return {
const definitions: AutocompletionDefinitions = {
"!doc":
"An input text field is used to capture a users textual input such as their names, numbers, emails etc. Inputs are used in forms and can have custom validations.",
"!url": "https://docs.appsmith.com/widget-reference/input",
@ -275,6 +281,8 @@ class InputWidget extends BaseInputWidget<InputWidgetProps, WidgetState> {
isVisible: DefaultAutocompleteDefinitions.isVisible,
isDisabled: "bool",
};
return definitions;
}
static getPropertyPaneContentConfig() {
return mergeWidgetConfig(
@ -590,6 +598,29 @@ class InputWidget extends BaseInputWidget<InputWidgetProps, WidgetState> {
}
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setValue: {
path: "defaultText",
type: "string",
},
},
};
}
resetWidgetText = () => {
this.props.updateWidgetMetaProperty("inputText", "");
this.props.updateWidgetMetaProperty(

View File

@ -97,6 +97,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
widgetSize: [

View File

@ -24,6 +24,7 @@ import { convertSchemaItemToFormData } from "../helper";
import type {
ButtonStyles,
ChildStylesheet,
SetterConfig,
Stylesheet,
} from "entities/AppTheming";
import type { BatchPropertyUpdatePayload } from "actions/controlActions";
@ -223,7 +224,8 @@ class JSONFormWidget extends BaseWidget<
}
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return (widget: JSONFormWidgetProps) => ({
return (widget: JSONFormWidgetProps) => {
const definitions: AutocompletionDefinitions = {
"!doc":
"JSON Form widget can be used to auto-generate forms by providing a JSON source data.",
// TODO: Update the url
@ -232,7 +234,25 @@ class JSONFormWidget extends BaseWidget<
sourceData: generateTypeDef(widget.sourceData),
fieldState: generateTypeDef(widget.fieldState),
isValid: "bool",
});
};
return definitions;
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setSourceData: {
path: "sourceData",
type: "object",
},
},
};
}
static defaultProps = {};

View File

@ -33,6 +33,19 @@ export const sourceDataValidationFn = (
};
}
if (_.isNumber(value) || _.isBoolean(value)) {
return {
isValid: false,
parsed: {},
messages: [
{
name: "ValidationError",
message: `Source data cannot be ${value}`,
},
],
};
}
if (_.isNil(value)) {
return {
isValid: true,

View File

@ -418,6 +418,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -3,7 +3,7 @@ import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import { GridDefaults, RenderModes } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import type { PrivateWidgets } from "entities/DataTree/types";
import equal from "fast-deep-equal/es6";
import { klona } from "klona/lite";
@ -79,6 +79,18 @@ class ListWidget extends BaseWidget<ListWidgetProps<WidgetProps>, WidgetState> {
pageSize: generateTypeDef(widget.pageSize),
});
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return PropertyPaneContentConfig;
}

View File

@ -477,6 +477,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
widgetSize: [

View File

@ -34,7 +34,7 @@ import { RenderModes, WIDGET_PADDING } from "constants/WidgetConstants";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { ModifyMetaWidgetPayload } from "reducers/entityReducers/metaWidgetsReducer";
import type { WidgetState } from "../../BaseWidget";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import type {
TabContainerWidgetProps,
TabsWidgetProps,
@ -159,13 +159,15 @@ class ListWidget extends BaseWidget<
}
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return (widget: ListWidgetProps, extraDefsToDefine?: ExtraDef) => ({
return (widget: ListWidgetProps, extraDefsToDefine?: ExtraDef) => {
const obj = {
"!doc":
"Containers are used to group widgets together to form logical higher order widgets. Containers let you organize your page better and move all the widgets inside them together.",
"!url": "https://docs.appsmith.com/widget-reference/list",
backgroundColor: {
"!type": "string",
"!url": "https://docs.appsmith.com/widget-reference/how-to-use-widgets",
"!url":
"https://docs.appsmith.com/widget-reference/how-to-use-widgets",
},
isVisible: DefaultAutocompleteDefinitions.isVisible,
itemSpacing: "number",
@ -186,7 +188,21 @@ class ListWidget extends BaseWidget<
widget.currentItemsView,
extraDefsToDefine,
),
});
};
return obj;
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getDerivedPropertiesMap() {

View File

@ -49,6 +49,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -4,7 +4,7 @@ import Skeleton from "components/utils/Skeleton";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { WidgetType } from "constants/WidgetConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { retryPromise } from "utils/AppsmithUtils";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
@ -78,6 +78,18 @@ class MapChartWidget extends BaseWidget<MapChartWidgetProps, WidgetState> {
},
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -35,6 +35,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

View File

@ -7,7 +7,7 @@ import MapComponent from "../component";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import styled from "styled-components";
import type { DerivedPropertiesMap } from "utils/WidgetFactory";
@ -67,6 +67,17 @@ class MapWidget extends BaseWidget<MapWidgetProps, WidgetState> {
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{

View File

@ -56,6 +56,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -1,6 +1,6 @@
import type { ExecuteTriggerPayload } from "constants/AppsmithActionConstants/ActionConstants";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { isArray, orderBy } from "lodash";
import { default as React } from "react";
import type { WidgetState } from "widgets/BaseWidget";
@ -114,6 +114,21 @@ class MenuButtonWidget extends BaseWidget<MenuButtonWidgetProps, WidgetState> {
return [];
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const { componentWidth } = this.getComponentDimensions();
const menuDropDownWidth = MinimumPopupRows * this.props.parentColumnSpace;

View File

@ -70,6 +70,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -5,7 +5,7 @@ import { Layers } from "constants/Layers";
import type { TextSize, WidgetType } from "constants/WidgetConstants";
import type { ValidationResponse } from "constants/WidgetValidation";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { isArray, xor } from "lodash";
import type { DefaultValueType } from "rc-tree-select/lib/interface";
@ -561,6 +561,25 @@ class MultiSelectTreeWidget extends BaseWidget<
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
},
};
}
getPageView() {
const options = isArray(this.props.options) ? this.props.options : [];
const dropDownWidth = MinimumPopupRows * this.props.parentColumnSpace;

View File

@ -44,6 +44,7 @@ export const CONFIG = {
config: Widget.getPropertyPaneConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
};

View File

@ -10,7 +10,7 @@ import BaseWidget from "widgets/BaseWidget";
import { Alignment } from "@blueprintjs/core";
import { LabelPosition } from "components/constants";
import { Layers } from "constants/Layers";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import type { DraftValueType } from "rc-select/lib/Select";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
@ -447,6 +447,29 @@ class MultiSelectWidget extends BaseWidget<
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setSelectedOptions: {
path: "defaultOptionValue",
type: "array",
},
},
};
}
getPageView() {
const options = isArray(this.props.options) ? this.props.options : [];
const values: string[] = isArray(this.props.selectedOptionValues)

View File

@ -55,6 +55,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -5,7 +5,7 @@ import { Layers } from "constants/Layers";
import type { WidgetType } from "constants/WidgetConstants";
import type { ValidationResponse } from "constants/WidgetValidation";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import equal from "fast-deep-equal/es6";
import type { LoDashStatic } from "lodash";
@ -714,6 +714,29 @@ class MultiSelectWidget extends BaseWidget<
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setRequired: {
path: "isRequired",
type: "boolean",
},
setSelectedOptions: {
path: "defaultOptionValue",
type: "array",
},
},
};
}
getPageView() {
const options = isArray(this.props.options) ? this.props.options : [];
const minDropDownWidth = MinimumPopupRows * this.props.parentColumnSpace;

View File

@ -48,6 +48,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -8,7 +8,7 @@ import type { SliderComponentProps } from "../component/Slider";
import SliderComponent from "../component/Slider";
import contentConfig from "./propertyConfig/contentConfig";
import styleConfig from "./propertyConfig/styleConfig";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -59,6 +59,25 @@ class NumberSliderWidget extends BaseWidget<
};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setValue: {
path: "defaultValue",
type: "number",
},
},
};
}
componentDidUpdate(prevProps: NumberSliderWidgetProps) {
/**
* If you change the defaultValue from the propertyPane

View File

@ -42,6 +42,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -26,7 +26,7 @@ import { AsYouType, parseIncompletePhoneNumber } from "libphonenumber-js";
import * as Sentry from "@sentry/react";
import log from "loglevel";
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import {
isAutoHeightEnabledForWidget,
DefaultAutocompleteDefinitions,
@ -365,6 +365,21 @@ class PhoneInputWidget extends BaseInputWidget<
this.props.updateWidgetMetaProperty("value", undefined);
};
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
},
};
}
getPageView() {
const value = this.props.text ?? "";
const isInvalid =

View File

@ -35,6 +35,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
disabledPropsDefaults: {

View File

@ -7,7 +7,7 @@ import BaseWidget from "widgets/BaseWidget";
import { Colors } from "constants/Colors";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import ProgressComponent from "../component";
import { ProgressType, ProgressVariant } from "../constants";
import type { AutocompletionDefinitions } from "widgets/constants";
@ -188,6 +188,21 @@ class ProgressWidget extends BaseWidget<ProgressWidgetProps, WidgetState> {
return {};
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setProgress: {
path: "progress",
type: "number",
},
},
};
}
getPageView() {
const {
borderRadius,

View File

@ -46,6 +46,7 @@ export const CONFIG = {
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
setterConfig: Widget.getSetterConfig(),
},
autoLayout: {
defaults: {

View File

@ -7,7 +7,7 @@ import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import type { TextSize, WidgetType } from "constants/WidgetConstants";
import type { ValidationResponse } from "constants/WidgetValidation";
import { ValidationTypes } from "constants/WidgetValidation";
import type { Stylesheet } from "entities/AppTheming";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
@ -572,6 +572,25 @@ class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
}
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setDisabled: {
path: "isDisabled",
type: "boolean",
},
setData: {
path: "options",
type: "array",
},
},
};
}
getPageView() {
const {
alignment,

View File

@ -48,6 +48,7 @@ export const CONFIG = {
contentConfig: Widget.getPropertyPaneContentConfig(),
styleConfig: Widget.getPropertyPaneStyleConfig(),
stylesheetConfig: Widget.getStylesheetConfig(),
setterConfig: Widget.getSetterConfig(),
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
},
autoLayout: {

Some files were not shown because too many files have changed in this diff Show More