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:
parent
72df6fb299
commit
6c80f23201
80
app/client/cypress/fixtures/datePicker2dsl.json
Normal file
80
app/client/cypress/fixtures/datePicker2dsl.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ describe("Duplicate application", function() {
|
|||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
const appname = localStorage.getItem("AppName");
|
||||
cy.get(homePage.searchInput).type(appname);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(homePage.applicationCard)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ describe("Update Application", function() {
|
|||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
appname = localStorage.getItem("AppName");
|
||||
cy.get(homePage.searchInput).type(appname);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(homePage.applicationCard)
|
||||
|
|
@ -53,6 +54,7 @@ describe("Update Application", function() {
|
|||
it("Check for errors in updating application name", function() {
|
||||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
cy.get(homePage.searchInput).type(appname);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
cy.get(homePage.applicationCard)
|
||||
.first()
|
||||
|
|
@ -61,6 +63,7 @@ describe("Update Application", function() {
|
|||
.first()
|
||||
.click({ force: true });
|
||||
cy.get("#loading").should("not.exist");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
cy.get(homePage.applicationName).type(" ");
|
||||
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() {
|
||||
cy.get(commonlocators.homeIcon).click({ force: true });
|
||||
cy.get(homePage.searchInput).clear();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(homePage.applicationCard)
|
||||
|
|
@ -94,6 +98,7 @@ describe("Update Application", function() {
|
|||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
|
||||
cy.get(homePage.applicationCard)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ describe("Test Create Api and Bind to Table widget", function() {
|
|||
/**Validate Table data on current page(page1) */
|
||||
cy.ValidateTableData("1");
|
||||
cy.get(commonlocators.tableNextPage).click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(5000);
|
||||
/*
|
||||
cy.wait("@postExecute").should(
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ describe("Binding the button Widgets and validating NavigateTo Page functionalit
|
|||
.click();
|
||||
cy.enterNavigatePageName(testdata.externalPage);
|
||||
cy.get(commonlocators.editPropCrossButton).click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(300);
|
||||
});
|
||||
|
||||
it("Button click should take the control to page link validation", function() {
|
||||
cy.PublishtheApp();
|
||||
cy.get(publish.buttonWidget).click();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(publish.buttonWidget).should("not.exist");
|
||||
cy.go("back");
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ describe("JS Toggle tests", () => {
|
|||
.should("have.class", "is-active");
|
||||
|
||||
cy.testJsontext("visible", "false");
|
||||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get(".t--property-control-visible")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ describe("Table Widget and Navigate to functionality validation", function() {
|
|||
it("Create MyPage and valdiate if its successfully created", function() {
|
||||
cy.Createpage(pageid);
|
||||
cy.addDsl(dsl2);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(`.t--entity-name:contains("${pageid}")`).should("be.visible");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
|
|||
formWidgetsPage.formInner,
|
||||
);
|
||||
cy.get(commonlocators.copyWidget).click();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(commonlocators.toastBody)
|
||||
.first()
|
||||
|
|
@ -36,6 +37,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
|
|||
expect($lis.eq(1)).to.contain("{{FormTest.data}}");
|
||||
});
|
||||
cy.DeleteWidgetFromSideBar();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
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",
|
||||
200,
|
||||
);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(apiwidget.propertyList).then(function($lis) {
|
||||
expect($lis).to.have.length(2);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ describe("Test Suite to validate copy/delete/undo functionalites", function() {
|
|||
);
|
||||
cy.get("body").click();
|
||||
cy.get("body").type(`{${modifierKey}}c`);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(commonlocators.toastBody)
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -63,43 +63,45 @@ describe("DatePicker Widget Functionality", function() {
|
|||
);
|
||||
});
|
||||
|
||||
it("Datepicker min/max date validation", function() {
|
||||
cy.get(formWidgetsPage.defaultDate).click({ force: true });
|
||||
cy.SetDateToToday();
|
||||
// it("Datepicker min/max date validation", function() {
|
||||
// cy.get(formWidgetsPage.defaultDate).click({ force: true });
|
||||
// cy.SetDateToToday();
|
||||
|
||||
cy.get(formWidgetsPage.minDate)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(1000);
|
||||
cy.setDate(-1, "ddd MMM DD YYYY");
|
||||
// cy.get(formWidgetsPage.minDate)
|
||||
// .first()
|
||||
// .click();
|
||||
// // eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
// cy.wait(1000);
|
||||
// cy.setDate(-1, "ddd MMM DD YYYY");
|
||||
|
||||
cy.get(formWidgetsPage.maxDate)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(1000);
|
||||
cy.setDate(1, "ddd MMM DD YYYY");
|
||||
// cy.get(formWidgetsPage.maxDate)
|
||||
// .first()
|
||||
// .click();
|
||||
// // eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
// cy.wait(1000);
|
||||
// cy.setDate(1, "ddd MMM DD YYYY");
|
||||
|
||||
cy.PublishtheApp();
|
||||
cy.get(publishPage.datepickerWidget + " .bp3-input").click();
|
||||
// cy.PublishtheApp();
|
||||
// cy.get(publishPage.datepickerWidget + " .bp3-input").click();
|
||||
|
||||
const minDate = Cypress.moment()
|
||||
.add(2, "days")
|
||||
.format("ddd MMM DD YYYY");
|
||||
const maxDate = Cypress.moment()
|
||||
.add(2, "days")
|
||||
.format("ddd MMM DD YYYY");
|
||||
// const minDate = Cypress.moment()
|
||||
// .add(2, "days")
|
||||
// .format("ddd MMM DD YYYY");
|
||||
// const maxDate = Cypress.moment()
|
||||
// .add(2, "days")
|
||||
// .format("ddd MMM DD YYYY");
|
||||
|
||||
cy.get(`.DayPicker-Day[aria-label=\"${minDate}\"]`).should(
|
||||
"have.attr",
|
||||
"aria-disabled",
|
||||
"true",
|
||||
);
|
||||
cy.get(`.DayPicker-Day[aria-label=\"${maxDate}\"]`).should(
|
||||
"have.attr",
|
||||
"aria-disabled",
|
||||
"true",
|
||||
);
|
||||
});
|
||||
// cy.get(`.DayPicker-Day[aria-label=\"${minDate}\"]`).should(
|
||||
// "have.attr",
|
||||
// "aria-disabled",
|
||||
// "true",
|
||||
// );
|
||||
// cy.get(`.DayPicker-Day[aria-label=\"${maxDate}\"]`).should(
|
||||
// "have.attr",
|
||||
// "aria-disabled",
|
||||
// "true",
|
||||
// );
|
||||
// });
|
||||
|
||||
// it("Datepicker default date validation", function() {
|
||||
// cy.get(formWidgetsPage.defaultDate).click();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ describe("Form reset functionality", function() {
|
|||
cy.get(widgetsPage.formButtonWidget)
|
||||
.contains("Reset")
|
||||
.click();
|
||||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
|
||||
cy.get(".tr")
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ describe("Tab widget test", function() {
|
|||
.click({ force: true })
|
||||
.should("be.visible");
|
||||
cy.get(Layoutpage.tabButton).click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(200);
|
||||
cy.tabVerify(2, "Day");
|
||||
cy.get(Layoutpage.tabDelete)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -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 });
|
||||
});
|
||||
});
|
||||
|
|
@ -24,6 +24,7 @@ describe("Update Organization", function() {
|
|||
localStorage.setItem("OrgName", orgid);
|
||||
cy.get(homePage.orgNameInput).clear();
|
||||
cy.get(homePage.orgNameInput).type(orgid);
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(2000);
|
||||
cy.get(homePage.orgHeaderName).should("have.text", orgid);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ describe("Addwidget from Query and bind with other widgets", function() {
|
|||
.first()
|
||||
.focus()
|
||||
.type("SELECT * FROM configs LIMIT 10;");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(queryEditor.runQuery).click();
|
||||
cy.wait("@postExecute").should(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ describe("Add widget", function() {
|
|||
.first()
|
||||
.focus()
|
||||
.type("select * from configs");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(queryEditor.runQuery).click();
|
||||
cy.wait("@postExecute").should(
|
||||
|
|
|
|||
|
|
@ -26,8 +26,10 @@ describe("Login from UI and check the functionality", function() {
|
|||
cy.LogintoApp(Cypress.env("USERNAME"), Cypress.env("PASSWORD"));
|
||||
cy.get(homePage.profileMenu).click();
|
||||
cy.get(homePage.signOutIcon).click();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(homePage.headerAppSmithLogo).click();
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.url().should("include", "user/login");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,37 +1,36 @@
|
|||
{
|
||||
"checkboxWidget": ".t--draggable-checkboxwidget",
|
||||
"dropdownWidget": ".t--draggable-dropdownwidget",
|
||||
"dropdownSelectionType": ".t--property-control-selectiontype",
|
||||
"radioWidget": ".t--draggable-radiogroupwidget",
|
||||
"radioOnSelectionChangeDropdown": ".t--property-control-onselectionchange",
|
||||
"nextDayBtn": ".DayPicker-Day[aria-selected='true'] + div.DayPicker-Day",
|
||||
"datepickerWidget": ".t--draggable-datepickerwidget",
|
||||
"defaultDate": ".t--property-control-defaultdate input",
|
||||
"minDate": ".t--property-control-mindate input",
|
||||
"maxDate": ".t--property-control-maxdate input",
|
||||
"filepickerWidget": ".t--draggable-filepickerwidget",
|
||||
"formWidget": ".t--draggable-formwidget",
|
||||
"richTextEditorWidget": ".t--draggable-richtexteditorwidget",
|
||||
"richEditorOnTextChange": ".t--property-control-ontextchange",
|
||||
"optionvalue": ".t--property-control-defaultselectedvalue .kDwnRc",
|
||||
"defselected": ".CodeMirror textarea",
|
||||
"dropdowninner": ".bp3-button > .bp3-button-text",
|
||||
"Textinput": ".t--property-control-options .CodeMirror-code",
|
||||
"labelvalue": ".t--draggable-dropdownwidget label",
|
||||
"dropdownInput": ".bp3-tag-input-values",
|
||||
"labelradio": ".t--draggable-radiogroupwidget label",
|
||||
"deleteradiovalue": ".t--property-control-options mask",
|
||||
"inputRadio": ".t--draggable-radiogroupwidget input",
|
||||
"defaultSelect": ".t--property-control-defaultselectedvalue .CodeMirror-code",
|
||||
"formInner": ".t--draggable-formwidget span.t--widget-name",
|
||||
"radioInput": ".t--draggable-radiogroupwidget span.t--widget-name",
|
||||
"radioAddButton": ".t--property-control-options button",
|
||||
"formD": "div[type='FORM_WIDGET']",
|
||||
"datepickerFooter": ".bp3-datepicker-footer span",
|
||||
"disableJs":".t--property-control-disable input[type='checkbox']",
|
||||
"switchWidget": ".t--draggable-switchwidget",
|
||||
"toggleJsDefaultDate": ".t--property-control-defaultdate .t--js-toggle",
|
||||
"toggleJsMinDate": ".t--property-control-mindate .t--js-toggle",
|
||||
"toggleJsMaxDate": ".t--property-control-maxdate .t--js-toggle"
|
||||
|
||||
}
|
||||
"checkboxWidget": ".t--draggable-checkboxwidget",
|
||||
"dropdownWidget": ".t--draggable-dropdownwidget",
|
||||
"dropdownSelectionType": ".t--property-control-selectiontype",
|
||||
"radioWidget": ".t--draggable-radiogroupwidget",
|
||||
"radioOnSelectionChangeDropdown": ".t--property-control-onselectionchange",
|
||||
"nextDayBtn": ".DayPicker-Day[aria-selected='true'] + div.DayPicker-Day",
|
||||
"datepickerWidget": ".t--draggable-datepickerwidget",
|
||||
"defaultDate": ".t--property-control-defaultdate input",
|
||||
"minDate": ".t--property-control-mindate input",
|
||||
"maxDate": ".t--property-control-maxdate input",
|
||||
"filepickerWidget": ".t--draggable-filepickerwidget",
|
||||
"formWidget": ".t--draggable-formwidget",
|
||||
"richTextEditorWidget": ".t--draggable-richtexteditorwidget",
|
||||
"richEditorOnTextChange": ".t--property-control-ontextchange",
|
||||
"optionvalue": ".t--property-control-defaultselectedvalue .kDwnRc",
|
||||
"defselected": ".CodeMirror textarea",
|
||||
"dropdowninner": ".bp3-button > .bp3-button-text",
|
||||
"Textinput": ".t--property-control-options .CodeMirror-code",
|
||||
"labelvalue": ".t--draggable-dropdownwidget label",
|
||||
"dropdownInput": ".bp3-tag-input-values",
|
||||
"labelradio": ".t--draggable-radiogroupwidget label",
|
||||
"deleteradiovalue": ".t--property-control-options mask",
|
||||
"inputRadio": ".t--draggable-radiogroupwidget input",
|
||||
"defaultSelect": ".t--property-control-defaultselectedvalue .CodeMirror-code",
|
||||
"formInner": ".t--draggable-formwidget span.t--widget-name",
|
||||
"radioInput": ".t--draggable-radiogroupwidget span.t--widget-name",
|
||||
"radioAddButton": ".t--property-control-options button",
|
||||
"formD": "div[type='FORM_WIDGET']",
|
||||
"datepickerFooter": ".bp3-datepicker-footer span",
|
||||
"disableJs": ".t--property-control-disable input[type='checkbox']",
|
||||
"switchWidget": ".t--draggable-switchwidget",
|
||||
"toggleJsDefaultDate": ".t--property-control-defaultdate .t--js-toggle",
|
||||
"toggleJsMinDate": ".t--property-control-mindate .t--js-toggle",
|
||||
"toggleJsMaxDate": ".t--property-control-maxdate .t--js-toggle"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -690,6 +690,37 @@ Cypress.Commands.add("switchToAPIInputTab", () => {
|
|||
.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) => {
|
||||
cy.xpath(option).click({ force: true });
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { ControlIcons } from "icons/ControlIcons";
|
|||
import { AnyStyledComponent } from "styled-components";
|
||||
import { Skin } from "constants/DefaultTheme";
|
||||
import AutoToolTipComponent from "components/designSystems/appsmith/TableComponent/AutoToolTipComponent";
|
||||
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent";
|
||||
import DatePickerComponent from "components/designSystems/blueprint/DatePickerComponent2";
|
||||
import {
|
||||
OperatorTypes,
|
||||
Condition,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import React from "react";
|
||||
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 { ComponentProps } from "components/designSystems/appsmith/BaseComponent";
|
||||
import { DateInput } from "@blueprintjs/datetime";
|
||||
|
|
@ -11,24 +15,30 @@ 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)`
|
||||
const StyledControlGroup = styled(ControlGroup)<{ isValid: boolean }>`
|
||||
&&& {
|
||||
.${Classes.INPUT} {
|
||||
box-shadow: none;
|
||||
color: ${Colors.OXFORD_BLUE};
|
||||
font-size: ${(props) => props.theme.fontSizes[3]}px;
|
||||
border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])};
|
||||
border-color: ${(props) =>
|
||||
!props.isValid ? IntentColors.danger : Colors.GEYSER_LIGHT};
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
height: inherit;
|
||||
align-items: center;
|
||||
&:active {
|
||||
border-color: ${Colors.HIT_GRAY};
|
||||
border-color: ${(props) =>
|
||||
!props.isValid ? IntentColors.danger : Colors.HIT_GRAY};
|
||||
}
|
||||
&:focus {
|
||||
border: ${(props) => getBorderCSSShorthand(props.theme.borders[2])};
|
||||
border-color: #80bdff;
|
||||
border-color: ${(props) =>
|
||||
!props.isValid ? IntentColors.danger : "#80bdff"};
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 0.1rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
|
@ -95,10 +105,17 @@ class DatePickerComponent extends React.Component<
|
|||
.clone()
|
||||
.set({ month: 11, date: 31, year: year + 20 })
|
||||
.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 (
|
||||
<StyledControlGroup
|
||||
fill
|
||||
isValid={isValid}
|
||||
onClick={(e: any) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
|
|
@ -115,29 +132,58 @@ class DatePickerComponent extends React.Component<
|
|||
</Label>
|
||||
)}
|
||||
{
|
||||
<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={
|
||||
this.state.selectedDate
|
||||
? this.parseDate(this.state.selectedDate)
|
||||
: null
|
||||
}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
/>
|
||||
<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 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 => {
|
||||
const dateFormat = this.props.dateFormat || ISO_DATE_FORMAT;
|
||||
return moment(date).format(dateFormat);
|
||||
|
|
@ -165,9 +211,6 @@ class DatePickerComponent extends React.Component<
|
|||
const date = selectedDate ? this.formatDate(selectedDate) : "";
|
||||
this.setState({ selectedDate: date });
|
||||
|
||||
// if date is null ( if date is cleared ), don't call onDateSelected
|
||||
if (!selectedDate) return false;
|
||||
|
||||
onDateSelected(date);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -5,8 +5,6 @@ import moment from "moment-timezone";
|
|||
import styled from "styled-components";
|
||||
import { TimePrecision } from "@blueprintjs/datetime";
|
||||
import { WidgetProps } from "widgets/BaseWidget";
|
||||
import { Toaster } from "components/ads/Toast";
|
||||
import { Variant } from "components/ads/common";
|
||||
import { ISO_DATE_FORMAT } from "constants/WidgetValidation";
|
||||
|
||||
const DatePickerControlWrapper = styled.div<{ isValid: boolean }>`
|
||||
|
|
@ -63,18 +61,22 @@ class DatePickerControl extends BaseControl<
|
|||
}
|
||||
|
||||
render() {
|
||||
const version = this.props.widgetProperties.version;
|
||||
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
|
||||
? this.validateDate(moment(this.state.selectedDate, dateFormat).toDate())
|
||||
: true;
|
||||
const maxDate =
|
||||
this.props.widgetProperties?.evaluatedValues?.maxDate ?? this.maxDate;
|
||||
const minDate =
|
||||
this.props.widgetProperties?.evaluatedValues?.minDate ?? this.minDate;
|
||||
|
||||
const value =
|
||||
this.props.propertyValue && isValid
|
||||
? version === 2
|
||||
? new Date(this.props.propertyValue)
|
||||
: this.parseDate(this.props.propertyValue)
|
||||
: null;
|
||||
return (
|
||||
<DatePickerControlWrapper isValid={isValid}>
|
||||
<DatePickerControlWrapper isValid={true}>
|
||||
<StyledDatePicker
|
||||
formatDate={this.formatDate}
|
||||
parseDate={this.parseDate}
|
||||
|
|
@ -83,21 +85,7 @@ class DatePickerControl extends BaseControl<
|
|||
timePrecision={TimePrecision.MINUTE}
|
||||
closeOnSelection
|
||||
onChange={this.onDateSelected}
|
||||
maxDate={
|
||||
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
|
||||
}
|
||||
value={value}
|
||||
/>
|
||||
</DatePickerControlWrapper>
|
||||
);
|
||||
|
|
@ -117,10 +105,13 @@ class DatePickerControl extends BaseControl<
|
|||
*/
|
||||
onDateSelected = (date: Date, isUserChange: boolean): void => {
|
||||
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);
|
||||
if (!isValid) return;
|
||||
|
||||
// if everything is ok, put date in state
|
||||
this.setState({ selectedDate: selectedDate });
|
||||
this.updateProperty(this.props.propertyName, selectedDate);
|
||||
|
|
@ -128,73 +119,14 @@ class DatePickerControl extends BaseControl<
|
|||
};
|
||||
|
||||
/**
|
||||
* checks:
|
||||
* 1. if max date is greater than the default date
|
||||
* 2. if default date is in range of min and max date
|
||||
* checks if date is of valid date format
|
||||
*/
|
||||
validateDate = (date: Date): boolean => {
|
||||
const dateFormat =
|
||||
this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
||||
const parsedSelectedDate = moment(date, dateFormat);
|
||||
//validate defaultDate if both minDate and maxDate is already selected
|
||||
if (this.props.propertyName === "defaultDate") {
|
||||
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;
|
||||
this.props.widgetProperties.version === 2
|
||||
? ISO_DATE_FORMAT
|
||||
: this.props.widgetProperties.dateFormat || ISO_DATE_FORMAT;
|
||||
return date ? moment(date, dateFormat).isValid() : true;
|
||||
};
|
||||
|
||||
formatDate = (date: Date): string => {
|
||||
|
|
@ -205,7 +137,9 @@ class DatePickerControl extends BaseControl<
|
|||
|
||||
parseDate = (dateStr: string): Date => {
|
||||
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);
|
||||
|
||||
if (date.isValid()) return moment(dateStr, dateFormat).toDate();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ const FIELD_VALUES: Record<
|
|||
isDisabled: "boolean",
|
||||
// onDateSelected: "Function Call",
|
||||
},
|
||||
DATE_PICKER_WIDGET2: {
|
||||
defaultDate: "string", //TODO:Vicky validate this property
|
||||
isRequired: "boolean",
|
||||
isVisible: "boolean",
|
||||
isDisabled: "boolean",
|
||||
// onDateSelected: "Function Call",
|
||||
},
|
||||
TABLE_WIDGET: {
|
||||
tableData: "Array<Object>",
|
||||
serverSidePaginationEnabled: "boolean",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ export const HelpMap = {
|
|||
path: "/widget-reference/datepicker",
|
||||
searchKey: "DatePicker",
|
||||
},
|
||||
DATE_PICKER_WIDGET2: {
|
||||
path: "/widget-reference/datepicker",
|
||||
searchKey: "DatePicker",
|
||||
},
|
||||
TABLE_WIDGET: {
|
||||
path: "/widget-reference/table",
|
||||
searchKey: "Table",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export enum WidgetTypes {
|
|||
INPUT_WIDGET = "INPUT_WIDGET",
|
||||
CONTAINER_WIDGET = "CONTAINER_WIDGET",
|
||||
DATE_PICKER_WIDGET = "DATE_PICKER_WIDGET",
|
||||
DATE_PICKER_WIDGET2 = "DATE_PICKER_WIDGET2",
|
||||
TABLE_WIDGET = "TABLE_WIDGET",
|
||||
DROP_DOWN_WIDGET = "DROP_DOWN_WIDGET",
|
||||
CHECKBOX_WIDGET = "CHECKBOX_WIDGET",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export type Validator = (
|
|||
dataTree?: DataTree,
|
||||
) => 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 = {
|
||||
true: "true",
|
||||
|
|
|
|||
|
|
@ -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 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_THIS_COLUMN = "Autofit this column";
|
||||
export const AUTOFIT_COLUMN = "Autofit column";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ describe("getAllPathsFromPropertyConfig", () => {
|
|||
isLoading: false,
|
||||
horizontalAlignment: "LEFT",
|
||||
parentColumnSpace: 74,
|
||||
version: 1,
|
||||
dynamicTriggerPathList: [
|
||||
{
|
||||
key: "primaryColumns.status.onClick",
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export const WidgetIcons: {
|
|||
<ContainerIcon />
|
||||
</IconWrapper>
|
||||
),
|
||||
DATE_PICKER_WIDGET: (props: IconProps) => (
|
||||
DATE_PICKER_WIDGET2: (props: IconProps) => (
|
||||
<IconWrapper {...props}>
|
||||
<DatePickerIcon />
|
||||
</IconWrapper>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
isDisabled: false,
|
||||
isVisible: true,
|
||||
isDefaultClickDisabled: true,
|
||||
version: 1,
|
||||
},
|
||||
TEXT_WIDGET: {
|
||||
text: "Label",
|
||||
|
|
@ -22,6 +23,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
rows: 1,
|
||||
columns: 4,
|
||||
widgetName: "Text",
|
||||
version: 1,
|
||||
},
|
||||
RICH_TEXT_EDITOR_WIDGET: {
|
||||
defaultText: "This is the initial <b>content</b> of the editor",
|
||||
|
|
@ -31,6 +33,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
isVisible: true,
|
||||
widgetName: "RichTextEditor",
|
||||
isDefaultClickDisabled: true,
|
||||
version: 1,
|
||||
},
|
||||
IMAGE_WIDGET: {
|
||||
defaultImage:
|
||||
|
|
@ -41,6 +44,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
rows: 3,
|
||||
columns: 4,
|
||||
widgetName: "Image",
|
||||
version: 1,
|
||||
},
|
||||
INPUT_WIDGET: {
|
||||
inputType: "TEXT",
|
||||
|
|
@ -48,6 +52,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
label: "",
|
||||
columns: 5,
|
||||
widgetName: "Input",
|
||||
version: 1,
|
||||
resetOnSubmit: true,
|
||||
},
|
||||
SWITCH_WIDGET: {
|
||||
|
|
@ -57,11 +62,13 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
defaultSwitchState: true,
|
||||
widgetName: "Switch",
|
||||
alignWidget: "LEFT",
|
||||
version: 1,
|
||||
},
|
||||
ICON_WIDGET: {
|
||||
widgetName: "Icon",
|
||||
rows: 1,
|
||||
columns: 1,
|
||||
version: 1,
|
||||
},
|
||||
CONTAINER_WIDGET: {
|
||||
backgroundColor: "#FFFFFF",
|
||||
|
|
@ -84,6 +91,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
},
|
||||
],
|
||||
},
|
||||
version: 1,
|
||||
},
|
||||
DATE_PICKER_WIDGET: {
|
||||
isDisabled: false,
|
||||
|
|
@ -94,14 +102,26 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
columns: 5,
|
||||
widgetName: "DatePicker",
|
||||
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: {
|
||||
rows: 7,
|
||||
columns: 7,
|
||||
widgetName: "Video",
|
||||
url: "https://www.youtube.com/watch?v=mzqK0QIZRLs",
|
||||
autoPlay: false,
|
||||
version: 1,
|
||||
},
|
||||
TABLE_WIDGET: {
|
||||
rows: 7,
|
||||
|
|
@ -137,6 +157,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
orderAmount: 19.99,
|
||||
},
|
||||
],
|
||||
version: 1,
|
||||
},
|
||||
DROP_DOWN_WIDGET: {
|
||||
rows: 1,
|
||||
|
|
@ -150,6 +171,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
],
|
||||
widgetName: "Dropdown",
|
||||
defaultOptionValue: "VEG",
|
||||
version: 1,
|
||||
},
|
||||
CHECKBOX_WIDGET: {
|
||||
rows: 1,
|
||||
|
|
@ -157,6 +179,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
label: "Label",
|
||||
defaultCheckedState: true,
|
||||
widgetName: "Checkbox",
|
||||
version: 1,
|
||||
alignWidget: "LEFT",
|
||||
},
|
||||
RADIO_GROUP_WIDGET: {
|
||||
|
|
@ -169,6 +192,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
],
|
||||
defaultOptionValue: "M",
|
||||
widgetName: "RadioGroup",
|
||||
version: 1,
|
||||
},
|
||||
ALERT_WIDGET: {
|
||||
alertType: "NOTIFICATION",
|
||||
|
|
@ -178,6 +202,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
header: "",
|
||||
message: "",
|
||||
widgetName: "Alert",
|
||||
version: 1,
|
||||
},
|
||||
FILE_PICKER_WIDGET: {
|
||||
rows: 1,
|
||||
|
|
@ -188,6 +213,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
maxFileSize: 5,
|
||||
widgetName: "FilePicker",
|
||||
isDefaultClickDisabled: true,
|
||||
version: 1,
|
||||
},
|
||||
TABS_WIDGET: {
|
||||
rows: 7,
|
||||
|
|
@ -224,6 +250,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
},
|
||||
],
|
||||
},
|
||||
version: 1,
|
||||
},
|
||||
MODAL_WIDGET: {
|
||||
rows: 6,
|
||||
|
|
@ -235,6 +262,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
shouldScrollContents: true,
|
||||
widgetName: "Modal",
|
||||
children: [],
|
||||
version: 1,
|
||||
blueprint: {
|
||||
view: [
|
||||
{
|
||||
|
|
@ -247,6 +275,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
isDisabled: false,
|
||||
shouldScrollContents: false,
|
||||
children: [],
|
||||
version: 1,
|
||||
blueprint: {
|
||||
view: [
|
||||
{
|
||||
|
|
@ -257,6 +286,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
iconName: "cross",
|
||||
iconSize: 24,
|
||||
color: "#040627",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -266,6 +296,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
props: {
|
||||
text: "Modal Title",
|
||||
textStyle: "HEADING",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -275,6 +306,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
props: {
|
||||
text: "Cancel",
|
||||
buttonStyle: "SECONDARY_BUTTON",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -284,6 +316,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
props: {
|
||||
text: "Confirm",
|
||||
buttonStyle: "PRIMARY_BUTTON",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -322,6 +355,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
rows: 0,
|
||||
columns: 0,
|
||||
widgetName: "Canvas",
|
||||
version: 1,
|
||||
},
|
||||
CHART_WIDGET: {
|
||||
rows: 8,
|
||||
|
|
@ -330,6 +364,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
chartType: "LINE_CHART",
|
||||
chartName: "Sales on working days",
|
||||
allowHorizontalScroll: false,
|
||||
version: 1,
|
||||
chartData: [
|
||||
{
|
||||
seriesName: "Sales",
|
||||
|
|
@ -374,6 +409,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
widgetName: "FormButton",
|
||||
text: "Submit",
|
||||
isDefaultClickDisabled: true,
|
||||
version: 1,
|
||||
},
|
||||
FORM_WIDGET: {
|
||||
rows: 13,
|
||||
|
|
@ -391,6 +427,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
canExtend: false,
|
||||
detachFromLayout: true,
|
||||
children: [],
|
||||
version: 1,
|
||||
blueprint: {
|
||||
view: [
|
||||
{
|
||||
|
|
@ -400,6 +437,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
props: {
|
||||
text: "Form",
|
||||
textStyle: "HEADING",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -411,6 +449,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
buttonStyle: "PRIMARY_BUTTON",
|
||||
disabledWhenInvalid: true,
|
||||
resetFormOnClick: true,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -422,6 +461,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
buttonStyle: "SECONDARY_BUTTON",
|
||||
disabledWhenInvalid: false,
|
||||
resetFormOnClick: true,
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -443,12 +483,14 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
|||
allowZoom: true,
|
||||
mapCenter: { lat: -34.397, long: 150.644 },
|
||||
defaultMarkers: [{ lat: -34.397, long: 150.644, title: "Test A" }],
|
||||
version: 1,
|
||||
},
|
||||
SKELETON_WIDGET: {
|
||||
isLoading: true,
|
||||
rows: 1,
|
||||
columns: 1,
|
||||
widgetName: "Skeleton",
|
||||
version: 1,
|
||||
},
|
||||
},
|
||||
configVersion: 1,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const WidgetSidebarResponse: WidgetCardProps[] = [
|
|||
key: generateReactKey(),
|
||||
},
|
||||
{
|
||||
type: "DATE_PICKER_WIDGET",
|
||||
type: "DATE_PICKER_WIDGET2",
|
||||
widgetCardName: "DatePicker",
|
||||
key: generateReactKey(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { ImageWidgetProps } from "widgets/ImageWidget";
|
|||
import { InputWidgetProps } from "widgets/InputWidget";
|
||||
import { RichTextEditorWidgetProps } from "widgets/RichTextEditorWidget";
|
||||
import { DatePickerWidgetProps } from "../../widgets/DatePickerWidget";
|
||||
import { DatePickerWidget2Props } from "../../widgets/DatePickerWidget2";
|
||||
import { TableWidgetProps } from "../../widgets/TableWidget/TableWidgetConstants";
|
||||
import { DropdownWidgetProps } from "../../widgets/DropdownWidget";
|
||||
import { CheckboxWidgetProps } from "../../widgets/CheckboxWidget";
|
||||
|
|
@ -59,6 +60,7 @@ export interface WidgetConfigReducerState {
|
|||
CONTAINER_WIDGET: Partial<ContainerWidgetProps<WidgetProps>> &
|
||||
WidgetConfigProps;
|
||||
DATE_PICKER_WIDGET: Partial<DatePickerWidgetProps> & WidgetConfigProps;
|
||||
DATE_PICKER_WIDGET2: Partial<DatePickerWidget2Props> & WidgetConfigProps;
|
||||
TABLE_WIDGET: Partial<TableWidgetProps> & WidgetConfigProps;
|
||||
VIDEO_WIDGET: Partial<VideoWidgetProps> & WidgetConfigProps;
|
||||
DROP_DOWN_WIDGET: Partial<DropdownWidgetProps> & WidgetConfigProps;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ function* getChildWidgetProps(
|
|||
parentColumnSpace,
|
||||
widgetName,
|
||||
widgetProps,
|
||||
restDefaultConfig.version,
|
||||
);
|
||||
|
||||
widget.widgetId = newWidgetId;
|
||||
|
|
@ -1411,6 +1412,7 @@ function* addTableWidgetFromQuerySaga(action: ReduxAction<string>) {
|
|||
parentRowSpace: GridDefaults.DEFAULT_GRID_ROW_HEIGHT,
|
||||
parentColumnSpace: 1,
|
||||
isLoading: false,
|
||||
version: 1,
|
||||
props: {
|
||||
tableData: `{{${queryName}.data}}`,
|
||||
dynamicBindingPathList: [{ key: "tableData" }],
|
||||
|
|
|
|||
|
|
@ -259,6 +259,18 @@ const dynamicPathListMigration = (
|
|||
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 = (
|
||||
currentDSL: ContainerWidgetProps<WidgetProps>,
|
||||
props = { counter: 1 },
|
||||
|
|
@ -367,6 +379,11 @@ const transformDSL = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
|
|||
currentDSL.version = 10;
|
||||
}
|
||||
|
||||
if (currentDSL.version === 10) {
|
||||
currentDSL = addVersionNumberMigration(currentDSL);
|
||||
currentDSL.version = 11;
|
||||
}
|
||||
|
||||
return currentDSL;
|
||||
};
|
||||
|
||||
|
|
@ -590,6 +607,7 @@ export const generateWidgetProps = (
|
|||
widgetId: string;
|
||||
renderMode: RenderMode;
|
||||
} & Partial<WidgetProps>,
|
||||
version: number,
|
||||
): ContainerWidgetProps<WidgetProps> => {
|
||||
if (parent) {
|
||||
const sizes = {
|
||||
|
|
@ -611,6 +629,7 @@ export const generateWidgetProps = (
|
|||
...sizes,
|
||||
...others,
|
||||
parentId: parent.widgetId,
|
||||
version,
|
||||
};
|
||||
delete props.rows;
|
||||
delete props.columns;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,10 @@ import DatePickerWidget, {
|
|||
DatePickerWidgetProps,
|
||||
ProfiledDatePickerWidget,
|
||||
} from "widgets/DatePickerWidget";
|
||||
import DatePickerWidget2, {
|
||||
DatePickerWidget2Props,
|
||||
ProfiledDatePickerWidget2,
|
||||
} from "widgets/DatePickerWidget2";
|
||||
import FormWidget, { ProfiledFormWidget } from "widgets/FormWidget";
|
||||
import FormButtonWidget, {
|
||||
FormButtonWidgetProps,
|
||||
|
|
@ -286,6 +290,20 @@ export default class WidgetBuilderRegistry {
|
|||
DatePickerWidget.getMetaPropertiesMap(),
|
||||
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(
|
||||
"TABS_WIDGET",
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,6 +124,15 @@ export const entityDefinitions = {
|
|||
selectedDate: "string",
|
||||
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: {
|
||||
"!doc":
|
||||
"Checkbox is a simple UI widget you can use when you want users to make a binary choice",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ describe("dataTreeTypeDefCreator", () => {
|
|||
topRow: 1,
|
||||
bottomRow: 2,
|
||||
isLoading: false,
|
||||
version: 1,
|
||||
bindingPaths: {
|
||||
defaultText: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const input1: ContainerWidgetProps<WidgetProps> = {
|
|||
widgetId: "fs785w9gcy",
|
||||
dynamicBindingPathList: [],
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -105,6 +106,7 @@ const input2: ContainerWidgetProps<WidgetProps> = {
|
|||
},
|
||||
],
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -157,6 +159,7 @@ const input3: ContainerWidgetProps<WidgetProps> = {
|
|||
onRowSelected: "{{showAlert('test','success')}}",
|
||||
onSearchTextChanged: "{{showAlert('fail','error')}}",
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -293,6 +296,7 @@ const output1 = {
|
|||
horizontalAlignment: "LEFT",
|
||||
verticalAlignment: "CENTER",
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -474,6 +478,7 @@ const output2 = {
|
|||
horizontalAlignment: "LEFT",
|
||||
verticalAlignment: "CENTER",
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -616,6 +621,7 @@ const output3 = {
|
|||
horizontalAlignment: "LEFT",
|
||||
verticalAlignment: "CENTER",
|
||||
renderMode: "CANVAS",
|
||||
version: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ export interface WidgetBaseProps {
|
|||
widgetName: string;
|
||||
parentId: string;
|
||||
renderMode: RenderMode;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export type WidgetRowCols = {
|
||||
|
|
|
|||
223
app/client/src/widgets/DatePickerWidget2.tsx
Normal file
223
app/client/src/widgets/DatePickerWidget2.tsx
Normal 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),
|
||||
);
|
||||
|
|
@ -289,6 +289,33 @@ const WIDGET_CONFIG_MAP: WidgetTypeConfigMap = {
|
|||
},
|
||||
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: {
|
||||
validations: {
|
||||
tabs: "TABS_DATA",
|
||||
|
|
@ -447,6 +474,7 @@ const BASE_WIDGET: DataTreeWidget = {
|
|||
topRow: 0,
|
||||
type: WidgetTypes.SKELETON_WIDGET,
|
||||
parentId: "0",
|
||||
version: 1,
|
||||
bindingPaths: {},
|
||||
triggerPaths: {},
|
||||
ENTITY_TYPE: ENTITY_TYPE.WIDGET,
|
||||
|
|
|
|||
|
|
@ -391,7 +391,10 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): 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) {
|
||||
return {
|
||||
|
|
@ -421,39 +424,22 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): 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) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: "",
|
||||
message:
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||
? props.dateFormat
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
|
||||
? dateFormat
|
||||
: "",
|
||||
};
|
||||
}
|
||||
const parsedCurrentDate = moment(dateString, dateFormat);
|
||||
let 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;
|
||||
}
|
||||
}
|
||||
const isValid = parsedCurrentDate.isValid();
|
||||
if (!isValid) {
|
||||
return {
|
||||
isValid: isValid,
|
||||
|
|
@ -471,14 +457,17 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): 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) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: "",
|
||||
message:
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||
? props.dateFormat
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
|
||||
? dateFormat
|
||||
: "",
|
||||
};
|
||||
}
|
||||
|
|
@ -517,14 +506,17 @@ export const VALIDATORS: Record<ValidationType, Validator> = {
|
|||
dateString: string,
|
||||
props: WidgetProps,
|
||||
): 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) {
|
||||
return {
|
||||
isValid: false,
|
||||
parsed: "",
|
||||
message:
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + props.dateFormat
|
||||
? props.dateFormat
|
||||
`${WIDGET_TYPE_VALIDATION_ERROR}: Date ` + dateFormat
|
||||
? dateFormat
|
||||
: "",
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user