Feature: DatePicker V2 (#2889)

Co-authored-by: vicky-primathon.in <vicky.bansal@primathon.in>
Co-authored-by: nandan.anantharamu <nandan.anantharamu@thoughtspot.com>
Co-authored-by: Abhinav Jha <abhinav@appsmith.com>
This commit is contained in:
NandanAnantharamu 2021-02-23 18:05:09 +05:30 committed by GitHub
parent 72df6fb299
commit 6c80f23201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1091 additions and 223 deletions

View File

@ -0,0 +1,80 @@
{
"dsl": {
"widgetName": "MainContainer",
"backgroundColor": "none",
"rightColumn": 1224,
"snapColumns": 16,
"detachFromLayout": true,
"widgetId": "0",
"topRow": 0,
"bottomRow": 1280,
"containerStyle": "none",
"snapRows": 33,
"parentRowSpace": 1,
"type": "CANVAS_WIDGET",
"canExtend": true,
"version": 9,
"minHeight": 1292,
"parentColumnSpace": 1,
"dynamicBindingPathList": [],
"leftColumn": 0,
"children": [
{
"isVisible": true,
"isDisabled": false,
"datePickerType": "DATE_PICKER",
"label": "",
"dateFormat": "DD/MM/YYYY HH:mm",
"widgetName": "DatePicker1",
"defaultDate": "2021-02-05T10:53:12.791Z",
"version": 2,
"type": "DATE_PICKER_WIDGET2",
"isLoading": false,
"parentColumnSpace": 74,
"parentRowSpace": 40,
"leftColumn": 5,
"rightColumn": 10,
"topRow": 0,
"bottomRow": 1,
"parentId": "0",
"widgetId": "w4htilgv5t"
},
{
"isVisible": true,
"text": "Label",
"textStyle": "LABEL",
"textAlign": "LEFT",
"widgetName": "Text1",
"version": 1,
"type": "TEXT_WIDGET",
"isLoading": false,
"parentColumnSpace": 74,
"parentRowSpace": 40,
"leftColumn": 1,
"rightColumn": 5,
"topRow": 3,
"bottomRow": 4,
"parentId": "0",
"widgetId": "voohxsv4t2"
},
{
"isVisible": true,
"text": "Label",
"textStyle": "LABEL",
"textAlign": "LEFT",
"widgetName": "Text2",
"version": 1,
"type": "TEXT_WIDGET",
"isLoading": false,
"parentColumnSpace": 74,
"parentRowSpace": 40,
"leftColumn": 8,
"rightColumn": 12,
"topRow": 3,
"bottomRow": 4,
"parentId": "0",
"widgetId": "xif8wugzjv"
}
]
}
}

View File

@ -13,6 +13,7 @@ describe("Duplicate application", function() {
cy.get(commonlocators.homeIcon).click({ force: true }); cy.get(commonlocators.homeIcon).click({ force: true });
const appname = localStorage.getItem("AppName"); const appname = localStorage.getItem("AppName");
cy.get(homePage.searchInput).type(appname); cy.get(homePage.searchInput).type(appname);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationCard) cy.get(homePage.applicationCard)

View File

@ -14,6 +14,7 @@ describe("Update Application", function() {
cy.get(commonlocators.homeIcon).click({ force: true }); cy.get(commonlocators.homeIcon).click({ force: true });
appname = localStorage.getItem("AppName"); appname = localStorage.getItem("AppName");
cy.get(homePage.searchInput).type(appname); cy.get(homePage.searchInput).type(appname);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationCard) cy.get(homePage.applicationCard)
@ -53,6 +54,7 @@ describe("Update Application", function() {
it("Check for errors in updating application name", function() { it("Check for errors in updating application name", function() {
cy.get(commonlocators.homeIcon).click({ force: true }); cy.get(commonlocators.homeIcon).click({ force: true });
cy.get(homePage.searchInput).type(appname); cy.get(homePage.searchInput).type(appname);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationCard) cy.get(homePage.applicationCard)
.first() .first()
@ -61,6 +63,7 @@ describe("Update Application", function() {
.first() .first()
.click({ force: true }); .click({ force: true });
cy.get("#loading").should("not.exist"); cy.get("#loading").should("not.exist");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationName).type(" "); cy.get(homePage.applicationName).type(" ");
cy.get(homePage.toastMessage).should( cy.get(homePage.toastMessage).should(
@ -79,6 +82,7 @@ describe("Update Application", function() {
it("Updates the name of first application to very long name and checks whether update is reflected in the application card with a popover", function() { it("Updates the name of first application to very long name and checks whether update is reflected in the application card with a popover", function() {
cy.get(commonlocators.homeIcon).click({ force: true }); cy.get(commonlocators.homeIcon).click({ force: true });
cy.get(homePage.searchInput).clear(); cy.get(homePage.searchInput).clear();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationCard) cy.get(homePage.applicationCard)
@ -94,6 +98,7 @@ describe("Update Application", function() {
"response.body.responseMeta.status", "response.body.responseMeta.status",
200, 200,
); );
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.applicationCard) cy.get(homePage.applicationCard)

View File

@ -31,6 +31,7 @@ describe("Test Create Api and Bind to Table widget", function() {
/**Validate Table data on current page(page1) */ /**Validate Table data on current page(page1) */
cy.ValidateTableData("1"); cy.ValidateTableData("1");
cy.get(commonlocators.tableNextPage).click({ force: true }); cy.get(commonlocators.tableNextPage).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(5000); cy.wait(5000);
/* /*
cy.wait("@postExecute").should( cy.wait("@postExecute").should(

View File

@ -22,12 +22,14 @@ describe("Binding the button Widgets and validating NavigateTo Page functionalit
.click(); .click();
cy.enterNavigatePageName(testdata.externalPage); cy.enterNavigatePageName(testdata.externalPage);
cy.get(commonlocators.editPropCrossButton).click({ force: true }); cy.get(commonlocators.editPropCrossButton).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(300); cy.wait(300);
}); });
it("Button click should take the control to page link validation", function() { it("Button click should take the control to page link validation", function() {
cy.PublishtheApp(); cy.PublishtheApp();
cy.get(publish.buttonWidget).click(); cy.get(publish.buttonWidget).click();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(publish.buttonWidget).should("not.exist"); cy.get(publish.buttonWidget).should("not.exist");
cy.go("back"); cy.go("back");

View File

@ -16,7 +16,7 @@ describe("JS Toggle tests", () => {
.should("have.class", "is-active"); .should("have.class", "is-active");
cy.testJsontext("visible", "false"); cy.testJsontext("visible", "false");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000); cy.wait(1000);
cy.get(".t--property-control-visible") cy.get(".t--property-control-visible")

View File

@ -29,6 +29,7 @@ describe("Table Widget and Navigate to functionality validation", function() {
it("Create MyPage and valdiate if its successfully created", function() { it("Create MyPage and valdiate if its successfully created", function() {
cy.Createpage(pageid); cy.Createpage(pageid);
cy.addDsl(dsl2); cy.addDsl(dsl2);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(`.t--entity-name:contains("${pageid}")`).should("be.visible"); cy.get(`.t--entity-name:contains("${pageid}")`).should("be.visible");
}); });

View File

@ -21,6 +21,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
formWidgetsPage.formInner, formWidgetsPage.formInner,
); );
cy.get(commonlocators.copyWidget).click(); cy.get(commonlocators.copyWidget).click();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(commonlocators.toastBody) cy.get(commonlocators.toastBody)
.first() .first()
@ -36,6 +37,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
expect($lis.eq(1)).to.contain("{{FormTest.data}}"); expect($lis.eq(1)).to.contain("{{FormTest.data}}");
}); });
cy.DeleteWidgetFromSideBar(); cy.DeleteWidgetFromSideBar();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(apiwidget.propertyList).should("not.exist"); cy.get(apiwidget.propertyList).should("not.exist");
/* /*
@ -53,6 +55,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
"response.body.responseMeta.status", "response.body.responseMeta.status",
200, 200,
); );
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(apiwidget.propertyList).then(function($lis) { cy.get(apiwidget.propertyList).then(function($lis) {
expect($lis).to.have.length(2); expect($lis).to.have.length(2);

View File

@ -24,6 +24,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
); );
cy.get("body").click(); cy.get("body").click();
cy.get("body").type(`{${modifierKey}}c`); cy.get("body").type(`{${modifierKey}}c`);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(commonlocators.toastBody) cy.get(commonlocators.toastBody)
.first() .first()

View File

@ -63,43 +63,45 @@ describe("DatePicker Widget Functionality", function() {
); );
}); });
it("Datepicker min/max date validation", function() { // it("Datepicker min/max date validation", function() {
cy.get(formWidgetsPage.defaultDate).click({ force: true }); // cy.get(formWidgetsPage.defaultDate).click({ force: true });
cy.SetDateToToday(); // cy.SetDateToToday();
cy.get(formWidgetsPage.minDate) // cy.get(formWidgetsPage.minDate)
.first() // .first()
.click(); // .click();
cy.wait(1000); // // eslint-disable-next-line cypress/no-unnecessary-waiting
cy.setDate(-1, "ddd MMM DD YYYY"); // cy.wait(1000);
// cy.setDate(-1, "ddd MMM DD YYYY");
cy.get(formWidgetsPage.maxDate) // cy.get(formWidgetsPage.maxDate)
.first() // .first()
.click(); // .click();
cy.wait(1000); // // eslint-disable-next-line cypress/no-unnecessary-waiting
cy.setDate(1, "ddd MMM DD YYYY"); // cy.wait(1000);
// cy.setDate(1, "ddd MMM DD YYYY");
cy.PublishtheApp(); // cy.PublishtheApp();
cy.get(publishPage.datepickerWidget + " .bp3-input").click(); // cy.get(publishPage.datepickerWidget + " .bp3-input").click();
const minDate = Cypress.moment() // const minDate = Cypress.moment()
.add(2, "days") // .add(2, "days")
.format("ddd MMM DD YYYY"); // .format("ddd MMM DD YYYY");
const maxDate = Cypress.moment() // const maxDate = Cypress.moment()
.add(2, "days") // .add(2, "days")
.format("ddd MMM DD YYYY"); // .format("ddd MMM DD YYYY");
cy.get(`.DayPicker-Day[aria-label=\"${minDate}\"]`).should( // cy.get(`.DayPicker-Day[aria-label=\"${minDate}\"]`).should(
"have.attr", // "have.attr",
"aria-disabled", // "aria-disabled",
"true", // "true",
); // );
cy.get(`.DayPicker-Day[aria-label=\"${maxDate}\"]`).should( // cy.get(`.DayPicker-Day[aria-label=\"${maxDate}\"]`).should(
"have.attr", // "have.attr",
"aria-disabled", // "aria-disabled",
"true", // "true",
); // );
}); // });
// it("Datepicker default date validation", function() { // it("Datepicker default date validation", function() {
// cy.get(formWidgetsPage.defaultDate).click(); // cy.get(formWidgetsPage.defaultDate).click();

View File

@ -19,7 +19,7 @@ describe("Form reset functionality", function() {
cy.get(widgetsPage.formButtonWidget) cy.get(widgetsPage.formButtonWidget)
.contains("Reset") .contains("Reset")
.click(); .click();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(".tr") cy.get(".tr")

View File

@ -32,6 +32,7 @@ describe("Tab widget test", function() {
.click({ force: true }) .click({ force: true })
.should("be.visible"); .should("be.visible");
cy.get(Layoutpage.tabButton).click({ force: true }); cy.get(Layoutpage.tabButton).click({ force: true });
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(200); cy.wait(200);
cy.tabVerify(2, "Day"); cy.tabVerify(2, "Day");
cy.get(Layoutpage.tabDelete) cy.get(Layoutpage.tabDelete)

View File

@ -0,0 +1,39 @@
const commonlocators = require("../../../locators/commonlocators.json");
const formWidgetsPage = require("../../../locators/FormWidgets.json");
const dsl = require("../../../fixtures/datePicker2dsl.json");
const publishPage = require("../../../locators/publishWidgetspage.json");
const pages = require("../../../locators/Pages.json");
describe("DatePicker Widget Property pane tests with js bindings", function() {
before(() => {
cy.addDsl(dsl);
});
it("Datepicker default date validation with js binding and default date", function() {
cy.openPropertyPane("datepickerwidget2");
cy.get(".t--property-control-defaultdate .bp3-input").clear();
cy.get(formWidgetsPage.toggleJsDefaultDate).click();
cy.testJsontext("defaultdate", "{{ moment().add(-1,'days') }}");
});
it("Text widgets binding with datepicker", function() {
cy.SearchEntityandOpen("Text1");
cy.testJsontext("text", "{{DatePicker1.formattedDate}}");
cy.closePropertyPane();
cy.SearchEntityandOpen("Text2");
cy.testJsontext("text", "{{DatePicker1.selectedDate}}");
cy.closePropertyPane();
});
it("Text widgets binding with datepicker", function() {
cy.openPropertyPane("datepickerwidget2");
cy.selectDateFormat("DD/MM/YYYY");
cy.assertDateFormat();
cy.closePropertyPane();
cy.assertDateFormat();
});
it("Datepicker default date validation with js binding", function() {
cy.PublishtheApp();
cy.wait(10000);
});
});

View File

@ -0,0 +1,79 @@
const commonlocators = require("../../../locators/commonlocators.json");
const formWidgetsPage = require("../../../locators/FormWidgets.json");
const dsl = require("../../../fixtures/datePicker2dsl.json");
const publishPage = require("../../../locators/publishWidgetspage.json");
const pages = require("../../../locators/Pages.json");
describe("DatePicker Widget Property pane tests with js bindings", function() {
before(() => {
cy.addDsl(dsl);
});
it("Datepicker default date validation with js binding", function() {
cy.openPropertyPane("datepickerwidget2");
cy.get(".t--property-control-defaultdate .bp3-input").clear();
cy.get(formWidgetsPage.toggleJsDefaultDate).click();
cy.testJsontext("defaultdate", "{{moment().toISOString()}}");
cy.get(formWidgetsPage.toggleJsMinDate).click();
cy.testJsontext(
"mindate",
"{{moment().subtract(10, 'days').toISOString()}}",
);
cy.get(formWidgetsPage.toggleJsMaxDate).click();
cy.testJsontext("maxdate", "{{moment().add(10, 'days').toISOString()}}");
/*
cy.get(formWidgetsPage.datepickerWidget + " .bp3-input").should(
"contain.value",
"14/02/2021",
);
cy.PublishtheApp();
cy.get(publishPage.datepickerWidget + " .bp3-input").should(
"contain.value",
"14/02/2021",
);
*/
});
it("Text widgets binding with datepicker", function() {
cy.SearchEntityandOpen("Text1");
cy.testJsontext("text", "{{DatePicker1.formattedDate}}");
cy.closePropertyPane();
cy.SearchEntityandOpen("Text2");
cy.testJsontext("text", "{{DatePicker1.selectedDate}}");
cy.closePropertyPane();
});
it("Text widgets binding with datepicker", function() {
cy.openPropertyPane("datepickerwidget2");
cy.selectDateFormat("YYYY-MM-DD");
cy.assertDateFormat();
cy.selectDateFormat("YYYY-MM-DD HH:mm");
cy.assertDateFormat();
cy.selectDateFormat("YYYY-MM-DDTHH:mm:ss.sssZ");
cy.assertDateFormat();
cy.selectDateFormat("DD/MM/YYYY");
cy.assertDateFormat();
cy.selectDateFormat("DD/MM/YYYY HH:mm");
cy.closePropertyPane();
cy.assertDateFormat();
});
it("Datepicker default date validation with strings", function() {
cy.openPropertyPane("datepickerwidget2");
cy.get(formWidgetsPage.toggleJsDefaultDate).click();
cy.get(".t--property-control-defaultdate .bp3-input").clear();
cy.get(".t--property-control-defaultdate .bp3-input").type("2020-02-01");
cy.closePropertyPane();
cy.openPropertyPane("datepickerwidget2");
cy.get(formWidgetsPage.toggleJsMinDate).click();
cy.get(".t--property-control-mindate .bp3-input").type("2020-01-01");
cy.get(formWidgetsPage.toggleJsMaxDate).click();
cy.get(".t--property-control-maxdate .bp3-input").type("2020-02-10");
cy.closePropertyPane();
});
it("Datepicker default date validation with js binding", function() {
cy.PublishtheApp();
cy.wait(10000);
});
});

View File

@ -0,0 +1,47 @@
const commonlocators = require("../../../locators/commonlocators.json");
const formWidgetsPage = require("../../../locators/FormWidgets.json");
const dsl = require("../../../fixtures/newFormDsl.json");
const publishPage = require("../../../locators/publishWidgetspage.json");
const pages = require("../../../locators/Pages.json");
describe("DatePicker Widget Property pane tests with js bindings", function() {
before(() => {
cy.addDsl(dsl);
});
beforeEach(() => {
cy.openPropertyPane("datepickerwidget");
});
it("Datepicker default date validation with js binding", function() {
cy.get(".t--property-control-defaultdate .bp3-input").clear();
cy.get(formWidgetsPage.toggleJsDefaultDate).click();
cy.testJsontext(
"defaultdate",
"{{moment('14/02/2021', 'DD/MM/YYYY').format('DD/MM/YYYY')}}",
);
cy.get(formWidgetsPage.toggleJsMinDate).click();
cy.testJsontext(
"mindate",
"{{moment('12/02/2021', 'DD/MM/YYYY').format('DD/MM/YYYY')}}",
);
cy.get(formWidgetsPage.toggleJsMaxDate).click();
cy.testJsontext(
"maxdate",
"{{moment('17/02/2021', 'DD/MM/YYYY').format('DD/MM/YYYY')}}",
);
cy.get(formWidgetsPage.datepickerWidget + " .bp3-input").should(
"contain.value",
"14/02/2021",
);
cy.PublishtheApp();
cy.get(publishPage.datepickerWidget + " .bp3-input").should(
"contain.value",
"14/02/2021",
);
});
afterEach(() => {
cy.get(publishPage.backToEditor).click({ force: true });
});
});

View File

@ -24,6 +24,7 @@ describe("Update Organization", function() {
localStorage.setItem("OrgName", orgid); localStorage.setItem("OrgName", orgid);
cy.get(homePage.orgNameInput).clear(); cy.get(homePage.orgNameInput).clear();
cy.get(homePage.orgNameInput).type(orgid); cy.get(homePage.orgNameInput).type(orgid);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(2000); cy.wait(2000);
cy.get(homePage.orgHeaderName).should("have.text", orgid); cy.get(homePage.orgHeaderName).should("have.text", orgid);
}); });

View File

@ -29,6 +29,7 @@ describe("Addwidget from Query and bind with other widgets", function() {
.first() .first()
.focus() .focus()
.type("SELECT * FROM configs LIMIT 10;"); .type("SELECT * FROM configs LIMIT 10;");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(queryEditor.runQuery).click(); cy.get(queryEditor.runQuery).click();
cy.wait("@postExecute").should( cy.wait("@postExecute").should(

View File

@ -22,6 +22,7 @@ describe("Add widget", function() {
.first() .first()
.focus() .focus()
.type("select * from configs"); .type("select * from configs");
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(queryEditor.runQuery).click(); cy.get(queryEditor.runQuery).click();
cy.wait("@postExecute").should( cy.wait("@postExecute").should(

View File

@ -26,8 +26,10 @@ describe("Login from UI and check the functionality", function() {
cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD")); cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
cy.get(homePage.profileMenu).click(); cy.get(homePage.profileMenu).click();
cy.get(homePage.signOutIcon).click(); cy.get(homePage.signOutIcon).click();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.get(homePage.headerAppSmithLogo).click(); cy.get(homePage.headerAppSmithLogo).click();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500); cy.wait(500);
cy.url().should("include", "user/login"); cy.url().should("include", "user/login");
}); });

View File

@ -1,37 +1,36 @@
{ {
"checkboxWidget": ".t--draggable-checkboxwidget", "checkboxWidget": ".t--draggable-checkboxwidget",
"dropdownWidget": ".t--draggable-dropdownwidget", "dropdownWidget": ".t--draggable-dropdownwidget",
"dropdownSelectionType": ".t--property-control-selectiontype", "dropdownSelectionType": ".t--property-control-selectiontype",
"radioWidget": ".t--draggable-radiogroupwidget", "radioWidget": ".t--draggable-radiogroupwidget",
"radioOnSelectionChangeDropdown": ".t--property-control-onselectionchange", "radioOnSelectionChangeDropdown": ".t--property-control-onselectionchange",
"nextDayBtn": ".DayPicker-Day[aria-selected='true'] + div.DayPicker-Day", "nextDayBtn": ".DayPicker-Day[aria-selected='true'] + div.DayPicker-Day",
"datepickerWidget": ".t--draggable-datepickerwidget", "datepickerWidget": ".t--draggable-datepickerwidget",
"defaultDate": ".t--property-control-defaultdate input", "defaultDate": ".t--property-control-defaultdate input",
"minDate": ".t--property-control-mindate input", "minDate": ".t--property-control-mindate input",
"maxDate": ".t--property-control-maxdate input", "maxDate": ".t--property-control-maxdate input",
"filepickerWidget": ".t--draggable-filepickerwidget", "filepickerWidget": ".t--draggable-filepickerwidget",
"formWidget": ".t--draggable-formwidget", "formWidget": ".t--draggable-formwidget",
"richTextEditorWidget": ".t--draggable-richtexteditorwidget", "richTextEditorWidget": ".t--draggable-richtexteditorwidget",
"richEditorOnTextChange": ".t--property-control-ontextchange", "richEditorOnTextChange": ".t--property-control-ontextchange",
"optionvalue": ".t--property-control-defaultselectedvalue .kDwnRc", "optionvalue": ".t--property-control-defaultselectedvalue .kDwnRc",
"defselected": ".CodeMirror textarea", "defselected": ".CodeMirror textarea",
"dropdowninner": ".bp3-button > .bp3-button-text", "dropdowninner": ".bp3-button > .bp3-button-text",
"Textinput": ".t--property-control-options .CodeMirror-code", "Textinput": ".t--property-control-options .CodeMirror-code",
"labelvalue": ".t--draggable-dropdownwidget label", "labelvalue": ".t--draggable-dropdownwidget label",
"dropdownInput": ".bp3-tag-input-values", "dropdownInput": ".bp3-tag-input-values",
"labelradio": ".t--draggable-radiogroupwidget label", "labelradio": ".t--draggable-radiogroupwidget label",
"deleteradiovalue": ".t--property-control-options mask", "deleteradiovalue": ".t--property-control-options mask",
"inputRadio": ".t--draggable-radiogroupwidget input", "inputRadio": ".t--draggable-radiogroupwidget input",
"defaultSelect": ".t--property-control-defaultselectedvalue .CodeMirror-code", "defaultSelect": ".t--property-control-defaultselectedvalue .CodeMirror-code",
"formInner": ".t--draggable-formwidget span.t--widget-name", "formInner": ".t--draggable-formwidget span.t--widget-name",
"radioInput": ".t--draggable-radiogroupwidget span.t--widget-name", "radioInput": ".t--draggable-radiogroupwidget span.t--widget-name",
"radioAddButton": ".t--property-control-options button", "radioAddButton": ".t--property-control-options button",
"formD": "div[type='FORM_WIDGET']", "formD": "div[type='FORM_WIDGET']",
"datepickerFooter": ".bp3-datepicker-footer span", "datepickerFooter": ".bp3-datepicker-footer span",
"disableJs":".t--property-control-disable input[type='checkbox']", "disableJs": ".t--property-control-disable input[type='checkbox']",
"switchWidget": ".t--draggable-switchwidget", "switchWidget": ".t--draggable-switchwidget",
"toggleJsDefaultDate": ".t--property-control-defaultdate .t--js-toggle", "toggleJsDefaultDate": ".t--property-control-defaultdate .t--js-toggle",
"toggleJsMinDate": ".t--property-control-mindate .t--js-toggle", "toggleJsMinDate": ".t--property-control-mindate .t--js-toggle",
"toggleJsMaxDate": ".t--property-control-maxdate .t--js-toggle" "toggleJsMaxDate": ".t--property-control-maxdate .t--js-toggle"
}
}

View File

@ -690,6 +690,37 @@ Cypress.Commands.add("switchToAPIInputTab", () => {
.click({ force: true }); .click({ force: true });
}); });
Cypress.Commands.add("selectDateFormat", (value) => {
cy.get(".t--property-control-dateformat button")
.first()
.click({ force: true });
cy.get("ul.bp3-menu")
.children()
.contains(value)
.click();
});
Cypress.Commands.add("assertDateFormat", () => {
cy.get(".t--draggable-datepickerwidget2 input")
.first()
.invoke("attr", "value")
.then((text) => {
const firstTxt = text;
cy.log("date time : ", firstTxt);
cy.get(commonlocators.labelTextStyle)
.first()
.should("contain", firstTxt);
cy.get(commonlocators.labelTextStyle)
.last()
.invoke("text")
.then((text) => {
const secondText = text;
cy.log("date time : ", secondText);
expect(firstTxt).not.to.equal(secondText);
});
});
});
Cypress.Commands.add("selectPaginationType", (option) => { Cypress.Commands.add("selectPaginationType", (option) => {
cy.xpath(option).click({ force: true }); cy.xpath(option).click({ force: true });
}); });

View File

@ -8,7 +8,7 @@ import { ControlIcons } from "icons/ControlIcons";
import { AnyStyledComponent } from "styled-components"; import { AnyStyledComponent } from "styled-components";
import { Skin } from "constants/DefaultTheme"; import { Skin } from "constants/DefaultTheme";
import AutoToolTipComponent from "components/designSystems/appsmith/TableComponent/AutoToolTipComponent"; import AutoToolTipComponent from "components/designSystems/appsmith/TableComponent/AutoToolTipComponent";
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent"; import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent2";
import { import {
OperatorTypes, OperatorTypes,
Condition, Condition,

View File

@ -1,6 +1,10 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import { getBorderCSSShorthand, labelStyle } from "constants/DefaultTheme"; import {
getBorderCSSShorthand,
labelStyle,
IntentColors,
} from "constants/DefaultTheme";
import { ControlGroup, Classes, Label } from "@blueprintjs/core"; import { ControlGroup, Classes, Label } from "@blueprintjs/core";
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent"; import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
import { DateInput } from "@blueprintjs/datetime"; import { DateInput } from "@blueprintjs/datetime";
@ -11,24 +15,30 @@ import { WIDGET_PADDING } from "constants/WidgetConstants";
import { TimePrecision } from "@blueprintjs/datetime"; import { TimePrecision } from "@blueprintjs/datetime";
import { Colors } from "constants/Colors"; import { Colors } from "constants/Colors";
import { ISO_DATE_FORMAT } from "constants/WidgetValidation"; import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
import ErrorTooltip from "components/editorComponents/ErrorTooltip";
import { DATE_WIDGET_DEFAULT_VALIDATION_ERROR } from "constants/messages";
const StyledControlGroup = styled(ControlGroup)` const StyledControlGroup = styled(ControlGroup)<{ isValid: boolean }>`
&&& { &&& {
.${Classes.INPUT} { .${Classes.INPUT} {
box-shadow: none; box-shadow: none;
color: ${Colors.OXFORD_BLUE}; color: ${Colors.OXFORD_BLUE};
font-size: ${(props) => props.theme.fontSizes[3]}px; font-size: ${(props) => props.theme.fontSizes[3]}px;
border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])}; border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])};
border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.GEYSER_LIGHT};
border-radius: 0; border-radius: 0;
width: 100%; width: 100%;
height: inherit; height: inherit;
align-items: center; align-items: center;
&:active { &:active {
border-color: ${Colors.HIT_GRAY}; border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.HIT_GRAY};
} }
&:focus { &:focus {
border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])}; border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])};
border-color: #80bdff; border-color: ${(props) =>
!props.isValid ? IntentColors.danger : "#80bdff"};
outline: 0; outline: 0;
box-shadow: 0 0 0 0.1rem rgba(0, 123, 255, 0.25); box-shadow: 0 0 0 0.1rem rgba(0, 123, 255, 0.25);
} }
@ -95,10 +105,17 @@ class DatePickerComponent extends React.Component<
.clone() .clone()
.set({ month: 11, date: 31, year: year + 20 }) .set({ month: 11, date: 31, year: year + 20 })
.toDate(); .toDate();
const isValid = this.state.selectedDate
? this.isValidDate(this.parseDate(this.state.selectedDate))
: true;
const value =
isValid && this.state.selectedDate
? this.parseDate(this.state.selectedDate)
: null;
return ( return (
<StyledControlGroup <StyledControlGroup
fill fill
isValid={isValid}
onClick={(e: any) => { onClick={(e: any) => {
e.stopPropagation(); e.stopPropagation();
}} }}
@ -115,29 +132,58 @@ class DatePickerComponent extends React.Component<
</Label> </Label>
)} )}
{ {
<DateInput <ErrorTooltip
className={this.props.isLoading ? "bp3-skeleton" : ""} isOpen={!isValid}
formatDate={this.formatDate} message={DATE_WIDGET_DEFAULT_VALIDATION_ERROR}
parseDate={this.parseDate} >
placeholder={"Select Date"} <DateInput
disabled={this.props.isDisabled} className={this.props.isLoading ? "bp3-skeleton" : ""}
showActionsBar={true} formatDate={this.formatDate}
timePrecision={TimePrecision.MINUTE} parseDate={this.parseDate}
closeOnSelection placeholder={"Select Date"}
onChange={this.onDateSelected} disabled={this.props.isDisabled}
value={ showActionsBar={true}
this.state.selectedDate timePrecision={TimePrecision.MINUTE}
? this.parseDate(this.state.selectedDate) closeOnSelection
: null onChange={this.onDateSelected}
} value={value}
minDate={minDate} minDate={minDate}
maxDate={maxDate} maxDate={maxDate}
/> />
</ErrorTooltip>
} }
</StyledControlGroup> </StyledControlGroup>
); );
} }
isValidDate = (date: Date): boolean => {
let isValid = true;
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
const parsedCurrentDate = moment(date);
if (this.props.minDate) {
const parsedMinDate = moment(this.props.minDate, dateFormat);
if (
this.props.minDate &&
parsedMinDate.isValid() &&
parsedCurrentDate.isBefore(parsedMinDate)
) {
isValid = false;
}
}
if (this.props.maxDate) {
const parsedMaxDate = moment(this.props.maxDate, dateFormat);
if (
isValid &&
this.props.maxDate &&
parsedMaxDate.isValid() &&
parsedCurrentDate.isAfter(parsedMaxDate)
) {
isValid = false;
}
}
return isValid;
};
formatDate = (date: Date): string => { formatDate = (date: Date): string => {
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT; const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
return moment(date).format(dateFormat); return moment(date).format(dateFormat);
@ -165,9 +211,6 @@ class DatePickerComponent extends React.Component<
const date = selectedDate ? this.formatDate(selectedDate) : ""; const date = selectedDate ? this.formatDate(selectedDate) : "";
this.setState({ selectedDate: date }); this.setState({ selectedDate: date });
// if date is null ( if date is cleared ), don't call onDateSelected
if (!selectedDate) return false;
onDateSelected(date); onDateSelected(date);
} }
}; };

