feat: Integrate one click binding to sourceData of select and multi select widget (#25750)
## Description We have changed the property control of sourceData of select and multi select widget to dropdowns which has one click-binding items. #### PR fixes following issue(s) Fixes https://github.com/appsmithorg/appsmith/issues/24780 #### Type of change - New feature (non-breaking change which adds functionality) ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [x] Manual - [ ] Cypress > > #### Test Plan >(https://github.com/appsmithorg/TestSmith/issues/2472) > > #### Issues raised during DP testing > (https://github.com/appsmithorg/appsmith/pull/25750#issuecomment-1665077044) > > > ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] 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 - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] 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/Guidelines-for-test-plans#speedbreakers-) have been covered - [x] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [x] Test plan has been peer reviewed by project stakeholders and other QA members - [x] 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
This commit is contained in:
parent
0d533dab90
commit
727d30ad92
|
|
@ -2,6 +2,7 @@ const testdata = require("../../../../fixtures/testdata.json");
|
|||
import {
|
||||
entityExplorer,
|
||||
agHelper,
|
||||
propPane,
|
||||
} from "../../../../support/Objects/ObjectsCore";
|
||||
|
||||
describe("Binding the multiple widgets and validating default data", function () {
|
||||
|
|
@ -11,6 +12,7 @@ describe("Binding the multiple widgets and validating default data", function ()
|
|||
|
||||
it("1. Dropdown widget test with invalid binding value", function () {
|
||||
entityExplorer.SelectEntityByName("Dropdown1");
|
||||
propPane.ToggleJSMode("sourcedata");
|
||||
cy.testJsontext("sourcedata", JSON.stringify(testdata.defaultdataBinding));
|
||||
cy.evaluateErrorMessage(testdata.dropdownErrorMsg);
|
||||
//Table widget test with invalid binding value
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ describe("Binding the multiple widgets and validating default data", function ()
|
|||
);
|
||||
//Dropdown widget test with default value from table widget
|
||||
entityExplorer.SelectEntityByName("Dropdown1");
|
||||
propPane.ToggleJSMode("sourcedata");
|
||||
cy.testJsontext(
|
||||
"sourcedata",
|
||||
JSON.stringify(testdata.deafultDropDownWidget),
|
||||
|
|
|
|||
|
|
@ -147,7 +147,10 @@ describe("excludeForAirgap", "Widget property navigation", () => {
|
|||
);
|
||||
_.agHelper.GetNClick(OneClickBindingLocator.searchableColumn);
|
||||
_.agHelper.GetNClick(
|
||||
OneClickBindingLocator.searchableColumnDropdownOption(),
|
||||
OneClickBindingLocator.columnDropdownOption(
|
||||
"searchableColumn",
|
||||
"imdb_id",
|
||||
),
|
||||
);
|
||||
_.agHelper.GetNClick(OneClickBindingLocator.connectData);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator";
|
||||
import { OneClickBinding } from "../spec_utility";
|
||||
import {
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
dataSources,
|
||||
draggableWidgets,
|
||||
assertHelper,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
import formWidgetsPage from "../../../../../locators/FormWidgets.json";
|
||||
import widgetsPage from "../../../../../locators/Widgets.json";
|
||||
import commonlocators from "../../../../../locators/commonlocators.json";
|
||||
|
||||
const oneClickBinding = new OneClickBinding();
|
||||
|
||||
describe("Table widget one click binding feature", () => {
|
||||
it("should check that queries are created and bound to table widget properly", () => {
|
||||
entityExplorer.DragDropWidgetNVerify(
|
||||
draggableWidgets.MULTISELECT,
|
||||
450,
|
||||
200,
|
||||
);
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
|
||||
dataSources.CreateDataSource("Mongo");
|
||||
|
||||
cy.get("@dsName").then((dsName) => {
|
||||
entityExplorer.NavigateToSwitcher("Widgets");
|
||||
|
||||
entityExplorer.SelectEntityByName("MultiSelect1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(`${dsName}`, dsName, "netflix", {
|
||||
label: "name",
|
||||
value: "director",
|
||||
});
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 450, 500);
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
`{{MultiSelect1.selectedOptionLabels.toString()}}:{{MultiSelect1.selectedOptionValues.toString()}}`,
|
||||
);
|
||||
|
||||
[
|
||||
{
|
||||
label: "I Care a Lot",
|
||||
text: "I Care a Lot:J Blakeson",
|
||||
},
|
||||
{
|
||||
label: "tick, tick...BOOM!",
|
||||
text: "I Care a Lot,tick, tick...BOOM!:J Blakeson,Lin-Manuel Miranda",
|
||||
},
|
||||
{
|
||||
label: "Munich – The Edge of War",
|
||||
text: "I Care a Lot,tick, tick...BOOM!,Munich – The Edge of War:J Blakeson,Lin-Manuel Miranda,Christian Schwochow",
|
||||
},
|
||||
].forEach((d) => {
|
||||
cy.get(formWidgetsPage.multiSelectWidget)
|
||||
.find(".rc-select-selector")
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(".rc-select-item").contains(d.label).click({
|
||||
force: true,
|
||||
});
|
||||
cy.get(commonlocators.TextInside).first().should("have.text", d.text);
|
||||
});
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(formWidgetsPage.multiselectWidgetv2search)
|
||||
.first()
|
||||
.focus({ force: true } as any)
|
||||
.type("Haunting", { force: true });
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(
|
||||
".rc-select-item-option:contains('The Haunting of Hill House')",
|
||||
).should("have.length", 1);
|
||||
cy.get(".rc-select-item")
|
||||
.contains("The Haunting of Hill House")
|
||||
.should("exist");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator";
|
||||
import { OneClickBinding } from "../spec_utility";
|
||||
import {
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
dataSources,
|
||||
draggableWidgets,
|
||||
assertHelper,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
import formWidgetsPage from "../../../../../locators/FormWidgets.json";
|
||||
import widgetsPage from "../../../../../locators/Widgets.json";
|
||||
import commonlocators from "../../../../../locators/commonlocators.json";
|
||||
|
||||
const oneClickBinding = new OneClickBinding();
|
||||
|
||||
describe("Table widget one click binding feature", () => {
|
||||
it("should check that queries are created and bound to table widget properly", () => {
|
||||
entityExplorer.DragDropWidgetNVerify(
|
||||
draggableWidgets.MULTISELECT,
|
||||
450,
|
||||
200,
|
||||
);
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
|
||||
dataSources.CreateDataSource("Postgres");
|
||||
|
||||
cy.get("@dsName").then((dsName) => {
|
||||
entityExplorer.NavigateToSwitcher("Widgets");
|
||||
|
||||
entityExplorer.SelectEntityByName("MultiSelect1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
`${dsName}`,
|
||||
dsName,
|
||||
"public.employees",
|
||||
{
|
||||
label: "first_name",
|
||||
value: "last_name",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 450, 500);
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
`{{MultiSelect1.selectedOptionLabels.toString()}}:{{MultiSelect1.selectedOptionValues.toString()}}`,
|
||||
);
|
||||
|
||||
[
|
||||
{
|
||||
label: "Andrew",
|
||||
text: "Andrew:Fuller",
|
||||
},
|
||||
{
|
||||
label: "Janet",
|
||||
text: "Andrew,Janet:Fuller,Leverling",
|
||||
},
|
||||
{
|
||||
label: "Margaret",
|
||||
text: "Andrew,Janet,Margaret:Fuller,Leverling,Peacock",
|
||||
},
|
||||
].forEach((d) => {
|
||||
cy.get(formWidgetsPage.multiSelectWidget)
|
||||
.find(".rc-select-selector")
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(".rc-select-item").contains(d.label).click({
|
||||
force: true,
|
||||
});
|
||||
cy.get(commonlocators.TextInside).first().should("have.text", d.text);
|
||||
});
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(formWidgetsPage.multiSelectWidget)
|
||||
.find(".rc-select-selector")
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(formWidgetsPage.multiselectwidgetv2)
|
||||
.find(".rc-select-selection-search-input")
|
||||
.first()
|
||||
.focus({ force: true } as any)
|
||||
.type("Anne", { force: true });
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(".rc-select-item").contains("Anne").should("exist");
|
||||
});
|
||||
});
|
||||
|
|
@ -99,23 +99,17 @@ describe("excludeForAirgap", "One click binding control", () => {
|
|||
|
||||
propPane.ToggleJSMode("Table data", false);
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
"Users",
|
||||
"Users",
|
||||
"public.users",
|
||||
"gender",
|
||||
);
|
||||
oneClickBinding.ChooseAndAssertForm("Users", "Users", "public.users", {
|
||||
searchableColumn: "gender",
|
||||
});
|
||||
|
||||
propPane.MoveToTab("Style");
|
||||
|
||||
propPane.MoveToTab("Content");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
"sample Movies",
|
||||
"movies",
|
||||
"movies",
|
||||
"status",
|
||||
);
|
||||
oneClickBinding.ChooseAndAssertForm("sample Movies", "movies", "movies", {
|
||||
searchableColumn: "status",
|
||||
});
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
dataSources.NavigateToDSCreateNew();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator";
|
||||
import { OneClickBinding } from "../spec_utility";
|
||||
import {
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
dataSources,
|
||||
draggableWidgets,
|
||||
assertHelper,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
import formWidgetsPage from "../../../../../locators/FormWidgets.json";
|
||||
import widgetsPage from "../../../../../locators/Widgets.json";
|
||||
import commonlocators from "../../../../../locators/commonlocators.json";
|
||||
|
||||
const oneClickBinding = new OneClickBinding();
|
||||
|
||||
describe("Table widget one click binding feature", () => {
|
||||
it("should check that queries are created and bound to table widget properly", () => {
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 450, 200);
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
|
||||
dataSources.CreateDataSource("Mongo");
|
||||
|
||||
cy.get("@dsName").then((dsName) => {
|
||||
entityExplorer.NavigateToSwitcher("Widgets");
|
||||
|
||||
entityExplorer.SelectEntityByName("Select1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(`${dsName}`, dsName, "netflix", {
|
||||
label: "name",
|
||||
value: "director",
|
||||
});
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 450, 500);
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
`{{Select1.selectedOptionLabel}}:{{Select1.selectedOptionValue}}`,
|
||||
);
|
||||
|
||||
[
|
||||
{
|
||||
label: "I Care a Lot",
|
||||
text: "I Care a Lot:J Blakeson",
|
||||
},
|
||||
{
|
||||
label: "tick, tick...BOOM!",
|
||||
text: "tick, tick...BOOM!:Lin-Manuel Miranda",
|
||||
},
|
||||
{
|
||||
label: "Munich – The Edge of War",
|
||||
text: "Munich – The Edge of War:Christian Schwochow",
|
||||
},
|
||||
].forEach((d) => {
|
||||
cy.get(formWidgetsPage.selectWidget)
|
||||
.find(widgetsPage.dropdownSingleSelect)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.singleSelectWidgetMenuItem)
|
||||
.contains(d.label)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.TextInside).first().should("have.text", d.text);
|
||||
});
|
||||
|
||||
cy.get(formWidgetsPage.selectWidget)
|
||||
.find(widgetsPage.dropdownSingleSelect)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.selectInputSearch).type("I Care a Lot");
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(".select-popover-wrapper .menu-item-link")
|
||||
.children()
|
||||
.should("have.length", 1);
|
||||
|
||||
agHelper.AssertElementExist(
|
||||
commonlocators.singleSelectWidgetMenuItem + `:contains(I Care a Lot)`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import oneClickBindingLocator from "../../../../../locators/OneClickBindingLocator";
|
||||
import { OneClickBinding } from "../spec_utility";
|
||||
import {
|
||||
agHelper,
|
||||
entityExplorer,
|
||||
dataSources,
|
||||
draggableWidgets,
|
||||
assertHelper,
|
||||
propPane,
|
||||
} from "../../../../../support/Objects/ObjectsCore";
|
||||
import formWidgetsPage from "../../../../../locators/FormWidgets.json";
|
||||
import widgetsPage from "../../../../../locators/Widgets.json";
|
||||
import commonlocators from "../../../../../locators/commonlocators.json";
|
||||
|
||||
const oneClickBinding = new OneClickBinding();
|
||||
|
||||
describe("Table widget one click binding feature", () => {
|
||||
it("should check that queries are created and bound to table widget properly", () => {
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 450, 200);
|
||||
|
||||
entityExplorer.NavigateToSwitcher("Explorer");
|
||||
|
||||
dataSources.CreateDataSource("Postgres");
|
||||
|
||||
cy.get("@dsName").then((dsName) => {
|
||||
entityExplorer.NavigateToSwitcher("Widgets");
|
||||
|
||||
entityExplorer.SelectEntityByName("Select1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
`${dsName}`,
|
||||
dsName,
|
||||
"public.employees",
|
||||
{
|
||||
label: "first_name",
|
||||
value: "last_name",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TEXT, 450, 500);
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Text",
|
||||
`{{Select1.selectedOptionLabel}}:{{Select1.selectedOptionValue}}`,
|
||||
);
|
||||
|
||||
[
|
||||
{
|
||||
label: "Andrew",
|
||||
text: "Andrew:Fuller",
|
||||
},
|
||||
{
|
||||
label: "Janet",
|
||||
text: "Janet:Leverling",
|
||||
},
|
||||
{
|
||||
label: "Margaret",
|
||||
text: "Margaret:Peacock",
|
||||
},
|
||||
].forEach((d) => {
|
||||
cy.get(formWidgetsPage.selectWidget)
|
||||
.find(widgetsPage.dropdownSingleSelect)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.singleSelectWidgetMenuItem)
|
||||
.contains(d.label)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.TextInside).first().should("have.text", d.text);
|
||||
});
|
||||
|
||||
cy.get(formWidgetsPage.selectWidget)
|
||||
.find(widgetsPage.dropdownSingleSelect)
|
||||
.click({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(commonlocators.selectInputSearch).type("Anne");
|
||||
|
||||
assertHelper.AssertNetworkStatus("@postExecute");
|
||||
|
||||
agHelper.Sleep(2000);
|
||||
|
||||
cy.get(".select-popover-wrapper .menu-item-link")
|
||||
.children()
|
||||
.should("have.length", 1);
|
||||
|
||||
agHelper.AssertElementExist(
|
||||
commonlocators.singleSelectWidgetMenuItem + `:contains(Anne)`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -25,12 +25,9 @@ describe("one click binding mongodb datasource", function () {
|
|||
cy.get("@dsName").then((dsName) => {
|
||||
entityExplorer.SelectEntityByName("Table1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
`${dsName}`,
|
||||
dsName,
|
||||
"netflix",
|
||||
"creator",
|
||||
);
|
||||
oneClickBinding.ChooseAndAssertForm(`${dsName}`, dsName, "netflix", {
|
||||
searchableColumn: "creator",
|
||||
});
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
|
|
|||
|
|
@ -23,12 +23,9 @@ describe.skip("Table widget one click binding feature", () => {
|
|||
|
||||
entityExplorer.SelectEntityByName("Table1", "Widgets");
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(
|
||||
`${dsName}`,
|
||||
dsName,
|
||||
"configs",
|
||||
"configName",
|
||||
);
|
||||
oneClickBinding.ChooseAndAssertForm(`${dsName}`, dsName, "configs", {
|
||||
searchableColumn: "configName",
|
||||
});
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ describe("Table widget one click binding feature", () => {
|
|||
`${dsName}`,
|
||||
dsName,
|
||||
"public.employees",
|
||||
"first_name",
|
||||
{
|
||||
searchableColumn: "first_name",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export class OneClickBinding {
|
|||
source?: string,
|
||||
selectedSource?: any,
|
||||
table?: string,
|
||||
column?: string,
|
||||
column: Record<string, string> = {},
|
||||
) {
|
||||
agHelper.GetNClick(oneClickBindingLocator.datasourceDropdownSelector);
|
||||
|
||||
|
|
@ -37,17 +37,19 @@ export class OneClickBinding {
|
|||
oneClickBindingLocator.tableOrSpreadsheetSelectedOption(table),
|
||||
);
|
||||
|
||||
agHelper.AssertElementExist(oneClickBindingLocator.searchableColumn);
|
||||
Object.entries(column).forEach(([key, value]) => {
|
||||
agHelper.AssertElementExist((oneClickBindingLocator as any)[key]);
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.searchableColumn);
|
||||
agHelper.GetNClick((oneClickBindingLocator as any)[key]);
|
||||
|
||||
agHelper.GetNClick(
|
||||
oneClickBindingLocator.searchableColumnDropdownOption(column),
|
||||
);
|
||||
agHelper.GetNClick(
|
||||
oneClickBindingLocator.columnDropdownOption(key, value),
|
||||
);
|
||||
|
||||
agHelper.AssertElementExist(
|
||||
oneClickBindingLocator.searchableColumnSelectedOption(column),
|
||||
);
|
||||
agHelper.AssertElementExist(
|
||||
oneClickBindingLocator.columnSelectedOption(key, value),
|
||||
);
|
||||
});
|
||||
|
||||
agHelper.AssertElementExist(oneClickBindingLocator.connectData);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ describe("Dropdown Widget Functionality", function () {
|
|||
|
||||
it("should check that empty value is allowed in options", () => {
|
||||
cy.openPropertyPane("selectwidget");
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-sourcedata",
|
||||
`[
|
||||
|
|
@ -35,16 +36,16 @@ describe("Dropdown Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("label key");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("value key");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
);
|
||||
});
|
||||
|
|
@ -68,7 +69,7 @@ describe("Dropdown Widget Functionality", function () {
|
|||
}
|
||||
]`,
|
||||
);
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"exist",
|
||||
);
|
||||
});
|
||||
|
|
@ -91,9 +92,7 @@ describe("Dropdown Widget Functionality", function () {
|
|||
}]`,
|
||||
);
|
||||
cy.updateCodeInput(".t--property-control-defaultselectedvalue", "BLUE");
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
);
|
||||
cy.get(".t--property-key .t--codemirror-has-error").should("not.exist");
|
||||
cy.get(
|
||||
".t--property-control-defaultselectedvalue .t--codemirror-has-error",
|
||||
).should("not.exist");
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ describe("Select Widgets", function () {
|
|||
100,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`{{[{
|
||||
|
|
@ -29,14 +31,14 @@ describe("Select Widgets", function () {
|
|||
}]}}`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("label key");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("value key");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Default selected values",
|
||||
|
|
@ -50,6 +52,8 @@ describe("Select Widgets", function () {
|
|||
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.SELECT, 250, 300);
|
||||
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`{{[{
|
||||
|
|
@ -58,14 +62,14 @@ describe("Select Widgets", function () {
|
|||
}]}}`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("label key");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("value key");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Default selected value",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.MULTISELECT);
|
||||
//should check that empty value is allowed in options", () => {
|
||||
cy.openPropertyPane("multiselectwidgetv2");
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-sourcedata",
|
||||
`[
|
||||
|
|
@ -30,16 +31,16 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("labelkey");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("valuekey");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
);
|
||||
});
|
||||
|
|
@ -63,7 +64,7 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
}
|
||||
]`,
|
||||
);
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"exist",
|
||||
);
|
||||
});
|
||||
|
|
@ -96,7 +97,7 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
}
|
||||
]`,
|
||||
);
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
);
|
||||
cy.get(
|
||||
|
|
@ -135,7 +136,7 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
"RED"
|
||||
]`,
|
||||
);
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
cy.get(".t--property-control-valuekey .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
);
|
||||
cy.get(
|
||||
|
|
|
|||
|
|
@ -18,19 +18,20 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
|
||||
it("1. Selects value with invalid default value", () => {
|
||||
cy.openPropertyPane("multiselectwidgetv2");
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
JSON.stringify(data.input),
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("labelkey");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("valuekey");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Default selected values",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
});
|
||||
it("1. Add new multiselect widget", () => {
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.MULTISELECT);
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`[
|
||||
|
|
@ -35,14 +36,14 @@ describe("MultiSelect Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("labelkey");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("valuekey");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Default selected values",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ describe("Select Widget Functionality", function () {
|
|||
);
|
||||
_.agHelper.AssertElementExist(".t--widget-multiselectwidgetv2");
|
||||
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`[
|
||||
|
|
@ -39,12 +41,12 @@ describe("Select Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("label"));
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("labelkey"));
|
||||
["1", "2", "3"].forEach((d) => {
|
||||
_.agHelper.AssertElementExist(_.propPane._dropDownValue(d));
|
||||
});
|
||||
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("value"), 0, true);
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("valuekey"), 0, true);
|
||||
["1", "2", "3"].forEach((d) => {
|
||||
_.agHelper.AssertElementExist(_.propPane._dropDownValue(d));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ describe("Select Widget Functionality", function () {
|
|||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.SELECT, 450, 200);
|
||||
_.agHelper.AssertElementExist(".t--widget-selectwidget");
|
||||
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
|
||||
_.propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`[
|
||||
|
|
@ -35,12 +37,12 @@ describe("Select Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("label"));
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("labelkey"));
|
||||
["1", "2", "3"].forEach((d) => {
|
||||
_.agHelper.AssertElementExist(_.propPane._dropDownValue(d));
|
||||
});
|
||||
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("value"), 0, true);
|
||||
_.agHelper.GetNClick(_.propPane._selectPropDropdown("valuekey"), 0, true);
|
||||
["1", "2", "3"].forEach((d) => {
|
||||
_.agHelper.AssertElementExist(_.propPane._dropDownValue(d));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ describe("Select Widget Functionality", function () {
|
|||
cy.get(explorer.addWidget).click();
|
||||
cy.dragAndDropToCanvas("selectwidget", { x: 300, y: 300 });
|
||||
cy.get(".t--widget-selectwidget").should("exist");
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-sourcedata",
|
||||
`[
|
||||
|
|
@ -38,14 +39,14 @@ describe("Select Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("labelkey");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("valuekey");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-defaultselectedvalue",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ describe("Select Widget Functionality", function () {
|
|||
|
||||
it("should check that virtualization works well", () => {
|
||||
cy.openPropertyPane("selectwidget");
|
||||
_.propPane.ToggleJSMode("sourcedata");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-sourcedata",
|
||||
`[
|
||||
|
|
@ -50,14 +51,14 @@ describe("Select Widget Functionality", function () {
|
|||
]`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("label");
|
||||
_.propPane.ToggleJSMode("labelkey");
|
||||
cy.updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
_.propPane.ToggleJSMode("value");
|
||||
cy.updateCodeInput(".t--property-control-value", `value`);
|
||||
_.propPane.ToggleJSMode("valuekey");
|
||||
cy.updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
cy.get(".t--property-control-value .t--codemirror-has-error").should(
|
||||
"not.exist",
|
||||
|
|
|
|||
|
|
@ -304,6 +304,7 @@ describe("JSObjects OnLoad Actions tests", function () {
|
|||
//jsEditor.EnableDisableAsyncFuncSettings("callCountry", false, true); Bug # 13826
|
||||
|
||||
entityExplorer.SelectEntityByName("Select1", "Widgets");
|
||||
propPane.ToggleJSMode("sourcedata");
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`{{ getCitiesList.data.map((row) => {
|
||||
|
|
|
|||
|
|
@ -18,19 +18,20 @@ describe("Bug #10784 - Passing params from JS to SQL query should not break", ()
|
|||
before(() => {
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.BUTTON, 100, 100);
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.SELECT, 500, 100);
|
||||
propPane.ToggleJSMode("sourcedata");
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Source Data",
|
||||
`[\n {\n \"label\": \"7\",\n \"value\": \"7\"\n },\n {\n \"label\": \"8\",\n \"value\": \"8\"\n },\n {\n \"label\": \"9\",\n \"value\": \"9\"\n }\n]`,
|
||||
);
|
||||
|
||||
propPane.ToggleJSMode("label");
|
||||
propPane.ToggleJSMode("labelkey");
|
||||
(cy as any).updateCodeInput(
|
||||
".t--property-control-wrapper.t--property-control-label",
|
||||
".t--property-control-wrapper.t--property-control-labelkey",
|
||||
`label`,
|
||||
);
|
||||
|
||||
propPane.ToggleJSMode("value");
|
||||
(cy as any).updateCodeInput(".t--property-control-value", `value`);
|
||||
propPane.ToggleJSMode("valuekey");
|
||||
(cy as any).updateCodeInput(".t--property-control-valuekey", `value`);
|
||||
|
||||
propPane.UpdatePropertyFieldValue(
|
||||
"Default selected value",
|
||||
|
|
|
|||
|
|
@ -150,7 +150,9 @@ describe("Validate MsSQL connection & basic querying with UI flows", () => {
|
|||
it.skip("3.One click binding - should check that queries are created and bound to table widget properly", () => {
|
||||
entityExplorer.DragDropWidgetNVerify(draggableWidgets.TABLE, 450, 200);
|
||||
|
||||
oneClickBinding.ChooseAndAssertForm(dsName, dsName, "Simpsons", "title");
|
||||
oneClickBinding.ChooseAndAssertForm(dsName, dsName, "Simpsons", {
|
||||
searchableColumn: "title",
|
||||
});
|
||||
|
||||
agHelper.GetNClick(oneClickBindingLocator.connectData);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
"sourceData": "",
|
||||
"optionLabel": "label",
|
||||
"optionValue": "value",
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"widgetName": "Dropdown1",
|
||||
"defaultOptionValue": {
|
||||
"value":"VEG",
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@
|
|||
"bottomRow": 23,
|
||||
"parentId": "anq2not518",
|
||||
"dynamicBindingPathList": [],
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"dynamicTriggerPathList": []
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@
|
|||
"sourceData": "[\n {\n \"label\": \"Blue\",\n \"value\": 0\n },\n {\n \"label\": \"Green\",\n \"value\": \"GREEN\"\n },\n {\n \"label\": \"Red\",\n \"value\": \"RED\"\n },\n\t{\n \"label\": \"Red2\",\n \"value\": \"\"\n }\n]",
|
||||
"optionLabel": "label",
|
||||
"optionValue": "value",
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"placeholderText": "Select option",
|
||||
"isDisabled": false,
|
||||
"key": "ber0u80gjl",
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@
|
|||
"sourceData": "",
|
||||
"optionLabel": "label",
|
||||
"optionValue": "value",
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"isDisabled": false
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@
|
|||
"sourceData": "",
|
||||
"optionLabel": "label",
|
||||
"optionValue": "value",
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"widgetName": "Dropdown1",
|
||||
"type": "SELECT_WIDGET",
|
||||
"isLoading": false,
|
||||
|
|
@ -135,6 +136,7 @@
|
|||
"leftColumn": 10,
|
||||
"optionLable": "label",
|
||||
"optionValue": "value",
|
||||
"dynamicPropertyPathList": [{"key": "sourceData"}],
|
||||
"sourceData": [
|
||||
{
|
||||
"label": "Hashirama Senju",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"dropdownWidget": ".t--draggable-selectwidget",
|
||||
"menuButtonWidget": ".t--draggable-menubuttonwidget",
|
||||
"multiselectwidgetv2": ".t--draggable-multiselectwidgetv2",
|
||||
"multiselectWidgetv2search": ".multi-select-dropdown .bp3-input",
|
||||
"multiselecttreeWidget": ".t--draggable-multiselecttreewidget",
|
||||
"singleselecttreeWidget": ".t--draggable-singleselecttreewidget",
|
||||
"dropdownSelectionType": ".t--property-control-selectiontype .bp3-popover-target",
|
||||
|
|
|
|||
|
|
@ -34,16 +34,6 @@ export default {
|
|||
`[data-testid="t--one-click-binding-table-selector"] .rc-select-selection-item${
|
||||
table ? `:contains(${table})` : ""
|
||||
}`,
|
||||
searchableColumn:
|
||||
'[data-testId="t--one-click-binding-column-searchableColumn"]',
|
||||
searchableColumnDropdownOption: (column?: string) =>
|
||||
`[data-testId='t--one-click-binding-column-searchableColumn--column']${
|
||||
column ? `:contains(${column})` : ""
|
||||
}`,
|
||||
searchableColumnSelectedOption: (column?: string) =>
|
||||
`[data-testId="t--one-click-binding-column-searchableColumn"] .rc-select-selection-item${
|
||||
column ? `:contains(${column})` : ""
|
||||
}`,
|
||||
validTableRowData:
|
||||
'.t--widget-tablewidgetv2 [role="rowgroup"] [role="button"]',
|
||||
tableError: (error: string) =>
|
||||
|
|
@ -52,4 +42,16 @@ export default {
|
|||
dayViewFromDate: ".DayPicker-Day",
|
||||
loadMore: "[data-testId='t--one-click-binding-datasource--load-more']",
|
||||
datasourceSearch: `[data-testId="t--one-click-binding-datasource--search"]`,
|
||||
searchableColumn:
|
||||
'[data-testId="t--one-click-binding-column-searchableColumn"]',
|
||||
label: '[data-testId="t--one-click-binding-column-label"]',
|
||||
value: '[data-testId="t--one-click-binding-column-value"]',
|
||||
columnDropdownOption: (column: string, value?: string) =>
|
||||
`[data-testId='t--one-click-binding-column-${column}--column']${
|
||||
value ? `:contains(${value})` : ""
|
||||
}`,
|
||||
columnSelectedOption: (column: string, value?: string) =>
|
||||
`[data-testId="t--one-click-binding-column-${column}"] .rc-select-selection-item${
|
||||
value ? `:contains(${value})` : ""
|
||||
}`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,35 +54,10 @@ export default abstract class GSheets extends BaseQueryGenerator {
|
|||
const { select } = widgetConfig;
|
||||
|
||||
if (select && formConfig.sheetName) {
|
||||
return {
|
||||
const queryPayload: any = {
|
||||
type: QUERY_TYPE.SELECT,
|
||||
name: `Find_${removeSpecialChars(formConfig.sheetName)}`,
|
||||
formData: {
|
||||
where: {
|
||||
data: {
|
||||
children: [
|
||||
{
|
||||
condition: "CONTAINS",
|
||||
key: `{{${select["where"]} ? "${formConfig.searchableColumn}" : ""}}`,
|
||||
value: `{{${select["where"]}}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
sortBy: {
|
||||
data: [
|
||||
{
|
||||
column: `{{${select["orderBy"]}}}`,
|
||||
order: select["sortOrder"],
|
||||
},
|
||||
],
|
||||
},
|
||||
pagination: {
|
||||
data: {
|
||||
limit: `{{${select["limit"]}}}`,
|
||||
offset: `{{${select["offset"]}}}`,
|
||||
},
|
||||
},
|
||||
...this.buildBasicConfig(
|
||||
COMMAND_TYPES.FIND,
|
||||
formConfig.tableName,
|
||||
|
|
@ -90,18 +65,56 @@ export default abstract class GSheets extends BaseQueryGenerator {
|
|||
formConfig.tableHeaderIndex,
|
||||
),
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "formData.where.data",
|
||||
},
|
||||
{
|
||||
key: "formData.sortBy.data",
|
||||
},
|
||||
{
|
||||
key: "formData.pagination.data",
|
||||
},
|
||||
],
|
||||
dynamicBindingPathList: [],
|
||||
};
|
||||
|
||||
if (select["where"]) {
|
||||
queryPayload.formData.where = {
|
||||
data: {
|
||||
children: [
|
||||
{
|
||||
condition: "CONTAINS",
|
||||
key: `{{${select["where"]} ? "${formConfig.searchableColumn}" : ""}}`,
|
||||
value: `{{${select["where"]}}}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.where.data",
|
||||
});
|
||||
}
|
||||
|
||||
if (select["sortOrder"] && select["orderBy"]) {
|
||||
queryPayload.formData.sortBy = {
|
||||
data: [
|
||||
{
|
||||
column: `{{${select["orderBy"]}}}`,
|
||||
order: select["sortOrder"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.sortBy.data",
|
||||
});
|
||||
}
|
||||
|
||||
if (select["limit"] && select["offset"]) {
|
||||
queryPayload.formData.pagination = {
|
||||
data: {
|
||||
limit: `{{${select["limit"]}}}`,
|
||||
offset: `{{${select["offset"]}}}`,
|
||||
},
|
||||
};
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.pagination.data",
|
||||
});
|
||||
}
|
||||
|
||||
return queryPayload;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ describe("Mongo WidgetQueryGenerator", () => {
|
|||
data: "{{data_table.pageSize}}",
|
||||
},
|
||||
query: {
|
||||
data: '{{{ title: {$regex: data_table.searchText||""} }}}',
|
||||
data: `{{{ title: {$regex: data_table.searchText||"", '$options' : 'i'} }}}`,
|
||||
},
|
||||
skip: {
|
||||
data: "{{(data_table.pageNo - 1) * data_table.pageSize}}",
|
||||
|
|
@ -152,7 +152,7 @@ describe("Mongo WidgetQueryGenerator", () => {
|
|||
data: "{{data_table.pageSize}}",
|
||||
},
|
||||
query: {
|
||||
data: '{{{ title: {$regex: data_table.searchText||""} }}}',
|
||||
data: `{{{ title: {$regex: data_table.searchText||"", '$options' : 'i'} }}}`,
|
||||
},
|
||||
skip: {
|
||||
data: "{{(data_table.pageNo - 1) * data_table.pageSize}}",
|
||||
|
|
|
|||
|
|
@ -30,39 +30,66 @@ export default abstract class MongoDB extends BaseQueryGenerator {
|
|||
const { select } = widgetConfig;
|
||||
|
||||
if (select) {
|
||||
return {
|
||||
const queryPayload: any = {
|
||||
type: QUERY_TYPE.SELECT,
|
||||
name: `Find_${removeSpecialChars(formConfig.tableName)}`,
|
||||
formData: {
|
||||
find: {
|
||||
skip: { data: `{{${select["offset"]}}}` },
|
||||
skip: { data: "" },
|
||||
query: {
|
||||
data: formConfig.searchableColumn
|
||||
? `{{{ ${formConfig.searchableColumn}: {$regex: ${select["where"]}} }}}`
|
||||
: "",
|
||||
data: "",
|
||||
},
|
||||
sort: {
|
||||
data: `{{ ${select["orderBy"]} ? { [${select["orderBy"]}]: ${select["sortOrder"]} ? 1 : -1 } : {}}}`,
|
||||
data: "",
|
||||
},
|
||||
limit: {
|
||||
data: "",
|
||||
},
|
||||
limit: { data: `{{${select["limit"]}}}` },
|
||||
},
|
||||
...this.buildBasicConfig(COMMAND_TYPES.FIND, formConfig.tableName),
|
||||
},
|
||||
dynamicBindingPathList: [
|
||||
{
|
||||
key: "formData.find.skip.data",
|
||||
},
|
||||
{
|
||||
key: "formData.find.query.data",
|
||||
},
|
||||
{
|
||||
key: "formData.find.sort.data",
|
||||
},
|
||||
{
|
||||
key: "formData.find.limit.data",
|
||||
},
|
||||
],
|
||||
dynamicBindingPathList: [],
|
||||
};
|
||||
|
||||
if (select["offset"]) {
|
||||
queryPayload.formData.find.skip = { data: `{{${select["offset"]}}}` };
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.find.skip.data",
|
||||
});
|
||||
}
|
||||
|
||||
if (formConfig.searchableColumn) {
|
||||
queryPayload.formData.find.query = {
|
||||
data: formConfig.searchableColumn
|
||||
? `{{{ ${formConfig.searchableColumn}: {$regex: ${select["where"]}, '$options' : 'i'} }}}`
|
||||
: "",
|
||||
};
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.find.query.data",
|
||||
});
|
||||
}
|
||||
|
||||
if (select["orderBy"] && select["sortOrder"]) {
|
||||
queryPayload.formData.find.sort = {
|
||||
data: `{{ ${select["orderBy"]} ? { [${select["orderBy"]}]: ${select["sortOrder"]} ? 1 : -1 } : {}}}`,
|
||||
};
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.find.sort.data",
|
||||
});
|
||||
}
|
||||
|
||||
if (select["limit"]) {
|
||||
queryPayload.formData.find.limit = { data: `{{${select["limit"]}}}` };
|
||||
|
||||
queryPayload.dynamicBindingPathList.push({
|
||||
key: "formData.find.limit.data",
|
||||
});
|
||||
}
|
||||
|
||||
return queryPayload;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ export type WidgetQueryGenerationFormConfig = {
|
|||
|
||||
export type WidgetQueryGenerationConfig = {
|
||||
select?: {
|
||||
limit: string;
|
||||
offset: string;
|
||||
where: string;
|
||||
orderBy: string;
|
||||
sortOrder: string;
|
||||
limit?: string;
|
||||
offset?: string;
|
||||
where?: string;
|
||||
orderBy?: string;
|
||||
sortOrder?: string;
|
||||
};
|
||||
create?: {
|
||||
value: string;
|
||||
|
|
@ -31,7 +31,7 @@ export type WidgetQueryGenerationConfig = {
|
|||
value: string;
|
||||
where?: string;
|
||||
};
|
||||
totalRecord: boolean;
|
||||
totalRecord?: boolean;
|
||||
};
|
||||
|
||||
export enum QUERY_TYPE {
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ function getWidgetProps(
|
|||
{ key: "sourceData" },
|
||||
{ key: "defaultOptionValue" },
|
||||
],
|
||||
dynamicPropertyPathList: [{ key: "sourceData" }],
|
||||
},
|
||||
};
|
||||
case "TEXT_WIDGET":
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export function useDatasource(searchText: string) {
|
|||
onSourceClose,
|
||||
propertyName,
|
||||
propertyValue,
|
||||
sampleData,
|
||||
updateConfig,
|
||||
widgetId,
|
||||
} = useContext(WidgetQueryGeneratorFormContext);
|
||||
|
|
@ -321,7 +322,7 @@ export function useDatasource(searchText: string) {
|
|||
const { pageId: currentPageId } = useParams<ExplorerURLParams>();
|
||||
|
||||
const otherOptions = useMemo(() => {
|
||||
return [
|
||||
const options = [
|
||||
{
|
||||
icon: <Icon name="plus" size="md" />,
|
||||
id: "Connect new datasource",
|
||||
|
|
@ -350,7 +351,35 @@ export function useDatasource(searchText: string) {
|
|||
},
|
||||
},
|
||||
];
|
||||
}, [currentPageId, history, propertyName]);
|
||||
|
||||
if (sampleData) {
|
||||
options.push({
|
||||
icon: <Icon name="code" size="md" />,
|
||||
id: "Sample data",
|
||||
label: "Sample data",
|
||||
value: "Sample data",
|
||||
onSelect: () => {
|
||||
addBinding(sampleData, false);
|
||||
|
||||
updateConfig({
|
||||
datasource: "",
|
||||
datasourcePluginType: "",
|
||||
datasourcePluginName: "",
|
||||
datasourceConnectionMode: "",
|
||||
});
|
||||
|
||||
AnalyticsUtil.logEvent("BIND_OTHER_ACTIONS", {
|
||||
widgetName: widget.widgetName,
|
||||
widgetType: widget.type,
|
||||
propertyName: propertyName,
|
||||
selectedAction: "Sample data",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}, [currentPageId, history, propertyName, sampleData, addBinding]);
|
||||
|
||||
const queries = useSelector(getActionsForCurrentPage);
|
||||
|
||||
|
|
@ -439,31 +468,47 @@ export function useDatasource(searchText: string) {
|
|||
];
|
||||
}, [searchText, datasourceOptions, otherOptions, queryOptions]);
|
||||
|
||||
const selected = useMemo(() => {
|
||||
let source;
|
||||
|
||||
if (config.datasource) {
|
||||
source = datasourceOptions.find(
|
||||
(option) => option.id === config.datasource,
|
||||
);
|
||||
} else if (
|
||||
sampleData ===
|
||||
(typeof propertyValue === "string"
|
||||
? propertyValue
|
||||
: JSON.stringify(propertyValue, null, 2))
|
||||
) {
|
||||
source = otherOptions.find((option) => option.value === "Sample data");
|
||||
} else if (propertyValue) {
|
||||
source = queryOptions.find((option) => option.value === propertyValue);
|
||||
}
|
||||
|
||||
if (source) {
|
||||
return (
|
||||
<DropdownOption
|
||||
label={source?.label?.replace("sample ", "")}
|
||||
leftIcon={source?.icon}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Placeholder>Connect data</Placeholder>;
|
||||
}
|
||||
}, [
|
||||
config,
|
||||
datasourceOptions,
|
||||
sampleData,
|
||||
propertyValue,
|
||||
otherOptions,
|
||||
queryOptions,
|
||||
]);
|
||||
|
||||
return {
|
||||
datasourceOptions: filteredDatasourceOptions,
|
||||
otherOptions,
|
||||
selected: (() => {
|
||||
let source;
|
||||
|
||||
if (config.datasource) {
|
||||
source = datasourceOptions.find(
|
||||
(option) => option.id === config.datasource,
|
||||
);
|
||||
} else if (propertyValue) {
|
||||
source = queryOptions.find((option) => option.value === propertyValue);
|
||||
}
|
||||
|
||||
if (source) {
|
||||
return (
|
||||
<DropdownOption
|
||||
label={source?.label?.replace("sample ", "")}
|
||||
leftIcon={source?.icon}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Placeholder>Connect data</Placeholder>;
|
||||
}
|
||||
})(),
|
||||
selected,
|
||||
queryOptions: filteredQueryOptions,
|
||||
isSourceOpen,
|
||||
onSourceClose,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
import { PluginPackageName } from "entities/Action";
|
||||
import { useContext } from "react";
|
||||
import { useContext, useMemo } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { getWidget } from "sagas/selectors";
|
||||
import { getPluginPackageFromDatasourceId } from "selectors/entitiesSelector";
|
||||
|
|
@ -14,7 +14,7 @@ import { useColumns } from "../WidgetSpecificControls/ColumnDropdown/useColumns"
|
|||
export function useConnectData() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { config, propertyName, widgetId } = useContext(
|
||||
const { aliases, config, propertyName, widgetId } = useContext(
|
||||
WidgetQueryGeneratorFormContext,
|
||||
);
|
||||
|
||||
|
|
@ -27,16 +27,30 @@ export function useConnectData() {
|
|||
);
|
||||
|
||||
const onClick = () => {
|
||||
const searchableColumn = (() => {
|
||||
if (config.searchableColumn) {
|
||||
return config.searchableColumn;
|
||||
} else {
|
||||
const alias = aliases?.find((d) => d.isSearcheable)?.name;
|
||||
|
||||
return alias && config.alias[alias];
|
||||
}
|
||||
})();
|
||||
|
||||
const payload = {
|
||||
tableName: config.table,
|
||||
sheetName: config.sheet,
|
||||
datasourceId: config.datasource,
|
||||
widgetId: widgetId,
|
||||
tableHeaderIndex: config.tableHeaderIndex,
|
||||
searchableColumn: config.searchableColumn,
|
||||
searchableColumn,
|
||||
columns: columns.map((column) => column.name),
|
||||
primaryColumn,
|
||||
connectionMode: config.datasourceConnectionMode,
|
||||
aliases: Object.entries(config.alias).map(([key, value]) => ({
|
||||
name: key,
|
||||
alias: value,
|
||||
})),
|
||||
};
|
||||
|
||||
dispatch({
|
||||
|
|
@ -54,6 +68,7 @@ export function useConnectData() {
|
|||
additionalData: {
|
||||
dataTableName: config.table,
|
||||
searchableColumn: config.searchableColumn,
|
||||
alias: config.alias,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -64,10 +79,17 @@ export function useConnectData() {
|
|||
|
||||
const show = !!config.datasource;
|
||||
|
||||
const disabled =
|
||||
!config.table ||
|
||||
(selectedDatasourcePluginPackageName === PluginPackageName.GOOGLE_SHEETS &&
|
||||
!isValidGsheetConfig(config));
|
||||
const disabled = useMemo(() => {
|
||||
return (
|
||||
!config.table ||
|
||||
(selectedDatasourcePluginPackageName ===
|
||||
PluginPackageName.GOOGLE_SHEETS &&
|
||||
!isValidGsheetConfig(config)) ||
|
||||
aliases?.some((alias) => {
|
||||
return alias.isRequired && !config.alias[alias.name];
|
||||
})
|
||||
);
|
||||
}, [config, aliases]);
|
||||
|
||||
return {
|
||||
show,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { ErrorMessage, Label, SelectWrapper } from "../../styles";
|
|||
import { useColumns } from "./useColumns";
|
||||
|
||||
type Props = {
|
||||
id: string;
|
||||
alias: string;
|
||||
label: string;
|
||||
onSelect: () => void;
|
||||
|
|
@ -29,7 +30,7 @@ function ColumnDropdown(props: Props) {
|
|||
<Label>{props.label}</Label>
|
||||
<Select
|
||||
allowClear
|
||||
data-testId={`t--one-click-binding-column-${props.alias}`}
|
||||
data-testId={`t--one-click-binding-column-${props.id}`}
|
||||
dropdownStyle={{
|
||||
minWidth: "350px",
|
||||
maxHeight: "300px",
|
||||
|
|
@ -51,7 +52,7 @@ function ColumnDropdown(props: Props) {
|
|||
{options.map((option) => {
|
||||
return (
|
||||
<Option
|
||||
data-testId={`t--one-click-binding-column-${props.alias}--column`}
|
||||
data-testId={`t--one-click-binding-column-${props.id}--column`}
|
||||
key={option.id}
|
||||
value={option.value}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import type { AppState } from "@appsmith/reducers";
|
|||
import { Icon } from "design-system";
|
||||
import { PluginPackageName } from "entities/Action";
|
||||
import { get, isArray } from "lodash";
|
||||
import { ALLOWED_SEARCH_DATATYPE } from "pages/Editor/GeneratePage/components/constants";
|
||||
import { useCallback, useContext, useMemo } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import {
|
||||
|
|
@ -70,28 +69,21 @@ export function useColumns(alias: string) {
|
|||
};
|
||||
});
|
||||
} else if (isArray(columns)) {
|
||||
return columns
|
||||
.filter((column: any) => {
|
||||
return (
|
||||
column.type &&
|
||||
ALLOWED_SEARCH_DATATYPE.includes(column.type.toLowerCase())
|
||||
);
|
||||
})
|
||||
.map((column: any) => {
|
||||
return {
|
||||
id: column.name,
|
||||
label: column.name,
|
||||
value: column.name,
|
||||
subText: column.type,
|
||||
icon: (
|
||||
<Icon
|
||||
color="var(--ads-v2-color-fg)"
|
||||
name="layout-column-line"
|
||||
size="md"
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
return columns.map((column: any) => {
|
||||
return {
|
||||
id: column.name,
|
||||
label: column.name,
|
||||
value: column.name,
|
||||
subText: column.type,
|
||||
icon: (
|
||||
<Icon
|
||||
color="var(--ads-v2-color-fg)"
|
||||
name="layout-column-line"
|
||||
size="md"
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,48 @@
|
|||
import React from "react";
|
||||
import ColumnDropdown from "./ColumnDropdown";
|
||||
import { noop } from "lodash";
|
||||
import type { Alias } from "../types";
|
||||
|
||||
type Props = {
|
||||
hasSearchableColumn?: boolean;
|
||||
hasAliasPicker?: boolean;
|
||||
aliases?: string[];
|
||||
aliases?: Alias[];
|
||||
};
|
||||
|
||||
export default function WidgetSpecificControls(props: Props) {
|
||||
let searchableColumn = null;
|
||||
let aliasPicker = null;
|
||||
let aliases = null;
|
||||
|
||||
if (props.hasSearchableColumn) {
|
||||
searchableColumn = (
|
||||
<ColumnDropdown
|
||||
alias="searchableColumn"
|
||||
id="searchableColumn"
|
||||
label="Select a searchable column"
|
||||
onSelect={noop}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (props.hasAliasPicker && props.aliases) {
|
||||
aliasPicker = props.aliases.map((alias) => {
|
||||
<ColumnDropdown alias={`alias.${alias}`} label={alias} onSelect={noop} />;
|
||||
if (props.aliases?.length) {
|
||||
aliases = props.aliases.map(({ name }) => {
|
||||
const label = name.slice(0, 1).toUpperCase() + name.slice(1);
|
||||
|
||||
return (
|
||||
<ColumnDropdown
|
||||
alias={`alias.${name}`}
|
||||
id={name}
|
||||
key={name}
|
||||
label={label}
|
||||
onSelect={noop}
|
||||
/>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{searchableColumn}
|
||||
{aliasPicker}
|
||||
{aliases}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
getOneClickBindingConfigForWidget,
|
||||
} from "selectors/oneClickBindingSelectors";
|
||||
import { updateOneClickBindingOptionsVisibility } from "actions/oneClickBindingActions";
|
||||
import type { Alias } from "./types";
|
||||
|
||||
type WidgetQueryGeneratorFormContextType = {
|
||||
widgetId: string;
|
||||
|
|
@ -39,6 +40,8 @@ type WidgetQueryGeneratorFormContextType = {
|
|||
onSourceClose: () => void;
|
||||
errorMsg: string;
|
||||
expectedType: string;
|
||||
sampleData: string;
|
||||
aliases: Alias[];
|
||||
};
|
||||
|
||||
const DEFAULT_CONFIG_VALUE = {
|
||||
|
|
@ -64,6 +67,8 @@ const DEFAULT_CONTEXT_VALUE = {
|
|||
errorMsg: "",
|
||||
propertyName: "",
|
||||
expectedType: "",
|
||||
sampleData: "",
|
||||
aliases: [],
|
||||
};
|
||||
|
||||
export const WidgetQueryGeneratorFormContext =
|
||||
|
|
@ -78,6 +83,9 @@ type Props = {
|
|||
widgetId: string;
|
||||
errorMsg: string;
|
||||
expectedType: string;
|
||||
aliases: Alias[];
|
||||
searchableColumn: boolean;
|
||||
sampleData: string;
|
||||
};
|
||||
|
||||
function WidgetQueryGeneratorForm(props: Props) {
|
||||
|
|
@ -86,11 +94,13 @@ function WidgetQueryGeneratorForm(props: Props) {
|
|||
const [pristine, setPristine] = useState(true);
|
||||
|
||||
const {
|
||||
aliases,
|
||||
errorMsg,
|
||||
expectedType,
|
||||
onUpdate,
|
||||
propertyPath,
|
||||
propertyValue,
|
||||
sampleData,
|
||||
widgetId,
|
||||
} = props;
|
||||
|
||||
|
|
@ -197,6 +207,8 @@ function WidgetQueryGeneratorForm(props: Props) {
|
|||
errorMsg,
|
||||
propertyName: propertyPath,
|
||||
expectedType,
|
||||
sampleData,
|
||||
aliases,
|
||||
};
|
||||
}, [
|
||||
config,
|
||||
|
|
@ -208,6 +220,8 @@ function WidgetQueryGeneratorForm(props: Props) {
|
|||
onSourceClose,
|
||||
errorMsg,
|
||||
propertyPath,
|
||||
sampleData,
|
||||
aliases,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -221,7 +235,10 @@ function WidgetQueryGeneratorForm(props: Props) {
|
|||
<WidgetQueryGeneratorFormContext.Provider value={contextValue}>
|
||||
<CommonControls />
|
||||
<DatasourceSpecificControls />
|
||||
<WidgetSpecificControls hasSearchableColumn />
|
||||
<WidgetSpecificControls
|
||||
aliases={props.aliases}
|
||||
hasSearchableColumn={props.searchableColumn}
|
||||
/>
|
||||
<ConnectData />
|
||||
</WidgetQueryGeneratorFormContext.Provider>
|
||||
</Wrapper>
|
||||
|
|
|
|||
|
|
@ -6,3 +6,9 @@ export interface DropdownOptionType {
|
|||
onSelect?: (value: string, option: DropdownOptionType) => void;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface Alias {
|
||||
name: string;
|
||||
isSearcheable?: boolean;
|
||||
isRequired?: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import WidgetQueryGeneratorForm from "components/editorComponents/WidgetQueryGeneratorForm";
|
||||
import type { Alias } from "components/editorComponents/WidgetQueryGeneratorForm/types";
|
||||
import React from "react";
|
||||
import type { ControlData, ControlProps } from "./BaseControl";
|
||||
import type { ControlProps } from "./BaseControl";
|
||||
import BaseControl from "./BaseControl";
|
||||
class OneClickBindingControl extends BaseControl<OneClickBindingControlProps> {
|
||||
constructor(props: OneClickBindingControlProps) {
|
||||
|
|
@ -15,9 +16,15 @@ class OneClickBindingControl extends BaseControl<OneClickBindingControlProps> {
|
|||
* Commenting out as we're not able to switch between the js modes without value being overwritten
|
||||
* with default value by platform
|
||||
*/
|
||||
static canDisplayValueInUI(config: ControlData, value: any): boolean {
|
||||
// {{query1.data}}
|
||||
return /^{{[^.]*\.data}}$/gi.test(value);
|
||||
static canDisplayValueInUI(
|
||||
config: OneClickBindingControlProps,
|
||||
value: any,
|
||||
): boolean {
|
||||
// {{query1.data}} || sample data
|
||||
return (
|
||||
/^{{[^.]*\.data}}$/gi.test(value) ||
|
||||
config.controlConfig?.sampleData === value
|
||||
);
|
||||
}
|
||||
|
||||
static shouldValidateValueOnDynamicPropertyOff() {
|
||||
|
|
@ -52,11 +59,14 @@ class OneClickBindingControl extends BaseControl<OneClickBindingControlProps> {
|
|||
public render() {
|
||||
return (
|
||||
<WidgetQueryGeneratorForm
|
||||
aliases={this.props.controlConfig.aliases}
|
||||
errorMsg={this.getErrorMessage()}
|
||||
expectedType={this.props.expected?.autocompleteDataType || ""}
|
||||
onUpdate={this.onUpdatePropertyValue}
|
||||
propertyPath={this.props.propertyName}
|
||||
propertyValue={this.props.propertyValue}
|
||||
sampleData={this.props.controlConfig.sampleData}
|
||||
searchableColumn={this.props.controlConfig.searchableColumn}
|
||||
widgetId={this.props.widgetProperties.widgetId}
|
||||
/>
|
||||
);
|
||||
|
|
@ -65,4 +75,10 @@ class OneClickBindingControl extends BaseControl<OneClickBindingControlProps> {
|
|||
|
||||
export default OneClickBindingControl;
|
||||
|
||||
export type OneClickBindingControlProps = ControlProps;
|
||||
export type OneClickBindingControlProps = ControlProps & {
|
||||
controlConfig: {
|
||||
aliases: Alias[];
|
||||
searchableColumn: boolean;
|
||||
sampleData: string;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -219,7 +219,11 @@ function* BindWidgetToDatasource(
|
|||
data: `{{${queryNameMap[QUERY_TYPE.SELECT]}.data}}`,
|
||||
run: `{{
|
||||
${queryNameMap[QUERY_TYPE.SELECT]}.run();
|
||||
${queryNameMap[QUERY_TYPE.TOTAL_RECORD]}.run();
|
||||
${
|
||||
createdQueryNames.includes(queryNameMap[QUERY_TYPE.TOTAL_RECORD])
|
||||
? queryNameMap[QUERY_TYPE.TOTAL_RECORD] + ".run()"
|
||||
: ""
|
||||
}
|
||||
}}`,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ import { DynamicHeight } from "utils/WidgetFeatures";
|
|||
import IconSVG from "./icon.svg";
|
||||
import Widget from "./widget";
|
||||
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
import type {
|
||||
WidgetQueryConfig,
|
||||
WidgetQueryGenerationFormConfig,
|
||||
} from "WidgetQueryGenerators/types";
|
||||
|
||||
export const CONFIG = {
|
||||
features: {
|
||||
|
|
@ -60,6 +65,22 @@ export const CONFIG = {
|
|||
autocompleteDefinitions: Widget.getAutocompleteDefinitions(),
|
||||
setterConfig: Widget.getSetterConfig(),
|
||||
},
|
||||
methods: {
|
||||
getQueryGenerationConfig: (widgetProps: WidgetProps) => {
|
||||
return Widget.getQueryGenerationConfig(widgetProps);
|
||||
},
|
||||
getPropertyUpdatesForQueryBinding: (
|
||||
queryConfig: WidgetQueryConfig,
|
||||
widget: WidgetProps,
|
||||
formConfig: WidgetQueryGenerationFormConfig,
|
||||
) => {
|
||||
return Widget.getPropertyUpdatesForQueryBinding(
|
||||
queryConfig,
|
||||
widget,
|
||||
formConfig,
|
||||
);
|
||||
},
|
||||
},
|
||||
autoLayout: {
|
||||
disabledPropsDefaults: {
|
||||
labelPosition: LabelPosition.Top,
|
||||
|
|
|
|||
|
|
@ -35,11 +35,46 @@ import {
|
|||
getLabelValueKeyOptions,
|
||||
valueKeyValidation,
|
||||
} from "./propertyUtils";
|
||||
import type {
|
||||
WidgetQueryConfig,
|
||||
WidgetQueryGenerationFormConfig,
|
||||
} from "WidgetQueryGenerators/types";
|
||||
|
||||
class MultiSelectWidget extends BaseWidget<
|
||||
MultiSelectWidgetProps,
|
||||
WidgetState
|
||||
> {
|
||||
static getQueryGenerationConfig(widget: WidgetProps) {
|
||||
return {
|
||||
select: {
|
||||
where: `${widget.widgetName}.filterText`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static getPropertyUpdatesForQueryBinding(
|
||||
queryConfig: WidgetQueryConfig,
|
||||
widget: WidgetProps,
|
||||
formConfig: WidgetQueryGenerationFormConfig,
|
||||
) {
|
||||
let modify;
|
||||
|
||||
if (queryConfig.select) {
|
||||
modify = {
|
||||
sourceData: queryConfig.select.data,
|
||||
optionLabel: formConfig.aliases.find((d) => d.name === "label")?.alias,
|
||||
optionValue: formConfig.aliases.find((d) => d.name === "value")?.alias,
|
||||
defaultOptionValue: "",
|
||||
serverSideFiltering: true,
|
||||
onFilterUpdate: queryConfig.select.run,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
modify,
|
||||
};
|
||||
}
|
||||
|
||||
static getAutocompleteDefinitions(): AutocompletionDefinitions {
|
||||
return {
|
||||
"!doc":
|
||||
|
|
@ -78,11 +113,33 @@ class MultiSelectWidget extends BaseWidget<
|
|||
"Takes in an array of objects to display options. Bind data from an API using {{}}",
|
||||
propertyName: "sourceData",
|
||||
label: "Source Data",
|
||||
controlType: "INPUT_TEXT",
|
||||
controlType: "ONE_CLICK_BINDING_CONTROL",
|
||||
controlConfig: {
|
||||
aliases: [
|
||||
{
|
||||
name: "label",
|
||||
isSearcheable: true,
|
||||
isRequired: true,
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
isRequired: true,
|
||||
},
|
||||
],
|
||||
sampleData: JSON.stringify(
|
||||
[
|
||||
{ name: "Blue", code: "BLUE" },
|
||||
{ name: "Green", code: "GREEN" },
|
||||
{ name: "Red", code: "RED" },
|
||||
],
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
isJSConvertible: true,
|
||||
placeholderText: '[{ "label": "Option1", "value": "Option2" }]',
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
isJSConvertible: false,
|
||||
validation: {
|
||||
type: ValidationTypes.ARRAY,
|
||||
params: {
|
||||
|
|
@ -98,9 +155,10 @@ class MultiSelectWidget extends BaseWidget<
|
|||
EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
},
|
||||
{
|
||||
helpText: "Sets the label of the option",
|
||||
helpText:
|
||||
"Choose or set a field from source data as the display label",
|
||||
propertyName: "optionLabel",
|
||||
label: "Label",
|
||||
label: "Label key",
|
||||
controlType: "DROP_DOWN",
|
||||
customJSControl: "WRAPPED_CODE_EDITOR",
|
||||
controlConfig: {
|
||||
|
|
@ -130,9 +188,9 @@ class MultiSelectWidget extends BaseWidget<
|
|||
additionalAutoComplete: getLabelValueAdditionalAutocompleteData,
|
||||
},
|
||||
{
|
||||
helpText: "Sets the value of the option",
|
||||
helpText: "Choose or set a field from source data as the value",
|
||||
propertyName: "optionValue",
|
||||
label: "Value",
|
||||
label: "Value key",
|
||||
controlType: "DROP_DOWN",
|
||||
customJSControl: "WRAPPED_CODE_EDITOR",
|
||||
controlConfig: {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,15 @@ import { LabelPosition } from "components/constants";
|
|||
import { FILL_WIDGET_MIN_WIDTH } from "constants/minWidthConstants";
|
||||
import { ResponsiveBehavior } from "utils/autoLayout/constants";
|
||||
import { DynamicHeight } from "utils/WidgetFeatures";
|
||||
|
||||
import IconSVG from "./icon.svg";
|
||||
import Widget from "./widget";
|
||||
import type { SnipingModeProperty, PropertyUpdates } from "widgets/constants";
|
||||
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||
import type { WidgetProps } from "widgets/BaseWidget";
|
||||
import type {
|
||||
WidgetQueryConfig,
|
||||
WidgetQueryGenerationFormConfig,
|
||||
} from "WidgetQueryGenerators/types";
|
||||
|
||||
export const CONFIG = {
|
||||
features: {
|
||||
|
|
@ -62,6 +66,20 @@ export const CONFIG = {
|
|||
setterConfig: Widget.getSetterConfig(),
|
||||
},
|
||||
methods: {
|
||||
getQueryGenerationConfig: (widgetProps: WidgetProps) => {
|
||||
return Widget.getQueryGenerationConfig(widgetProps);
|
||||
},
|
||||
getPropertyUpdatesForQueryBinding: (
|
||||
queryConfig: WidgetQueryConfig,
|
||||
widget: WidgetProps,
|
||||
formConfig: WidgetQueryGenerationFormConfig,
|
||||
) => {
|
||||
return Widget.getPropertyUpdatesForQueryBinding(
|
||||
queryConfig,
|
||||
widget,
|
||||
formConfig,
|
||||
);
|
||||
},
|
||||
getSnipingModeUpdates: (
|
||||
propValueMap: SnipingModeProperty,
|
||||
): PropertyUpdates[] => {
|
||||
|
|
|
|||
|
|
@ -36,12 +36,47 @@ import {
|
|||
getLabelValueKeyOptions,
|
||||
valueKeyValidation,
|
||||
} from "./propertyUtils";
|
||||
import type {
|
||||
WidgetQueryConfig,
|
||||
WidgetQueryGenerationFormConfig,
|
||||
} from "WidgetQueryGenerators/types";
|
||||
|
||||
class SelectWidget extends BaseWidget<SelectWidgetProps, WidgetState> {
|
||||
constructor(props: SelectWidgetProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static getQueryGenerationConfig(widget: WidgetProps) {
|
||||
return {
|
||||
select: {
|
||||
where: `${widget.widgetName}.filterText`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static getPropertyUpdatesForQueryBinding(
|
||||
queryConfig: WidgetQueryConfig,
|
||||
widget: WidgetProps,
|
||||
formConfig: WidgetQueryGenerationFormConfig,
|
||||
) {
|
||||
let modify;
|
||||
|
||||
if (queryConfig.select) {
|
||||
modify = {
|
||||
sourceData: queryConfig.select.data,
|
||||
optionLabel: formConfig.aliases.find((d) => d.name === "label")?.alias,
|
||||
optionValue: formConfig.aliases.find((d) => d.name === "value")?.alias,
|
||||
defaultOptionValue: "",
|
||||
serverSideFiltering: true,
|
||||
onFilterUpdate: queryConfig.select.run,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
modify,
|
||||
};
|
||||
}
|
||||
|
||||
static getAutocompleteDefinitions(): AutocompletionDefinitions {
|
||||
return {
|
||||
"!doc":
|
||||
|
|
@ -79,7 +114,30 @@ class SelectWidget extends BaseWidget<SelectWidgetProps, WidgetState> {
|
|||
"Takes in an array of objects to display options. Bind data from an API using {{}}",
|
||||
propertyName: "sourceData",
|
||||
label: "Source Data",
|
||||
controlType: "INPUT_TEXT",
|
||||
controlType: "ONE_CLICK_BINDING_CONTROL",
|
||||
controlConfig: {
|
||||
aliases: [
|
||||
{
|
||||
name: "label",
|
||||
isSearcheable: true,
|
||||
isRequired: true,
|
||||
},
|
||||
{
|
||||
name: "value",
|
||||
isRequired: true,
|
||||
},
|
||||
],
|
||||
sampleData: JSON.stringify(
|
||||
[
|
||||
{ name: "Blue", code: "BLUE" },
|
||||
{ name: "Green", code: "GREEN" },
|
||||
{ name: "Red", code: "RED" },
|
||||
],
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
isJSConvertible: true,
|
||||
placeholderText: '[{ "label": "label1", "value": "value1" }]',
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
|
|
@ -98,9 +156,10 @@ class SelectWidget extends BaseWidget<SelectWidgetProps, WidgetState> {
|
|||
EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||
},
|
||||
{
|
||||
helpText: "Sets the label of the option",
|
||||
helpText:
|
||||
"Choose or set a field from source data as the display label",
|
||||
propertyName: "optionLabel",
|
||||
label: "Label",
|
||||
label: "Label key",
|
||||
controlType: "DROP_DOWN",
|
||||
customJSControl: "WRAPPED_CODE_EDITOR",
|
||||
controlConfig: {
|
||||
|
|
@ -131,9 +190,9 @@ class SelectWidget extends BaseWidget<SelectWidgetProps, WidgetState> {
|
|||
additionalAutoComplete: getLabelValueAdditionalAutocompleteData,
|
||||
},
|
||||
{
|
||||
helpText: "Sets the value of the option",
|
||||
helpText: "Choose or set a field from source data as the value",
|
||||
propertyName: "optionValue",
|
||||
label: "Value",
|
||||
label: "Value key",
|
||||
controlType: "DROP_DOWN",
|
||||
customJSControl: "WRAPPED_CODE_EDITOR",
|
||||
controlConfig: {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ export default [
|
|||
propertyName: "tableData",
|
||||
label: "Table data",
|
||||
controlType: "ONE_CLICK_BINDING_CONTROL",
|
||||
controlConfig: {
|
||||
searchableColumn: true,
|
||||
},
|
||||
placeholderText: '[{ "name": "John" }]',
|
||||
inputType: "ARRAY",
|
||||
isBindProperty: true,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user