View File

@ -0,0 +1,236 @@
import React from "react";
import styled from "styled-components";
import { labelStyle, IntentColors } from "constants/DefaultTheme";
import { ControlGroup, Classes, Label } from "@blueprintjs/core";
import { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
import { DateInput } from "@blueprintjs/datetime";
import moment from "moment-timezone";
import "../../../../node_modules/@blueprintjs/datetime/lib/css/blueprint-datetime.css";
import { DatePickerType } from "widgets/DatePickerWidget";
import { WIDGET_PADDING } from "constants/WidgetConstants";
import { TimePrecision } from "@blueprintjs/datetime";
import { Colors } from "constants/Colors";
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
import ErrorTooltip from "components/editorComponents/ErrorTooltip";
import { DATE_WIDGET_DEFAULT_VALIDATION_ERROR } from "constants/messages";
const StyledControlGroup = styled(ControlGroup)<{ isValid: boolean }>`
&&& {
.${Classes.INPUT} {
box-shadow: none;
border: 1px solid;
border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.GEYSER_LIGHT};
border-radius: ${(props) => props.theme.radii[1]}px;
width: 100%;
height: inherit;
align-items: center;
&:active {
border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.HIT_GRAY};
}
&:focus {
border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.MYSTIC};
}
}
.${Classes.INPUT_GROUP} {
display: block;
margin: 0;
}
.${Classes.CONTROL_GROUP} {
justify-content: flex-start;
}
label {
${labelStyle}
flex: 0 1 30%;
margin: 7px ${WIDGET_PADDING * 2}px 0 0;
text-align: right;
align-self: flex-start;
max-width: calc(30% - ${WIDGET_PADDING}px);
}
}
&&& {
input {
border: 1px solid;
border-color: ${(props) =>
!props.isValid ? IntentColors.danger : Colors.HIT_GRAY};
border-radius: ${(props) => props.theme.radii[1]}px;
box-shadow: none;
color: ${Colors.OXFORD_BLUE};
font-size: ${(props) => props.theme.fontSizes[3]}px;
}
}
`;
class DatePickerComponent extends React.Component<
DatePickerComponentProps,
DatePickerComponentState
> {
constructor(props: DatePickerComponentProps) {
super(props);
this.state = {
selectedDate: props.selectedDate,
};
}
componentDidUpdate(prevProps: DatePickerComponentProps) {
if (
this.props.selectedDate !== this.state.selectedDate &&
!moment(this.props.selectedDate).isSame(
moment(prevProps.selectedDate),
"seconds",
)
) {
this.setState({ selectedDate: this.props.selectedDate });
}
}
getValidDate = (date: string, format: string) => {
const _date = moment(date, format);
return _date.isValid() ? _date.toDate() : undefined;
};
render() {
const now = moment();
const year = now.get("year");
const minDate = this.props.minDate
? new Date(this.props.minDate)
: now
.clone()
.set({ month: 0, date: 1, year: year - 100 })
.toDate();
const maxDate = this.props.maxDate
? new Date(this.props.maxDate)
: now
.clone()
.set({ month: 11, date: 31, year: year + 20 })
.toDate();
const isValid = this.state.selectedDate
? this.isValidDate(new Date(this.state.selectedDate))
: true;
const value =
isValid && this.state.selectedDate
? new Date(this.state.selectedDate)
: null;
return (
<StyledControlGroup
fill
isValid={isValid}
onClick={(e: any) => {
e.stopPropagation();
}}
>
{this.props.label && (
<Label
className={
this.props.isLoading
? Classes.SKELETON
: Classes.TEXT_OVERFLOW_ELLIPSIS
}
>
{this.props.label}
</Label>
)}
{
<ErrorTooltip
isOpen={!isValid}
message={DATE_WIDGET_DEFAULT_VALIDATION_ERROR}
>
<DateInput
className={this.props.isLoading ? "bp3-skeleton" : ""}
formatDate={this.formatDate}
parseDate={this.parseDate}
placeholder={"Select Date"}
disabled={this.props.isDisabled}
showActionsBar={true}
timePrecision={TimePrecision.MINUTE}
closeOnSelection
onChange={this.onDateSelected}
value={value}
minDate={minDate}
maxDate={maxDate}
/>
</ErrorTooltip>
}
</StyledControlGroup>
);
}
isValidDate = (date: Date): boolean => {
let isValid = true;
const parsedCurrentDate = moment(date);
if (this.props.minDate) {
const parsedMinDate = moment(this.props.minDate);
if (
this.props.minDate &&
parsedMinDate.isValid() &&
parsedCurrentDate.isBefore(parsedMinDate)
) {
isValid = false;
}
}
if (this.props.maxDate) {
const parsedMaxDate = moment(this.props.maxDate);
if (
isValid &&
this.props.maxDate &&
parsedMaxDate.isValid() &&
parsedCurrentDate.isAfter(parsedMaxDate)
) {
isValid = false;
}
}
return isValid;
};
formatDate = (date: Date): string => {
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
return moment(date).format(dateFormat);
};
parseDate = (dateStr: string): Date => {
const date = moment(dateStr);
if (date.isValid()) return moment(dateStr).toDate();
else return moment().toDate();
};
/**
* checks if selelectedDate is null or not,
* sets state and calls props onDateSelected
* if its null, don't call onDateSelected
*
* @param selectedDate
*/
onDateSelected = (selectedDate: Date, isUserChange: boolean) => {
if (isUserChange) {
const { onDateSelected } = this.props;
const date = selectedDate ? selectedDate.toISOString() : "";
this.setState({ selectedDate: date });
onDateSelected(date);
}
};
}
interface DatePickerComponentProps extends ComponentProps {
label: string;
dateFormat: string;
enableTimePicker?: boolean;
selectedDate?: string;
minDate?: string;
maxDate?: string;
timezone?: string;
datePickerType: DatePickerType;
isDisabled: boolean;
onDateSelected: (selectedDate: string) => void;
isLoading: boolean;
}
interface DatePickerComponentState {
selectedDate?: string;
}
export default DatePickerComponent;

View File

@ -5,8 +5,6 @@ import moment from "moment-timezone";
import styled from "styled-components"; import styled from "styled-components";
import { TimePrecision } from "@blueprintjs/datetime"; import { TimePrecision } from "@blueprintjs/datetime";
import { WidgetProps } from "widgets/BaseWidget"; import { WidgetProps } from "widgets/BaseWidget";
import { Toaster } from "components/ads/Toast";
import { Variant } from "components/ads/common";
import { ISO_DATE_FORMAT } from "constants/WidgetValidation"; import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
const DatePickerControlWrapper = styled.div<{ isValid: boolean }>` const DatePickerControlWrapper = styled.div<{ isValid: boolean }>`
@ -63,18 +61,22 @@ class DatePickerControl extends BaseControl<
} }
render() { render() {
const version = this.props.widgetProperties.version;
const dateFormat = const dateFormat =
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT; version === 2
? ISO_DATE_FORMAT
: this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
const isValid = this.state.selectedDate const isValid = this.state.selectedDate
? this.validateDate(moment(this.state.selectedDate, dateFormat).toDate()) ? this.validateDate(moment(this.state.selectedDate, dateFormat).toDate())
: true; : true;
const maxDate = const value =
this.props.widgetProperties?.evaluatedValues?.maxDate ?? this.maxDate; this.props.propertyValue && isValid
const minDate = ? version === 2
this.props.widgetProperties?.evaluatedValues?.minDate ?? this.minDate; ? new Date(this.props.propertyValue)
: this.parseDate(this.props.propertyValue)
: null;
return ( return (
<DatePickerControlWrapper isValid={isValid}> <DatePickerControlWrapper isValid={true}>
<StyledDatePicker <StyledDatePicker
formatDate={this.formatDate} formatDate={this.formatDate}
parseDate={this.parseDate} parseDate={this.parseDate}
@ -83,21 +85,7 @@ class DatePickerControl extends BaseControl<
timePrecision={TimePrecision.MINUTE} timePrecision={TimePrecision.MINUTE}
closeOnSelection closeOnSelection
onChange={this.onDateSelected} onChange={this.onDateSelected}
maxDate={ value={value}
this.props.propertyName === "defaultDate"
? this.getValidDate(maxDate, dateFormat)
: undefined
}
minDate={
this.props.propertyName === "defaultDate"
? this.getValidDate(minDate, dateFormat)
: undefined
}
value={
this.props.propertyValue && isValid
? this.parseDate(this.props.propertyValue)
: null
}
/> />
</DatePickerControlWrapper> </DatePickerControlWrapper>
); );
@ -117,10 +105,13 @@ class DatePickerControl extends BaseControl<
*/ */
onDateSelected = (date: Date, isUserChange: boolean): void => { onDateSelected = (date: Date, isUserChange: boolean): void => {
if (isUserChange) { if (isUserChange) {
const selectedDate = date ? this.formatDate(date) : undefined; const selectedDate = date
? this.props.widgetProperties.version === 2
? date.toISOString()
: this.formatDate(date)
: undefined;
const isValid = this.validateDate(date); const isValid = this.validateDate(date);
if (!isValid) return; if (!isValid) return;
// if everything is ok, put date in state // if everything is ok, put date in state
this.setState({ selectedDate: selectedDate }); this.setState({ selectedDate: selectedDate });
this.updateProperty(this.props.propertyName, selectedDate); this.updateProperty(this.props.propertyName, selectedDate);
@ -128,73 +119,14 @@ class DatePickerControl extends BaseControl<
}; };
/** /**
* checks: * checks if date is of valid date format
* 1. if max date is greater than the default date
* 2. if default date is in range of min and max date
*/ */
validateDate = (date: Date): boolean => { validateDate = (date: Date): boolean => {
const dateFormat = const dateFormat =
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT; this.props.widgetProperties.version === 2
const parsedSelectedDate = moment(date, dateFormat); ? ISO_DATE_FORMAT
//validate defaultDate if both minDate and maxDate is already selected : this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
if (this.props.propertyName === "defaultDate") { return date ? moment(date, dateFormat).isValid() : true;
if (
parsedSelectedDate.isValid() &&
this.props.widgetProperties?.evaluatedValues?.minDate &&
this.props.widgetProperties?.evaluatedValues?.maxDate
) {
const parsedMinDate = moment(
this.props.widgetProperties.evaluatedValues.minDate,
dateFormat,
);
const parsedMaxDate = moment(
this.props.widgetProperties.evaluatedValues.maxDate,
dateFormat,
);
if (
parsedSelectedDate.isBefore(parsedMinDate) ||
parsedSelectedDate.isAfter(parsedMaxDate)
) {
return false;
}
}
}
if (this.props.widgetProperties?.evaluatedValues?.value) {
const parsedWidgetDate = moment(
this.props.widgetProperties.evaluatedValues.value,
dateFormat,
);
// checking if widget date is after min date
if (this.props.propertyName === "minDate") {
if (
parsedSelectedDate.isValid() &&
parsedWidgetDate.isBefore(parsedSelectedDate)
) {
Toaster.show({
text: "Min date cannot be greater than current widget value.",
variant: Variant.danger,
});
return false;
}
}
// checking if widget date is before max date
if (this.props.propertyName === "maxDate") {
if (
parsedSelectedDate.isValid() &&
parsedWidgetDate.isAfter(parsedSelectedDate)
) {
Toaster.show({
text: "Max date cannot be less than current widget value.",
variant: Variant.danger,
});
return false;
}
}
}
return true;
}; };
formatDate = (date: Date): string => { formatDate = (date: Date): string => {
@ -205,7 +137,9 @@ class DatePickerControl extends BaseControl<
parseDate = (dateStr: string): Date => { parseDate = (dateStr: string): Date => {
const dateFormat = const dateFormat =
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT; this.props.widgetProperties.version === 2
? ISO_DATE_FORMAT
: this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
const date = moment(dateStr, dateFormat); const date = moment(dateStr, dateFormat);
if (date.isValid()) return moment(dateStr, dateFormat).toDate(); if (date.isValid()) return moment(dateStr, dateFormat).toDate();

View File

@ -24,6 +24,13 @@ const FIELD_VALUES: Record<
isDisabled: "boolean", isDisabled: "boolean",
// onDateSelected: "Function Call", // onDateSelected: "Function Call",
}, },
DATE_PICKER_WIDGET2: {
defaultDate: "string", //TODO:Vicky validate this property
isRequired: "boolean",
isVisible: "boolean",
isDisabled: "boolean",
// onDateSelected: "Function Call",
},
TABLE_WIDGET: { TABLE_WIDGET: {
tableData: "Array<Object>", tableData: "Array<Object>",
serverSidePaginationEnabled: "boolean", serverSidePaginationEnabled: "boolean",

View File

@ -27,6 +27,10 @@ export const HelpMap = {
path: "/widget-reference/datepicker", path: "/widget-reference/datepicker",
searchKey: "DatePicker", searchKey: "DatePicker",
}, },
DATE_PICKER_WIDGET2: {
path: "/widget-reference/datepicker",
searchKey: "DatePicker",
},
TABLE_WIDGET: { TABLE_WIDGET: {
path: "/widget-reference/table", path: "/widget-reference/table",
searchKey: "Table", searchKey: "Table",

View File

@ -5,6 +5,7 @@ export enum WidgetTypes {
INPUT_WIDGET = "INPUT_WIDGET", INPUT_WIDGET = "INPUT_WIDGET",
CONTAINER_WIDGET = "CONTAINER_WIDGET", CONTAINER_WIDGET = "CONTAINER_WIDGET",
DATE_PICKER_WIDGET = "DATE_PICKER_WIDGET", DATE_PICKER_WIDGET = "DATE_PICKER_WIDGET",
DATE_PICKER_WIDGET2 = "DATE_PICKER_WIDGET2",
TABLE_WIDGET = "TABLE_WIDGET", TABLE_WIDGET = "TABLE_WIDGET",
DROP_DOWN_WIDGET = "DROP_DOWN_WIDGET", DROP_DOWN_WIDGET = "DROP_DOWN_WIDGET",
CHECKBOX_WIDGET = "CHECKBOX_WIDGET", CHECKBOX_WIDGET = "CHECKBOX_WIDGET",

View File

@ -42,7 +42,7 @@ export type Validator = (
dataTree?: DataTree, dataTree?: DataTree,
) => ValidationResponse; ) => ValidationResponse;
export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.Z"; export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.sssZ";
export const JAVASCRIPT_KEYWORDS = { export const JAVASCRIPT_KEYWORDS = {
true: "true", true: "true",

View File

@ -138,6 +138,8 @@ export const FORGOT_PASSWORD_PAGE_LOGIN_LINK = "Back to Sign In";
export const ADD_API_TO_PAGE_SUCCESS_MESSAGE = "Api added to page."; export const ADD_API_TO_PAGE_SUCCESS_MESSAGE = "Api added to page.";
export const INPUT_WIDGET_DEFAULT_VALIDATION_ERROR = "Invalid input"; export const INPUT_WIDGET_DEFAULT_VALIDATION_ERROR = "Invalid input";
export const DATE_WIDGET_DEFAULT_VALIDATION_ERROR = "Date out of range";
export const AUTOFIT_ALL_COLUMNS = "Autofit all columns"; export const AUTOFIT_ALL_COLUMNS = "Autofit all columns";
export const AUTOFIT_THIS_COLUMN = "Autofit this column"; export const AUTOFIT_THIS_COLUMN = "Autofit this column";
export const AUTOFIT_COLUMN = "Autofit column"; export const AUTOFIT_COLUMN = "Autofit column";

View File

@ -29,6 +29,7 @@ describe("getAllPathsFromPropertyConfig", () => {
isLoading: false, isLoading: false,
horizontalAlignment: "LEFT", horizontalAlignment: "LEFT",
parentColumnSpace: 74, parentColumnSpace: 74,
version: 1,
dynamicTriggerPathList: [ dynamicTriggerPathList: [
{ {
key: "primaryColumns.status.onClick", key: "primaryColumns.status.onClick",

View File

@ -51,7 +51,7 @@ export const WidgetIcons: {
<ContainerIcon /> <ContainerIcon />
</IconWrapper> </IconWrapper>
), ),
DATE_PICKER_WIDGET: (props: IconProps) => ( DATE_PICKER_WIDGET2: (props: IconProps) => (
<IconWrapper {...props}> <IconWrapper {...props}>
<DatePickerIcon /> <DatePickerIcon />
</IconWrapper> </IconWrapper>

View File

@ -14,6 +14,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
isDisabled: false, isDisabled: false,
isVisible: true, isVisible: true,
isDefaultClickDisabled: true, isDefaultClickDisabled: true,
version: 1,
}, },
TEXT_WIDGET: { TEXT_WIDGET: {
text: "Label", text: "Label",
@ -22,6 +23,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
rows: 1, rows: 1,
columns: 4, columns: 4,
widgetName: "Text", widgetName: "Text",
version: 1,
}, },
RICH_TEXT_EDITOR_WIDGET: { RICH_TEXT_EDITOR_WIDGET: {
defaultText: "This is the initial <b>content</b> of the editor", defaultText: "This is the initial <b>content</b> of the editor",
@ -31,6 +33,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
isVisible: true, isVisible: true,
widgetName: "RichTextEditor", widgetName: "RichTextEditor",
isDefaultClickDisabled: true, isDefaultClickDisabled: true,
version: 1,
}, },
IMAGE_WIDGET: { IMAGE_WIDGET: {
defaultImage: defaultImage:
@ -41,6 +44,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
rows: 3, rows: 3,
columns: 4, columns: 4,
widgetName: "Image", widgetName: "Image",
version: 1,
}, },
INPUT_WIDGET: { INPUT_WIDGET: {
inputType: "TEXT", inputType: "TEXT",
@ -48,6 +52,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
label: "", label: "",
columns: 5, columns: 5,
widgetName: "Input", widgetName: "Input",
version: 1,
resetOnSubmit: true, resetOnSubmit: true,
}, },
SWITCH_WIDGET: { SWITCH_WIDGET: {
@ -57,11 +62,13 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
defaultSwitchState: true, defaultSwitchState: true,
widgetName: "Switch", widgetName: "Switch",
alignWidget: "LEFT", alignWidget: "LEFT",
version: 1,
}, },
ICON_WIDGET: { ICON_WIDGET: {
widgetName: "Icon", widgetName: "Icon",
rows: 1, rows: 1,
columns: 1, columns: 1,
version: 1,
}, },
CONTAINER_WIDGET: { CONTAINER_WIDGET: {
backgroundColor: "#FFFFFF", backgroundColor: "#FFFFFF",
@ -84,6 +91,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
}, },
], ],
}, },
version: 1,
}, },
DATE_PICKER_WIDGET: { DATE_PICKER_WIDGET: {
isDisabled: false, isDisabled: false,
@ -94,14 +102,26 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
columns: 5, columns: 5,
widgetName: "DatePicker", widgetName: "DatePicker",
defaultDate: moment().format("DD/MM/YYYY HH:mm"), defaultDate: moment().format("DD/MM/YYYY HH:mm"),
version: 1,
},
DATE_PICKER_WIDGET2: {
isDisabled: false,
datePickerType: "DATE_PICKER",
rows: 1,
label: "",
dateFormat: "DD/MM/YYYY HH:mm",
columns: 5,
widgetName: "DatePicker",
defaultDate: moment().toISOString(),
version: 2,
}, },
VIDEO_WIDGET: { VIDEO_WIDGET: {
rows: 7, rows: 7,
columns: 7, columns: 7,
widgetName: "Video", widgetName: "Video",
url: "https://www.youtube.com/watch?v=mzqK0QIZRLs", url: "https://www.youtube.com/watch?v=mzqK0QIZRLs",
autoPlay: false, autoPlay: false,
version: 1,
}, },
TABLE_WIDGET: { TABLE_WIDGET: {
rows: 7, rows: 7,
@ -137,6 +157,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
orderAmount: 19.99, orderAmount: 19.99,
}, },
], ],
version: 1,
}, },
DROP_DOWN_WIDGET: { DROP_DOWN_WIDGET: {
rows: 1, rows: 1,
@ -150,6 +171,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
], ],
widgetName: "Dropdown", widgetName: "Dropdown",
defaultOptionValue: "VEG", defaultOptionValue: "VEG",
version: 1,
}, },
CHECKBOX_WIDGET: { CHECKBOX_WIDGET: {
rows: 1, rows: 1,
@ -157,6 +179,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
label: "Label", label: "Label",
defaultCheckedState: true, defaultCheckedState: true,
widgetName: "Checkbox", widgetName: "Checkbox",
version: 1,
alignWidget: "LEFT", alignWidget: "LEFT",
}, },
RADIO_GROUP_WIDGET: { RADIO_GROUP_WIDGET: {
@ -169,6 +192,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
], ],
defaultOptionValue: "M", defaultOptionValue: "M",
widgetName: "RadioGroup", widgetName: "RadioGroup",
version: 1,
}, },
ALERT_WIDGET: { ALERT_WIDGET: {
alertType: "NOTIFICATION", alertType: "NOTIFICATION",
@ -178,6 +202,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
header: "", header: "",
message: "", message: "",
widgetName: "Alert", widgetName: "Alert",
version: 1,
}, },
FILE_PICKER_WIDGET: { FILE_PICKER_WIDGET: {
rows: 1, rows: 1,
@ -188,6 +213,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
maxFileSize: 5, maxFileSize: 5,
widgetName: "FilePicker", widgetName: "FilePicker",
isDefaultClickDisabled: true, isDefaultClickDisabled: true,
version: 1,
}, },
TABS_WIDGET: { TABS_WIDGET: {
rows: 7, rows: 7,
@ -224,6 +250,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
}, },
], ],
}, },
version: 1,
}, },
MODAL_WIDGET: { MODAL_WIDGET: {
rows: 6, rows: 6,
@ -235,6 +262,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
shouldScrollContents: true, shouldScrollContents: true,
widgetName: "Modal", widgetName: "Modal",
children: [], children: [],
version: 1,
blueprint: { blueprint: {
view: [ view: [
{ {
@ -247,6 +275,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
isDisabled: false, isDisabled: false,
shouldScrollContents: false, shouldScrollContents: false,
children: [], children: [],
version: 1,
blueprint: { blueprint: {
view: [ view: [
{ {
@ -257,6 +286,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
iconName: "cross", iconName: "cross",
iconSize: 24, iconSize: 24,
color: "#040627", color: "#040627",
version: 1,
}, },
}, },
{ {
@ -266,6 +296,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
props: { props: {
text: "Modal Title", text: "Modal Title",
textStyle: "HEADING", textStyle: "HEADING",
version: 1,
}, },
}, },
{ {
@ -275,6 +306,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
props: { props: {
text: "Cancel", text: "Cancel",
buttonStyle: "SECONDARY_BUTTON", buttonStyle: "SECONDARY_BUTTON",
version: 1,
}, },
}, },
{ {
@ -284,6 +316,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
props: { props: {
text: "Confirm", text: "Confirm",
buttonStyle: "PRIMARY_BUTTON", buttonStyle: "PRIMARY_BUTTON",
version: 1,
}, },
}, },
], ],
@ -322,6 +355,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
rows: 0, rows: 0,
columns: 0, columns: 0,
widgetName: "Canvas", widgetName: "Canvas",
version: 1,
}, },
CHART_WIDGET: { CHART_WIDGET: {
rows: 8, rows: 8,
@ -330,6 +364,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
chartType: "LINE_CHART", chartType: "LINE_CHART",
chartName: "Sales on working days", chartName: "Sales on working days",
allowHorizontalScroll: false, allowHorizontalScroll: false,
version: 1,
chartData: [ chartData: [
{ {
seriesName: "Sales", seriesName: "Sales",
@ -374,6 +409,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
widgetName: "FormButton", widgetName: "FormButton",
text: "Submit", text: "Submit",
isDefaultClickDisabled: true, isDefaultClickDisabled: true,
version: 1,
}, },
FORM_WIDGET: { FORM_WIDGET: {
rows: 13, rows: 13,
@ -391,6 +427,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
canExtend: false, canExtend: false,
detachFromLayout: true, detachFromLayout: true,
children: [], children: [],
version: 1,
blueprint: { blueprint: {
view: [ view: [
{ {
@ -400,6 +437,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
props: { props: {
text: "Form", text: "Form",
textStyle: "HEADING", textStyle: "HEADING",
version: 1,
}, },
}, },
{ {
@ -411,6 +449,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
buttonStyle: "PRIMARY_BUTTON", buttonStyle: "PRIMARY_BUTTON",
disabledWhenInvalid: true, disabledWhenInvalid: true,
resetFormOnClick: true, resetFormOnClick: true,
version: 1,
}, },
}, },
{ {
@ -422,6 +461,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
buttonStyle: "SECONDARY_BUTTON", buttonStyle: "SECONDARY_BUTTON",
disabledWhenInvalid: false, disabledWhenInvalid: false,
resetFormOnClick: true, resetFormOnClick: true,
version: 1,
}, },
}, },
], ],
@ -443,12 +483,14 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
allowZoom: true, allowZoom: true,
mapCenter: { lat: -34.397, long: 150.644 }, mapCenter: { lat: -34.397, long: 150.644 },
defaultMarkers: [{ lat: -34.397, long: 150.644, title: "Test A" }], defaultMarkers: [{ lat: -34.397, long: 150.644, title: "Test A" }],
version: 1,
}, },
SKELETON_WIDGET: { SKELETON_WIDGET: {
isLoading: true, isLoading: true,
rows: 1, rows: 1,
columns: 1, columns: 1,
widgetName: "Skeleton", widgetName: "Skeleton",
version: 1,
}, },
}, },
configVersion: 1, configVersion: 1,

View File

@ -29,7 +29,7 @@ const WidgetSidebarResponse: WidgetCardProps[] = [
key: generateReactKey(), key: generateReactKey(),
}, },
{ {
type: "DATE_PICKER_WIDGET", type: "DATE_PICKER_WIDGET2",
widgetCardName: "DatePicker", widgetCardName: "DatePicker",
key: generateReactKey(), key: generateReactKey(),
}, },

View File

@ -9,6 +9,7 @@ import { ImageWidgetProps } from "widgets/ImageWidget";
import { InputWidgetProps } from "widgets/InputWidget"; import { InputWidgetProps } from "widgets/InputWidget";
import { RichTextEditorWidgetProps } from "widgets/RichTextEditorWidget"; import { RichTextEditorWidgetProps } from "widgets/RichTextEditorWidget";
import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget"; import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget";
import { DatePickerWidget2Props } from "../../widgets/DatePickerWidget2";
import { TableWidgetProps } from "../../widgets/TableWidget/TableWidgetConstants"; import { TableWidgetProps } from "../../widgets/TableWidget/TableWidgetConstants";
import { DropdownWidgetProps } from "../../widgets/DropdownWidget"; import { DropdownWidgetProps } from "../../widgets/DropdownWidget";
import { CheckboxWidgetProps } from "../../widgets/CheckboxWidget"; import { CheckboxWidgetProps } from "../../widgets/CheckboxWidget";
@ -59,6 +60,7 @@ export interface WidgetConfigReducerState {
CONTAINER_WIDGET: Partial<ContainerWidgetProps<WidgetProps>> & CONTAINER_WIDGET: Partial<ContainerWidgetProps<WidgetProps>> &
WidgetConfigProps; WidgetConfigProps;
DATE_PICKER_WIDGET: Partial<DatePickerWidgetProps> & WidgetConfigProps; DATE_PICKER_WIDGET: Partial<DatePickerWidgetProps> & WidgetConfigProps;
DATE_PICKER_WIDGET2: Partial<DatePickerWidget2Props> & WidgetConfigProps;
TABLE_WIDGET: Partial<TableWidgetProps> & WidgetConfigProps; TABLE_WIDGET: Partial<TableWidgetProps> & WidgetConfigProps;
VIDEO_WIDGET: Partial<VideoWidgetProps> & WidgetConfigProps; VIDEO_WIDGET: Partial<VideoWidgetProps> & WidgetConfigProps;
DROP_DOWN_WIDGET: Partial<DropdownWidgetProps> & WidgetConfigProps; DROP_DOWN_WIDGET: Partial<DropdownWidgetProps> & WidgetConfigProps;

View File

@ -143,6 +143,7 @@ function* getChildWidgetProps(
parentColumnSpace, parentColumnSpace,
widgetName, widgetName,
widgetProps, widgetProps,
restDefaultConfig.version,
); );
widget.widgetId = newWidgetId; widget.widgetId = newWidgetId;
@ -1411,6 +1412,7 @@ function* addTableWidgetFromQuerySaga(action: ReduxAction<string>) {
parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT, parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
parentColumnSpace: 1, parentColumnSpace: 1,
isLoading: false, isLoading: false,
version: 1,
props: { props: {
tableData: `{{${queryName}.data}}`, tableData: `{{${queryName}.data}}`,
dynamicBindingPathList: [{ key: "tableData" }], dynamicBindingPathList: [{ key: "tableData" }],

View File

@ -259,6 +259,18 @@ const dynamicPathListMigration = (
return currentDSL; return currentDSL;
}; };
const addVersionNumberMigration = (
currentDSL: ContainerWidgetProps<WidgetProps>,
) => {
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map(addVersionNumberMigration);
}
if (currentDSL.version === undefined) {
currentDSL.version = 1;
}
return currentDSL;
};
const canvasNameConflictMigration = ( const canvasNameConflictMigration = (
currentDSL: ContainerWidgetProps<WidgetProps>, currentDSL: ContainerWidgetProps<WidgetProps>,
props = { counter: 1 }, props = { counter: 1 },
@ -367,6 +379,11 @@ const transformDSL = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
currentDSL.version = 10; currentDSL.version = 10;
} }
if (currentDSL.version === 10) {
currentDSL = addVersionNumberMigration(currentDSL);
currentDSL.version = 11;
}
return currentDSL; return currentDSL;
}; };
@ -590,6 +607,7 @@ export const generateWidgetProps = (
widgetId: string; widgetId: string;
renderMode: RenderMode; renderMode: RenderMode;
} & Partial<WidgetProps>, } & Partial<WidgetProps>,
version: number,
): ContainerWidgetProps<WidgetProps> => { ): ContainerWidgetProps<WidgetProps> => {
if (parent) { if (parent) {
const sizes = { const sizes = {
@ -611,6 +629,7 @@ export const generateWidgetProps = (
...sizes, ...sizes,
...others, ...others,
parentId: parent.widgetId, parentId: parent.widgetId,
version,
}; };
delete props.rows; delete props.rows;
delete props.columns; delete props.columns;

View File

@ -71,6 +71,10 @@ import DatePickerWidget, {
DatePickerWidgetProps, DatePickerWidgetProps,
ProfiledDatePickerWidget, ProfiledDatePickerWidget,
} from "widgets/DatePickerWidget"; } from "widgets/DatePickerWidget";
import DatePickerWidget2, {
DatePickerWidget2Props,
ProfiledDatePickerWidget2,
} from "widgets/DatePickerWidget2";
import FormWidget, { ProfiledFormWidget } from "widgets/FormWidget"; import FormWidget, { ProfiledFormWidget } from "widgets/FormWidget";
import FormButtonWidget, { import FormButtonWidget, {
FormButtonWidgetProps, FormButtonWidgetProps,
@ -286,6 +290,20 @@ export default class WidgetBuilderRegistry {
DatePickerWidget.getMetaPropertiesMap(), DatePickerWidget.getMetaPropertiesMap(),
DatePickerWidget.getPropertyPaneConfig(), DatePickerWidget.getPropertyPaneConfig(),
); );
WidgetFactory.registerWidgetBuilder(
"DATE_PICKER_WIDGET2",
{
buildWidget(widgetData: DatePickerWidget2Props): JSX.Element {
return <ProfiledDatePickerWidget2 {...widgetData} />;
},
},
DatePickerWidget2.getPropertyValidationMap(),
DatePickerWidget2.getDerivedPropertiesMap(),
DatePickerWidget2.getTriggerPropertyMap(),
DatePickerWidget2.getDefaultPropertiesMap(),
DatePickerWidget2.getMetaPropertiesMap(),
DatePickerWidget.getPropertyPaneConfig(),
);
WidgetFactory.registerWidgetBuilder( WidgetFactory.registerWidgetBuilder(
"TABS_WIDGET", "TABS_WIDGET",
{ {

View File

@ -124,6 +124,15 @@ export const entityDefinitions = {
selectedDate: "string", selectedDate: "string",
isDisabled: "bool", isDisabled: "bool",
}, },
DATE_PICKER_WIDGET2: {
"!doc":
"Datepicker is used to capture the date and time from a user. It can be used to filter data base on the input date range as well as to capture personal information such as date of birth",
"!url": "https://docs.appsmith.com/widget-reference/datepicker",
isVisible: isVisible,
selectedDate: "string",
formattedDate: "string",
isDisabled: "bool",
},
CHECKBOX_WIDGET: { CHECKBOX_WIDGET: {
"!doc": "!doc":
"Checkbox is a simple UI widget you can use when you want users to make a binary choice", "Checkbox is a simple UI widget you can use when you want users to make a binary choice",

View File

@ -24,6 +24,7 @@ describe("dataTreeTypeDefCreator", () => {
topRow: 1, topRow: 1,
bottomRow: 2, bottomRow: 2,
isLoading: false, isLoading: false,
version: 1,
bindingPaths: { bindingPaths: {
defaultText: true, defaultText: true,
}, },

View File

@ -44,6 +44,7 @@ const input1: ContainerWidgetProps<WidgetProps> = {
widgetId: "fs785w9gcy", widgetId: "fs785w9gcy",
dynamicBindingPathList: [], dynamicBindingPathList: [],
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };
@ -105,6 +106,7 @@ const input2: ContainerWidgetProps<WidgetProps> = {
}, },
], ],
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };
@ -157,6 +159,7 @@ const input3: ContainerWidgetProps<WidgetProps> = {
onRowSelected: "{{showAlert('test','success')}}", onRowSelected: "{{showAlert('test','success')}}",
onSearchTextChanged: "{{showAlert('fail','error')}}", onSearchTextChanged: "{{showAlert('fail','error')}}",
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };
@ -293,6 +296,7 @@ const output1 = {
horizontalAlignment: "LEFT", horizontalAlignment: "LEFT",
verticalAlignment: "CENTER", verticalAlignment: "CENTER",
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };
@ -474,6 +478,7 @@ const output2 = {
horizontalAlignment: "LEFT", horizontalAlignment: "LEFT",
verticalAlignment: "CENTER", verticalAlignment: "CENTER",
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };
@ -616,6 +621,7 @@ const output3 = {
horizontalAlignment: "LEFT", horizontalAlignment: "LEFT",
verticalAlignment: "CENTER", verticalAlignment: "CENTER",
renderMode: "CANVAS", renderMode: "CANVAS",
version: 1,
}, },
], ],
}; };

View File

@ -319,6 +319,7 @@ export interface WidgetBaseProps {
widgetName: string; widgetName: string;
parentId: string; parentId: string;
renderMode: RenderMode; renderMode: RenderMode;
version: number;
} }
export type WidgetRowCols = { export type WidgetRowCols = {

View File

@ -0,0 +1,223 @@
import React from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import { EventType } from "constants/ActionConstants";
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent2";
import {
WidgetPropertyValidationType,
BASE_WIDGET_VALIDATION,
} from "utils/WidgetValidation";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import {
DerivedPropertiesMap,
TriggerPropertiesMap,
} from "utils/WidgetFactory";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class DatePickerWidget extends BaseWidget<DatePickerWidget2Props, WidgetState> {
static getPropertyPaneConfig() {
return [
{
sectionName: "General",
children: [
{
propertyName: "defaultDate",
label: "Default Date",
helpText:
"Sets the default date of the widget. The date is updated if the default date changes",
controlType: "DATE_PICKER",
placeholderText: "Enter Default Date",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
{
helpText: "Sets the format of the selected date",
propertyName: "dateFormat",
label: "Date Format",
controlType: "DROP_DOWN",
isJSConvertible: true,
options: [
{
label: "YYYY-MM-DD",
value: "YYYY-MM-DD",
},
{
label: "YYYY-MM-DD HH:mm",
value: "YYYY-MM-DD HH:mm",
},
{
label: "YYYY-MM-DDTHH:mm:ss.sssZ",
value: "YYYY-MM-DDTHH:mm:ss.sssZ",
},
{
label: "DD/MM/YYYY",
value: "DD/MM/YYYY",
},
{
label: "DD/MM/YYYY HH:mm",
value: "DD/MM/YYYY HH:mm",
},
],
isBindProperty: true,
isTriggerProperty: false,
},
{
propertyName: "isRequired",
label: "Required",
helpText: "Makes input to the widget mandatory",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
{
propertyName: "isVisible",
label: "Visible",
helpText: "Controls the visibility of the widget",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
{
propertyName: "isDisabled",
label: "Disabled",
helpText: "Disables input to this widget",
controlType: "SWITCH",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
{
propertyName: "minDate",
label: "Min Date",
helpText: "Defines the min date for this widget",
controlType: "DATE_PICKER",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
{
propertyName: "maxDate",
label: "Max Date",
helpText: "Defines the max date for this widget",
controlType: "DATE_PICKER",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
},
],
},
{
sectionName: "Actions",
children: [
{
propertyName: "onDateSelected",
label: "onDateSelected",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
...BASE_WIDGET_VALIDATION,
defaultDate: VALIDATION_TYPES.DEFAULT_DATE,
timezone: VALIDATION_TYPES.TEXT,
enableTimePicker: VALIDATION_TYPES.BOOLEAN,
dateFormat: VALIDATION_TYPES.TEXT,
label: VALIDATION_TYPES.TEXT,
datePickerType: VALIDATION_TYPES.TEXT,
maxDate: VALIDATION_TYPES.DATE,
minDate: VALIDATION_TYPES.DATE,
isRequired: VALIDATION_TYPES.BOOLEAN,
// onDateSelected: VALIDATION_TYPES.ACTION_SELECTOR,
// onDateRangeSelected: VALIDATION_TYPES.ACTION_SELECTOR,
};
}
static getDerivedPropertiesMap(): DerivedPropertiesMap {
return {
isValid: `{{ this.isRequired ? !!this.selectedDate : true }}`,
selectedDate: `{{ this.value ? moment(this.value).toISOString() : (this.defaultDate ? moment(this.defaultDate).toISOString() : "")}}`,
formattedDate: `{{ this.value ? moment(this.value).format(this.dateFormat) : (this.defaultDate ? moment(this.defaultDate).format(this.dateFormat) : "")}}`,
};
}
static getTriggerPropertyMap(): TriggerPropertiesMap {
return {
onDateSelected: true,
};
}
static getDefaultPropertiesMap(): Record<string, string> {
return {
value: "defaultDate",
};
}
static getMetaPropertiesMap(): Record<string, any> {
return {
value: undefined,
};
}
getPageView() {
return (
<DatePickerComponent
label={`${this.props.label}`}
dateFormat={this.props.dateFormat}
widgetId={this.props.widgetId}
isDisabled={this.props.isDisabled}
datePickerType={"DATE_PICKER"}
onDateSelected={this.onDateSelected}
selectedDate={this.props.value}
isLoading={this.props.isLoading}
minDate={this.props.minDate}
maxDate={this.props.maxDate}
/>
);
}
onDateSelected = (selectedDate: string) => {
this.props.updateWidgetMetaProperty("value", selectedDate, {
dynamicString: this.props.onDateSelected,
event: {
type: EventType.ON_DATE_SELECTED,
},
});
};
getWidgetType(): WidgetType {
return "DATE_PICKER_WIDGET2";
}
}
export type DatePickerType = "DATE_PICKER" | "DATE_RANGE_PICKER";
export interface DatePickerWidget2Props extends WidgetProps, WithMeta {
defaultDate: string;
selectedDate: string;
formattedDate: string;
isDisabled: boolean;
dateFormat: string;
label: string;
datePickerType: DatePickerType;
onDateSelected?: string;
onDateRangeSelected?: string;
maxDate: string;
minDate: string;
isRequired?: boolean;
}
export default DatePickerWidget;
export const ProfiledDatePickerWidget2 = Sentry.withProfiler(
withMeta(DatePickerWidget),
);

View File

@ -289,6 +289,33 @@ const WIDGET_CONFIG_MAP: WidgetTypeConfigMap = {
}, },
metaProperties: {}, metaProperties: {},
}, },
DATE_PICKER_WIDGET2: {
validations: {
isLoading: "BOOLEAN",
isVisible: "BOOLEAN",
isDisabled: "BOOLEAN",
defaultDate: "DATE",
timezone: "TEXT",
enableTimePicker: "BOOLEAN",
dateFormat: "TEXT",
label: "TEXT",
datePickerType: "TEXT",
maxDate: "DATE",
minDate: "DATE",
isRequired: "BOOLEAN",
},
defaultProperties: {
selectedDate: "defaultDate",
},
derivedProperties: {
isValid: "{{ this.isRequired ? !!this.selectedDate : true }}",
value: "{{ this.selectedDate }}",
},
triggerProperties: {
onDateSelected: true,
},
metaProperties: {},
},
TABS_WIDGET: { TABS_WIDGET: {
validations: { validations: {
tabs: "TABS_DATA", tabs: "TABS_DATA",
@ -447,6 +474,7 @@ const BASE_WIDGET: DataTreeWidget = {
topRow: 0, topRow: 0,
type: WidgetTypes.SKELETON_WIDGET, type: WidgetTypes.SKELETON_WIDGET,
parentId: "0", parentId: "0",
version: 1,
bindingPaths: {}, bindingPaths: {},
triggerPaths: {}, triggerPaths: {},
ENTITY_TYPE: ENTITY_TYPE.WIDGET, ENTITY_TYPE: ENTITY_TYPE.WIDGET,

View File

@ -391,7 +391,10 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
dateString: string, dateString: string,
props: WidgetProps, props: WidgetProps,
): ValidationResponse => { ): ValidationResponse => {
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT; const dateFormat =
props.version === 2
? ISO_DATE_FORMAT
: props.dateFormat || ISO_DATE_FORMAT;
if (dateString === undefined) { if (dateString === undefined) {
return { return {
@ -421,39 +424,22 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
dateString: string, dateString: string,
props: WidgetProps, props: WidgetProps,
): ValidationResponse => { ): ValidationResponse => {
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT; const dateFormat =
props.version === 2
? ISO_DATE_FORMAT
: props.dateFormat || ISO_DATE_FORMAT;
if (dateString === undefined) { if (dateString === undefined) {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: message:
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat `${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
? props.dateFormat ? dateFormat
: "", : "",
}; };
} }
const parsedCurrentDate = moment(dateString, dateFormat); const parsedCurrentDate = moment(dateString, dateFormat);
let isValid = parsedCurrentDate.isValid(); const isValid = parsedCurrentDate.isValid();
const parsedMinDate = moment(props.minDate, dateFormat);
const parsedMaxDate = moment(props.maxDate, dateFormat);
// checking for max/min date range
if (isValid) {
if (
parsedMinDate.isValid() &&
parsedCurrentDate.isBefore(parsedMinDate)
) {
isValid = false;
}
if (
isValid &&
parsedMaxDate.isValid() &&
parsedCurrentDate.isAfter(parsedMaxDate)
) {
isValid = false;
}
}
if (!isValid) { if (!isValid) {
return { return {
isValid: isValid, isValid: isValid,
@ -471,14 +457,17 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
dateString: string, dateString: string,
props: WidgetProps, props: WidgetProps,
): ValidationResponse => { ): ValidationResponse => {
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT; const dateFormat =
props.version === 2
? ISO_DATE_FORMAT
: props.dateFormat || ISO_DATE_FORMAT;
if (dateString === undefined) { if (dateString === undefined) {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: message:
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat `${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
? props.dateFormat ? dateFormat
: "", : "",
}; };
} }
@ -517,14 +506,17 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
dateString: string, dateString: string,
props: WidgetProps, props: WidgetProps,
): ValidationResponse => { ): ValidationResponse => {
const dateFormat = props.dateFormat ? props.dateFormat : ISO_DATE_FORMAT; const dateFormat =
props.version === 2
? ISO_DATE_FORMAT
: props.dateFormat || ISO_DATE_FORMAT;
if (dateString === undefined) { if (dateString === undefined) {
return { return {
isValid: false, isValid: false,
parsed: "", parsed: "",
message: message:
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat `${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
? props.dateFormat ? dateFormat
: "", : "",
}; };
} }