feat: App Theming (#9714)
* fix style bugs * fix select styles * test: fix font size issue for cypress tests * incorporate ashit feedback * test: addresed review comments for cypress tests * add analytics events * height issue in view mode * incorporate code review feedbacks * incorporate code review feedbacks * refactor: addressed review comments; removed border radius and box shadow for text widget; Updated migrations * feat: Makes shadow and radius controls keyboard accessible (#11547) * makes shadow and radius controls keyboard accessible * removes unused imports * moves options out of render method * fix: changed the misnomer background property name to the relevant property name * fix: border radius issue for the map widget * address qa bugs * address qa bugs * fix ux of theming pane when widget is selected * fix: * added backgroundColor to the video widget * restricted pop-over border radius to 0.375rem * added box shadow for the input group for select widget * fix: added delete icon in the delete theme modal * address qa bugs * change checkbox column size in config * add js convertible to button color * remove unused imports * test: fixed jest tests * fix primary color typo * fix: migrations for the theming * fix: * Removed background color from MultiTreeSelect and TreeSelect component. * grouped button's menu button pop over border radius restricting to 0.375rem. * test: updated Dsl migration UT * address qa bugs * address qa bugs * fix: address qa comments * address qa bugs * fix: * migration issue; * unit test cases; * fix rating widget scroll issue * fix youtube video border radius bug * fix select widget * fix select widgets styles * address qa bugs * merge conflicts * makes the reset button keyboard accessible (#12134) * -resolved merge conflicts * address qa bugs * fix: labelTextSize migration fixes * refactor: * made changes to the fontSizeUtils function * fixed the issue related to unit tests * fix button group widget * remove unused imports * fix: fixed the text size migration for the table widget * refactor: addressed review comments for the table widget theming migration * fix button group widget * add init calls for view mode * json form init theme changes * fix: added migration for boxShadow, borderRadius and textSizes for table widget * fix broken fields * test: fixed unit tests * wip * inconsistancy fixes and schemaItem update in updateHook/fieldConfiguration * feat: init json form migration theming * json form primaryColor -> accentColor * update table widget * update table widget * object field label styling * fix: migration related to the JSON form * fix: fixed labelTextSize migration for JSON form nested widgets * property control nested stylesheet lookup * JSONForm label styles form array items * show label for checkbox field array item * fix button group widget * wip * refactor: addressed table widget review comments * refactor: addressed ashit review comments; * added childStylesheet for widgets * feat: Keyboard navigable Color Picker control (#11797) * Makes ColorPicker keyboard accessible * seperate out keyboard and mouse interactions * fix issue with not focusing back to input * Adds test for Color picker * chore: added comment for the boxShadow property * fix: * added unit test cases for the widget and property utils * resolved warning messages * wip * theme config update * fix merge conflicts * refactor: moved theming migration inside the migrations folder * fix qa bugs * fix jest test * fix: unit test cases * fix table column creation logic * refactor: addressed review comments for migrations * fix: Overriding margin and padding for custom render in the dropdown component (#12875) * * fix for custom render padding and margin in ADS dropdown * * fix for removing padding from normal render options * refactor: moved the boxShadow condition to the variable * fix qa bugs * fix: migration QA callouts for audio recorder widget * refactor: added updated comments for boxShadow migration for table widget * fix theme binfings for JSONForm fields under Object * fix table widget theming bug * fix: addressed code review comments * fix: unit test cases * fix: qa migration callouts * fix table widget theming bug * fix JSONForm currency input dropdown not submit form * Added new tests - AppThemingSpec * fix qa bugs * fix unit test * fix JSONForm cellBorderWidth to have default value post migration * fix unit test * fix qa bugs * remove unused imports * fix qa bugs * fix JSONForm input height issue * fix qa bugs * Updating Theming spec * * dropdown color fixes (#13249) * fix caching issue ; * Fixed Theming tests * fix tests * fix tab widget tests * fix: json form children level migration issue * fix table widget tests * Updated test * updated tests * updated test * updated tests * updated tests * updated pageload * fix cypress tests * remove cypress created files * fix color picker issues * Failure fixes * Fixed some more tests * fix: cypress test failures * fix tests * remove consoles * fix table tests * fix qa bugs * updating snapshots for AppPageLayout_spec as per new UI * fix rating widget bug * fix qa bugs * fix: * cypress failing tests * Migration QA callouts * Removed unused imports * update constract check algo * fix color contrast issue * fix: cypress failure test cases * update font sizes labels * fix regression bugs * fix: * JSON form labelTextSize issue fix * Updated comment for the fontSizeUtility function * migrations issues related to table widget borderRadius and boxShadow * fix: default labelTextSize issue for the Input and Select families * fix regression bugs * fix regression bugs * PassingParams spec - added wait time * fix: font family default value issue on JS toggle * fix js toggle issue in text widget * fix tests * fix tests * fix tests * fix cypress tests * fix regression bugs * fix regression bugs * fix: * refactored table widget migration function as per review comments, * added default value to the widget * fix: failing unit test cases * fix theming spec * fix cypress tests * test: fixed failed cypress test * incorporate ashit feedback * fix cypress tests * fix: addressed review comments * comment out table cypress test * fix merge conflicts * comment out color picker tests Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local> Co-authored-by: keyurparalkar <keyur@appsmith.com> Co-authored-by: Aswath K <aswath@appsmith.com> Co-authored-by: Nayan <nayan@appsmith.com> Co-authored-by: Ashit Rath <ashit@appsmith.com> Co-authored-by: balajisoundar <balaji@appsmith.com> Co-authored-by: albinAppsmith <87797149+albinAppsmith@users.noreply.github.com> Co-authored-by: Aishwarya UR <aishwarya@appsmith.com> Co-authored-by: apple <nandan@thinkify.io> Co-authored-by: Parthvi Goswami <parthvigoswami@Parthvis-MacBook-Pro.local>
This commit is contained in:
parent
8163becacc
commit
809a633306
|
|
@ -108,9 +108,9 @@
|
|||
"TextLabelValue": "Test Text Label",
|
||||
"TextLabelValueScrollable": "Test Text Label to check scroll feature",
|
||||
"TextName": "TestTextBox",
|
||||
"TextLabel": "Paragraph",
|
||||
"TextBody": "Heading 2",
|
||||
"TextHeading": "Heading 1",
|
||||
"TextLabel": "S",
|
||||
"TextBody": "L",
|
||||
"TextHeading": "M",
|
||||
"Datepickername": "Datepicker",
|
||||
"DatepickerLable": "date",
|
||||
"RichTextEditorName": "RichtextEditor",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||
const widgetLocators = require("../../../../locators/publishWidgetspage.json");
|
||||
const widgetsPage = require("../../../../locators/Widgets.json");
|
||||
const explorer = require("../../../../locators/explorerlocators.json");
|
||||
const publish = require("../../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../../fixtures/replay.json");
|
||||
|
||||
describe("App Theming funtionality", function() {
|
||||
/**
|
||||
* Test cases; Check:
|
||||
* 1. If theme can be changed*
|
||||
* 2. If the theme can edited*
|
||||
* 4. If the save theme can be used.
|
||||
* 5. If the theme can be deleled
|
||||
*/
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
|
||||
it("checks if theme can be changed", function() {
|
||||
cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
// select a theme
|
||||
cy.get(commonlocators.themeCard)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
|
||||
// check for alert
|
||||
cy.get(`${commonlocators.themeCard}`)
|
||||
.last()
|
||||
.siblings("div")
|
||||
.first()
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
cy.get(commonlocators.toastmsg).contains(`Theme ${text} Applied`);
|
||||
});
|
||||
|
||||
// check if color of canvas is same as theme bg color
|
||||
cy.get(`${commonlocators.themeCard} > main`)
|
||||
.last()
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
cy.get(commonlocators.canvas).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
backgroudColor,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("checks if theme can be edited", function() {
|
||||
// drop a button widget and click on body
|
||||
cy.get(explorer.addWidget).click();
|
||||
cy.dragAndDropToCanvas("buttonwidget", { x: 300, y: 80 });
|
||||
cy.wait(5000);
|
||||
cy.get("#canvas-selection-0").click({ force: true });
|
||||
|
||||
//Click the back button
|
||||
//cy.get(commonlocators.selectThemeBackBtn).click({ force: true });
|
||||
|
||||
//Click the border radius toggle
|
||||
|
||||
// change app border radius
|
||||
cy.get(commonlocators.themeAppBorderRadiusBtn)
|
||||
.eq(1)
|
||||
.click({ force: true });
|
||||
|
||||
// check if border radius is changed on button
|
||||
cy.get(`${commonlocators.themeAppBorderRadiusBtn} > div`)
|
||||
.eq(1)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
|
||||
// publish the app
|
||||
// cy.PublishtheApp();
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
});
|
||||
cy.contains("Border").click({ force: true });
|
||||
//Change the font
|
||||
|
||||
cy.get("span[name='expand-more']").then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.wait(250);
|
||||
cy.get(".ads-dropdown-options-wrapper div")
|
||||
.children()
|
||||
.eq(2)
|
||||
.then(($childElem) => {
|
||||
cy.get($childElem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
$childElem
|
||||
.children()
|
||||
.last()
|
||||
.text(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
cy.contains("Font").click({ force: true });
|
||||
|
||||
//Change the shadow
|
||||
cy.contains("App Box Shadow")
|
||||
.siblings("div")
|
||||
.children("span")
|
||||
.last()
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
$elem.css("box-shadow"),
|
||||
);
|
||||
});
|
||||
cy.contains("Shadow").click({ force: true });
|
||||
|
||||
//Change the primary color:
|
||||
cy.get(".border-2")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(".t--colorpicker-v2-popover input").click({ force: true });
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(-3)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
|
||||
//Change the background color:
|
||||
cy.get(".border-2")
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.get(".t--colorpicker-v2-popover input").click({ force: true });
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.first()
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(commonlocators.canvas).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("Checks if the theme can be saved", () => {
|
||||
//Click on dropDown elipses
|
||||
cy.get(".t--property-pane-sidebar .remixicon-icon")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
// .then(($elem) => {
|
||||
// cy.get(`${$elem} button`).click({ force: true });
|
||||
// })
|
||||
cy.wait(1000);
|
||||
|
||||
//Click on save theme dropdown option
|
||||
cy.contains("Save theme").click({ force: true });
|
||||
|
||||
cy.wait(200);
|
||||
|
||||
//Type the name of the theme:
|
||||
cy.get("input[placeholder='My theme']").type("testtheme");
|
||||
|
||||
//Click on save theme button
|
||||
cy.get("a[type='submit']").click({ force: true });
|
||||
|
||||
cy.wait(200);
|
||||
|
||||
//Click on change theme:
|
||||
cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
//Check if the saved theme is present under 'Yours Themes' section
|
||||
cy.contains("Your Themes")
|
||||
.siblings()
|
||||
.find(".t--theme-card")
|
||||
.parent()
|
||||
.should("contain.text", "testtheme");
|
||||
});
|
||||
|
||||
it("Checks if the theme can be deleted", () => {
|
||||
cy.wait(300);
|
||||
|
||||
//Check if the saved theme is present under 'Yours Themes' section
|
||||
cy.contains("Your Themes")
|
||||
.siblings()
|
||||
.find(".t--theme-card")
|
||||
.parent()
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
|
||||
cy.contains("Delete").click({ force: true });
|
||||
|
||||
//check for delete alert
|
||||
cy.wait(1000);
|
||||
cy.get(commonlocators.toastMsg).contains("Theme testtheme Deleted");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,969 @@
|
|||
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||
const widgetsPage = require("../../../../locators/Widgets.json");
|
||||
const explorer = require("../../../../locators/explorerlocators.json");
|
||||
const publish = require("../../../../locators/publishWidgetspage.json");
|
||||
const dsl = require("../../../../fixtures/replay.json");
|
||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
let ee = ObjectsRegistry.EntityExplorer;
|
||||
|
||||
describe("App Theming funtionality", function() {
|
||||
before(() => {
|
||||
cy.addDsl(dsl);
|
||||
});
|
||||
|
||||
let themesSection = (sectionName, themeName) =>
|
||||
"//*[text()='" +
|
||||
sectionName +
|
||||
"']/following-sibling::div//*[text()='" +
|
||||
themeName +
|
||||
"']";
|
||||
let applyTheme = (sectionName, themeName) =>
|
||||
themesSection(sectionName, themeName) +
|
||||
"/parent::div/following-sibling::div[contains(@class, 't--theme-card')]//div[text()='Apply Theme']";
|
||||
let themesDeletebtn = (sectionName, themeName) =>
|
||||
themesSection(sectionName, themeName) + "/following-sibling::button";
|
||||
|
||||
it("1. Checks if theme can be changed to one of the existing themes", function() {
|
||||
cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
// select a theme
|
||||
cy.get(commonlocators.themeCard)
|
||||
.last()
|
||||
.click({ force: true });
|
||||
|
||||
// check for alert
|
||||
cy.get(`${commonlocators.themeCard}`)
|
||||
.last()
|
||||
.siblings("div")
|
||||
.first()
|
||||
.invoke("text")
|
||||
.then((text) => {
|
||||
cy.get(commonlocators.toastmsg).contains(`Theme ${text} Applied`);
|
||||
});
|
||||
|
||||
// check if color of canvas is same as theme bg color
|
||||
cy.get(`${commonlocators.themeCard} > main`)
|
||||
.last()
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
cy.get(commonlocators.canvas).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
backgroudColor,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("2. Checks if theme can be edited", function() {
|
||||
cy.get(commonlocators.selectThemeBackBtn).click({ force: true });
|
||||
// drop a button widget and click on body
|
||||
cy.get(explorer.widgetSwitchId).click();
|
||||
cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 200 }); //iconbuttonwidget
|
||||
cy.assertPageSave();
|
||||
cy.get("canvas")
|
||||
.first(0)
|
||||
.trigger("click", { force: true });
|
||||
|
||||
//Click the back button //Commenting below since expanded by default
|
||||
//cy.get(commonlocators.selectThemeBackBtn).click({ force: true });
|
||||
|
||||
//Click the border radius toggle
|
||||
// cy.contains("Border")
|
||||
// .click({ force: true })
|
||||
// .wait(500);
|
||||
|
||||
// change app border radius
|
||||
cy.get(commonlocators.themeAppBorderRadiusBtn)
|
||||
.eq(1)
|
||||
.click({ force: true });
|
||||
|
||||
// check if border radius is changed on button
|
||||
cy.get(`${commonlocators.themeAppBorderRadiusBtn} > div`)
|
||||
.eq(1)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
|
||||
// publish the app
|
||||
// cy.PublishtheApp();
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
});
|
||||
|
||||
//Change the color://Commenting below since expanded by default
|
||||
//cy.contains("Color").click({ force: true });
|
||||
|
||||
//Change the primary color:
|
||||
cy.get(".border-2")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait(500);
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(-3)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
|
||||
//Change the background color:
|
||||
cy.get(".border-2")
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.wait(500);
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.first()
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(commonlocators.canvas).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
|
||||
//Change the shadow //Commenting below since expanded by default
|
||||
//cy.contains("Shadow").click({ force: true });
|
||||
cy.contains("App Box Shadow")
|
||||
.siblings("div")
|
||||
.children("span")
|
||||
.last()
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
$elem.css("box-shadow"),
|
||||
);
|
||||
});
|
||||
|
||||
//Change the font //Commenting below since expanded by default
|
||||
//cy.contains("Font").click({ force: true });
|
||||
|
||||
cy.get("span[name='expand-more']").then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.wait(250);
|
||||
cy.get(".ads-dropdown-options-wrapper div")
|
||||
.children()
|
||||
.eq(2)
|
||||
.then(($childElem) => {
|
||||
cy.get($childElem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
$childElem
|
||||
.children()
|
||||
.last()
|
||||
.text(),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("3. Checks if the theme can be saved", () => {
|
||||
//Click on dropDown elipses
|
||||
cy.contains("Theme Properties")
|
||||
.closest("div")
|
||||
.siblings()
|
||||
.first()
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
// .then(($elem) => {
|
||||
// cy.get(`${$elem} button`).click({ force: true });
|
||||
// })
|
||||
|
||||
cy.wait(300);
|
||||
|
||||
//Click on save theme dropdown option
|
||||
cy.contains("Save theme").click({ force: true });
|
||||
|
||||
cy.wait(200);
|
||||
|
||||
//Type the name of the theme:
|
||||
cy.get("input[placeholder='My theme']").type("testtheme");
|
||||
|
||||
//Click on save theme button
|
||||
cy.get("a[type='submit']").click({ force: true });
|
||||
|
||||
cy.wait(200);
|
||||
cy.get(commonlocators.toastMsg).contains("Theme testtheme Saved");
|
||||
});
|
||||
|
||||
it("4. Verify Save Theme after changing all properties & widgets conform to the selected theme", () => {
|
||||
cy.get(explorer.widgetSwitchId).click();
|
||||
cy.dragAndDropToCanvas("iconbuttonwidget", { x: 200, y: 300 });
|
||||
cy.assertPageSave();
|
||||
cy.get("canvas")
|
||||
.first(0)
|
||||
.trigger("click", { force: true });
|
||||
|
||||
//#region Change Font & verify widgets:
|
||||
// cy.contains("Font")
|
||||
// .click({ force: true })
|
||||
// .wait(200);//Commenting below since expanded by default
|
||||
cy.get("span[name='expand-more']").then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.wait(250);
|
||||
cy.get(".ads-dropdown-options-wrapper div")
|
||||
.children()
|
||||
.eq(4)
|
||||
.then(($childElem) => {
|
||||
cy.get($childElem).click({ force: true });
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
$childElem
|
||||
.children()
|
||||
.last()
|
||||
.text(),
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"font-family",
|
||||
$childElem
|
||||
.children()
|
||||
.last()
|
||||
.text(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Change Color & verify widgets:
|
||||
//Change the primary color:
|
||||
// cy.contains("Color")
|
||||
// .click({ force: true })
|
||||
// .wait(200);
|
||||
cy.get(".border-2")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait(500);
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(-15)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
|
||||
//Change the background color:
|
||||
cy.get(".border-2")
|
||||
.last()
|
||||
.click({ force: true });
|
||||
cy.wait(500);
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(23)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(commonlocators.canvas).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"),
|
||||
);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Change Border radius & verify widgets
|
||||
// cy.contains("Border")
|
||||
// .click({ force: true })
|
||||
// .wait(200);
|
||||
cy.get(commonlocators.themeAppBorderRadiusBtn)
|
||||
.eq(2)
|
||||
.click({ force: true });
|
||||
cy.get(`${commonlocators.themeAppBorderRadiusBtn} > div`)
|
||||
.eq(2)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius,
|
||||
);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Change the shadow & verify widgets
|
||||
//cy.contains("Shadow").click({ force: true });
|
||||
cy.contains("App Box Shadow")
|
||||
.siblings("div")
|
||||
.children("span")
|
||||
.first()
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
$elem.css("box-shadow"),
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
$elem.css("box-shadow"),
|
||||
);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Click on dropDown elipses
|
||||
cy.contains("Theme Properties")
|
||||
.closest("div")
|
||||
.siblings()
|
||||
.first()
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
cy.wait(300);
|
||||
//#endregion
|
||||
|
||||
//Click on save theme dropdown option & close it
|
||||
cy.contains("Save theme").click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.xpath("//*[text()='Save Theme']/following-sibling::button").click();
|
||||
|
||||
//Click on save theme dropdown option & cancel it
|
||||
cy.contains("Theme Properties")
|
||||
.closest("div")
|
||||
.siblings()
|
||||
.first()
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
cy.wait(300);
|
||||
cy.contains("Save theme").click({ force: true });
|
||||
cy.wait(200);
|
||||
cy.xpath("//span[text()='Cancel']/parent::a").click();
|
||||
|
||||
//Click on save theme dropdown option, give duplicte name & save it
|
||||
cy.contains("Theme Properties")
|
||||
.closest("div")
|
||||
.siblings()
|
||||
.first()
|
||||
.find("button")
|
||||
.click({ force: true });
|
||||
cy.wait(300);
|
||||
cy.contains("Save theme").click({ force: true });
|
||||
cy.wait(200);
|
||||
//Type the name of the theme:
|
||||
cy.get("input[placeholder='My theme']").type("testtheme");
|
||||
cy.contains("Name must be unique");
|
||||
|
||||
cy.get("input[placeholder='My theme']")
|
||||
.clear()
|
||||
.type("VioletYellowTheme");
|
||||
|
||||
//Click on save theme button
|
||||
cy.xpath("//span[text()='Save theme']/parent::a").click({ force: true });
|
||||
|
||||
cy.wait(200);
|
||||
cy.get(commonlocators.toastMsg).contains("Theme VioletYellowTheme Saved");
|
||||
});
|
||||
|
||||
it("5. Verify Themes exists under respective section when ChangeTheme button is cicked in properties with Apply Theme & Trash as applicable", () => {
|
||||
//Click on change theme:
|
||||
cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
cy.xpath(applyTheme("Your Themes", "testtheme"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to testtheme
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > main")
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(131, 24, 67)");
|
||||
});
|
||||
|
||||
//Check if the saved theme is present under 'Yours Themes' section with Trash button
|
||||
cy.xpath(applyTheme("Your Themes", "testtheme")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Your Themes", "testtheme")).should("exist");
|
||||
|
||||
cy.xpath(applyTheme("Your Themes", "VioletYellowTheme")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Your Themes", "VioletYellowTheme")).should(
|
||||
"exist",
|
||||
);
|
||||
|
||||
cy.xpath(applyTheme("Featured Themes", "Classic")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Featured Themes", "Classic")).should("not.exist");
|
||||
|
||||
cy.xpath(applyTheme("Featured Themes", "Modern")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Featured Themes", "Modern")).should("not.exist");
|
||||
|
||||
cy.xpath(applyTheme("Featured Themes", "Sharp")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Featured Themes", "Sharp")).should("not.exist");
|
||||
|
||||
cy.xpath(applyTheme("Featured Themes", "Rounded")).should("exist");
|
||||
cy.xpath(themesDeletebtn("Featured Themes", "Rounded")).should("not.exist");
|
||||
|
||||
// cy.contains("Featured Themes")
|
||||
// .siblings()
|
||||
// .find(".t--theme-card")
|
||||
// .siblings()
|
||||
// .should("contain.text", "Rounded").siblings()
|
||||
// .contains('Apply Theme');
|
||||
});
|
||||
|
||||
it("6. Verify the custom theme can be deleted", () => {
|
||||
//Check if the saved theme is present under 'Yours Themes' section
|
||||
// cy.contains("Your Themes")
|
||||
// .siblings()
|
||||
// .find(".t--theme-card")
|
||||
// .parent()
|
||||
// .find("button").eq(0)
|
||||
// .click({ force: true });
|
||||
// cy.wait(200);
|
||||
|
||||
cy.xpath(themesDeletebtn("Your Themes", "testtheme"))
|
||||
.click()
|
||||
.wait(200);
|
||||
cy.contains(
|
||||
"Do you really want to delete this theme? This process cannot be undone.",
|
||||
);
|
||||
|
||||
//Click on Delete theme trash icon & close it
|
||||
cy.xpath("//*[text()='Are you sure?']/following-sibling::button").click();
|
||||
cy.get(commonlocators.toastMsg).should("not.exist");
|
||||
|
||||
//Click on Delete theme trash icon & cancel it
|
||||
cy.xpath(themesDeletebtn("Your Themes", "testtheme"))
|
||||
.click()
|
||||
.wait(200);
|
||||
cy.xpath("//span[text()='Cancel']/parent::a").click();
|
||||
cy.get(commonlocators.toastMsg).should("not.exist");
|
||||
|
||||
//Click on Delete theme trash icon & delete it
|
||||
cy.xpath(themesDeletebtn("Your Themes", "testtheme"))
|
||||
.click()
|
||||
.wait(200);
|
||||
cy.contains("Delete").click({ force: true });
|
||||
|
||||
//check for delete alert
|
||||
cy.wait(500);
|
||||
cy.get(commonlocators.toastMsg).contains("Theme testtheme Deleted");
|
||||
cy.xpath(applyTheme("Your Themes", "testtheme")).should("not.exist");
|
||||
});
|
||||
|
||||
it("7. Verify user able to change between saved theme & already existing Featured themes", () => {
|
||||
//#region Modern
|
||||
cy.xpath(applyTheme("Featured Themes", "Modern"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to one of featured themes
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(85, 61, 233)");
|
||||
});
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(246, 246, 246)");
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Classic
|
||||
cy.xpath(applyTheme("Featured Themes", "Classic"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to one of featured themes
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(22, 163, 74)");
|
||||
});
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(246, 246, 246)");
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Sharp
|
||||
cy.xpath(applyTheme("Featured Themes", "Sharp"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to one of featured themes
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(59, 125, 221)");
|
||||
});
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(255, 255, 255)");
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Rounded
|
||||
cy.xpath(applyTheme("Featured Themes", "Rounded"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to one of featured themes
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(222, 21, 147)");
|
||||
});
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(246, 246, 246)");
|
||||
});
|
||||
//#endregion
|
||||
|
||||
//#region VioletYellowTheme
|
||||
cy.xpath(applyTheme("Your Themes", "VioletYellowTheme"))
|
||||
.click({ force: true })
|
||||
.wait(1000); //Changing to created test theme
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(0)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(126, 34, 206)");
|
||||
});
|
||||
|
||||
cy.contains("Current Theme")
|
||||
.click()
|
||||
.parent()
|
||||
.siblings()
|
||||
.find(".t--theme-card > main > section > div > main")
|
||||
.eq(1)
|
||||
.invoke("css", "background-color")
|
||||
.then((backgroudColor) => {
|
||||
expect(backgroudColor).to.eq("rgb(253, 224, 71)");
|
||||
});
|
||||
|
||||
//#endregion
|
||||
});
|
||||
|
||||
it("8. Verify widgets conform to the selected theme in Publish mode", () => {
|
||||
cy.PublishtheApp();
|
||||
|
||||
cy.wait(2000); //for theme to settle
|
||||
|
||||
cy.get("body").should("have.css", "font-family", "Montserrat"); //Font
|
||||
|
||||
cy.xpath("//div[@id='root']//section/parent::div").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(253, 224, 71)",
|
||||
); //Background Color
|
||||
cy.get(widgetsPage.widgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
); //Widget Color
|
||||
cy.get(publish.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
); //Widget Color
|
||||
|
||||
cy.get(widgetsPage.widgetBtn).should("have.css", "border-radius", "24px"); //Border Radius
|
||||
cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px"); //Border Radius
|
||||
|
||||
cy.get(widgetsPage.widgetBtn).should("have.css", "box-shadow", "none"); //Shadow
|
||||
cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none"); //Shadow
|
||||
|
||||
//Verify Share button
|
||||
cy.contains("Share").should(
|
||||
"have.css",
|
||||
"border-top-color",
|
||||
"rgb(126, 34, 206)",
|
||||
); //Color
|
||||
cy.contains("Share")
|
||||
.closest("div")
|
||||
.should("have.css", "font-family", "Montserrat"); //Font
|
||||
|
||||
//Verify Edit App button
|
||||
cy.contains("Edit App").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
); //Color
|
||||
cy.contains("Edit App")
|
||||
.closest("div")
|
||||
.should("have.css", "font-family", "Montserrat"); //Font
|
||||
|
||||
cy.get(publish.backToEditor)
|
||||
.click({ force: true })
|
||||
.wait(3000);
|
||||
});
|
||||
|
||||
it("9. Verify Adding new Individual widgets & it can change Color, Border radius, Shadow & can revert [Color/Border Radius] to already selected theme", () => {
|
||||
cy.get(explorer.widgetSwitchId).click();
|
||||
cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 400 }); //another button widget
|
||||
cy.assertPageSave();
|
||||
|
||||
//Change Color & verify
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(35)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"), //rgb(134, 239, 172)
|
||||
); //new widget with its own color
|
||||
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should("have.css", "background-color", "rgb(126, 34, 206)"); //old widgets still conforming to theme color
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
});
|
||||
|
||||
//Change Border & verify
|
||||
|
||||
cy.get(".t--button-tab-0px").click();
|
||||
cy.get(".t--button-tab-0px")
|
||||
.eq(0)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius, //0px
|
||||
);
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
"24px",
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should("have.css", "border-radius", "24px");
|
||||
});
|
||||
|
||||
//Change Shadow & verify
|
||||
cy.get(".t--button-tab-0.10px").click();
|
||||
cy.get(".t--button-tab-0.10px div")
|
||||
.eq(0)
|
||||
.invoke("css", "box-shadow")
|
||||
.then((boxshadow) => {
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
boxshadow, //rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px
|
||||
);
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
"none",
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should("have.css", "box-shadow", "none");
|
||||
});
|
||||
|
||||
cy.assertPageSave();
|
||||
|
||||
//the new widget with changed styles is not showin in deploy mode - hence commenting below
|
||||
// cy.PublishtheApp();
|
||||
|
||||
// //Verify Background color
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgb(134, 239, 172)", //rgb(134, 239, 172)
|
||||
// ); //new widget with its own color
|
||||
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgb(126, 34, 206)",
|
||||
// ); //old widgets still conforming to theme color
|
||||
// cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgb(126, 34, 206)",
|
||||
// );
|
||||
|
||||
// //Verify Border radius
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should(
|
||||
// "have.css",
|
||||
// "border-radius",
|
||||
// "0px"
|
||||
// );
|
||||
// cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
// "have.css",
|
||||
// "border-radius",
|
||||
// "24px",
|
||||
// );
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should(
|
||||
// "have.css",
|
||||
// "border-radius",
|
||||
// "24px",
|
||||
// );
|
||||
|
||||
// //Verify Box shadow
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should(
|
||||
// "have.css",
|
||||
// "box-shadow",
|
||||
// "rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px"
|
||||
// );
|
||||
// cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
// "have.css",
|
||||
// "box-shadow",
|
||||
// "none",
|
||||
// );
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should(
|
||||
// "have.css",
|
||||
// "box-shadow",
|
||||
// "none",
|
||||
// );
|
||||
|
||||
// cy.get(publish.backToEditor).click({ force: true }).wait(1000);
|
||||
|
||||
//Resetting back to theme
|
||||
ee.NavigateToSwitcher("explorer");
|
||||
ee.expandCollapseEntity("WIDGETS"); //to expand widgets
|
||||
ee.SelectEntityByName("Button2");
|
||||
cy.get(".t--property-control-buttoncolor .reset-button").then(($elem) => {
|
||||
$elem[0].removeAttribute("display: none");
|
||||
$elem[0].click();
|
||||
});
|
||||
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should("have.css", "background-color", "rgb(126, 34, 206)"); //verify widget reverted to theme color
|
||||
|
||||
cy.get(".t--property-control-borderradius .reset-button").then(($elem) => {
|
||||
$elem[0].removeAttribute("display: none");
|
||||
$elem[0].click();
|
||||
});
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should("have.css", "border-radius", "24px");
|
||||
|
||||
//the new widget with reverted styles is not showin in deploy mode - hence commenting below
|
||||
// cy.PublishtheApp();
|
||||
|
||||
// cy.wait(2000)//for theme to settle
|
||||
// cy.get('body').should('have.css', "font-family", "Montserrat")//Font
|
||||
|
||||
// cy.xpath("//div[@id='root']//section/parent::div").should('have.css', "background-color", "rgb(253, 224, 71)")//Background Color
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should("have.css", "background-color", "rgb(126, 34, 206)");//Widget Color
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should("have.css", "background-color", "rgb(126, 34, 206)");//Widget Color
|
||||
// cy.get(publish.iconWidgetBtn).should("have.css", "background-color", "rgb(126, 34, 206)",);//Widget Color
|
||||
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should("have.css", "border-radius", "24px",);//Border Radius
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should("have.css", "border-radius", "24px",);//Border Radius
|
||||
// cy.get(publish.iconWidgetBtn).should("have.css", "border-radius", "24px",);//Border Radius
|
||||
|
||||
// cy.get(widgetsPage.widgetBtn).eq(0).should("have.css", "box-shadow", "none");//Shadow
|
||||
// cy.get(widgetsPage.widgetBtn).eq(1).should("have.css", "box-shadow", "none");//Shadow
|
||||
// cy.get(publish.iconWidgetBtn).should("have.css", "box-shadow", "none");//Shadow
|
||||
|
||||
// //Verify Share button
|
||||
// cy.contains('Share').should("have.css", "border-top-color", "rgb(126, 34, 206)")//Color
|
||||
// cy.contains('Share').closest('div').should("have.css", "font-family", "Montserrat")//Font
|
||||
|
||||
// //Verify Edit App button
|
||||
// cy.contains('Edit App').should("have.css", "background-color", "rgb(126, 34, 206)")//Color
|
||||
// cy.contains('Edit App').closest('div').should("have.css", "font-family", "Montserrat")//Font
|
||||
|
||||
// cy.get(publish.backToEditor).click({ force: true }).wait(1000);
|
||||
});
|
||||
|
||||
it("10. Verify Chainging theme should not affect Individual widgets with changed Color, Border radius, Shadow & can revert to newly selected theme", () => {
|
||||
cy.get("canvas")
|
||||
.first(0)
|
||||
.trigger("click", { force: true });
|
||||
|
||||
cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
//Changing to one of featured themes & then changing individual widget properties
|
||||
cy.xpath(applyTheme("Featured Themes", "Rounded"))
|
||||
.click({ force: true })
|
||||
.wait(1000);
|
||||
|
||||
//Change individual widget properties for Button1
|
||||
ee.SelectEntityByName("Button1");
|
||||
|
||||
//Change Color & verify
|
||||
cy.get(widgetsPage.colorPickerV2Popover)
|
||||
.click({ force: true })
|
||||
.click();
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(17)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
$elem.css("background-color"), //rgb(134, 239, 172)
|
||||
); //new widget with its own color
|
||||
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should("have.css", "background-color", "rgb(222, 21, 147)"); //old widgets still conforming to theme color
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(222, 21, 147)",
|
||||
);
|
||||
});
|
||||
|
||||
//Change Border & verify
|
||||
|
||||
cy.get(".t--button-tab-0\\.375rem")
|
||||
.click()
|
||||
.wait(500);
|
||||
cy.get(".t--button-tab-0\\.375rem div")
|
||||
.eq(0)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
borderRadius, //6px
|
||||
);
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"border-radius",
|
||||
"24px",
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should("have.css", "border-radius", "24px");
|
||||
});
|
||||
|
||||
//Change Shadow & verify
|
||||
cy.get(".t--button-tab-0.1px")
|
||||
.click()
|
||||
.wait(500);
|
||||
cy.get(".t--button-tab-0.1px div")
|
||||
.invoke("css", "box-shadow")
|
||||
.then((boxshadow) => {
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(0)
|
||||
.should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
boxshadow, //rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px
|
||||
);
|
||||
cy.get(widgetsPage.iconWidgetBtn).should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
"none",
|
||||
);
|
||||
cy.get(widgetsPage.widgetBtn)
|
||||
.eq(1)
|
||||
.should(
|
||||
"have.css",
|
||||
"box-shadow",
|
||||
//same value as previous box shadow selection
|
||||
//since revertion is not possible for box shadow - hence this widget maintains the same value
|
||||
"rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px",
|
||||
);
|
||||
});
|
||||
|
||||
cy.assertPageSave();
|
||||
|
||||
//Add deploy mode verification here also!
|
||||
});
|
||||
});
|
||||
|
|
@ -72,7 +72,9 @@ describe("Fork application across orgs", function() {
|
|||
}
|
||||
|
||||
cy.PublishtheApp();
|
||||
cy.get(homePage.shareButton).click();
|
||||
cy.get("button:contains('Share')")
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.enablePublicAccess();
|
||||
|
||||
cy.url().then((url) => {
|
||||
|
|
@ -81,15 +83,19 @@ describe("Fork application across orgs", function() {
|
|||
cy.get(homePage.signOutIcon).click();
|
||||
|
||||
cy.visit(forkableAppUrl);
|
||||
cy.get(applicationLocators.forkButton).click();
|
||||
|
||||
cy.get(applicationLocators.forkButton)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(loginPageLocators.signupLink).click();
|
||||
|
||||
cy.generateUUID().then((uid) => {
|
||||
cy.get(signupPageLocators.username).type(`${uid}@appsmith.com`);
|
||||
cy.get(signupPageLocators.password).type(uid);
|
||||
cy.get(signupPageLocators.submitBtn).click();
|
||||
cy.wait(1000);
|
||||
cy.wait(10000);
|
||||
cy.get(applicationLocators.forkButton)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(homePage.forkAppOrgButton).should("be.visible");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ describe("Binding the API with pageOnLoad and input Widgets", function() {
|
|||
.last()
|
||||
.invoke("attr", "value")
|
||||
.should("contain", "23");
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ describe("Addwidget from Query and bind with other widgets", function() {
|
|||
cy.url().then((url) => {
|
||||
currentUrl = url;
|
||||
cy.log("Published url is: " + currentUrl);
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.wait(2000);
|
||||
cy.visit(currentUrl);
|
||||
cy.wait("@getPagesForViewApp").should(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ describe("Binding the input Widget with tab Widget", function() {
|
|||
cy.get(publish.tabWidget)
|
||||
.contains("Tab 2")
|
||||
.click({ force: true })
|
||||
.should("be.selected");
|
||||
.should("have.class", "is-selected");
|
||||
|
||||
cy.get(publish.inputWidget + " " + "input")
|
||||
.first()
|
||||
|
|
@ -36,7 +36,7 @@ describe("Binding the input Widget with tab Widget", function() {
|
|||
cy.get(publish.tabWidget)
|
||||
.contains("Tab 1")
|
||||
.click({ force: true })
|
||||
.should("be.selected");
|
||||
.should("have.class", "is-selected");
|
||||
|
||||
cy.get(publish.inputWidget + " " + "input")
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -33,9 +33,7 @@ describe("Binding the button Widgets and validating NavigateTo Page functionalit
|
|||
cy.wait(500);
|
||||
cy.get(publish.buttonWidget).should("not.exist");
|
||||
cy.go("back");
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.wait("@getPage").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ describe("Table Widget property pane feature validation", function() {
|
|||
.click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
cy.selectTextSize("Heading 1");
|
||||
cy.selectTxtSize("XL");
|
||||
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "24px");
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "30px");
|
||||
});
|
||||
|
||||
it("Table widget toggle test for text size", function() {
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Email", function() {
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.isSelectRow(2);
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{Table1.selectedRow.email}}");
|
||||
|
|
@ -71,9 +69,7 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Total Length", function() {
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.openPropertyPane("textwidget");
|
||||
cy.testJsontext("text", "{{Table1.pageSize}}");
|
||||
cy.get(commonlocators.TableRow)
|
||||
|
|
@ -97,9 +93,7 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Table Widget Functionality To Verify Default Row Selection is working", function() {
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
cy.testJsontext("defaultselectedrow", "2");
|
||||
cy.wait("@updateLayout");
|
||||
|
|
@ -118,9 +112,7 @@ describe("Text-Table Binding Functionality", function() {
|
|||
});
|
||||
});
|
||||
it("Text-Table Binding Functionality For Username", function() {
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
/**
|
||||
* @param(Index) Provide index value to select the row.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -62,9 +62,7 @@ describe("Binding the multiple input Widget", function() {
|
|||
cy.xpath(testdata.input2)
|
||||
.invoke("attr", "value")
|
||||
.should("contain", testdata.defaultdata);
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
|
||||
it("4. Binding third input widget with first input widget and validating", function() {
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ describe("Migration Validate", function() {
|
|||
.first()
|
||||
.invoke("attr", "value")
|
||||
.should("contain", "#FFC13D");
|
||||
cy.get(widgetsPage.selectedTextSize).should("have.text", "24px");
|
||||
cy.validateCodeEditorContent(".t--property-control-textsize", "1.5rem");
|
||||
});
|
||||
|
||||
// it("2. Add dsl and Validate Migration on pageload", function () {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ describe("Statbox Widget Functionality", function() {
|
|||
// changing the background color of statbox and verying it
|
||||
cy.get(".t--property-pane-section-general").then(() => {
|
||||
cy.get(".bp3-input-group")
|
||||
.first()
|
||||
.clear()
|
||||
.wait(400)
|
||||
.type("#FFC13D");
|
||||
cy.get(".bp3-input").should("have.value", "#FFC13D");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,18 +11,13 @@ describe("Table Widget property pane feature validation", function() {
|
|||
// Open property pane
|
||||
cy.openPropertyPane("tablewidget");
|
||||
// Click on text color input field
|
||||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
// Select green color
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.selectColor("textcolor");
|
||||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
// Verify the text color is green
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(3, 179, 101)");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
// Change the text color and enter purple in input field
|
||||
cy.get(widgetsPage.textColor)
|
||||
.scrollIntoView()
|
||||
|
|
@ -32,16 +27,11 @@ describe("Table Widget property pane feature validation", function() {
|
|||
// Verify the text color is purple
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(128, 0, 128)");
|
||||
// Click on cell background color
|
||||
cy.get(`${widgetsPage.cellBackground} input`)
|
||||
.first()
|
||||
.scrollIntoView()
|
||||
.click({ force: true });
|
||||
cy.selectColor("cellbackgroundcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
// select the green color
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
|
||||
cy.wait("@updateLayout");
|
||||
cy.assertPageSave();
|
||||
cy.PublishtheApp();
|
||||
|
|
@ -52,7 +42,7 @@ describe("Table Widget property pane feature validation", function() {
|
|||
"1",
|
||||
"1",
|
||||
"background-color",
|
||||
"rgb(3, 179, 101)",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.openPropertyPane("tablewidget");
|
||||
|
|
|
|||
|
|
@ -139,15 +139,15 @@ describe("Table Widget property pane feature validation", function() {
|
|||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
// Select Heading 1 text size
|
||||
cy.selectTextSize("Heading 1");
|
||||
cy.selectTxtSize("L");
|
||||
// Verify the font size is 24px
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "24px");
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "20px");
|
||||
// close propert pane
|
||||
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(1000);
|
||||
// Verify the font size is 24px
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "24px");
|
||||
cy.readTabledataValidateCSS("0", "0", "font-size", "20px");
|
||||
});
|
||||
|
||||
it("8. Test to validate open new tab icon shows when URL type data validate link text ", function() {
|
||||
|
|
|
|||
|
|
@ -273,41 +273,34 @@ describe("Table Widget property pane feature validation", function() {
|
|||
cy.readTabledataValidateCSS("0", "0", "align-items", "flex-end", true);
|
||||
});
|
||||
|
||||
it("11. Test to validate text color and text background", function() {
|
||||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
// Changing text color to GREEN and validate
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
it("Test to validate text color and text background", function() {
|
||||
cy.openPropertyPane("tablewidget");
|
||||
|
||||
// Changing text color to rgb(126, 34, 206) and validate
|
||||
cy.selectColor("textcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(5000);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(3, 179, 101)", true);
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(126, 34, 206)");
|
||||
|
||||
// Changing text color to PURPLE and validate using JS
|
||||
cy.get(widgetsPage.toggleJsColor).click();
|
||||
cy.testCodeMirrorLast("purple");
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(128, 0, 128)", true);
|
||||
// Changing Cell backgroud color to GREEN and validate
|
||||
cy.get(widgetsPage.backgroundColor)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS("1", "0", "color", "rgb(128, 0, 128)");
|
||||
|
||||
// Changing Cell backgroud color to rgb(126, 34, 206) and validate
|
||||
cy.selectColor("cellbackground");
|
||||
cy.readTabledataValidateCSS(
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"background",
|
||||
"rgb(3, 179, 101) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
"rgb(126, 34, 206) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
true,
|
||||
);
|
||||
// Changing Cell backgroud color to PURPLE and validate using JS
|
||||
cy.get(widgetsPage.toggleJsBcgColor).click();
|
||||
cy.testCodeMirrorLast("purple");
|
||||
cy.updateCodeInput(".t--property-control-cellbackground", "purple");
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTabledataValidateCSS(
|
||||
"0",
|
||||
|
|
@ -343,94 +336,94 @@ describe("Table Widget property pane feature validation", function() {
|
|||
cy.get(widgetsPage.selectedRow).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(236, 249, 243)",
|
||||
"rgb(224, 251, 234)",
|
||||
);
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
|
||||
it("14. Verify table column type button with button variant", function() {
|
||||
// Open property pane
|
||||
cy.openPropertyPane("tablewidget");
|
||||
// Add new column in the table with name "CustomColumn"
|
||||
cy.addColumn("CustomColumn");
|
||||
// it("14. Verify table column type button with button variant", function() {
|
||||
// // Open property pane
|
||||
// cy.openPropertyPane("tablewidget");
|
||||
// // Add new column in the table with name "CustomColumn"
|
||||
// cy.addColumn("CustomColumn");
|
||||
|
||||
cy.tableColumnDataValidation("customColumn2"); //To be updated later
|
||||
// cy.tableColumnDataValidation("customColumn2"); //To be updated later
|
||||
|
||||
cy.editColumn("customColumn2");
|
||||
cy.changeColumnType("Button");
|
||||
// default selected opts
|
||||
cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
"have.text",
|
||||
"Primary",
|
||||
);
|
||||
cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
cy.get(selector + " button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(3, 179, 101)",
|
||||
);
|
||||
cy.get(selector + " button > span").should(
|
||||
"have.css",
|
||||
"color",
|
||||
"rgb(255, 255, 255)",
|
||||
);
|
||||
});
|
||||
cy.selectDropdownValue(commonlocators.tableButtonVariant, "Secondary");
|
||||
cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
"have.text",
|
||||
"Secondary",
|
||||
);
|
||||
cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
cy.get(selector + " button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgba(0, 0, 0, 0)",
|
||||
);
|
||||
cy.get(selector + " button > span").should(
|
||||
"have.css",
|
||||
"color",
|
||||
"rgb(3, 179, 101)",
|
||||
);
|
||||
cy.get(selector + " button").should(
|
||||
"have.css",
|
||||
"border",
|
||||
"1px solid rgb(3, 179, 101)",
|
||||
);
|
||||
});
|
||||
cy.selectDropdownValue(commonlocators.tableButtonVariant, "Tertiary");
|
||||
cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
"have.text",
|
||||
"Tertiary",
|
||||
);
|
||||
cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
cy.get(selector + " button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgba(0, 0, 0, 0)",
|
||||
);
|
||||
cy.get(selector + " button > span").should(
|
||||
"have.css",
|
||||
"color",
|
||||
"rgb(3, 179, 101)",
|
||||
);
|
||||
cy.get(selector + " button").should(
|
||||
"have.css",
|
||||
"border",
|
||||
"0px none rgb(24, 32, 38)",
|
||||
);
|
||||
});
|
||||
cy.closePropertyPane();
|
||||
});
|
||||
// cy.editColumn("customColumn2");
|
||||
// cy.changeColumnType("Button");
|
||||
// // default selected opts
|
||||
// cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
// "have.text",
|
||||
// "Primary",
|
||||
// );
|
||||
// cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
// cy.get(selector + " button").should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgb(22, 163, 74)",
|
||||
// );
|
||||
// cy.get(selector + " button > span").should(
|
||||
// "have.css",
|
||||
// "color",
|
||||
// "rgb(255, 255, 255)",
|
||||
// );
|
||||
// });
|
||||
// cy.selectDropdownValue(commonlocators.tableButtonVariant, "Secondary");
|
||||
// cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
// "have.text",
|
||||
// "Secondary",
|
||||
// );
|
||||
// cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
// cy.get(selector + " button").should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgba(0, 0, 0, 0)",
|
||||
// );
|
||||
// cy.get(selector + " button > span").should(
|
||||
// "have.css",
|
||||
// "color",
|
||||
// "rgb(22, 163, 74)",
|
||||
// );
|
||||
// cy.get(selector + " button").should(
|
||||
// "have.css",
|
||||
// "border",
|
||||
// `1px solid rgb(22, 163, 74)`,
|
||||
// );
|
||||
// });
|
||||
// cy.selectDropdownValue(commonlocators.tableButtonVariant, "Tertiary");
|
||||
// cy.get(commonlocators.tableButtonVariant + " span[type='p1']").should(
|
||||
// "have.text",
|
||||
// "Tertiary",
|
||||
// );
|
||||
// cy.getTableDataSelector("1", "6").then((selector) => {
|
||||
// cy.get(selector + " button").should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// "rgba(0, 0, 0, 0)",
|
||||
// );
|
||||
// cy.get(selector + " button > span").should(
|
||||
// "have.css",
|
||||
// "color",
|
||||
// "rgb(22, 163, 74)",
|
||||
// );
|
||||
// cy.get(selector + " button").should(
|
||||
// "have.css",
|
||||
// "border",
|
||||
// "0px none rgb(24, 32, 38)",
|
||||
// );
|
||||
// });
|
||||
// cy.closePropertyPane();
|
||||
// });
|
||||
|
||||
it("15. Table-Delete Verification", function() {
|
||||
// Open property pane
|
||||
cy.openPropertyPane("tablewidget");
|
||||
// Delete the Table widget
|
||||
cy.deleteWidget(widgetsPage.tableWidget);
|
||||
cy.PublishtheApp();
|
||||
// Verify the Table widget is deleted
|
||||
cy.get(widgetsPage.tableWidget).should("not.exist");
|
||||
});
|
||||
// it("15. Table-Delete Verification", function() {
|
||||
// // Open property pane
|
||||
// cy.openPropertyPane("tablewidget");
|
||||
// // Delete the Table widget
|
||||
// cy.deleteWidget(widgetsPage.tableWidget);
|
||||
// cy.PublishtheApp();
|
||||
// // Verify the Table widget is deleted
|
||||
// cy.get(widgetsPage.tableWidget).should("not.exist");
|
||||
// });
|
||||
|
||||
afterEach(() => {
|
||||
// put your clean up code if any
|
||||
|
|
|
|||
|
|
@ -292,6 +292,8 @@ describe("Table Widget property pane feature validation", function() {
|
|||
|
||||
//cy.closePropertyPane();
|
||||
|
||||
cy.closePropertyPane();
|
||||
|
||||
// disable menu item 3
|
||||
//cy.openPropertyPane("tablewidget");
|
||||
|
||||
|
|
@ -352,14 +354,15 @@ describe("Table Widget property pane feature validation", function() {
|
|||
cy.get(".t--property-pane-back-btn").click({ force: true });
|
||||
});
|
||||
|
||||
it("9. Table widget test on button when transparent", () => {
|
||||
it("8. Table widget test on button when transparent", () => {
|
||||
cy.openPropertyPane("tablewidget");
|
||||
// Open column details of "id".
|
||||
cy.editColumn("id");
|
||||
// Changing column "Button" color to transparent
|
||||
|
||||
cy.get(widgetsPage.buttonColor).click({ force: true });
|
||||
cy.xpath(widgetsPage.transparent).click();
|
||||
cy.wait(2000);
|
||||
cy.get(widgetsPage.transparent).click({ force: true });
|
||||
cy.get(".td[data-colindex=5][data-rowindex=0] .bp3-button").should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ describe("Table Widget Functionality", function() {
|
|||
|
||||
it("Table Widget Functionality To Verify The Visiblity mode functionality", function() {
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click();
|
||||
cy.isSelectRow(1);
|
||||
cy.readTabledataPublish("1", "3").then(tabData => {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ describe("Table Widget", function() {
|
|||
});
|
||||
|
||||
cy.get(publish.backToEditor)
|
||||
.first()
|
||||
.click()
|
||||
.wait(1000);
|
||||
cy.wait(30000);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ describe("Text Widget color/font/alignment Functionality", function() {
|
|||
cy.PublishtheApp();
|
||||
cy.get(commonlocators.headingTextStyle)
|
||||
.should("have.text", this.data.TextLabelValueScrollable)
|
||||
.should("have.css", "font-size", "24px");
|
||||
.should("have.css", "font-size", "16px");
|
||||
cy.get(publishPage.backToEditor).click({ force: true });
|
||||
});
|
||||
|
||||
|
|
@ -74,31 +74,39 @@ describe("Text Widget color/font/alignment Functionality", function() {
|
|||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.selectColor("textcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(3, 179, 101)");
|
||||
cy.readTextDataValidateCSS("color", "rgb(126, 34, 206)");
|
||||
cy.get(widgetsPage.textColor)
|
||||
.clear({ force: true })
|
||||
.type("purple", { force: true });
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(128, 0, 128)");
|
||||
|
||||
//Checks the cell background with color picker
|
||||
cy.get(`${widgetsPage.cellBackground} input`)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.selectColor("cellbackgroundcolor");
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
cy.PublishtheApp();
|
||||
cy.get(publishPage.backToEditor).click({ force: true });
|
||||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
|
||||
//Toggle JS check with cell background:
|
||||
cy.get(widgetsPage.cellBackgroundToggle).click({ force: true });
|
||||
cy.updateCodeInput(widgetsPage.cellBackground, "purple");
|
||||
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(128, 0, 128)");
|
||||
});
|
||||
|
||||
it("Test to validate text alignment", function() {
|
||||
|
|
@ -134,20 +142,13 @@ describe("Text Widget color/font/alignment Functionality", function() {
|
|||
});
|
||||
it("Test border width, color and verity", function() {
|
||||
cy.testJsontext("borderwidth", "10");
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
)
|
||||
.should("have.css", "border-width")
|
||||
.and("eq", "10px");
|
||||
|
||||
cy.get(widgetsPage.borderColorPickerNew)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.xpath(widgetsPage.yellowColor).click();
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
)
|
||||
.should("have.css", "border-color")
|
||||
.and("eq", "rgb(255, 193, 61)");
|
||||
cy.wait("@updateLayout");
|
||||
cy.get(`${widgetsPage.textWidget} .t--text-widget-container`).should(
|
||||
"have.css",
|
||||
"border-width",
|
||||
"10px",
|
||||
);
|
||||
cy.selectColor("bordercolor");
|
||||
cy.readTextDataValidateCSS("border-color", "rgb(229, 231, 235)");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe("Text Widget Functionality", function() {
|
|||
cy.PublishtheApp();
|
||||
cy.get(commonlocators.headingTextStyle)
|
||||
.should("have.text", this.data.TextLabelValue)
|
||||
.should("have.css", "font-size", "24px");
|
||||
.should("have.css", "font-size", "16px");
|
||||
});
|
||||
|
||||
it("Text Email Parsing Validation", function() {
|
||||
|
|
@ -70,7 +70,7 @@ describe("Text Widget Functionality", function() {
|
|||
cy.PublishtheApp();
|
||||
cy.get(commonlocators.bodyTextStyle)
|
||||
.should("have.text", this.data.TextLabelValue)
|
||||
.should("have.css", "font-size", "18px");
|
||||
.should("have.css", "font-size", "20px");
|
||||
});
|
||||
|
||||
it("Text widget depends on itself", function() {
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ describe("Select Widget Functionality", function() {
|
|||
}`,
|
||||
);
|
||||
cy.PublishtheApp();
|
||||
cy.get(".bp3-button")
|
||||
cy.get(".bp3-button.select-button")
|
||||
.eq(0)
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ describe("Select Widget Functionality", function() {
|
|||
cy.get(".bp3-disabled").should("be.visible");
|
||||
cy.get(widgetsPage.disable).scrollIntoView({ force: true });
|
||||
cy.get(widgetsPage.selectWidgetDisabled).click({ force: true });
|
||||
cy.get(".bp3-button").should("be.visible");
|
||||
cy.get(".t--widget-selectwidget .bp3-button").should("be.visible");
|
||||
cy.PublishtheApp();
|
||||
cy.get(".bp3-button")
|
||||
cy.get(".t--widget-selectwidget .bp3-button")
|
||||
.should("be.visible")
|
||||
.click({ force: true });
|
||||
cy.get(commonlocators.singleSelectActiveMenuItem).should(
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ describe("Entity explorer Drag and Drop widgets testcases", function() {
|
|||
it("Drag and drop form widget and validate", function() {
|
||||
cy.log("Login Successful");
|
||||
cy.reload(); // To remove the rename tooltip
|
||||
cy.wait(40000);
|
||||
cy.get(explorer.addWidget).click();
|
||||
cy.get(explorer.addWidget).click({ force: true });
|
||||
cy.get(commonlocators.entityExplorersearch).should("be.visible");
|
||||
cy.get(commonlocators.entityExplorersearch)
|
||||
.clear()
|
||||
|
|
@ -33,15 +32,10 @@ describe("Entity explorer Drag and Drop widgets testcases", function() {
|
|||
/**
|
||||
* @param{Text} Random Colour
|
||||
*/
|
||||
cy.get(widgetsPage.backgroundcolorPickerNew)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.selectColor("backgroundcolor");
|
||||
cy.get(formWidgetsPage.formD)
|
||||
.should("have.css", "background-color")
|
||||
.and("eq", "rgb(3, 179, 101)");
|
||||
.and("eq", "rgb(126, 34, 206)");
|
||||
/**
|
||||
* @param{toggleButton Css} Assert to be checked
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ describe("Tab widget test", function() {
|
|||
});
|
||||
|
||||
it("Tab Widget Functionality To Unchecked Visible Widget", function() {
|
||||
cy.get(publish.backToEditor).click();
|
||||
cy.get(publish.backToEditor).first().click();
|
||||
cy.openPropertyPane("tabswidget");
|
||||
cy.closePropertyPane();
|
||||
cy.get(Layoutpage.tabWidget)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@ describe("In a button group widget, menu button width", function() {
|
|||
.then((targetWidth) => {
|
||||
expect(targetWidth).to.be.lessThan(minWidth);
|
||||
// Check if popover width is set to its target width
|
||||
cy.get(
|
||||
`.bp3-popover2.menu-button-width-${widgetId}-${menuButtonId}`,
|
||||
).should("have.css", "width", `${minWidth}px`);
|
||||
cy.get(`.bp3-popover2.button-group-${widgetId}`).should(
|
||||
"have.css",
|
||||
"width",
|
||||
`${minWidth}px`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -48,9 +50,11 @@ describe("In a button group widget, menu button width", function() {
|
|||
.then((targetWidth) => {
|
||||
expect(targetWidth).to.be.greaterThan(minWidth);
|
||||
// Check if popover width is set to its target width
|
||||
cy.get(
|
||||
`.bp3-popover2.menu-button-width-${widgetId}-${menuButtonId}`,
|
||||
).should("have.css", "width", `${targetWidth}px`);
|
||||
cy.get(`.bp3-popover2.button-group-${widgetId}`).should(
|
||||
"have.css",
|
||||
"width",
|
||||
`${targetWidth}px`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -75,9 +79,11 @@ describe("In a button group widget, menu button width", function() {
|
|||
.then((targetWidth) => {
|
||||
expect(targetWidth).to.be.greaterThan(minWidth);
|
||||
// Check if popover width is set to its target width
|
||||
cy.get(
|
||||
`.bp3-popover2.menu-button-width-${widgetId}-${menuButtonId}`,
|
||||
).should("have.css", "width", `${targetWidth}px`);
|
||||
cy.get(`.bp3-popover2.button-group-${widgetId}`).should(
|
||||
"have.css",
|
||||
"width",
|
||||
`${targetWidth}px`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -108,9 +114,11 @@ describe("In a button group widget, menu button width", function() {
|
|||
.then((targetWidth) => {
|
||||
expect(targetWidth).to.be.greaterThan(minWidth);
|
||||
// Check if popover width is set to its target width
|
||||
cy.get(
|
||||
`.bp3-popover2.menu-button-width-${widgetId}-${menuButtonId}`,
|
||||
).should("have.css", "width", `${targetWidth}px`);
|
||||
cy.get(`.bp3-popover2.button-group-${widgetId}`).should(
|
||||
"have.css",
|
||||
"width",
|
||||
`${targetWidth}px`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -136,9 +144,11 @@ describe("In a button group widget, menu button width", function() {
|
|||
.invoke("outerWidth")
|
||||
.then((targetWidth) => {
|
||||
// Check if popover width is set to its target width
|
||||
cy.get(
|
||||
`.bp3-popover2.menu-button-width-${widgetId}-${menuButtonId}`,
|
||||
).should("have.css", "width", `${targetWidth}px`);
|
||||
cy.get(`.bp3-popover2.button-group-${widgetId}`).should(
|
||||
"have.css",
|
||||
"width",
|
||||
`${targetWidth}px`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ describe("Checkbox Group Widget Functionality", function() {
|
|||
cy.openPropertyPane("checkboxgroupwidget");
|
||||
cy.togglebar(commonlocators.visibleCheckbox);
|
||||
cy.PublishtheApp();
|
||||
cy.wait(500);
|
||||
cy.get(publish.checkboxGroupWidget + " " + "input")
|
||||
.eq(0)
|
||||
.should("exist");
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ describe("Currency widget - ", () => {
|
|||
].forEach((d) => {
|
||||
enterAndTest(d[0], d[1]);
|
||||
});
|
||||
cy.get(".currency-type-trigger").should("contain", "$");
|
||||
cy.get(".currency-change-dropdown-trigger").should("contain", "$");
|
||||
|
||||
cy.openPropertyPane(widgetName);
|
||||
cy.selectDropdownValue(
|
||||
|
|
@ -74,7 +74,7 @@ describe("Currency widget - ", () => {
|
|||
"INR - Indian Rupee",
|
||||
);
|
||||
enterAndTest("100.22", "100.22:100.22:true:string:number:IN:INR");
|
||||
cy.get(".currency-type-trigger").should("contain", "₹");
|
||||
cy.get(".currency-change-dropdown-trigger").should("contain", "₹");
|
||||
|
||||
cy.openPropertyPane(widgetName);
|
||||
cy.get(".t--property-control-allowcurrencychange label")
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ describe("Text Widget Cell Background and Text Size Validation", function() {
|
|||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(3, 179, 101)",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
|
||||
//Toggle to JS mode
|
||||
|
|
@ -73,12 +73,12 @@ describe("Text Widget Cell Background and Text Size Validation", function() {
|
|||
.click({ force: true });
|
||||
|
||||
cy.wait(100);
|
||||
cy.selectTextSize("Heading 1");
|
||||
cy.selectTextSize("S");
|
||||
|
||||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"font-size",
|
||||
"24px",
|
||||
"14px",
|
||||
);
|
||||
|
||||
//Toggle JS mode
|
||||
|
|
@ -87,7 +87,7 @@ describe("Text Widget Cell Background and Text Size Validation", function() {
|
|||
.wait(200);
|
||||
|
||||
//Check if the typed size HEADING2 is reflecting in the background color and in the evaluated value
|
||||
cy.updateCodeInput(".t--property-control-textsize", "HEADING2");
|
||||
cy.updateCodeInput(".t--property-control-textsize", "18px");
|
||||
|
||||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
|
|
@ -95,24 +95,17 @@ describe("Text Widget Cell Background and Text Size Validation", function() {
|
|||
"18px",
|
||||
);
|
||||
|
||||
cy.EvaluateCurrentValue("HEADING2");
|
||||
|
||||
//Check for if the text size changes to default size when set to blank in JS mode:
|
||||
cy.updateCodeInput(".t--property-control-textsize", "");
|
||||
|
||||
cy.get(`${widgetsPage.textWidget} .bp3-ui-text`).should(
|
||||
"have.css",
|
||||
"font-size",
|
||||
"14px",
|
||||
"16px",
|
||||
);
|
||||
|
||||
cy.get(commonlocators.evaluatedCurrentValue)
|
||||
.first()
|
||||
.should("not.be.visible");
|
||||
|
||||
//Check the values not allowed error message
|
||||
cy.updateCodeInput(".t--property-control-textsize", "HEADING10");
|
||||
|
||||
cy.evaluateErrorMessage("Disallowed value: HEADING10");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ describe("Dropdown Widget Functionality", function() {
|
|||
|
||||
it("Verify dropdown width of Select widgets and menu button", function() {
|
||||
// Select
|
||||
cy.wait(450);
|
||||
cy.get(formWidgetsPage.selectwidget)
|
||||
.find(widgetLocators.dropdownSingleSelect)
|
||||
.invoke("outerWidth")
|
||||
|
|
@ -26,7 +27,9 @@ describe("Dropdown Widget Functionality", function() {
|
|||
cy.get(formWidgetsPage.menuButtonWidget)
|
||||
.find(widgetLocators.menuButton)
|
||||
.invoke("outerWidth")
|
||||
.should("eq", 147.1875);
|
||||
.then((width) => {
|
||||
expect(parseInt(width)).to.equal(147);
|
||||
});
|
||||
cy.get(formWidgetsPage.menuButtonWidget)
|
||||
.find(widgetLocators.menuButton)
|
||||
.click({
|
||||
|
|
@ -34,7 +37,9 @@ describe("Dropdown Widget Functionality", function() {
|
|||
});
|
||||
cy.get(".menu-button-popover")
|
||||
.invoke("outerWidth")
|
||||
.should("eq", 147.1875);
|
||||
.then((width) => {
|
||||
expect(parseInt(width)).to.equal(147);
|
||||
});
|
||||
|
||||
// MultiSelect
|
||||
cy.get(formWidgetsPage.multiselectwidgetv2)
|
||||
|
|
|
|||
|
|
@ -25,10 +25,11 @@ describe("Container Widget Functionality", function() {
|
|||
*/
|
||||
cy.get(widgetsPage.borderColorPickerNew)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.xpath(widgetsPage.yellowColor).click();
|
||||
.click({ force: true })
|
||||
.clear()
|
||||
.type(widgetsPage.yellowColorHex);
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "border-color")
|
||||
.and("eq", "rgb(255, 193, 61)");
|
||||
|
|
@ -37,13 +38,15 @@ describe("Container Widget Functionality", function() {
|
|||
*/
|
||||
cy.get(widgetsPage.backgroundcolorPickerNew)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
.click({ force: true })
|
||||
.clear()
|
||||
.type(widgetsPage.greenColorHex);
|
||||
cy.get(widgetsPage.containerD)
|
||||
.should("have.css", "background-color")
|
||||
.and("eq", "rgb(3, 179, 101)");
|
||||
.should("have.css", "background")
|
||||
.and(
|
||||
"eq",
|
||||
"rgb(3, 179, 101) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
);
|
||||
/**
|
||||
* @param{toggleButton Css} Assert to be checked
|
||||
*/
|
||||
|
|
@ -57,8 +60,11 @@ describe("Container Widget Functionality", function() {
|
|||
it("Container Widget Functionality To Verify The Colour", function() {
|
||||
cy.get(widgetsPage.containerD)
|
||||
.eq(0)
|
||||
.should("have.css", "background-color")
|
||||
.and("eq", "rgb(3, 179, 101)");
|
||||
.should("have.css", "background")
|
||||
.and(
|
||||
"eq",
|
||||
"rgb(3, 179, 101) none repeat scroll 0% 0% / auto padding-box border-box",
|
||||
);
|
||||
});
|
||||
|
||||
it("Test border width and verity", function() {
|
||||
|
|
@ -67,64 +73,42 @@ describe("Container Widget Functionality", function() {
|
|||
|
||||
cy.testJsontext("borderwidth", "10");
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "border-width")
|
||||
.and("eq", "10px");
|
||||
});
|
||||
|
||||
it("Test border radius and verity", function() {
|
||||
cy.testJsontext("borderradius", "10");
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
)
|
||||
.should("have.css", "border-radius")
|
||||
.and("eq", "10px");
|
||||
// should have overflow : hidden to show border edges
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}'] div`,
|
||||
)
|
||||
.should("have.css", "overflow")
|
||||
.and("eq", "hidden");
|
||||
// wrapper should have same border radius
|
||||
// check if border radius is changed on button
|
||||
|
||||
cy.get(`.t--property-control-borderradius button > div`)
|
||||
.eq(0)
|
||||
.click({ force: true });
|
||||
|
||||
cy.get(`.t--property-control-borderradius button > div`)
|
||||
.eq(0)
|
||||
.invoke("css", "border-top-left-radius")
|
||||
.then((borderRadius) => {
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "border-radius")
|
||||
.and("eq", "10px");
|
||||
).should("have.css", "border-radius", borderRadius);
|
||||
});
|
||||
});
|
||||
|
||||
it("Test Box shadow and verity", function() {
|
||||
cy.get(widgetsPage.boxShadow)
|
||||
.children()
|
||||
.eq(3)
|
||||
cy.get(`.t--property-control-boxshadow button > div`)
|
||||
.eq(0)
|
||||
.click({ force: true });
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "box-shadow")
|
||||
.and("eq", "rgba(0, 0, 0, 0.5) 0px 1px 3px 0px");
|
||||
|
||||
// change shadow color and check box-shadow again
|
||||
cy.get(widgetsPage.boxShadowColorPicker)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.xpath(widgetsPage.blueColor).click();
|
||||
cy.get(`.t--property-control-boxshadow button > div`)
|
||||
.eq(0)
|
||||
.invoke("css", "box-shadow")
|
||||
.then((boxShadow) => {
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "box-shadow")
|
||||
.and("eq", "rgb(51, 102, 255) 0px 1px 3px 0px");
|
||||
).should("have.css", "box-shadow", boxShadow);
|
||||
});
|
||||
|
||||
it("Test overflow of widget boundaries", function() {
|
||||
cy.testJsontext("borderwidth", "500");
|
||||
// prevent overflow of widget boundaries
|
||||
cy.get(
|
||||
`div[data-testid='container-wrapper-${dsl.dsl.children[0].widgetId}']`,
|
||||
)
|
||||
.should("have.css", "overflow")
|
||||
.and("eq", "hidden");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ describe("Container Widget Functionality", function() {
|
|||
cy.CheckAndUnfoldEntityItem("WIDGETS");
|
||||
cy.selectEntityByName("List1");
|
||||
// Scroll down to Styles and Add background colour
|
||||
cy.selectColor("backgroundcolor");
|
||||
cy.selectColor("background");
|
||||
cy.wait(1000);
|
||||
cy.selectColor("itembackgroundcolor");
|
||||
// Click on Deploy and ensure it is deployed appropriately
|
||||
|
|
@ -181,13 +181,13 @@ describe("Container Widget Functionality", function() {
|
|||
cy.get(widgetsPage.listWidget).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(3, 179, 101)",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
// Verify List Item Background Color
|
||||
cy.get(widgetsPage.itemContainerWidget).should(
|
||||
"have.css",
|
||||
"background-color",
|
||||
"rgb(3, 179, 101)",
|
||||
"rgb(126, 34, 206)",
|
||||
);
|
||||
cy.get(publishPage.backToEditor).click({ force: true });
|
||||
});
|
||||
|
|
@ -198,7 +198,7 @@ describe("Container Widget Functionality", function() {
|
|||
cy.selectEntityByName("List1");
|
||||
// Scroll down to Styles and Add background colour
|
||||
cy.get(widgetsPage.backgroundColorToggle).click({ force: true });
|
||||
cy.testJsontext("backgroundcolor", "#FFC13D");
|
||||
cy.testJsontext("background", "#FFC13D");
|
||||
cy.wait(1000);
|
||||
cy.get(widgetsPage.itemBackgroundColorToggle).click({ force: true });
|
||||
cy.testJsontext("itembackgroundcolor", "#38AFF4");
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ describe("Tab widget test", function() {
|
|||
cy.get(publish.tabWidget)
|
||||
.contains(this.data.tabName)
|
||||
.click({ force: true })
|
||||
.should("be.selected");
|
||||
.should("have.class", "is-selected");
|
||||
cy.get(publish.backToEditor).click();
|
||||
});
|
||||
it("Tab Widget Functionality To Unchecked Visible Widget", function() {
|
||||
|
|
@ -133,20 +133,21 @@ describe("Tab widget test", function() {
|
|||
*/
|
||||
it("Tabs widget should have navigation arrows if tabs don't fit", function() {
|
||||
const rightNavButtonSelector =
|
||||
Layoutpage.tabWidget + " button.scroll-nav-right-button";
|
||||
Layoutpage.tabWidget + " .scroll-nav-right-button";
|
||||
const leftNavButtonSelector =
|
||||
Layoutpage.tabWidget + " button.scroll-nav-left-button";
|
||||
Layoutpage.tabWidget + " .scroll-nav-left-button";
|
||||
|
||||
cy.openPropertyPane("tabswidget");
|
||||
// Add a new tab
|
||||
cy.get(Layoutpage.tabButton).click({ force: true });
|
||||
cy.tabVerify(2, "Tab3-for-testing-scroll-navigation-controls");
|
||||
cy.get(Layoutpage.tabButton).click({ force: true });
|
||||
cy.tabVerify(3, "Tab3-for-testing-scroll-navigation-controls");
|
||||
// Should show off right navigation arrow
|
||||
cy.get(rightNavButtonSelector).should("exist");
|
||||
// Click on the right navigation arrow
|
||||
cy.get(rightNavButtonSelector).click({ force: true });
|
||||
// Should show off left navigation arrow
|
||||
cy.get(leftNavButtonSelector).should("exist");
|
||||
// Click on the right navigation arrow
|
||||
cy.get(leftNavButtonSelector).click({ force: true });
|
||||
// Should show off left navigation arrow
|
||||
cy.get(rightNavButtonSelector).should("exist");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ describe("Page Load tests", () => {
|
|||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.should("have.class", "is-active");
|
||||
// Assert active page DSL
|
||||
cy.get(commonlocators.headingTextStyle).should(
|
||||
|
|
@ -48,7 +47,6 @@ describe("Page Load tests", () => {
|
|||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.should("have.class", "is-active");
|
||||
// Assert active page DSL
|
||||
cy.get(commonlocators.headingTextStyle).should(
|
||||
|
|
@ -67,7 +65,6 @@ describe("Page Load tests", () => {
|
|||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.parent()
|
||||
.should("have.class", "is-active");
|
||||
// Assert active page DSL
|
||||
cy.get(commonlocators.headingTextStyle).should(
|
||||
|
|
|
|||
|
|
@ -170,16 +170,12 @@ describe("Undo/Redo functionality", function() {
|
|||
|
||||
it("checks undo/redo for color picker", function() {
|
||||
cy.dragAndDropToCanvas("textwidget", { x: 100, y: 100 });
|
||||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.get(widgetsPage.greenColor)
|
||||
.last()
|
||||
.click();
|
||||
cy.selectColor("textcolor");
|
||||
cy.get("body").click({ force: true });
|
||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||
cy.wait(500);
|
||||
cy.wait("@updateLayout");
|
||||
cy.readTextDataValidateCSS("color", "rgb(3, 179, 101)");
|
||||
cy.readTextDataValidateCSS("color", "rgb(126, 34, 206)");
|
||||
|
||||
cy.get("body").type(`{${modifierKey}}z`);
|
||||
cy.get(widgetsPage.textColor)
|
||||
|
|
@ -192,7 +188,7 @@ describe("Undo/Redo functionality", function() {
|
|||
cy.get(widgetsPage.textColor)
|
||||
.first()
|
||||
.invoke("attr", "value")
|
||||
.should("contain", "#03b365");
|
||||
.should("contain", "#7e22ce");
|
||||
});
|
||||
|
||||
it("checks undo/redo for option control for radio button", function() {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,9 @@ describe("Create a rest datasource", function() {
|
|||
cy.NavigateToAPI_Panel();
|
||||
cy.CreateAPI("Testapi");
|
||||
cy.enterDatasourceAndPath(testdata.baseUrl, testdata.methods);
|
||||
|
||||
cy.get(".t--store-as-datasource").click();
|
||||
|
||||
cy.get(".t--store-as-datasource").click({ force: true });
|
||||
cy.saveDatasource();
|
||||
cy.contains(".datasource-highlight", "https://mock-api.appsmith.com");
|
||||
|
||||
cy.SaveAndRunAPI();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
|
||||
let dsl: any;
|
||||
let agHelper = ObjectsRegistry.AggregateHelper,
|
||||
const agHelper = ObjectsRegistry.AggregateHelper,
|
||||
homePage = ObjectsRegistry.HomePage,
|
||||
ee = ObjectsRegistry.EntityExplorer,
|
||||
apiPage = ObjectsRegistry.ApiPage,
|
||||
|
|
@ -61,7 +61,7 @@ describe("Layout OnLoad Actions tests", function() {
|
|||
//apiPage.RunAPI();
|
||||
|
||||
//Adding dependency in right order matters!
|
||||
ee.SelectEntityByName("WIDGETS");
|
||||
ee.expandCollapseEntity("WIDGETS");
|
||||
ee.SelectEntityByName("Image1");
|
||||
jsEditor.EnterJSContext("Image", `{{RandomFlora.data}}`, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("7");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("7");
|
||||
});
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("9");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("9");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -87,7 +87,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("7");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("7");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -102,7 +102,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("9");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("9");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -117,7 +117,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("7");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("7");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -132,7 +132,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("9");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("9");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -147,7 +147,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("7");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("7");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -162,7 +162,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("8");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("8");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
@ -177,7 +177,7 @@ describe("[Bug] - 10784 - Passing params from JS to SQL query should not break",
|
|||
agHelper.SelectDropDown("9");
|
||||
agHelper.ClickButton("Submit");
|
||||
agHelper.ValidateNetworkExecutionSuccess("@postExecute");
|
||||
table.ReadTableRowColumnData(0, 0).then((cellData) => {
|
||||
table.ReadTableRowColumnData(0, 0, 2000).then((cellData) => {
|
||||
expect(cellData).to.be.equal("9");
|
||||
});
|
||||
agHelper.NavigateBacktoEditor()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
"removeWidget": ".t--delete-widget svg",
|
||||
"propertypaneText": ".t--propertypane .t--property-pane-view",
|
||||
"formButtonWidget": ".t--widget-formbuttonwidget",
|
||||
"selectwidget": ".t--widget-selectwidget",
|
||||
"textWidget": ".t--draggable-textwidget",
|
||||
"tableWidget": ".t--draggable-tablewidget",
|
||||
"jsonFormWidget": ".t--draggable-jsonformwidget",
|
||||
|
|
@ -100,8 +99,10 @@
|
|||
"boxShadow": ".t--property-control-boxshadow .bp3-button-group",
|
||||
"backgroundcolorPicker": ".t--property-control-backgroundcolour input",
|
||||
"backgroundcolorPickerNew": ".t--property-control-backgroundcolor input",
|
||||
"greenColor": "div[color='#03B365']",
|
||||
"transparent": "//div[@color='transparent']",
|
||||
"greenColorHex": "#03b365",
|
||||
"yellowColorHex": "#FFC13D",
|
||||
"greenColor": "//div[@color='#03b365']",
|
||||
"transparent": ".diagnol-cross",
|
||||
"yellowColor": "//div[@color='#FFC13D']",
|
||||
"blueColor": "//div[@color='#3366FF']",
|
||||
"toggleJsColor": ".t--property-control-textcolor .t--js-toggle",
|
||||
|
|
@ -123,8 +124,8 @@
|
|||
"inputToggleOnClick": ".t--property-control-onclick div.CodeMirror-lines",
|
||||
"tableBtn": ".t--draggable-tablewidget .bp3-button",
|
||||
"tableIconBtn": ".t--draggable-tablewidget .bp3-icon",
|
||||
"toastAction": ".Toastify__toast-container--top-right .t--toast-action",
|
||||
"toastActionText": ".Toastify__toast-container--top-right .t--toast-action span",
|
||||
"toastAction": ".t--toast-action",
|
||||
"toastActionText": ".t--toast-action span",
|
||||
"defaultColName": "[data-rbd-draggable-id='customColumn1'] input",
|
||||
"selectWidget": ".t--open-dropdown-Select-Widget",
|
||||
"switchWidget": ".t--widget-switchwidget",
|
||||
|
|
@ -169,10 +170,12 @@
|
|||
"selectwidget": ".t--draggable-selectwidget",
|
||||
"selectWidgetDisabled": ".t--property-control-disabled input",
|
||||
"itemBackgroundColorToggle": ".t--property-control-itembackgroundcolor .t--js-toggle",
|
||||
"backgroundColorToggle": ".t--property-control-backgroundcolor .t--js-toggle",
|
||||
"backgroundColorToggle": ".t--property-control-background .t--js-toggle",
|
||||
"cellBackground": ".t--property-control-cellbackgroundcolor",
|
||||
"cellBackgroundToggle": ".t--property-control-cellbackgroundcolor .t--js-toggle",
|
||||
"borderColorPickerNew": ".t--property-control-bordercolor input",
|
||||
"selectedTextSize": ".t--property-control-textsize .bp3-popover-target .sub-text",
|
||||
"colorPickerV2Popover": ".t--colorpicker-v2-popover",
|
||||
"colorPickerV2Color": ".t--colorpicker-v2-color",
|
||||
"modalCloseButton": ".t--draggable-iconbuttonwidget .bp3-button"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,5 +170,11 @@
|
|||
"filepickerv2": ".t--draggable-filepickerwidgetv2",
|
||||
"dashboardItemName": ".uppy-Dashboard-Item-name",
|
||||
"mapChartShowLabels": ".t--property-control-showlabels input",
|
||||
"widgetSection": ".t--entity.widgets > .t--entity-item > a.t--entity-collapse-toggle"
|
||||
"widgetSection": ".t--entity.widgets > .t--entity-item > a.t--entity-collapse-toggle",
|
||||
"changeThemeBtn": ".t--change-theme-btn",
|
||||
"editThemeBtn": ".t--edit-theme-btn",
|
||||
"themeCard": ".t--theme-card",
|
||||
"saveThemeBtn": ".t--save-theme-btn",
|
||||
"selectThemeBackBtn": ".t--theme-select-back-btn",
|
||||
"themeAppBorderRadiusBtn": ".t--theme-appBorderRadius"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,215 @@
|
|||
// const commonlocators = require("../../locators/commonlocators.json");
|
||||
// const widgetLocators = require("../../locators/publishWidgetspage.json");
|
||||
// const widgetsPage = require("../../locators/Widgets.json");
|
||||
// const explorer = require("../../locators/explorerlocators.json");
|
||||
// const publish = require("../../locators/publishWidgetspage.json");
|
||||
// const dsl = require("../../fixtures/replay.json");
|
||||
|
||||
// describe("App Theming funtionality", function() {
|
||||
// /**
|
||||
// * Test cases; Check:
|
||||
// * 1. If theme can be changed*
|
||||
// * 2. If the theme can edited*
|
||||
// * 4. If the save theme can be used.
|
||||
// * 5. If the theme can be deleled
|
||||
// */
|
||||
// before(() => {
|
||||
// cy.addDsl(dsl);
|
||||
// });
|
||||
|
||||
// it("checks if theme can be changed", function() {
|
||||
// cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
// // select a theme
|
||||
// cy.get(commonlocators.themeCard)
|
||||
// .last()
|
||||
// .click({ force: true });
|
||||
|
||||
// // check for alert
|
||||
// cy.get(`${commonlocators.themeCard}`)
|
||||
// .last()
|
||||
// .siblings("div")
|
||||
// .first()
|
||||
// .invoke("text")
|
||||
// .then((text) => {
|
||||
// cy.get(commonlocators.toastmsg).contains(`Theme ${text} Applied`);
|
||||
// });
|
||||
|
||||
// // check if color of canvas is same as theme bg color
|
||||
// cy.get(`${commonlocators.themeCard} > main`)
|
||||
// .last()
|
||||
// .invoke("css", "background-color")
|
||||
// .then((backgroudColor) => {
|
||||
// cy.get(commonlocators.canvas).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// backgroudColor,
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("checks if theme can be edited", function() {
|
||||
// // drop a button widget and click on body
|
||||
// cy.get(explorer.addWidget).click();
|
||||
// cy.dragAndDropToCanvas("buttonwidget", { x: 200, y: 200 });
|
||||
// cy.get("body").click();
|
||||
|
||||
// //Click the back button
|
||||
// cy.get(commonlocators.selectThemeBackBtn).click({ force: true });
|
||||
|
||||
// //Click the border radius toggle
|
||||
// cy.contains("Border").click({ force: true });
|
||||
|
||||
// // change app border radius
|
||||
// cy.get(commonlocators.themeAppBorderRadiusBtn)
|
||||
// .eq(1)
|
||||
// .click({ force: true });
|
||||
|
||||
// // check if border radius is changed on button
|
||||
// cy.get(`${commonlocators.themeAppBorderRadiusBtn} > div`)
|
||||
// .eq(1)
|
||||
// .invoke("css", "border-top-left-radius")
|
||||
// .then((borderRadius) => {
|
||||
// cy.get(widgetsPage.widgetBtn).should(
|
||||
// "have.css",
|
||||
// "border-radius",
|
||||
// borderRadius,
|
||||
// );
|
||||
|
||||
// // publish the app
|
||||
// // cy.PublishtheApp();
|
||||
// cy.get(widgetsPage.widgetBtn).should(
|
||||
// "have.css",
|
||||
// "border-radius",
|
||||
// borderRadius,
|
||||
// );
|
||||
// });
|
||||
|
||||
// //Change the color:
|
||||
// cy.contains("Colour").click({ force: true });
|
||||
|
||||
// //Change the primary color:
|
||||
// cy.get(".border-2")
|
||||
// .first()
|
||||
// .click({ force: true });
|
||||
// cy.get(widgetsPage.colorPickerV2Popover).click({ force: true });
|
||||
// cy.get(widgetsPage.colorPickerV2Color)
|
||||
// .eq(-3)
|
||||
// .then(($elem) => {
|
||||
// cy.get($elem).click({ force: true });
|
||||
// cy.get(widgetsPage.widgetBtn).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// $elem.css("background-color"),
|
||||
// );
|
||||
// });
|
||||
|
||||
// //Change the background color:
|
||||
// cy.get(".border-2")
|
||||
// .last()
|
||||
// .click({ force: true });
|
||||
// cy.get(widgetsPage.colorPickerV2Popover).click({ force: true });
|
||||
// cy.get(widgetsPage.colorPickerV2Color)
|
||||
// .first()
|
||||
// .then(($elem) => {
|
||||
// cy.get($elem).click({ force: true });
|
||||
// cy.get(commonlocators.canvas).should(
|
||||
// "have.css",
|
||||
// "background-color",
|
||||
// $elem.css("background-color"),
|
||||
// );
|
||||
// });
|
||||
|
||||
// //Change the shadow
|
||||
// cy.contains("Shadow").click({ force: true });
|
||||
// cy.contains("App Box Shadow")
|
||||
// .siblings("div")
|
||||
// .children("span")
|
||||
// .last()
|
||||
// .then(($elem) => {
|
||||
// cy.get($elem).click({ force: true });
|
||||
// cy.get(widgetsPage.widgetBtn).should(
|
||||
// "have.css",
|
||||
// "box-shadow",
|
||||
// $elem.css("box-shadow"),
|
||||
// );
|
||||
// });
|
||||
|
||||
// //Change the font
|
||||
// cy.contains("Font").click({ force: true });
|
||||
|
||||
// cy.get("span[name='expand-more']").then(($elem) => {
|
||||
// cy.get($elem).click({ force: true });
|
||||
// cy.wait(250);
|
||||
// cy.get(".ads-dropdown-options-wrapper div")
|
||||
// .children()
|
||||
// .eq(2)
|
||||
// .then(($childElem) => {
|
||||
// cy.get($childElem).click({ force: true });
|
||||
// cy.get(widgetsPage.widgetBtn).should(
|
||||
// "have.css",
|
||||
// "font-family",
|
||||
// $childElem
|
||||
// .children()
|
||||
// .last()
|
||||
// .text(),
|
||||
// );
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("Checks if the theme can be saved", () => {
|
||||
// //Click on dropDown elipses
|
||||
// cy.contains("Theme Properties")
|
||||
// .siblings()
|
||||
// .first()
|
||||
// .find("button")
|
||||
// .click({ force: true });
|
||||
// // .then(($elem) => {
|
||||
// // cy.get(`${$elem} button`).click({ force: true });
|
||||
// // })
|
||||
|
||||
// cy.wait(300);
|
||||
|
||||
// //Click on save theme dropdown option
|
||||
// cy.contains("Save theme").click({ force: true });
|
||||
|
||||
// cy.wait(200);
|
||||
|
||||
// //Type the name of the theme:
|
||||
// cy.get("input[placeholder='My theme']").type("test theme");
|
||||
|
||||
// //Click on save theme button
|
||||
// cy.get("a[type='submit']").click({ force: true });
|
||||
|
||||
// cy.wait(200);
|
||||
|
||||
// //Click on change theme:
|
||||
// cy.get(commonlocators.changeThemeBtn).click({ force: true });
|
||||
|
||||
// //Check if the saved theme is present under 'Yours Themes' section
|
||||
// cy.contains("Your Themes")
|
||||
// .siblings()
|
||||
// .find(".t--theme-card")
|
||||
// .parent()
|
||||
// .should("contain.text", "test theme");
|
||||
// });
|
||||
|
||||
// it("Checks if the theme can be deleted", () => {
|
||||
// cy.wait(300);
|
||||
|
||||
// //Check if the saved theme is present under 'Yours Themes' section
|
||||
// cy.contains("Your Themes")
|
||||
// .siblings()
|
||||
// .find(".t--theme-card")
|
||||
// .parent()
|
||||
// .find("button")
|
||||
// .click({ force: true });
|
||||
|
||||
// cy.contains("Delete").click({ force: true });
|
||||
|
||||
// //check for delete alert
|
||||
// cy.wait(300);
|
||||
// cy.get(commonlocators.toastMsg).contains("Theme test theme Deleted");
|
||||
// });
|
||||
// });
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 43 KiB |
|
|
@ -131,13 +131,18 @@ Cypress.Commands.add("shareAndPublic", (email, role) => {
|
|||
});
|
||||
|
||||
Cypress.Commands.add("enablePublicAccess", () => {
|
||||
cy.get(homePage.enablePublicAccess).click();
|
||||
cy.get(homePage.enablePublicAccess)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
cy.wait("@changeAccess").should(
|
||||
"have.nested.property",
|
||||
"response.body.responseMeta.status",
|
||||
200,
|
||||
);
|
||||
cy.get(homePage.closeBtn).click();
|
||||
cy.wait(10000);
|
||||
cy.get(homePage.closeBtn)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("deleteUserFromOrg", (orgName) => {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ export class JSEditor {
|
|||
input.type(JSCode, {
|
||||
parseSpecialCharSequences: false,
|
||||
delay: 150,
|
||||
force: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ export class Table {
|
|||
cy.xpath(this._liCurrentSelectedPage).invoke('text').then($currentPageNo =>
|
||||
curPageNo = Number($currentPageNo))
|
||||
cy.get(this._liNextPage).click()
|
||||
cy.scrollTo('top', { easing: 'linear' })
|
||||
//cy.scrollTo('top', { easing: 'linear' })
|
||||
cy.xpath(this._liCurrentSelectedPage).invoke('text').then($newPageNo =>
|
||||
expect(Number($newPageNo)).to.eq(curPageNo + 1))
|
||||
}
|
||||
|
|
@ -241,7 +241,7 @@ export class Table {
|
|||
cy.xpath(this._liCurrentSelectedPage).invoke('text').then($currentPageNo =>
|
||||
curPageNo = Number($currentPageNo))
|
||||
cy.get(this._liPreviousPage).click()
|
||||
cy.scrollTo('top', { easing: 'linear' })
|
||||
//cy.scrollTo('top', { easing: 'linear' })
|
||||
cy.xpath(this._liCurrentSelectedPage).invoke('text').then($newPageNo =>
|
||||
expect(Number($newPageNo)).to.eq(curPageNo - 1))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -942,7 +942,7 @@ Cypress.Commands.add("startServerAndRoutes", () => {
|
|||
|
||||
cy.route("PUT", "/api/v1/organizations/*").as("updateOrganization");
|
||||
cy.route("GET", "/api/v1/pages/view/application/*").as("viewApp");
|
||||
cy.route("GET", "/api/v1/pages/*/view").as("viewPage");
|
||||
cy.route("GET", "/api/v1/pages/*/view?*").as("viewPage");
|
||||
cy.route("POST", "/api/v1/organizations/*/logo").as("updateLogo");
|
||||
cy.route("DELETE", "/api/v1/organizations/*/logo").as("deleteLogo");
|
||||
cy.route("POST", "/api/v1/applications/*/fork/*").as("postForkAppOrg");
|
||||
|
|
|
|||
|
|
@ -431,9 +431,12 @@ Cypress.Commands.add("selectColor", (GivenProperty) => {
|
|||
).click({
|
||||
force: true,
|
||||
});
|
||||
cy.get(widgetsPage.colorsAvailable)
|
||||
.first()
|
||||
.click({ force: true });
|
||||
|
||||
cy.get(widgetsPage.colorPickerV2Color)
|
||||
.eq(-15)
|
||||
.then(($elem) => {
|
||||
cy.get($elem).click({ force: true });
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("toggleJsAndUpdate", (endp, value) => {
|
||||
|
|
@ -785,6 +788,12 @@ Cypress.Commands.add("selectTextSize", (text) => {
|
|||
.click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("selectTxtSize", (text) => {
|
||||
cy.get(".t--dropdown-option")
|
||||
.contains(text)
|
||||
.click({ force: true });
|
||||
});
|
||||
|
||||
Cypress.Commands.add("getAlert", (alertcss) => {
|
||||
cy.get(commonlocators.dropdownSelectButton).click({ force: true });
|
||||
cy.get(widgetsPage.menubar)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"@sentry/tracing": "^6.2.4",
|
||||
"@sentry/webpack-plugin": "^1.12.1",
|
||||
"@tinymce/tinymce-react": "^3.13.0",
|
||||
"@types/webfontloader": "^1.6.33",
|
||||
"@uppy/core": "^1.16.0",
|
||||
"@uppy/dashboard": "^1.16.0",
|
||||
"@uppy/file-input": "^1.4.22",
|
||||
|
|
@ -55,6 +56,7 @@
|
|||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-xml-parser": "^3.17.5",
|
||||
"flow-bin": "^0.148.0",
|
||||
"focus-trap-react": "^8.9.2",
|
||||
"fuse.js": "^3.4.5",
|
||||
"fusioncharts": "^3.18.0",
|
||||
"fusionmaps": "^3.18.0",
|
||||
|
|
@ -158,6 +160,7 @@
|
|||
"typescript": "^4.1.3",
|
||||
"unescape-js": "^1.1.4",
|
||||
"url-search-params-polyfill": "^8.0.0",
|
||||
"webfontloader": "^1.6.28",
|
||||
"worker-loader": "^3.0.2",
|
||||
"yjs": "^13.5.12",
|
||||
"zipcelx": "^1.6.2"
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ import { ERROR_CODES } from "@appsmith/constants/ApiConstants";
|
|||
import TemplatesListLoader from "pages/Templates/loader";
|
||||
import { fetchFeatureFlagsInit } from "actions/userActions";
|
||||
import FeatureFlags from "entities/FeatureFlags";
|
||||
import WDSPage from "components/wds/Showcase";
|
||||
|
||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||
|
||||
|
|
@ -121,6 +122,7 @@ function AppRouter(props: {
|
|||
<SentryRoute component={OrganizationLoader} path={ORG_URL} />
|
||||
<SentryRoute component={Users} exact path={USERS_URL} />
|
||||
<SentryRoute component={UserAuth} path={USER_AUTH_URL} />
|
||||
<SentryRoute component={WDSPage} path="/wds" />
|
||||
<SentryRoute
|
||||
component={ApplicationListLoader}
|
||||
exact
|
||||
|
|
|
|||
168
app/client/src/actions/appThemingActions.tsx
Normal file
168
app/client/src/actions/appThemingActions.tsx
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
import { AppTheme } from "entities/AppTheming";
|
||||
import { AppThemingMode } from "selectors/appThemingSelectors";
|
||||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* ACTION TYPES
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type FetchAppThemesAction = {
|
||||
applicationId: string;
|
||||
};
|
||||
|
||||
export type FetchSelectedAppThemeAction = {
|
||||
applicationId: string;
|
||||
};
|
||||
|
||||
export type UpdateSelectedAppThemeAction = {
|
||||
applicationId: string;
|
||||
theme: AppTheme;
|
||||
shouldReplay?: boolean;
|
||||
};
|
||||
|
||||
export type ChangeSelectedAppThemeAction = {
|
||||
applicationId: string;
|
||||
theme: AppTheme;
|
||||
shouldReplay?: boolean;
|
||||
};
|
||||
|
||||
export type HydrateSelectedAppThemeAction = {
|
||||
theme: AppTheme;
|
||||
};
|
||||
|
||||
export type SaveAppThemeAction = {
|
||||
applicationId: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type DeleteAppThemeAction = {
|
||||
themeId: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* ACTIONS
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* set theming mode
|
||||
*
|
||||
* @param mode
|
||||
* @returns
|
||||
*/
|
||||
export const setAppThemingModeStackAction = (stack: AppThemingMode[]) => ({
|
||||
type: ReduxActionTypes.SET_APP_THEMING_STACK,
|
||||
payload: stack,
|
||||
});
|
||||
|
||||
/**
|
||||
* fetches themes
|
||||
*
|
||||
* @param mode
|
||||
* @returns
|
||||
*/
|
||||
export const fetchAppThemesAction = (applicationId: string) => ({
|
||||
type: ReduxActionTypes.FETCH_APP_THEMES_INIT,
|
||||
payload: {
|
||||
applicationId,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* fetch selected theme
|
||||
*
|
||||
* @param mode
|
||||
* @returns
|
||||
*/
|
||||
export const fetchSelectedAppThemeAction = (applicationId: string) => ({
|
||||
type: ReduxActionTypes.FETCH_SELECTED_APP_THEME_INIT,
|
||||
payload: {
|
||||
applicationId,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* update selected theme
|
||||
*
|
||||
* @param payload
|
||||
* @returns
|
||||
*/
|
||||
export const updateSelectedAppThemeAction = (
|
||||
payload: UpdateSelectedAppThemeAction,
|
||||
) => ({
|
||||
type: ReduxActionTypes.UPDATE_SELECTED_APP_THEME_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* change selected theme
|
||||
*
|
||||
* @param payload
|
||||
* @returns
|
||||
*/
|
||||
export const changeSelectedAppThemeAction = (
|
||||
payload: ChangeSelectedAppThemeAction,
|
||||
) => ({
|
||||
type: ReduxActionTypes.CHANGE_SELECTED_APP_THEME_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* set the preview theme
|
||||
*
|
||||
* @param payload
|
||||
* @returns
|
||||
*/
|
||||
export const setPreviewAppThemeAction = (payload?: AppTheme) => ({
|
||||
type: ReduxActionTypes.SET_PREVIEW_APP_THEME,
|
||||
payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* set the preview theme
|
||||
*
|
||||
* @param payload
|
||||
* @returns
|
||||
*/
|
||||
export const saveSelectedThemeAction = (payload?: SaveAppThemeAction) => ({
|
||||
type: ReduxActionTypes.SAVE_APP_THEME_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* delete app theme
|
||||
*
|
||||
* @param payload
|
||||
* @returns
|
||||
*/
|
||||
export const deleteAppThemeAction = (payload?: DeleteAppThemeAction) => ({
|
||||
type: ReduxActionTypes.DELETE_APP_THEME_INIT,
|
||||
payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* close beta card
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const closeAppThemingBetaCard = () => {
|
||||
return {
|
||||
type: ReduxActionTypes.CLOSE_BETA_CARD_SHOWN,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* close beta card
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const updateisBetaCardShownAction = (payload: boolean) => {
|
||||
return {
|
||||
type: ReduxActionTypes.UPDATE_BETA_CARD_SHOWN,
|
||||
payload,
|
||||
};
|
||||
};
|
||||
18
app/client/src/actions/appViewActions.ts
Normal file
18
app/client/src/actions/appViewActions.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* ACTIONS
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* set app view header height
|
||||
*
|
||||
* @param mode
|
||||
* @returns
|
||||
*/
|
||||
export const setAppViewHeaderHeight = (height: number) => ({
|
||||
type: ReduxActionTypes.SET_APP_VIEWER_HEADER_HEIGHT,
|
||||
payload: height,
|
||||
});
|
||||
|
|
@ -61,6 +61,7 @@ export const setWidgetDynamicProperty = (
|
|||
widgetId: string,
|
||||
propertyPath: string,
|
||||
isDynamic: boolean,
|
||||
shouldRejectDynamicBindingPathList = true,
|
||||
): ReduxAction<SetWidgetDynamicPropertyPayload> => {
|
||||
return {
|
||||
type: ReduxActionTypes.SET_WIDGET_DYNAMIC_PROPERTY,
|
||||
|
|
@ -68,6 +69,7 @@ export const setWidgetDynamicProperty = (
|
|||
widgetId,
|
||||
propertyPath,
|
||||
isDynamic,
|
||||
shouldRejectDynamicBindingPathList,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
@ -97,6 +99,7 @@ export interface SetWidgetDynamicPropertyPayload {
|
|||
widgetId: string;
|
||||
propertyPath: string;
|
||||
isDynamic: boolean;
|
||||
shouldRejectDynamicBindingPathList?: boolean;
|
||||
}
|
||||
|
||||
export interface DeleteWidgetPropertyPayload {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,10 @@ export const EVALUATE_REDUX_ACTIONS = [
|
|||
ReduxActionTypes.RESET_WIDGET_META,
|
||||
// Batches
|
||||
ReduxActionTypes.BATCH_UPDATES_SUCCESS,
|
||||
// App Theme
|
||||
ReduxActionTypes.UPDATE_SELECTED_APP_THEME_SUCCESS,
|
||||
ReduxActionTypes.CHANGE_SELECTED_APP_THEME_SUCCESS,
|
||||
ReduxActionTypes.SET_PREVIEW_APP_THEME,
|
||||
];
|
||||
// Topics used for datsource and query form evaluations
|
||||
export const FORM_EVALUATION_REDUX_ACTIONS = [
|
||||
|
|
|
|||
102
app/client/src/api/AppThemingApi.tsx
Normal file
102
app/client/src/api/AppThemingApi.tsx
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
import API from "api/Api";
|
||||
import { AxiosPromise } from "axios";
|
||||
import { AppTheme } from "entities/AppTheming";
|
||||
import { GenericApiResponse } from "./ApiResponses";
|
||||
|
||||
class AppThemingApi extends API {
|
||||
static baseUrl = "/v1";
|
||||
|
||||
/**
|
||||
* fires api to get all themes
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
static fetchThemes(
|
||||
applicationId: string,
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.get(
|
||||
`${AppThemingApi.baseUrl}/themes/applications/${applicationId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fires api to fetch selected theme
|
||||
*
|
||||
* @param applicationId
|
||||
* @returns
|
||||
*/
|
||||
static fetchSelected(
|
||||
applicationId: string,
|
||||
mode = "EDIT",
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.get(
|
||||
`${AppThemingApi.baseUrl}/themes/applications/${applicationId}/current?mode=${mode}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fires api to updating current theme
|
||||
*
|
||||
* @param applicationId
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
static updateTheme(
|
||||
applicationId: string,
|
||||
theme: AppTheme,
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.put(
|
||||
`${AppThemingApi.baseUrl}/themes/applications/${applicationId}`,
|
||||
theme,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fires api to updating current theme
|
||||
*
|
||||
* @param applicationId
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
static changeTheme(
|
||||
applicationId: string,
|
||||
theme: AppTheme,
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.patch(
|
||||
`${AppThemingApi.baseUrl}/applications/${applicationId}/themes/${theme.id}`,
|
||||
theme,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fires api for saving current theme
|
||||
*
|
||||
* @param applicationId
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
static saveTheme(
|
||||
applicationId: string,
|
||||
payload: { name: string },
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.patch(
|
||||
`${AppThemingApi.baseUrl}/themes/applications/${applicationId}`,
|
||||
payload,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* fires api for deleting theme
|
||||
*
|
||||
* @param applicationId
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
static deleteTheme(
|
||||
themeId: string,
|
||||
): AxiosPromise<GenericApiResponse<AppTheme[]>> {
|
||||
return API.delete(`${AppThemingApi.baseUrl}/themes/${themeId}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default AppThemingApi;
|
||||
3
app/client/src/assets/icons/control/undo_2.svg
Normal file
3
app/client/src/assets/icons/control/undo_2.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.5 8.5C9.85 8.5 7.45 9.49 5.6 11.1L2 7.5V16.5H11L7.38 12.88C8.77 11.72 10.54 11 12.5 11C16.04 11 19.05 13.31 20.1 16.5L22.47 15.72C21.08 11.53 17.15 8.5 12.5 8.5Z" fill="#575757"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 296 B |
|
|
@ -6,7 +6,7 @@
|
|||
* ---------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
body, html {
|
||||
@apply overflow-x-hidden;
|
||||
@apply w-full h-full overflow-x-hidden;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -28,6 +28,7 @@ body, html {
|
|||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(209, 213, 219, var(--tw-bg-opacity)) white;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
|
|
@ -46,3 +47,22 @@ body, html {
|
|||
:hover::-webkit-scrollbar-thumb {
|
||||
@apply bg-gray-300;
|
||||
}
|
||||
|
||||
|
||||
.diagnol-cross {
|
||||
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' preserveAspectRatio='none' viewBox='0 0 100 100'><path d='M0 99 L99 0 L100 1 L1 100' fill='red' /></svg>");
|
||||
background-repeat:no-repeat;
|
||||
background-position:center center;
|
||||
background-size: 100% 100%, auto;
|
||||
}
|
||||
|
||||
|
||||
.hidden-scrollbar {
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.hidden-scrollbar::-webkit-scrollbar {
|
||||
display: none; /* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
|
|
|||
12
app/client/src/assets/svg/appsmith-logo-no-pad.svg
Normal file
12
app/client/src/assets/svg/appsmith-logo-no-pad.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<svg width="783" height="131" viewBox="0 0 783 131" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M510.51 17.21C509.564 16.309 508.816 15.2218 508.312 14.017C507.807 12.8122 507.558 11.5159 507.58 10.21C507.58 7.55784 508.634 5.0143 510.509 3.13894C512.384 1.26357 514.928 0.210005 517.58 0.210005C518.886 0.188131 520.182 0.437208 521.387 0.941511C522.592 1.44581 523.679 2.19439 524.58 3.14C525.508 4.06766 526.239 5.17263 526.73 6.38903C527.222 7.60542 527.463 8.90832 527.44 10.22C527.462 11.5259 527.213 12.8222 526.708 14.027C526.204 15.2318 525.456 16.319 524.51 17.22C523.605 18.1384 522.523 18.865 521.331 19.3564C520.139 19.8478 518.86 20.0939 517.57 20.08C516.261 20.0985 514.962 19.854 513.749 19.361C512.536 18.868 511.435 18.1365 510.51 17.21V17.21Z" fill="#1A1A1A"/>
|
||||
<path d="M52.81 102.78C51.95 101.253 51.2833 98.2533 50.81 93.78C45.85 100.94 37.9333 104.517 27.06 104.51C18.9467 104.51 12.4833 102.557 7.67001 98.65C2.85668 94.7433 0.450012 89.3033 0.450012 82.33C0.450012 68.8833 9.89335 61.2167 28.78 59.33L39.94 58.33C43.66 57.86 46.33 56.97 47.94 55.69C48.7694 54.9797 49.421 54.0853 49.843 53.0782C50.2649 52.0711 50.4454 50.9793 50.37 49.89C50.37 46.7433 49.3467 44.43 47.3 42.95C45.2534 41.47 41.7933 40.73 36.92 40.73C31.68 40.73 27.9134 41.6133 25.62 43.38C23.33 45.15 21.99 48.17 21.62 52.47H3.87002C4.91668 35.6833 15.9833 27.2867 37.07 27.28C57.5833 27.28 67.8367 34.6733 67.83 49.46V88.81C67.83 95.3033 68.83 99.97 70.83 102.81L52.81 102.78ZM45.08 87C48.6134 83.9 50.3767 79.44 50.37 73.62V66.9C48.66 68.43 45.84 69.43 41.93 69.9L32.2 71C27.4 71.58 24 72.7033 22 74.37C20.9609 75.2535 20.1416 76.3668 19.607 77.6216C19.0725 78.8765 18.8372 80.2385 18.92 81.6C18.8401 82.9965 19.0868 84.3924 19.6405 85.677C20.1943 86.9615 21.0398 88.0993 22.11 89C24.2633 90.76 27.34 91.64 31.34 91.64C36.9733 91.62 41.5534 90.0733 45.08 87Z" fill="#1A1A1A"/>
|
||||
<path d="M157.26 37.67C163.18 44.73 166.137 54.1267 166.13 65.86C166.123 77.5933 163.167 86.9267 157.26 93.86C151.26 100.92 143.2 104.45 133.08 104.45C122.96 104.45 115.327 100.683 110.18 93.15V130.78H92.18V28.94H109.49V39.53C114.823 31.33 122.693 27.2267 133.1 27.22C143.2 27.22 151.253 30.7033 157.26 37.67V37.67ZM128.79 89.61C134.697 89.61 139.363 87.4633 142.79 83.17C146.217 78.8767 147.883 72.9167 147.79 65.29C147.79 57.75 146.143 52 142.85 48.04C139.557 44.08 134.86 42.1 128.76 42.1C122.76 42.1 118.093 44.1533 114.76 48.26C111.427 52.3667 109.76 58.2333 109.76 65.86C109.76 73.58 111.477 79.4467 114.91 83.46C118.15 87.56 122.777 89.61 128.79 89.61Z" fill="#1A1A1A"/>
|
||||
<path d="M250 37.67C255.92 44.73 258.877 54.1267 258.87 65.86C258.863 77.5933 255.907 86.9267 250 93.86C244 100.92 235.94 104.45 225.82 104.45C215.7 104.45 208.067 100.683 202.92 93.15V130.78H184.92V28.94H202.24V39.53C207.573 31.33 215.443 27.2267 225.85 27.22C235.91 27.22 243.96 30.7033 250 37.67ZM221.53 89.61C227.437 89.61 232.103 87.4633 235.53 83.17C238.957 78.8767 240.623 72.9167 240.53 65.29C240.53 57.75 238.883 52 235.59 48.04C232.297 44.08 227.6 42.1 221.5 42.1C215.5 42.1 210.833 44.1533 207.5 48.26C204.167 52.3667 202.5 58.2333 202.5 65.86C202.5 73.58 204.22 79.4467 207.66 83.46C210.86 87.56 215.467 89.61 221.48 89.61H221.53Z" fill="#1A1A1A"/>
|
||||
<path d="M275.13 79.31H292.73C293.21 83.89 294.713 87.1333 297.24 89.04C299.767 90.9467 303.75 91.9 309.19 91.9C318.923 91.9 323.79 88.9433 323.79 83.03C323.842 81.82 323.579 80.6172 323.027 79.5392C322.475 78.4613 321.652 77.545 320.64 76.88C318.54 75.4467 314.77 74.2533 309.33 73.3L300.89 71.87C284.77 69.2033 276.71 61.7633 276.71 49.55C276.71 42.5833 279.377 37.12 284.71 33.16C290.043 29.2 297.58 27.22 307.32 27.22C328.4 27.22 339.277 35.5533 339.95 52.22H322.95C322.757 47.84 321.373 44.7167 318.8 42.85C316.227 40.9833 312.41 40.0533 307.35 40.06C298.763 40.06 294.47 42.9233 294.47 48.65C294.425 49.7772 294.663 50.8978 295.163 51.9092C295.662 52.9207 296.407 53.7908 297.33 54.44C299.243 55.82 302.393 56.8933 306.78 57.66L316.08 59.09C325.047 60.71 331.557 63.2867 335.61 66.82C339.663 70.3533 341.69 75.2667 341.69 81.56C341.69 89 338.83 94.7233 333.11 98.73C327.39 102.737 319.327 104.737 308.92 104.73C287.36 104.763 276.097 96.29 275.13 79.31V79.31Z" fill="#1A1A1A"/>
|
||||
<path d="M465.09 34.38C469.617 39.1533 471.883 45.6867 471.89 53.98V102.78H453.89V56.84C453.89 47.5067 449.643 42.84 441.15 42.84C439.04 42.7592 436.939 43.1604 435.007 44.0128C433.075 44.8653 431.363 46.1468 430 47.76C427.193 51.0467 425.787 55.84 425.78 62.14V102.78H407.92V56.84C407.92 47.5067 403.63 42.84 395.05 42.84C392.97 42.7797 390.903 43.1931 389.006 44.0489C387.109 44.9047 385.431 46.1806 384.1 47.78C381.28 51.0667 379.873 55.86 379.88 62.16V102.8H361.88V28.94H379.34V39.53C384.387 31.33 391.387 27.2267 400.34 27.22C411.6 27.22 419.233 31.8 423.24 40.96C428.767 31.8 436.397 27.22 446.13 27.22C454.243 27.22 460.563 29.6067 465.09 34.38V34.38Z" fill="#1A1A1A"/>
|
||||
<path d="M610 42.68H587V82.6C587 84.98 587.643 86.6467 588.93 87.6C590.217 88.5533 592.373 89.02 595.4 89H608.57V102.74C604.66 103.12 594.5 103.31 592.11 103.31C584.11 103.31 578.267 101.807 574.58 98.8C570.893 95.7933 569.057 91 569.07 84.42V42.68H552.33V28.94H569.07V4.29001H587V28.94H610V42.68Z" fill="#1A1A1A"/>
|
||||
<path d="M690.66 34.16C695.293 38.7933 697.607 45.3533 697.6 53.84V102.78H679.6V56.84C679.6 47.5067 674.973 42.84 665.72 42.84C663.531 42.7946 661.357 43.2091 659.338 44.0566C657.319 44.9041 655.501 46.1657 654 47.76C650.813 51.0467 649.217 55.6 649.21 61.42V102.78H631.21V4.29001H649.21V38.81C654.837 31.09 662.323 27.2267 671.67 27.22C679.71 27.22 686.04 29.5333 690.66 34.16V34.16Z" fill="#1A1A1A"/>
|
||||
<path d="M526.75 89.04V28.94H488.84V42.68H508.73V89.04H488.84V102.78H546.64V89.04H526.75Z" fill="#1A1A1A"/>
|
||||
<path d="M712.16 127.1V113.36H782.56V127.1H712.16Z" fill="#FF6D2D"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
|
|
@ -678,6 +678,20 @@ export const ReduxActionTypes = {
|
|||
DELETE_ORG_SUCCESS: "DELETE_ORG_SUCCESS",
|
||||
SET_USER_CURRENT_GEO_LOCATION: "SET_USER_CURRENT_GEO_LOCATION",
|
||||
SET_DISCONNECTING_GIT_APPLICATION: "SET_DISCONNECTING_GIT_APPLICATION",
|
||||
SET_APP_THEMING_STACK: "SET_APP_THEMING_STACK",
|
||||
FETCH_APP_THEMES_INIT: "FETCH_APP_THEMES_INIT",
|
||||
FETCH_APP_THEMES_SUCCESS: "FETCH_APP_THEMES_SUCCESS",
|
||||
FETCH_SELECTED_APP_THEME_INIT: "FETCH_SELECTED_APP_THEME_INIT",
|
||||
FETCH_SELECTED_APP_THEME_SUCCESS: "FETCH_SELECTED_APP_THEME_SUCCESS",
|
||||
UPDATE_SELECTED_APP_THEME_INIT: "UPDATE_SELECTED_APP_THEME_INIT",
|
||||
UPDATE_SELECTED_APP_THEME_SUCCESS: "UPDATE_SELECTED_APP_THEME_SUCCESS",
|
||||
CHANGE_SELECTED_APP_THEME_INIT: "CHANGE_SELECTED_APP_THEME_INIT",
|
||||
CHANGE_SELECTED_APP_THEME_SUCCESS: "CHANGE_SELECTED_APP_THEME_SUCCESS",
|
||||
SET_PREVIEW_APP_THEME: "SET_PREVIEW_APP_THEME",
|
||||
SAVE_APP_THEME_INIT: "SAVE_APP_THEME_INIT",
|
||||
SAVE_APP_THEME_SUCCESS: "SAVE_APP_THEME_SUCCESS",
|
||||
DELETE_APP_THEME_INIT: "DELETE_APP_THEME_INIT",
|
||||
DELETE_APP_THEME_SUCCESS: "DELETE_APP_THEME_SUCCESS",
|
||||
GET_ALL_TEMPLATES_INIT: "GET_ALL_TEMPLATES_INIT",
|
||||
GET_ALL_TEMPLATES_SUCCESS: "GET_ALL_TEMPLATES_SUCCESS",
|
||||
UPDATE_TEMPLATE_FILTERS: "UPDATE_TEMPLATE_FILTERS",
|
||||
|
|
@ -693,6 +707,9 @@ export const ReduxActionTypes = {
|
|||
ENTITY_UPDATE_STARTED: "ENTITY_UPDATE_STARTED",
|
||||
ENTITY_UPDATE_SUCCESS: "ENTITY_UPDATE_SUCCESS",
|
||||
FETCH_PLUGIN_AND_JS_ACTIONS_SUCCESS: "FETCH_PLUGIN_AND_JS_ACTIONS_SUCCESS",
|
||||
SET_APP_VIEWER_HEADER_HEIGHT: "SET_APP_VIEWER_HEADER_HEIGHT",
|
||||
UPDATE_BETA_CARD_SHOWN: "UPDATE_BETA_CARD_SHOWN",
|
||||
CLOSE_BETA_CARD_SHOWN: "CLOSE_BETA_CARD_SHOWN",
|
||||
GET_DEFAULT_PLUGINS_REQUEST: "GET_DEFAULT_PLUGINS_REQUEST",
|
||||
GET_DEFAULT_PLUGINS_SUCCESS: "GET_DEFAULT_PLUGINS_SUCCESS",
|
||||
GET_TEMPLATE_INIT: "GET_TEMPLATES_INIT",
|
||||
|
|
@ -861,9 +878,15 @@ export const ReduxActionErrorTypes = {
|
|||
FETCH_RELEASES_ERROR: "FETCH_RELEASES_ERROR",
|
||||
RESTART_SERVER_ERROR: "RESTART_SERVER_ERROR",
|
||||
UPDATE_JS_ACTION_BODY_ERROR: "UPDATE_JS_ACTION_BODY_ERROR",
|
||||
FETCH_APP_THEMES_ERROR: "FETCH_APP_THEMES_ERROR",
|
||||
FETCH_SELECTED_APP_THEME_ERROR: "FETCH_SELECTED_APP_THEME_ERROR",
|
||||
UPDATE_SELECTED_APP_THEME_ERROR: "UPDATE_SELECTED_APP_THEME_ERROR",
|
||||
CHANGE_SELECTED_APP_THEME_ERROR: "CHANGE_SELECTED_APP_THEME_ERROR",
|
||||
UPDATE_JS_FUNCTION_PROPERTY_ERROR: "UPDATE_JS_FUNCTION_PROPERTY_ERROR",
|
||||
DELETE_ORG_ERROR: "DELETE_ORG_ERROR",
|
||||
REFLOW_BETA_FLAGS_INIT_ERROR: "REFLOW_BETA_FLAGS_INIT_ERROR",
|
||||
SAVE_APP_THEME_ERROR: "SAVE_APP_THEME_ERROR",
|
||||
DELETE_APP_THEME_ERROR: "DELETE_APP_THEME_ERROR",
|
||||
GET_ALL_TEMPLATES_ERROR: "GET_ALL_TEMPLATES_ERROR",
|
||||
GET_SIMILAR_TEMPLATES_ERROR: "GET_SIMILAR_TEMPLATES_ERROR",
|
||||
IMPORT_TEMPLATE_TO_ORGANISATION_ERROR:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export const VALID_FUNCTION_NAME_ERROR = () =>
|
|||
`Must be a valid variable name (camelCase)`;
|
||||
export const UNIQUE_NAME_ERROR = () => `Name must be unique`;
|
||||
export const NAME_SPACE_ERROR = () => `Name must not have spaces`;
|
||||
export const SPECIAL_CHARACTER_ERROR = () => `Name must be alphanumeric`;
|
||||
|
||||
export const FORM_VALIDATION_EMPTY_EMAIL = () => `Please enter an email`;
|
||||
export const FORM_VALIDATION_INVALID_EMAIL = () =>
|
||||
|
|
@ -1049,7 +1050,20 @@ export const TABLE_WIDGET_TOTAL_RECORD_TOOLTIP = () =>
|
|||
export const CREATE_DATASOURCE_TOOLTIP = () => "Add a new datasource";
|
||||
export const ADD_QUERY_JS_TOOLTIP = () => "Create New";
|
||||
|
||||
// Add datasource
|
||||
export const GENERATE_APPLICATION_TITLE = () => "Generate Page";
|
||||
export const GENERATE_APPLICATION_DESCRIPTION = () =>
|
||||
"Quickly generate a page to perform CRUD operations on your database tables";
|
||||
export const DELETE_ORG_SUCCESSFUL = () => "Organization deleted successfully";
|
||||
// theming
|
||||
export const CHANGE_APP_THEME = (name: string) => `Theme ${name} Applied`;
|
||||
export const SAVE_APP_THEME = (name: string) => `Theme ${name} Saved`;
|
||||
export const DELETE_APP_THEME = (name: string) => `Theme ${name} Deleted`;
|
||||
export const DELETE_APP_THEME_WARNING = () =>
|
||||
`Do you really want to delete this theme? This process cannot be undone.`;
|
||||
export const APP_THEME_BETA_CARD_HEADING = () => `🎨 Theme your app`;
|
||||
export const APP_THEME_BETA_CARD_CONTENT = () =>
|
||||
`Customize your app's look through global styles. Full widget support coming soon`;
|
||||
|
||||
export const UPGRADE_TO_EE = (authLabel: string) =>
|
||||
`Hello, I would like to upgrade and start using ${authLabel} authentication.`;
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ function CommentCard({
|
|||
<CommentHeader data-cy="comments-card-header">
|
||||
<HeaderSection>
|
||||
<ProfileImage
|
||||
side={25}
|
||||
size={25}
|
||||
source={profilePhotoUrl}
|
||||
userName={authorName || ""}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { Colors } from "constants/Colors";
|
||||
import { ControlIcons, ControlIconName } from "icons/ControlIcons";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import _ from "lodash";
|
||||
|
||||
const ItemWrapper = styled.div<{ selected: boolean }>`
|
||||
min-width: 32px;
|
||||
|
|
@ -39,7 +40,7 @@ const FlexWrapper = styled.div`
|
|||
`;
|
||||
|
||||
export interface ButtonTabOption {
|
||||
icon: string;
|
||||
icon: string | JSX.Element;
|
||||
value: string;
|
||||
width?: number;
|
||||
}
|
||||
|
|
@ -94,8 +95,13 @@ function ButtonTabComponent(props: ButtonTabComponentProps) {
|
|||
>
|
||||
{props.options.map(
|
||||
({ icon, value, width = 24 }: ButtonTabOption, index: number) => {
|
||||
const controlIconName: ControlIconName = icon;
|
||||
const ControlIcon = ControlIcons[controlIconName];
|
||||
let ControlIcon;
|
||||
if (_.isString(icon)) {
|
||||
const Icon = ControlIcons[icon];
|
||||
ControlIcon = <Icon height={24} width={width} />;
|
||||
} else {
|
||||
ControlIcon = icon;
|
||||
}
|
||||
const isSelected = valueSet.has(value);
|
||||
return (
|
||||
<ItemWrapper
|
||||
|
|
@ -111,7 +117,7 @@ function ButtonTabComponent(props: ButtonTabComponentProps) {
|
|||
role="tab"
|
||||
selected={isSelected}
|
||||
>
|
||||
<ControlIcon height={24} width={width} />
|
||||
{ControlIcon}
|
||||
</ItemWrapper>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
208
app/client/src/components/ads/ColorPickerComponentV2.test.tsx
Normal file
208
app/client/src/components/ads/ColorPickerComponentV2.test.tsx
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
import React from "react";
|
||||
import store from "store";
|
||||
import { Provider } from "react-redux";
|
||||
import "@testing-library/jest-dom";
|
||||
import {
|
||||
render,
|
||||
screen,
|
||||
waitForElementToBeRemoved,
|
||||
} from "@testing-library/react";
|
||||
import { ThemeProvider } from "constants/DefaultTheme";
|
||||
import ColorPickerComponent from "./ColorPickerComponentV2";
|
||||
import { lightTheme } from "selectors/themeSelectors";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
const getTestComponent = (handleOnChange: any = undefined) => (
|
||||
<Provider store={store}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<ColorPickerComponent
|
||||
changeColor={handleOnChange}
|
||||
color="#ffffff"
|
||||
showApplicationColors
|
||||
showThemeColors
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
describe("<ColorPicker />", () => {
|
||||
it("Clicking the input should open the colorpicker", () => {
|
||||
render(getTestComponent());
|
||||
expect(screen.queryByTestId("color-picker")).not.toBeInTheDocument();
|
||||
screen.getByRole("textbox").click();
|
||||
expect(screen.getByTestId("color-picker")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Clicking the color inside input should open the colorpicker", () => {
|
||||
render(getTestComponent());
|
||||
expect(screen.queryByTestId("color-picker")).not.toBeInTheDocument();
|
||||
(screen.getByRole("textbox")?.previousSibling as HTMLElement)?.click();
|
||||
expect(screen.getByTestId("color-picker")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Focusing the input using mouse should open the colorpicker and keep the focus on the input", () => {
|
||||
render(getTestComponent());
|
||||
expect(screen.queryByTestId("color-picker")).not.toBeInTheDocument();
|
||||
|
||||
// Simulating clicking and focus
|
||||
screen.getByRole("textbox").focus();
|
||||
screen.getByRole("textbox").click();
|
||||
|
||||
expect(screen.getByRole("textbox")).toHaveFocus();
|
||||
expect(screen.getByTestId("color-picker")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("<ColorPicker /> - Keyboard Navigation", () => {
|
||||
it("Pressing tab should focus the component", () => {
|
||||
render(getTestComponent());
|
||||
userEvent.tab();
|
||||
expect(screen.getByRole("textbox")).toHaveFocus();
|
||||
});
|
||||
|
||||
it("Pressing {Enter} should open the colorpicker", async () => {
|
||||
render(getTestComponent());
|
||||
userEvent.tab();
|
||||
expect(screen.queryByTestId("color-picker")).toBeNull();
|
||||
userEvent.keyboard("{Enter}");
|
||||
expect(screen.queryByTestId("color-picker")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("Pressing {Escape} should close the colorpicker", async () => {
|
||||
render(getTestComponent());
|
||||
userEvent.tab();
|
||||
expect(screen.queryByTestId("color-picker")).toBeNull();
|
||||
userEvent.keyboard("{Enter}");
|
||||
expect(screen.queryByTestId("color-picker")).toBeInTheDocument();
|
||||
userEvent.keyboard("{Escape}");
|
||||
await waitForElementToBeRemoved(screen.queryByTestId("color-picker"));
|
||||
});
|
||||
|
||||
// it("Pressing {Tab} should shift sections in the colorpicker", async () => {
|
||||
// render(getTestComponent());
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
|
||||
// userEvent.tab();
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[0],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.tab();
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// // Back to first color
|
||||
// userEvent.tab();
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[0],
|
||||
// ).toHaveFocus();
|
||||
// });
|
||||
|
||||
// it("Pressing {ArrowRight} should shift focus to color to the right", () => {
|
||||
// render(getTestComponent());
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
|
||||
// userEvent.tab();
|
||||
// userEvent.tab();
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowRight}");
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[1],
|
||||
// ).toHaveFocus();
|
||||
// });
|
||||
|
||||
// it("Pressing {ArrowLeft} should shift focus to color to the left", () => {
|
||||
// render(getTestComponent());
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
|
||||
// userEvent.tab();
|
||||
// userEvent.tab();
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowRight}");
|
||||
// userEvent.keyboard("{ArrowRight}");
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[2],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowLeft}");
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[1],
|
||||
// ).toHaveFocus();
|
||||
// });
|
||||
|
||||
// it("Pressing {ArrowDown} should shift focus to color to the bottom", () => {
|
||||
// render(getTestComponent());
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
|
||||
// userEvent.tab();
|
||||
// userEvent.tab();
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowDown}");
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[10],
|
||||
// ).toHaveFocus();
|
||||
// });
|
||||
|
||||
// it("Pressing {ArrowUp} should shift focus to color to the top", () => {
|
||||
// render(getTestComponent());
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
|
||||
// userEvent.tab();
|
||||
// userEvent.tab();
|
||||
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowRight}");
|
||||
// userEvent.keyboard("{ArrowDown}");
|
||||
// userEvent.keyboard("{ArrowDown}");
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[21],
|
||||
// ).toHaveFocus();
|
||||
|
||||
// userEvent.keyboard("{ArrowUp}");
|
||||
// expect(
|
||||
// document.querySelectorAll("[tabindex='0'].t--colorpicker-v2-color")[1]
|
||||
// .parentElement?.childNodes[11],
|
||||
// ).toHaveFocus();
|
||||
// });
|
||||
|
||||
// it("Pressing {Enter} should select the color in focus", async () => {
|
||||
// const onColorChange = jest.fn();
|
||||
// render(getTestComponent(onColorChange));
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{Enter}");
|
||||
// userEvent.tab();
|
||||
// userEvent.tab();
|
||||
// userEvent.keyboard("{ArrowRight}");
|
||||
// userEvent.keyboard("{Enter}");
|
||||
// expect(onColorChange).toBeCalled();
|
||||
// await waitForElementToBeRemoved(screen.queryByTestId("color-picker"));
|
||||
// });
|
||||
});
|
||||
502
app/client/src/components/ads/ColorPickerComponentV2.tsx
Normal file
502
app/client/src/components/ads/ColorPickerComponentV2.tsx
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
import React, { useEffect, useRef, useMemo, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
Popover,
|
||||
InputGroup,
|
||||
PopoverInteractionKind,
|
||||
Classes,
|
||||
} from "@blueprintjs/core";
|
||||
import { ReactComponent as ColorPickerIcon } from "assets/icons/control/color-picker.svg";
|
||||
import { debounce, get } from "lodash";
|
||||
import { Colors } from "constants/Colors";
|
||||
import { useSelector } from "store";
|
||||
import { getSelectedAppThemeProperties } from "selectors/appThemingSelectors";
|
||||
import {
|
||||
colorsPropertyName,
|
||||
getThemePropertyBinding,
|
||||
} from "constants/ThemeConstants";
|
||||
import { getWidgets } from "sagas/selectors";
|
||||
import { extractColorsFromString } from "utils/helpers";
|
||||
import { TAILWIND_COLORS } from "constants/ThemeConstants";
|
||||
const FocusTrap = require("focus-trap-react");
|
||||
|
||||
const MAX_COLS = 10;
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* TYPES
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
interface ColorPickerProps {
|
||||
color: string;
|
||||
changeColor: (color: string) => void;
|
||||
showThemeColors?: boolean;
|
||||
showApplicationColors?: boolean;
|
||||
evaluatedColorValue?: string;
|
||||
autoFocus?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* STYLED
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
const ColorIcon = styled.div<{ color: string }>`
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 3px solid ${(props) => props.theme.colors.propertyPane.bg};
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
background: ${(props) => (props.color ? props.color : "transparent")};
|
||||
`;
|
||||
|
||||
const ColorPickerIconContainer = styled.div`
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
const StyledInputGroup = styled(InputGroup)`
|
||||
.${Classes.INPUT} {
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
&&& input {
|
||||
padding-left: 36px;
|
||||
height: 36px;
|
||||
border: 1px solid ${Colors.GREY_5};
|
||||
background: ${(props) =>
|
||||
props.theme.colors.propertyPane.multiDropdownBoxHoverBg};
|
||||
color: ${(props) => props.theme.colors.propertyPane.label};
|
||||
|
||||
&:focus {
|
||||
border: 1px solid ${Colors.GREY_9};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const COLOR_BOX_CLASSES = `w-6 h-6 transform border rounded-full cursor-pointer hover:ring-1 ring-gray-500 t--colorpicker-v2-color focus:ring-2`;
|
||||
|
||||
interface ColorPickerPopupProps {
|
||||
color: string;
|
||||
containerRef: React.MutableRefObject<HTMLDivElement | null>;
|
||||
setColor: (color: string) => unknown;
|
||||
setIsOpen: (isOpen: boolean) => unknown;
|
||||
changeColor: (color: string) => unknown;
|
||||
showThemeColors?: boolean;
|
||||
showApplicationColors?: boolean;
|
||||
}
|
||||
|
||||
function ColorPickerPopup(props: ColorPickerPopupProps) {
|
||||
const themeColors = useSelector(getSelectedAppThemeProperties).colors;
|
||||
const widgets = useSelector(getWidgets);
|
||||
const DSLStringified = JSON.stringify(widgets);
|
||||
const applicationColors = useMemo(() => {
|
||||
return extractColorsFromString(DSLStringified);
|
||||
}, [DSLStringified]);
|
||||
const {
|
||||
changeColor,
|
||||
color,
|
||||
containerRef,
|
||||
setColor,
|
||||
setIsOpen,
|
||||
showApplicationColors,
|
||||
showThemeColors,
|
||||
} = props;
|
||||
|
||||
const isClick = useRef(false);
|
||||
const [isFocusTrapped, setIsFocusTrapped] = useState(false);
|
||||
|
||||
function handleFocus() {
|
||||
if (!isClick.current) setIsFocusTrapped(true);
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
isClick.current = true;
|
||||
}
|
||||
|
||||
function handleKeyDown() {
|
||||
isClick.current = false;
|
||||
}
|
||||
|
||||
const popup = (
|
||||
<div
|
||||
className="p-3 space-y-2 w-72"
|
||||
data-testid="color-picker"
|
||||
onClick={handleClick}
|
||||
onFocus={handleFocus}
|
||||
onKeyDown={handleKeyDown}
|
||||
ref={containerRef}
|
||||
>
|
||||
{showThemeColors && (
|
||||
<div className="space-y-2">
|
||||
<h2 className="pb-2 font-semibold border-b">Color Styles</h2>
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">Theme Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
{Object.keys(themeColors).map((colorKey, colorIndex) => (
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ${
|
||||
props.color === themeColors[colorKey] ? "ring-1" : ""
|
||||
}`}
|
||||
key={`color-picker-v2-${colorKey}`}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setColor(themeColors[colorKey]);
|
||||
setIsOpen(false);
|
||||
changeColor(
|
||||
getThemePropertyBinding(
|
||||
`${colorsPropertyName}.${colorKey}`,
|
||||
),
|
||||
);
|
||||
}}
|
||||
style={{ backgroundColor: themeColors[colorKey] }}
|
||||
tabIndex={colorIndex === 0 ? 0 : -1}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)}
|
||||
{showApplicationColors && applicationColors.length > 0 && (
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">Application Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
{Object.values(applicationColors).map(
|
||||
(colorCode: string, colorIndex) => (
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ring-gray-500 ${
|
||||
color === colorCode ? "ring-1" : ""
|
||||
}`}
|
||||
key={colorCode}
|
||||
onClick={() => {
|
||||
setColor(colorCode);
|
||||
setIsOpen(false);
|
||||
changeColor(colorCode);
|
||||
}}
|
||||
style={{ backgroundColor: colorCode }}
|
||||
tabIndex={colorIndex === 0 ? 0 : -1}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs">All Colors</h3>
|
||||
<div className="grid grid-cols-10 gap-2">
|
||||
{Object.keys(TAILWIND_COLORS).map((colorKey, rowIndex) =>
|
||||
Object.keys(get(TAILWIND_COLORS, `${colorKey}`)).map(
|
||||
(singleColorKey, colIndex) => (
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ${
|
||||
color === TAILWIND_COLORS[colorKey][singleColorKey]
|
||||
? "ring-1"
|
||||
: ""
|
||||
}`}
|
||||
key={`all-colors-${colorKey}-${singleColorKey}`}
|
||||
onClick={(e) => {
|
||||
setIsOpen(false);
|
||||
e.stopPropagation();
|
||||
setColor(TAILWIND_COLORS[colorKey][singleColorKey]);
|
||||
changeColor(TAILWIND_COLORS[colorKey][singleColorKey]);
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: TAILWIND_COLORS[colorKey][singleColorKey],
|
||||
}}
|
||||
tabIndex={rowIndex === 0 && colIndex === 0 ? 0 : -1}
|
||||
/>
|
||||
),
|
||||
),
|
||||
)}
|
||||
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} ${
|
||||
color === "#fff" ? "ring-1" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setColor("#fff");
|
||||
changeColor("#fff");
|
||||
}}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<div
|
||||
className={`${COLOR_BOX_CLASSES} diagnol-cross ${
|
||||
color === "transparent" ? "ring-1" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setColor("transparent");
|
||||
changeColor("transparent");
|
||||
}}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<FocusTrap
|
||||
active={isFocusTrapped}
|
||||
focusTrapOptions={{
|
||||
onDeactivate: () => {
|
||||
setIsFocusTrapped(false);
|
||||
},
|
||||
clickOutsideDeactivates: true,
|
||||
returnFocusOnDeactivate: true,
|
||||
}}
|
||||
>
|
||||
{popup}
|
||||
</FocusTrap>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* COMPONENT
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
interface LeftIconProps {
|
||||
color: string;
|
||||
handleInputClick?: () => void;
|
||||
}
|
||||
|
||||
function LeftIcon(props: LeftIconProps) {
|
||||
return props.color ? (
|
||||
<ColorIcon
|
||||
className="rounded-full cursor-pointer"
|
||||
color={props.color}
|
||||
onClick={props.handleInputClick}
|
||||
/>
|
||||
) : (
|
||||
<ColorPickerIconContainer
|
||||
className="cursor-pointer"
|
||||
onClick={props.handleInputClick}
|
||||
>
|
||||
<ColorPickerIcon />
|
||||
</ColorPickerIconContainer>
|
||||
);
|
||||
}
|
||||
|
||||
const DEBOUNCE_TIMER = 250;
|
||||
const POPOVER_MODFIER = {
|
||||
offset: {
|
||||
offset: "0, 10px",
|
||||
},
|
||||
};
|
||||
|
||||
function ColorPickerComponent(props: ColorPickerProps) {
|
||||
const inputRef = useRef<HTMLDivElement>(null);
|
||||
const popupRef = useRef<HTMLDivElement>(null);
|
||||
const inputGroupRef = useRef<HTMLInputElement>(null);
|
||||
// isClick is used to track whether the input field is in focus by mouse click or by keyboard
|
||||
// This is used since we open the popup only on mouse click not on keyboard focus
|
||||
const isClick = useRef(false);
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [color, setColor] = React.useState(
|
||||
props.evaluatedColorValue || props.color,
|
||||
);
|
||||
|
||||
const debouncedOnChange = React.useCallback(
|
||||
debounce((color: string) => {
|
||||
props.changeColor(color);
|
||||
}, DEBOUNCE_TIMER),
|
||||
[],
|
||||
);
|
||||
|
||||
const currentFocus = useRef(0);
|
||||
|
||||
const handleKeydown = (e: KeyboardEvent) => {
|
||||
if (isOpen) {
|
||||
switch (e.key) {
|
||||
case "Escape":
|
||||
setIsOpen(false);
|
||||
setTimeout(() => {
|
||||
inputGroupRef.current?.focus();
|
||||
}, 300);
|
||||
e.stopPropagation();
|
||||
break;
|
||||
case "Tab":
|
||||
currentFocus.current = 0;
|
||||
if (document.activeElement === inputGroupRef.current) {
|
||||
setTimeout(() => {
|
||||
const firstElement = popupRef.current?.querySelectorAll(
|
||||
"[tabindex='0']",
|
||||
)?.[0] as any;
|
||||
firstElement?.focus();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "Enter":
|
||||
case " ":
|
||||
(document.activeElement as any)?.click();
|
||||
setTimeout(() => {
|
||||
inputGroupRef.current?.focus();
|
||||
}, 300);
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "ArrowRight": {
|
||||
const totalColors =
|
||||
document.activeElement?.parentElement?.childElementCount ?? 0;
|
||||
currentFocus.current = currentFocus.current + 1;
|
||||
if (
|
||||
currentFocus.current % MAX_COLS === 0 ||
|
||||
currentFocus.current >= totalColors
|
||||
)
|
||||
currentFocus.current =
|
||||
currentFocus.current % MAX_COLS === 0
|
||||
? currentFocus.current - MAX_COLS
|
||||
: totalColors - (totalColors % MAX_COLS);
|
||||
(document.activeElement?.parentElement?.childNodes[
|
||||
currentFocus.current
|
||||
] as any).focus();
|
||||
break;
|
||||
}
|
||||
case "ArrowLeft": {
|
||||
const totalColors =
|
||||
document.activeElement?.parentElement?.childElementCount ?? 0;
|
||||
currentFocus.current = currentFocus.current - 1;
|
||||
if (
|
||||
currentFocus.current < 0 ||
|
||||
currentFocus.current % MAX_COLS === MAX_COLS - 1
|
||||
) {
|
||||
currentFocus.current = currentFocus.current + MAX_COLS;
|
||||
if (currentFocus.current > totalColors)
|
||||
currentFocus.current = totalColors - 1;
|
||||
}
|
||||
(document.activeElement?.parentElement?.childNodes[
|
||||
currentFocus.current
|
||||
] as any).focus();
|
||||
break;
|
||||
}
|
||||
case "ArrowDown": {
|
||||
const totalColors =
|
||||
document.activeElement?.parentElement?.childElementCount ?? 0;
|
||||
if (totalColors < MAX_COLS) break;
|
||||
currentFocus.current = currentFocus.current + MAX_COLS;
|
||||
if (currentFocus.current >= totalColors)
|
||||
currentFocus.current = currentFocus.current % MAX_COLS;
|
||||
(document.activeElement?.parentElement?.childNodes[
|
||||
currentFocus.current
|
||||
] as any).focus();
|
||||
break;
|
||||
}
|
||||
case "ArrowUp": {
|
||||
const totalColors =
|
||||
document.activeElement?.parentElement?.childElementCount ?? 0;
|
||||
if (totalColors < MAX_COLS) break;
|
||||
currentFocus.current = currentFocus.current - MAX_COLS;
|
||||
if (currentFocus.current < 0) {
|
||||
const factor = Math.floor(totalColors / MAX_COLS) * MAX_COLS;
|
||||
const nextIndex = factor + currentFocus.current + MAX_COLS;
|
||||
if (nextIndex >= totalColors)
|
||||
currentFocus.current = nextIndex - MAX_COLS;
|
||||
else currentFocus.current = nextIndex;
|
||||
}
|
||||
(document.activeElement?.parentElement?.childNodes[
|
||||
currentFocus.current
|
||||
] as any).focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (document.activeElement === inputGroupRef.current) {
|
||||
switch (e.key) {
|
||||
case "Enter":
|
||||
setIsOpen(true);
|
||||
const firstElement = popupRef.current?.querySelectorAll(
|
||||
"[tabindex='0']",
|
||||
)?.[0] as any;
|
||||
firstElement?.focus();
|
||||
break;
|
||||
case "Escape":
|
||||
inputGroupRef.current?.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.body.addEventListener("keydown", handleKeydown);
|
||||
return () => {
|
||||
document.body.removeEventListener("keydown", handleKeydown);
|
||||
};
|
||||
}, [handleKeydown]);
|
||||
|
||||
const handleChangeColor = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.value;
|
||||
debouncedOnChange(value);
|
||||
setColor(value);
|
||||
};
|
||||
|
||||
// if props.color changes and state color is different,
|
||||
// sets the state color to props color
|
||||
useEffect(() => {
|
||||
if (props.color !== color) {
|
||||
setColor(props.color);
|
||||
}
|
||||
}, [props.color]);
|
||||
|
||||
const handleInputClick = () => {
|
||||
isClick.current = true;
|
||||
};
|
||||
|
||||
const handleOnInteraction = (nextOpenState: boolean) => {
|
||||
if (isOpen !== nextOpenState) {
|
||||
if (isClick.current) setIsOpen(true);
|
||||
else setIsOpen(nextOpenState);
|
||||
isClick.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="popover-target-colorpicker t--colorpicker-v2-popover"
|
||||
ref={inputRef}
|
||||
>
|
||||
<Popover
|
||||
autoFocus={false}
|
||||
boundary="viewport"
|
||||
enforceFocus={false}
|
||||
interactionKind={PopoverInteractionKind.CLICK}
|
||||
isOpen={isOpen}
|
||||
minimal
|
||||
modifiers={POPOVER_MODFIER}
|
||||
onInteraction={handleOnInteraction}
|
||||
>
|
||||
<StyledInputGroup
|
||||
autoFocus={props.autoFocus}
|
||||
inputRef={inputGroupRef}
|
||||
leftIcon={
|
||||
<LeftIcon color={color} handleInputClick={handleInputClick} />
|
||||
}
|
||||
onChange={handleChangeColor}
|
||||
onClick={handleInputClick}
|
||||
placeholder="enter color name or hex"
|
||||
value={color}
|
||||
/>
|
||||
|
||||
<ColorPickerPopup
|
||||
changeColor={props.changeColor}
|
||||
color={color}
|
||||
containerRef={popupRef}
|
||||
setColor={setColor}
|
||||
setIsOpen={setIsOpen}
|
||||
showApplicationColors={props.showApplicationColors}
|
||||
showThemeColors={props.showThemeColors}
|
||||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ColorPickerComponent;
|
||||
|
|
@ -44,6 +44,7 @@ export interface DropdownSearchProps {
|
|||
enableSearch?: boolean;
|
||||
searchPlaceholder?: string;
|
||||
onSearch?: (value: any) => void;
|
||||
searchAutoFocus?: boolean;
|
||||
}
|
||||
|
||||
export interface RenderDropdownOptionType {
|
||||
|
|
@ -56,7 +57,7 @@ export interface RenderDropdownOptionType {
|
|||
optionWidth: string;
|
||||
}
|
||||
|
||||
type RenderOption = ({
|
||||
export type RenderOption = ({
|
||||
hasError,
|
||||
index,
|
||||
option,
|
||||
|
|
@ -89,6 +90,7 @@ export type DropdownProps = CommonComponentProps &
|
|||
errorMsg?: string; // If errorMsg is defined, we show dropDown's error state with the message.
|
||||
placeholder?: string;
|
||||
helperText?: string;
|
||||
wrapperBgColor?: string;
|
||||
/**
|
||||
* if fillOptions is true,
|
||||
* dropdown popover width will be same as dropdown width
|
||||
|
|
@ -102,6 +104,7 @@ export type DropdownProps = CommonComponentProps &
|
|||
defaultIcon?: IconName;
|
||||
allowDeselection?: boolean; //prevents de-selection of the selected option
|
||||
truncateOption?: boolean; // enabled wrapping and adding tooltip on option item of dropdown menu
|
||||
portalClassName?: string;
|
||||
customBadge?: JSX.Element;
|
||||
selectedHighlightBg?: string;
|
||||
};
|
||||
|
|
@ -137,8 +140,7 @@ const DropdownTriggerWrapper = styled.div<{
|
|||
props.isOpen && !props.disabled
|
||||
? `
|
||||
box-sizing: border-box;
|
||||
border: 1px solid ${Colors.GREEN_1};
|
||||
box-shadow: 0px 0px 0px 2px ${Colors.GREEN_2};
|
||||
border: 1px solid var(--appsmith-color-black-900);
|
||||
`
|
||||
: null};
|
||||
.${Classes.TEXT} {
|
||||
|
|
@ -252,7 +254,8 @@ const Selected = styled.div<{
|
|||
? props.hasError
|
||||
? Colors.FAIR_PINK
|
||||
: props.theme.colors.dropdown.hovered.bg
|
||||
: Colors.WHITE}
|
||||
: Colors.WHITE};
|
||||
}
|
||||
`;
|
||||
|
||||
export const DropdownContainer = styled.div<{ width: string; height?: string }>`
|
||||
|
|
@ -282,11 +285,12 @@ const DropdownSelect = styled.div``;
|
|||
export const DropdownWrapper = styled.div<{
|
||||
width: string;
|
||||
isOpen: boolean;
|
||||
wrapperBgColor?: string;
|
||||
}>`
|
||||
width: ${(props) => props.width};
|
||||
height: fit-content;
|
||||
z-index: 1;
|
||||
background-color: ${(props) => props.theme.colors.dropdown.menu.bg};
|
||||
background-color: ${(props) => props.wrapperBgColor};
|
||||
border: 1px solid ${(props) => props.theme.colors.dropdown.menu.border};
|
||||
padding: ${(props) => props.theme.spaces[3]}px 0;
|
||||
overflow: hidden;
|
||||
|
|
@ -302,8 +306,7 @@ export const DropdownWrapper = styled.div<{
|
|||
padding-left: 36px !important;
|
||||
|
||||
&:focus {
|
||||
border: 1.2px solid ${Colors.GREEN_1};
|
||||
box-shadow: 0px 0px 0px 2px ${Colors.GREEN_2};
|
||||
border: 1.2px solid var(--appsmith-color-black-900);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +326,7 @@ export const DropdownWrapper = styled.div<{
|
|||
`;
|
||||
|
||||
const SearchComponentWrapper = styled.div`
|
||||
margin: 0px 5px;
|
||||
margin: 0px 8px 8px 8px;
|
||||
`;
|
||||
|
||||
const DropdownOptionsWrapper = styled.div<{
|
||||
|
|
@ -349,8 +352,7 @@ const OptionWrapper = styled.div<{
|
|||
align-items: center;
|
||||
min-height: 36px;
|
||||
background-color: ${(props) =>
|
||||
props.selected ? props.selectedHighlightBg || Colors.GREEN_3 : null};
|
||||
|
||||
props.selected ? `var(--appsmith-color-black-200)` : null};
|
||||
&&& svg {
|
||||
rect {
|
||||
fill: ${(props) => props.theme.colors.dropdownIconBg};
|
||||
|
|
@ -381,7 +383,7 @@ const OptionWrapper = styled.div<{
|
|||
}
|
||||
|
||||
&:hover {
|
||||
background-color: ${(props) => props.selectedHighlightBg || Colors.GREEN_3};
|
||||
background-color: ${(props) => props.theme.colors.dropdown.menu.hover};
|
||||
|
||||
&&& svg {
|
||||
rect {
|
||||
|
|
@ -459,6 +461,14 @@ const SelectedDropDownHolder = styled.div`
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&.custom-render-option > * {
|
||||
// below if to override any custom margin and padding added in the render option
|
||||
// because the above container already comes with a padding
|
||||
// which will result broken UI
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const SelectedIcon = styled(Icon)`
|
||||
|
|
@ -491,7 +501,6 @@ const SelectedIcon = styled(Icon)`
|
|||
`;
|
||||
|
||||
const DropdownIcon = styled(Icon)`
|
||||
margin-right: 7px;
|
||||
svg {
|
||||
fill: ${(props) =>
|
||||
props.fillColor ? props.fillColor : props.theme.colors.dropdown.icon};
|
||||
|
|
@ -606,7 +615,9 @@ function DefaultDropDownValueNode({
|
|||
}
|
||||
|
||||
return (
|
||||
<SelectedDropDownHolder>
|
||||
<SelectedDropDownHolder
|
||||
className={renderNode ? "custom-render-option" : ""}
|
||||
>
|
||||
{renderNode ? (
|
||||
renderNode({
|
||||
isSelectedNode: true,
|
||||
|
|
@ -653,6 +664,7 @@ interface DropdownOptionsProps extends DropdownProps, DropdownSearchProps {
|
|||
headerLabel?: string;
|
||||
selected: DropdownOption | DropdownOption[];
|
||||
optionWidth: string;
|
||||
wrapperBgColor?: string;
|
||||
isMultiSelect?: boolean;
|
||||
allowDeselection?: boolean;
|
||||
isOpen: boolean; // dropdown popover options flashes when closed, this prop helps to make sure it never happens again.
|
||||
|
|
@ -686,10 +698,12 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
|||
data-testid="dropdown-options-wrapper"
|
||||
isOpen={props.isOpen}
|
||||
width={optionWidth}
|
||||
wrapperBgColor={props.wrapperBgColor}
|
||||
>
|
||||
{props.enableSearch && (
|
||||
<SearchComponentWrapper>
|
||||
<SearchComponent
|
||||
autoFocus={props.searchAutoFocus}
|
||||
onSearch={onOptionSearch}
|
||||
placeholder={props.searchPlaceholder || ""}
|
||||
value={searchValue}
|
||||
|
|
@ -727,7 +741,7 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
|||
return !option.isSectionHeader ? (
|
||||
<OptionWrapper
|
||||
aria-selected={isSelected}
|
||||
className="t--dropdown-option"
|
||||
className={`t--dropdown-option ${isSelected ? "selected" : ""}`}
|
||||
key={index}
|
||||
onClick={
|
||||
// users should be able to unselect a selected option by clicking the option again.
|
||||
|
|
@ -817,6 +831,7 @@ export default function Dropdown(props: DropdownProps) {
|
|||
helperText,
|
||||
removeSelectedOption,
|
||||
hasError,
|
||||
wrapperBgColor,
|
||||
closeOnSpace = true,
|
||||
} = { ...props };
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
|
@ -1055,6 +1070,7 @@ export default function Dropdown(props: DropdownProps) {
|
|||
modifiers={{ arrow: { enabled: true } }}
|
||||
onInteraction={(state) => !disabled && setIsOpen(state)}
|
||||
popoverClassName={`${props.className} none-shadow-popover`}
|
||||
portalClassName={props.portalClassName}
|
||||
position={Position.BOTTOM_LEFT}
|
||||
usePortal={!props.dontUsePortal}
|
||||
>
|
||||
|
|
@ -1068,6 +1084,7 @@ export default function Dropdown(props: DropdownProps) {
|
|||
optionWidth={dropdownOptionWidth}
|
||||
selected={selected ? selected : { id: undefined, value: undefined }}
|
||||
selectedOptionClickHandler={selectedOptionClickHandler}
|
||||
wrapperBgColor={wrapperBgColor}
|
||||
/>
|
||||
</Popover>
|
||||
</DropdownContainer>
|
||||
|
|
|
|||
87
app/client/src/components/ads/DropdownV2.tsx
Normal file
87
app/client/src/components/ads/DropdownV2.tsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
IMenuProps,
|
||||
IMenuItemProps,
|
||||
IPopoverProps,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* TYPES
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
type Props = {
|
||||
children: React.ReactElement[] | React.ReactElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* STYLED
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const StyledMenuItem = styled(MenuItem)`
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
`;
|
||||
|
||||
const StyledMenu = styled(Menu)`
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* COMPONENTS
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
function Dropdown(props: IPopoverProps & Props) {
|
||||
const { children, ...rest } = props;
|
||||
|
||||
const menus =
|
||||
(Array.isArray(children) &&
|
||||
children.find(
|
||||
(child: any) => child.type.displayName === "DropdownList",
|
||||
)) ||
|
||||
undefined;
|
||||
|
||||
const trigger =
|
||||
Array.isArray(children) &&
|
||||
children.find((child: any) => child.type.displayName === "DropdownTrigger");
|
||||
|
||||
return (
|
||||
<Popover
|
||||
{...rest}
|
||||
content={menus}
|
||||
popoverClassName="dropdown-v2"
|
||||
transitionDuration={-1}
|
||||
>
|
||||
{trigger}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownList(props: IMenuProps) {
|
||||
return <StyledMenu {...props} />;
|
||||
}
|
||||
|
||||
DropdownList.displayName = "DropdownList";
|
||||
|
||||
function DropdownTrigger(props: any) {
|
||||
return <div {...props} />;
|
||||
}
|
||||
|
||||
DropdownTrigger.displayName = "DropdownTrigger";
|
||||
|
||||
function DropdownItem(props: IMenuItemProps) {
|
||||
return <StyledMenuItem {...props} />;
|
||||
}
|
||||
|
||||
DropdownItem.displayName = "DropdownItem";
|
||||
|
||||
export { Dropdown, DropdownList, DropdownItem, DropdownTrigger };
|
||||
|
|
@ -150,6 +150,7 @@ import EditBoxLineIcon from "remixicon-react/EditBoxLineIcon";
|
|||
import StarLineIcon from "remixicon-react/StarLineIcon";
|
||||
import StarFillIcon from "remixicon-react/StarFillIcon";
|
||||
import Settings2LineIcon from "remixicon-react/Settings2LineIcon";
|
||||
import DownloadIcon from "remixicon-react/DownloadLineIcon";
|
||||
import UploadCloud2LineIcon from "remixicon-react/UploadCloud2LineIcon";
|
||||
import DownloadLineIcon from "remixicon-react/DownloadLineIcon";
|
||||
import FileListLineIcon from "remixicon-react/FileListLineIcon";
|
||||
|
|
@ -380,6 +381,7 @@ const ICON_LOOKUP = {
|
|||
warning: <WarningIcon />,
|
||||
widget: <WidgetIcon />,
|
||||
workspace: <WorkspaceIcon />,
|
||||
download2: <DownloadIcon />,
|
||||
upgrade: <DvdLineIcon />,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@ import styled, { css } from "styled-components";
|
|||
import { Alignment, Classes, Label, Position } from "@blueprintjs/core";
|
||||
|
||||
import { LabelPosition } from "components/constants";
|
||||
import {
|
||||
FontStyleTypes,
|
||||
TextSize,
|
||||
TEXT_SIZES,
|
||||
} from "constants/WidgetConstants";
|
||||
import { FontStyleTypes } from "constants/WidgetConstants";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { isEllipsisActive } from "utils/helpers";
|
||||
import { Colors } from "constants/Colors";
|
||||
|
|
@ -20,7 +16,7 @@ export interface LabelWithTooltipProps {
|
|||
color?: string;
|
||||
compact: boolean;
|
||||
disabled?: boolean;
|
||||
fontSize?: TextSize;
|
||||
fontSize?: string;
|
||||
fontStyle?: string;
|
||||
helpText?: string;
|
||||
cyHelpTextClassName?: string;
|
||||
|
|
@ -45,7 +41,7 @@ export interface StyledLabelProps {
|
|||
color?: string;
|
||||
compact: boolean;
|
||||
disabled?: boolean;
|
||||
fontSize?: TextSize;
|
||||
fontSize?: string;
|
||||
fontStyle?: string;
|
||||
hasHelpText: boolean;
|
||||
position?: LabelPosition;
|
||||
|
|
@ -178,7 +174,7 @@ export const StyledLabel = styled(Label)<StyledLabelProps>`
|
|||
|
||||
${({ color, disabled, fontSize, fontStyle }) => `
|
||||
color: ${disabled ? Colors.GREY_8 : color || "inherit"};
|
||||
font-size: ${fontSize ? TEXT_SIZES[fontSize] : TEXT_SIZES.PARAGRAPH};
|
||||
font-size: ${fontSize ?? "inherit"};
|
||||
font-weight: ${
|
||||
fontStyle?.includes(FontStyleTypes.BOLD) ? "bold" : "normal"
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ function SuggestionComponent(props: EntryComponentProps) {
|
|||
<StyledSuggestionsComponent ref={mentionRef} {...parentProps}>
|
||||
<div style={{ flexShrink: 0 }}>
|
||||
<ProfileImage
|
||||
side={25}
|
||||
size={25}
|
||||
source={`/api/${USER_PHOTO_URL}/${user?.username}`}
|
||||
userName={user?.username || ""}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -337,8 +337,9 @@ const TextInput = forwardRef(
|
|||
setInputValue(inputValue);
|
||||
const inputValueValidation =
|
||||
props.validator && props.validator(inputValue);
|
||||
if (inputValueValidation && inputValueValidation.isValid) {
|
||||
if (inputValueValidation) {
|
||||
props.validator && setValidation(inputValueValidation);
|
||||
|
||||
return (
|
||||
inputValueValidation.isValid &&
|
||||
props.onChange &&
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ export const Toaster = {
|
|||
pauseOnFocusLoss: !config.dispatchableAction && !config.hideProgressBar,
|
||||
autoClose: false,
|
||||
closeOnClick: true,
|
||||
position: "top-center",
|
||||
hideProgressBar: config.hideProgressBar,
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export type TooltipProps = CommonComponentProps & {
|
|||
modifiers?: Modifiers;
|
||||
isOpen?: boolean;
|
||||
onOpening?: typeof noop;
|
||||
popoverClassName?: string;
|
||||
donotUsePortal?: boolean;
|
||||
};
|
||||
|
||||
|
|
@ -45,7 +46,8 @@ function TooltipComponent(props: TooltipProps) {
|
|||
}}
|
||||
onOpening={props.onOpening}
|
||||
openOnTargetFocus={props.openOnTargetFocus}
|
||||
popoverClassName={GLOBAL_STYLE_TOOLTIP_CLASSNAME}
|
||||
popoverClassName={`${GLOBAL_STYLE_TOOLTIP_CLASSNAME} ${props.popoverClassName ??
|
||||
""}`}
|
||||
portalContainer={portalContainer as HTMLDivElement}
|
||||
position={props.position}
|
||||
usePortal={!props.donotUsePortal}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export enum ButtonBorderRadiusTypes {
|
|||
ROUNDED = "ROUNDED",
|
||||
CIRCLE = "CIRCLE",
|
||||
}
|
||||
|
||||
export type ButtonBorderRadius = keyof typeof ButtonBorderRadiusTypes;
|
||||
|
||||
export enum ButtonBoxShadowTypes {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { ThemeProp } from "components/ads/common";
|
|||
import _ from "lodash";
|
||||
import {
|
||||
ButtonStyleTypes,
|
||||
ButtonBoxShadow,
|
||||
ButtonBoxShadowTypes,
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
|
|
@ -279,8 +278,7 @@ type ButtonStyleProps = {
|
|||
buttonStyle?: ButtonStyleType;
|
||||
prevButtonStyle?: ButtonStyleType;
|
||||
buttonVariant?: ButtonVariant;
|
||||
boxShadow?: ButtonBoxShadow;
|
||||
boxShadowColor?: string;
|
||||
boxShadow?: string;
|
||||
borderRadius?: ButtonBorderRadius;
|
||||
iconName?: IconName;
|
||||
iconAlign?: Alignment;
|
||||
|
|
@ -291,7 +289,6 @@ export function BaseButton(props: IButtonProps & ButtonStyleProps) {
|
|||
const {
|
||||
borderRadius,
|
||||
boxShadow,
|
||||
boxShadowColor,
|
||||
buttonColor,
|
||||
buttonStyle,
|
||||
buttonVariant,
|
||||
|
|
@ -313,7 +310,6 @@ export function BaseButton(props: IButtonProps & ButtonStyleProps) {
|
|||
alignText={iconName ? Alignment.LEFT : Alignment.CENTER}
|
||||
borderRadius={borderRadius}
|
||||
boxShadow={boxShadow}
|
||||
boxShadowColor={boxShadowColor}
|
||||
buttonColor={buttonColor}
|
||||
buttonStyle={buttonStyle}
|
||||
buttonVariant={buttonVariant}
|
||||
|
|
@ -335,7 +331,6 @@ export function BaseButton(props: IButtonProps & ButtonStyleProps) {
|
|||
alignText={iconName ? Alignment.RIGHT : Alignment.CENTER}
|
||||
borderRadius={borderRadius}
|
||||
boxShadow={boxShadow}
|
||||
boxShadowColor={boxShadowColor}
|
||||
buttonColor={buttonColor}
|
||||
buttonStyle={buttonStyle}
|
||||
buttonVariant={buttonVariant}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,9 @@
|
|||
import styled from "styled-components";
|
||||
|
||||
/**
|
||||
* Common component, mostly use to show loader / message
|
||||
*
|
||||
* Used By:
|
||||
* AppViewerPageContainer
|
||||
* - parent component AppViewer -> AppViewerBody's height calculated good enough
|
||||
* - inherited height works fine here.
|
||||
* CanvasContainer
|
||||
* - calculated height looks good
|
||||
* DefaultOrgPage
|
||||
* - calculated height looks good
|
||||
*/
|
||||
export default styled.div<{
|
||||
isInheritedHeight?: boolean;
|
||||
}>`
|
||||
height: ${(props) =>
|
||||
props.isInheritedHeight
|
||||
? "inherit"
|
||||
: `calc(100vh - ${props.theme.smallHeaderHeight})`};
|
||||
export default styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ interface SearchProps {
|
|||
placeholder: string;
|
||||
value: string;
|
||||
className?: string;
|
||||
autoFocus?: boolean;
|
||||
}
|
||||
|
||||
const SearchComponentWrapper = styled.div`
|
||||
|
|
@ -112,6 +113,7 @@ class SearchComponent extends React.Component<
|
|||
return (
|
||||
<SearchComponentWrapper>
|
||||
<SearchInputWrapper
|
||||
autoFocus={this.props.autoFocus}
|
||||
className={`${this.props.className} t--search-input`}
|
||||
leftIcon="search"
|
||||
onChange={this.handleSearch}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import React, { ReactNode } from "react";
|
|||
import styled from "styled-components";
|
||||
import { ContainerStyle } from "widgets/ContainerWidget/component";
|
||||
import { Color } from "constants/Colors";
|
||||
import { Theme } from "constants/DefaultTheme";
|
||||
|
||||
export enum BoxShadowTypes {
|
||||
NONE = "NONE",
|
||||
|
|
@ -23,55 +22,19 @@ export interface WidgetStyleContainerProps {
|
|||
borderWidth?: number;
|
||||
borderRadius?: number;
|
||||
boxShadow?: BoxShadow;
|
||||
boxShadowColor?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// get box shadow style string based on boxShadow and boxShadowColor
|
||||
const getBoxShadow = ({
|
||||
boxShadow,
|
||||
boxShadowColor,
|
||||
theme,
|
||||
}: {
|
||||
boxShadow?: BoxShadow;
|
||||
boxShadowColor?: string;
|
||||
theme: Theme;
|
||||
}) => {
|
||||
switch (boxShadow) {
|
||||
case BoxShadowTypes.VARIANT1:
|
||||
return `0px 0px 4px 3px ${boxShadowColor ||
|
||||
theme.colors.button.boxShadow.default.variant1}`;
|
||||
case BoxShadowTypes.VARIANT2:
|
||||
return `3px 3px 4px ${boxShadowColor ||
|
||||
theme.colors.button.boxShadow.default.variant2}`;
|
||||
case BoxShadowTypes.VARIANT3:
|
||||
return `0px 1px 3px ${boxShadowColor ||
|
||||
theme.colors.button.boxShadow.default.variant3}`;
|
||||
case BoxShadowTypes.VARIANT4:
|
||||
return `2px 2px 0px ${boxShadowColor ||
|
||||
theme.colors.button.boxShadow.default.variant4}`;
|
||||
case BoxShadowTypes.VARIANT5:
|
||||
return `-2px -2px 0px ${boxShadowColor ||
|
||||
theme.colors.button.boxShadow.default.variant5}`;
|
||||
default:
|
||||
return "none";
|
||||
}
|
||||
};
|
||||
|
||||
const WidgetStyle = styled.div<WidgetStyleContainerProps>`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
border-radius: ${(props) => props.borderRadius}px;
|
||||
box-shadow: ${(props) => getBoxShadow(props)} !important;
|
||||
border-radius: ${({ borderRadius }) => borderRadius};
|
||||
box-shadow: ${(props) => props.boxShadow} !important;
|
||||
border-width: ${(props) => props.borderWidth}px;
|
||||
border-color: ${(props) => props.borderColor || "transparent"};
|
||||
border-style: solid;
|
||||
|
||||
& > div {
|
||||
${(props) =>
|
||||
props.containerStyle !== "none"
|
||||
? `
|
||||
border-width: ${props.borderWidth}px;
|
||||
border-radius: ${props.borderRadius}px;
|
||||
border-color: ${props.borderColor || "transparent"};
|
||||
border-style: solid;`
|
||||
: ""}
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
11
app/client/src/components/editorComponents/BetaCard.tsx
Normal file
11
app/client/src/components/editorComponents/BetaCard.tsx
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import React from "react";
|
||||
|
||||
function BetaCard() {
|
||||
return (
|
||||
<div className="py-0.5 px-1 text-xs font-semibold text-gray-700 uppercase border border-gray-700">
|
||||
beta
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BetaCard;
|
||||
|
|
@ -29,8 +29,11 @@ const buttonStyles = css<Partial<ButtonProps>>`
|
|||
border-radius: 0;
|
||||
background: ${(props) =>
|
||||
props.filled || props.outline ? "inherit" : "transparent"};
|
||||
|
||||
border-radius: ${({ borderRadius }) => borderRadius};
|
||||
box-shadow: ${({ boxShadow }) => `${boxShadow}`} !important;
|
||||
width: ${(props) => (props.fluid ? "100%" : "auto")};
|
||||
height: 100%;
|
||||
padding: 0 10px;
|
||||
}
|
||||
&&&&&& {
|
||||
&.bp3-button span {
|
||||
|
|
@ -86,6 +89,9 @@ export type ButtonProps = {
|
|||
fluid?: boolean;
|
||||
skin?: Skin;
|
||||
target?: string;
|
||||
borderRadius?: string;
|
||||
boxShadow?: string;
|
||||
boxShadowColor?: string;
|
||||
};
|
||||
|
||||
export const Button = (props: ButtonProps) => {
|
||||
|
|
@ -129,6 +135,9 @@ export const Button = (props: ButtonProps) => {
|
|||
} else
|
||||
return (
|
||||
<StyledButton
|
||||
borderRadius={props.borderRadius}
|
||||
boxShadow={props.boxShadow}
|
||||
boxShadowColor={props.boxShadowColor}
|
||||
icon={icon}
|
||||
rightIcon={rightIcon}
|
||||
{...baseProps}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import { commentModeSelector } from "selectors/commentsSelectors";
|
|||
import { getIsDraggingForSelection } from "selectors/canvasSelectors";
|
||||
import MultiSelectPropertyPane from "pages/Editor/MultiSelectPropertyPane";
|
||||
import { getWidgets } from "sagas/selectors";
|
||||
import { ThemePropertyPane } from "pages/Editor/ThemePropertyPane";
|
||||
import { getAppThemingStack } from "selectors/appThemingSelectors";
|
||||
|
||||
type Props = {
|
||||
width: number;
|
||||
|
|
@ -40,6 +42,7 @@ export const PropertyPaneSidebar = memo((props: Props) => {
|
|||
const canvasWidgets = useSelector(getWidgets);
|
||||
const isPreviewMode = useSelector(previewModeSelector);
|
||||
const isCommentMode = useSelector(commentModeSelector);
|
||||
const themingStack = useSelector(getAppThemingStack);
|
||||
const selectedWidgetIds = useSelector(getSelectedWidgets);
|
||||
const selectedWidgets = useMemo(
|
||||
() =>
|
||||
|
|
@ -64,16 +67,18 @@ export const PropertyPaneSidebar = memo((props: Props) => {
|
|||
*/
|
||||
const propertyPane = useMemo(() => {
|
||||
switch (true) {
|
||||
case selectedWidgets.length == 0:
|
||||
return <CanvasPropertyPane />;
|
||||
case selectedWidgets.length > 1:
|
||||
return <MultiSelectPropertyPane />;
|
||||
case selectedWidgets.length === 1:
|
||||
return <WidgetPropertyPane />;
|
||||
case themingStack.length > 0:
|
||||
return <ThemePropertyPane />;
|
||||
case selectedWidgets.length === 0:
|
||||
return <CanvasPropertyPane />;
|
||||
default:
|
||||
return <CanvasPropertyPane />;
|
||||
}
|
||||
}, [selectedWidgets.length, isDraggingForSelection]);
|
||||
}, [selectedWidgets.length, isDraggingForSelection, themingStack.join(",")]);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
|
|
|
|||
|
|
@ -1,114 +1,64 @@
|
|||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Button, ButtonGroup, IButtonProps } from "@blueprintjs/core";
|
||||
|
||||
import TooltipComponent from "components/ads/Tooltip";
|
||||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import { ThemeProp } from "components/ads/common";
|
||||
import {
|
||||
ButtonBorderRadius,
|
||||
ButtonBorderRadiusTypes,
|
||||
} from "components/constants";
|
||||
import { replayHighlightClass } from "globalStyles/portals";
|
||||
|
||||
const StyledButtonGroup = styled(ButtonGroup)`
|
||||
height: 33px;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)<ThemeProp & IButtonProps>`
|
||||
border: ${(props) =>
|
||||
props.active ? `1px solid #6A86CE` : `1px solid #A9A7A7`};
|
||||
border-radius: 0;
|
||||
box-shadow: none !important;
|
||||
background-image: none !important;
|
||||
background-color: #ffffff !important;
|
||||
& > div {
|
||||
display: flex;
|
||||
}
|
||||
&.bp3-active {
|
||||
box-shadow: none !important;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
`;
|
||||
import { borderRadiusOptions } from "constants/ThemeConstants";
|
||||
import { ButtonTabComponent } from "components/ads";
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* TYPES
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
export interface BorderRadiusOptionsControlProps extends ControlProps {
|
||||
propertyValue: ButtonBorderRadius | undefined;
|
||||
onChange: (borderRaidus: ButtonBorderRadius) => void;
|
||||
options: any[];
|
||||
propertyValue: string | undefined;
|
||||
}
|
||||
|
||||
const options = Object.keys(borderRadiusOptions).map((optionKey) => ({
|
||||
icon: (
|
||||
<TooltipComponent
|
||||
content={
|
||||
<div>
|
||||
<div>{optionKey}</div>
|
||||
</div>
|
||||
}
|
||||
key={optionKey}
|
||||
openOnTargetFocus={false}
|
||||
>
|
||||
<button>
|
||||
<div
|
||||
className="w-5 h-5 border-t-2 border-l-2 border-gray-500"
|
||||
style={{ borderTopLeftRadius: borderRadiusOptions[optionKey] }}
|
||||
/>
|
||||
</button>
|
||||
</TooltipComponent>
|
||||
),
|
||||
value: borderRadiusOptions[optionKey],
|
||||
}));
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------
|
||||
* COMPONENT
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
class BorderRadiusOptionsControl extends BaseControl<
|
||||
BorderRadiusOptionsControlProps
|
||||
> {
|
||||
constructor(props: BorderRadiusOptionsControlProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static getControlType() {
|
||||
return "BORDER_RADIUS_OPTIONS";
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { options, propertyValue } = this.props;
|
||||
|
||||
return (
|
||||
<StyledButtonGroup className={replayHighlightClass} fill>
|
||||
{options.map((option: ButtonBorderRadius) => {
|
||||
const active =
|
||||
option === ButtonBorderRadiusTypes.SHARP
|
||||
? propertyValue === option || propertyValue === undefined
|
||||
: propertyValue === option;
|
||||
const icon =
|
||||
option === ButtonBorderRadiusTypes.SHARP ? (
|
||||
<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />
|
||||
) : option === ButtonBorderRadiusTypes.ROUNDED ? (
|
||||
<ControlIcons.BORDER_RADIUS_ROUNDED color="#979797" width={15} />
|
||||
) : (
|
||||
<ControlIcons.BORDER_RADIUS_CIRCLE color="#979797" width={15} />
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
active={active}
|
||||
icon={icon}
|
||||
key={option}
|
||||
large
|
||||
onClick={() => this.toggleOption(option)}
|
||||
<ButtonTabComponent
|
||||
options={options}
|
||||
selectButton={(value) => {
|
||||
this.updateProperty(this.props.propertyName, value);
|
||||
}}
|
||||
values={this.props.evaluatedValue ? [this.props.evaluatedValue] : []}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{/* <StyledButton
|
||||
active={propertyValue === ButtonBorderRadiusTypes.SHARP || undefined}
|
||||
icon={<ControlIcons.BORDER_RADIUS_SHARP color="#979797" width={15} />}
|
||||
large
|
||||
onClick={() => this.toggleOption(ButtonBorderRadiusTypes.SHARP)}
|
||||
/>
|
||||
<StyledButton
|
||||
active={propertyValue === ButtonBorderRadiusTypes.ROUNDED}
|
||||
icon={
|
||||
<ControlIcons.BORDER_RADIUS_ROUNDED color="#979797" width={15} />
|
||||
}
|
||||
large
|
||||
onClick={() => this.toggleOption(ButtonBorderRadiusTypes.ROUNDED)}
|
||||
/>
|
||||
<StyledButton
|
||||
active={propertyValue === ButtonBorderRadiusTypes.CIRCLE}
|
||||
icon={
|
||||
<ControlIcons.BORDER_RADIUS_CIRCLE color="#979797" width={15} />
|
||||
}
|
||||
large
|
||||
onClick={() => this.toggleOption(ButtonBorderRadiusTypes.CIRCLE)}
|
||||
/> */}
|
||||
</StyledButtonGroup>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleOption = (option: ButtonBorderRadius) => {
|
||||
this.updateProperty(this.props.propertyName, option);
|
||||
};
|
||||
}
|
||||
|
||||
export default BorderRadiusOptionsControl;
|
||||
|
|
|
|||
|
|
@ -1,141 +1,58 @@
|
|||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Button, ButtonGroup, IButtonProps } from "@blueprintjs/core";
|
||||
|
||||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import { ControlIcons } from "icons/ControlIcons";
|
||||
import { ThemeProp } from "components/ads/common";
|
||||
import { ButtonBoxShadow, ButtonBoxShadowTypes } from "components/constants";
|
||||
import { replayHighlightClass } from "globalStyles/portals";
|
||||
|
||||
const StyledButtonGroup = styled(ButtonGroup)`
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)<ThemeProp & IButtonProps>`
|
||||
margin-right: 0 !important;
|
||||
border: ${(props) =>
|
||||
props.active ? `1px solid #6A86CE` : `1px solid #E0DEDE`};
|
||||
border-radius: 0;
|
||||
box-shadow: none !important;
|
||||
background-image: none;
|
||||
background-color: #ffffff !important;
|
||||
& > div {
|
||||
display: flex;
|
||||
}
|
||||
&.bp3-active {
|
||||
box-shadow: none !important;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
`;
|
||||
|
||||
import TooltipComponent from "components/ads/Tooltip";
|
||||
import { boxShadowOptions } from "constants/ThemeConstants";
|
||||
import CloseLineIcon from "remixicon-react/CloseLineIcon";
|
||||
import { ButtonTabComponent } from "components/ads";
|
||||
export interface BoxShadowOptionsControlProps extends ControlProps {
|
||||
propertyValue: ButtonBoxShadow | undefined;
|
||||
propertyValue: string | undefined;
|
||||
}
|
||||
|
||||
const buttonConfigs = [
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.NONE,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_NONE,
|
||||
color: "#CACACA",
|
||||
width: 16,
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.VARIANT1,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_VARIANT1,
|
||||
height: 32,
|
||||
width: 40,
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.VARIANT2,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_VARIANT2,
|
||||
height: 28,
|
||||
width: 36,
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.VARIANT3,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_VARIANT3,
|
||||
height: 27,
|
||||
width: 32,
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.VARIANT4,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_VARIANT4,
|
||||
height: 26,
|
||||
width: 34,
|
||||
},
|
||||
},
|
||||
{
|
||||
variant: ButtonBoxShadowTypes.VARIANT5,
|
||||
icon: {
|
||||
element: ControlIcons.BOX_SHADOW_VARIANT5,
|
||||
height: 26,
|
||||
width: 34,
|
||||
},
|
||||
},
|
||||
];
|
||||
const options = Object.keys(boxShadowOptions).map((optionKey) => ({
|
||||
icon: (
|
||||
<TooltipComponent
|
||||
content={
|
||||
<div>
|
||||
<div>{optionKey}</div>
|
||||
</div>
|
||||
}
|
||||
key={optionKey}
|
||||
openOnTargetFocus={false}
|
||||
>
|
||||
<button>
|
||||
<div
|
||||
className="flex items-center justify-center w-5 h-5 bg-white"
|
||||
style={{ boxShadow: boxShadowOptions[optionKey] }}
|
||||
>
|
||||
{boxShadowOptions[optionKey] === "none" && (
|
||||
<CloseLineIcon className="text-gray-700" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
</TooltipComponent>
|
||||
),
|
||||
value: boxShadowOptions[optionKey],
|
||||
}));
|
||||
|
||||
class BoxShadowOptionsControl extends BaseControl<
|
||||
BoxShadowOptionsControlProps
|
||||
> {
|
||||
constructor(props: BoxShadowOptionsControlProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
static getControlType() {
|
||||
return "BOX_SHADOW_OPTIONS";
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { propertyValue } = this.props;
|
||||
|
||||
return (
|
||||
<StyledButtonGroup className={replayHighlightClass} fill>
|
||||
{buttonConfigs.map(({ icon, variant }) => {
|
||||
const active =
|
||||
variant === ButtonBoxShadowTypes.NONE
|
||||
? propertyValue === variant || propertyValue === undefined
|
||||
: propertyValue === variant;
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
active={active}
|
||||
icon={
|
||||
<icon.element
|
||||
color={icon.color}
|
||||
height={icon.height}
|
||||
keepColors
|
||||
width={icon.width}
|
||||
/>
|
||||
}
|
||||
key={variant}
|
||||
large
|
||||
onClick={() => this.toggleOption(variant)}
|
||||
<ButtonTabComponent
|
||||
options={options}
|
||||
selectButton={(value) => {
|
||||
this.updateProperty(this.props.propertyName, value);
|
||||
}}
|
||||
values={this.props.evaluatedValue ? [this.props.evaluatedValue] : []}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StyledButtonGroup>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleOption = (option: ButtonBoxShadow) => {
|
||||
this.updateProperty(this.props.propertyName, option);
|
||||
};
|
||||
}
|
||||
|
||||
export default BoxShadowOptionsControl;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ const StyledButton = styled(Button)<ThemeProp & IButtonProps>`
|
|||
box-shadow: none !important;
|
||||
background-image: none !important;
|
||||
background-color: #ffffff !important;
|
||||
min-height: 100% !important;
|
||||
& > div {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import orderBy from "lodash/orderBy";
|
|||
import isString from "lodash/isString";
|
||||
import isUndefined from "lodash/isUndefined";
|
||||
import { Category, Size } from "components/ads/Button";
|
||||
import { Colors } from "constants/Colors";
|
||||
import { ButtonPlacementTypes } from "components/constants";
|
||||
import { DraggableListCard } from "components/ads/DraggableListCard";
|
||||
|
||||
|
|
@ -179,6 +178,7 @@ class ButtonListControl extends BaseControl<ControlProps, State> {
|
|||
"Group Button ",
|
||||
groupButtonsArray.map((groupButton: any) => groupButton.label),
|
||||
);
|
||||
|
||||
groupButtons = {
|
||||
...groupButtons,
|
||||
[newGroupButtonId]: {
|
||||
|
|
@ -187,11 +187,12 @@ class ButtonListControl extends BaseControl<ControlProps, State> {
|
|||
label: newGroupButtonLabel,
|
||||
menuItems: {},
|
||||
buttonType: "SIMPLE",
|
||||
buttonColor: Colors.GREEN,
|
||||
placement: ButtonPlacementTypes.CENTER,
|
||||
widgetId: generateReactKey(),
|
||||
isDisabled: false,
|
||||
isVisible: true,
|
||||
buttonColor: this.props.widgetProperties.childStylesheet.button
|
||||
.buttonColor,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,29 @@
|
|||
import React from "react";
|
||||
|
||||
import BaseControl, { ControlProps } from "./BaseControl";
|
||||
import ColorPickerComponent from "components/ads/ColorPickerComponent";
|
||||
import ColorPickerComponent from "components/ads/ColorPickerComponentV2";
|
||||
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
||||
|
||||
class ColorPickerControl extends BaseControl<ColorPickerControlProps> {
|
||||
handleChangeColor = (color: string) => {
|
||||
this.updateProperty(this.props.propertyName, color);
|
||||
};
|
||||
|
||||
render() {
|
||||
const computedEvaluatedValue = Array.isArray(this.props.evaluatedValue)
|
||||
? this.props.evaluatedValue[0]
|
||||
: this.props.evaluatedValue;
|
||||
|
||||
return (
|
||||
<ColorPickerComponent
|
||||
changeColor={this.handleChangeColor}
|
||||
color={
|
||||
this.props.propertyValue
|
||||
? this.props.propertyValue
|
||||
: this.props.defaultColor
|
||||
this.props.propertyValue && isDynamicValue(this.props.propertyValue)
|
||||
? computedEvaluatedValue
|
||||
: this.props.propertyValue || ""
|
||||
}
|
||||
showApplicationColors
|
||||
showThemeColors
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import BaseControl, { ControlProps } from "./BaseControl";
|
|||
import { StyledDropDown, StyledDropDownContainer } from "./StyledControls";
|
||||
import { DropdownOption } from "components/ads/Dropdown";
|
||||
import { isNil } from "lodash";
|
||||
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
||||
|
||||
class DropDownControl extends BaseControl<DropDownControlProps> {
|
||||
render() {
|
||||
|
|
@ -19,8 +20,14 @@ class DropDownControl extends BaseControl<DropDownControlProps> {
|
|||
);
|
||||
}
|
||||
|
||||
const computedValue =
|
||||
!isNil(this.props.propertyValue) &&
|
||||
isDynamicValue(this.props.propertyValue)
|
||||
? this.props.evaluatedValue
|
||||
: this.props.propertyValue;
|
||||
|
||||
const selected: DropdownOption = options.find(
|
||||
(option) => option.value === this.props.propertyValue,
|
||||
(option) => option.value === computedValue,
|
||||
);
|
||||
|
||||
if (selected) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { DraggableListCard } from "components/ads/DraggableListCard";
|
|||
import { StyledPropertyPaneButton } from "./StyledControls";
|
||||
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||
import { InputText } from "./InputTextControl";
|
||||
import { JSONFormWidgetProps } from "widgets/JSONFormWidget/widget";
|
||||
|
||||
type DroppableItem = BaseItemProps & {
|
||||
index: number;
|
||||
|
|
@ -119,7 +120,10 @@ class FieldConfigurationControl extends BaseControl<ControlProps, State> {
|
|||
if (this.isArrayItem()) return;
|
||||
|
||||
const { propertyValue = {}, propertyName, widgetProperties } = this.props;
|
||||
const { widgetName } = widgetProperties;
|
||||
const {
|
||||
childStylesheet,
|
||||
widgetName,
|
||||
} = widgetProperties as JSONFormWidgetProps;
|
||||
const schema: Schema = propertyValue;
|
||||
const existingKeys = getKeysFromSchema(schema, ["identifier", "accessor"]);
|
||||
const schemaItems = Object.values(schema);
|
||||
|
|
@ -132,19 +136,33 @@ class FieldConfigurationControl extends BaseControl<ControlProps, State> {
|
|||
isCustomField: true,
|
||||
skipDefaultValueProcessing: true,
|
||||
identifier: nextFieldKey,
|
||||
fieldThemeStylesheets: childStylesheet,
|
||||
});
|
||||
|
||||
schemaItem.position = lastSchemaItemPosition + 1;
|
||||
|
||||
const path = `${propertyName}.${nextFieldKey}`;
|
||||
|
||||
if (isEmpty(widgetProperties.schema)) {
|
||||
const newSchema = {
|
||||
schema: SchemaParser.parse(widgetProperties.widgetName, {}),
|
||||
};
|
||||
set(newSchema, `${propertyName}.${nextFieldKey}`, schemaItem);
|
||||
set(newSchema, path, schemaItem);
|
||||
|
||||
this.updateProperty("schema", newSchema.schema);
|
||||
} else {
|
||||
this.updateProperty(`${propertyName}.${nextFieldKey}`, schemaItem);
|
||||
/**
|
||||
* TODO(Ashit): Not suppose to update the whole schema but just
|
||||
* the path within the schema. This is just a hack to make sure
|
||||
* the new added paths gets into the dynamicBindingPathList until
|
||||
* the updateProperty function is fixed.
|
||||
*/
|
||||
const updatedSchema = {
|
||||
schema: klona(widgetProperties.schema),
|
||||
};
|
||||
set(updatedSchema, path, schemaItem);
|
||||
|
||||
this.updateProperty("schema", updatedSchema.schema);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const IconSelectContainerStyles = createGlobalStyle<{
|
|||
}>`
|
||||
.bp3-select-popover {
|
||||
width: ${({ targetWidth }) => targetWidth}px;
|
||||
background: white;
|
||||
|
||||
.bp3-input-group {
|
||||
margin: 5px !important;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ class PrimaryColumnsControl extends BaseControl<ControlProps, State> {
|
|||
const columnProps: ColumnProperties = getDefaultColumnProperties(
|
||||
newColumnName,
|
||||
nextIndex,
|
||||
this.props.widgetProperties.widgetName,
|
||||
this.props.widgetProperties,
|
||||
true,
|
||||
);
|
||||
const tableStyles = getTableStyles(this.props.widgetProperties);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ export const ControlWrapper = styled.div<ControlWrapperProps>`
|
|||
&&& > label {
|
||||
display: inline-block;
|
||||
}
|
||||
&:focus-within .reset-button {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
|
||||
export const ControlPropertyLabelContainer = styled.div`
|
||||
|
|
|
|||
180
app/client/src/components/wds/Button/index.tsx
Normal file
180
app/client/src/components/wds/Button/index.tsx
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
IButtonProps,
|
||||
MaybeElement,
|
||||
Button as BlueprintButton,
|
||||
} from "@blueprintjs/core";
|
||||
import { IconName } from "@blueprintjs/icons";
|
||||
import { withTooltip } from "components/wds";
|
||||
|
||||
import { Colors } from "constants/Colors";
|
||||
|
||||
import _ from "lodash";
|
||||
import {
|
||||
ButtonPlacement,
|
||||
ButtonVariant,
|
||||
ButtonVariantTypes,
|
||||
} from "components/constants";
|
||||
import {
|
||||
getComplementaryGrayscaleColor,
|
||||
lightenColor,
|
||||
} from "widgets/WidgetUtils";
|
||||
import { borderRadiusOptions } from "constants/ThemeConstants";
|
||||
import withRecaptcha, { RecaptchaProps } from "./withRecaptcha";
|
||||
|
||||
type ButtonStyleProps = {
|
||||
buttonColor?: string;
|
||||
buttonVariant?: ButtonVariant;
|
||||
iconName?: IconName;
|
||||
placement?: ButtonPlacement;
|
||||
justifyContent?:
|
||||
| "flex-start"
|
||||
| "flex-end"
|
||||
| "center"
|
||||
| "space-between"
|
||||
| "space-around"
|
||||
| "space-evenly";
|
||||
};
|
||||
|
||||
export interface ButtonProps
|
||||
extends IButtonProps,
|
||||
ButtonStyleProps,
|
||||
RecaptchaProps {
|
||||
variant?: keyof typeof VariantTypes;
|
||||
boxShadow?: string;
|
||||
borderRadius?: string;
|
||||
tooltip?: string;
|
||||
children?: React.ReactNode;
|
||||
leftIcon?: IconName | MaybeElement;
|
||||
isDisabled?: boolean;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
enum VariantTypes {
|
||||
solid = "solid",
|
||||
outline = "outline",
|
||||
ghost = "ghost",
|
||||
link = "link",
|
||||
}
|
||||
|
||||
export const StyledButton = styled((props) => (
|
||||
<BlueprintButton
|
||||
{..._.omit(props, [
|
||||
"borderRadius",
|
||||
"boxShadow",
|
||||
"buttonColor",
|
||||
"buttonVariant",
|
||||
"variant",
|
||||
"justifyContent",
|
||||
])}
|
||||
/>
|
||||
))<ButtonProps>`
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
padding: 0px 10px;
|
||||
background-image: none !important;
|
||||
border-radius: ${({ borderRadius }) => borderRadius};
|
||||
box-shadow: ${({ boxShadow }) => `${boxShadow}`} !important;
|
||||
justify-content: ${({ justifyContent }) => `${justifyContent}`} !important;
|
||||
flex-direction: ${({ iconAlign }) => `${iconAlign}`};
|
||||
|
||||
${({ buttonColor }) => `
|
||||
&.button--solid {
|
||||
&:enabled {
|
||||
background: ${buttonColor};
|
||||
color: ${getComplementaryGrayscaleColor(buttonColor)}
|
||||
}
|
||||
}
|
||||
|
||||
&.button--outline {
|
||||
&:enabled {
|
||||
background: none;
|
||||
border: 1px solid ${buttonColor};
|
||||
color: ${buttonColor};
|
||||
}
|
||||
|
||||
&:enabled:hover {
|
||||
background: ${lightenColor(buttonColor)};
|
||||
}
|
||||
}
|
||||
|
||||
&.button--ghost {
|
||||
&:enabled {
|
||||
background: none;
|
||||
color: ${buttonColor};
|
||||
}
|
||||
|
||||
&:enabled:hover {
|
||||
background: ${lightenColor(buttonColor)};
|
||||
}
|
||||
}
|
||||
|
||||
&.button--link {
|
||||
&:enabled {
|
||||
background: none;
|
||||
color: ${buttonColor};
|
||||
}
|
||||
|
||||
&:enabled:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: ${Colors.GREY_1} !important;
|
||||
color: ${Colors.GREY_9} !important;
|
||||
box-shadow: none !important;
|
||||
pointer-events: none;
|
||||
border-color: ${Colors.GREY_1} !important;
|
||||
> span {
|
||||
color: ${Colors.GREY_9} !important;
|
||||
}
|
||||
}
|
||||
|
||||
& > * {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
& > span, & > span.bp3-icon {
|
||||
max-height: 100%;
|
||||
max-width: 99%;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: normal;
|
||||
color: inherit;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
function Button(props: ButtonProps) {
|
||||
const { children, isDisabled, isLoading, leftIcon, ...rest } = props;
|
||||
|
||||
return (
|
||||
<StyledButton
|
||||
{...rest}
|
||||
className={`button--${props.variant} ${props.className}`}
|
||||
disabled={isDisabled}
|
||||
icon={leftIcon}
|
||||
loading={isLoading}
|
||||
text={children}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Button.defaultProps = {
|
||||
buttonVariant: ButtonVariantTypes.PRIMARY,
|
||||
disabled: false,
|
||||
text: "Button Text",
|
||||
minimal: true,
|
||||
variant: "solid",
|
||||
buttonColor: "#553DE9",
|
||||
borderRadius: borderRadiusOptions.md,
|
||||
justifyContent: "center",
|
||||
} as ButtonProps;
|
||||
|
||||
export default withRecaptcha(withTooltip(Button));
|
||||
172
app/client/src/components/wds/Button/withRecaptcha.tsx
Normal file
172
app/client/src/components/wds/Button/withRecaptcha.tsx
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript";
|
||||
import {
|
||||
GOOGLE_RECAPTCHA_KEY_ERROR,
|
||||
GOOGLE_RECAPTCHA_DOMAIN_ERROR,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import { RecaptchaType, RecaptchaTypes } from "components/constants";
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
import { Variant } from "components/ads/common";
|
||||
|
||||
const RecaptchaWrapper = styled.div`
|
||||
position: relative;
|
||||
.grecaptcha-badge {
|
||||
visibility: hidden;
|
||||
}
|
||||
`;
|
||||
|
||||
export interface RecaptchaProps {
|
||||
googleRecaptchaKey?: string;
|
||||
clickWithRecaptcha?: (token: string) => void;
|
||||
handleRecaptchaV2Loading?: (isLoading: boolean) => void;
|
||||
recaptchaType?: RecaptchaType;
|
||||
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
}
|
||||
|
||||
import { Toaster } from "components/ads/Toast";
|
||||
|
||||
export default function withRecaptcha<
|
||||
T extends RecaptchaProps = RecaptchaProps
|
||||
>(WrappedComponent: React.ComponentType<T>) {
|
||||
const displayName =
|
||||
WrappedComponent.displayName || WrappedComponent.name || "Component";
|
||||
|
||||
function ComponentWithRecaptcha(props: T) {
|
||||
if (!props.googleRecaptchaKey) {
|
||||
return <WrappedComponent {...props} {...(props as T)} />;
|
||||
}
|
||||
|
||||
const handleError = (
|
||||
event: React.MouseEvent<HTMLElement>,
|
||||
error: string,
|
||||
) => {
|
||||
Toaster.show({
|
||||
text: error,
|
||||
variant: Variant.danger,
|
||||
});
|
||||
props.onClick && props.onClick(event);
|
||||
};
|
||||
|
||||
if (props.recaptchaType === RecaptchaTypes.V2) {
|
||||
return (
|
||||
<RecaptchaV2Component {...props} handleError={handleError}>
|
||||
<WrappedComponent {...props} {...(props as T)} />
|
||||
</RecaptchaV2Component>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<RecaptchaV3Component {...props} handleError={handleError}>
|
||||
<WrappedComponent {...props} {...(props as T)} />
|
||||
</RecaptchaV3Component>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ComponentWithRecaptcha.displayName = `withRecaptcha(${displayName})`;
|
||||
|
||||
return ComponentWithRecaptcha;
|
||||
}
|
||||
|
||||
function RecaptchaV2Component(
|
||||
props: {
|
||||
children: any;
|
||||
recaptchaType?: RecaptchaType;
|
||||
handleError: (event: React.MouseEvent<HTMLElement>, error: string) => void;
|
||||
} & RecaptchaProps,
|
||||
) {
|
||||
const recaptchaRef = useRef<ReCAPTCHA>(null);
|
||||
const [isInvalidKey, setInvalidKey] = useState(false);
|
||||
const handleRecaptchaLoading = (isloading: boolean) => {
|
||||
props.handleRecaptchaV2Loading && props.handleRecaptchaV2Loading(isloading);
|
||||
};
|
||||
const handleBtnClick = async (event: React.MouseEvent<HTMLElement>) => {
|
||||
if (isInvalidKey) {
|
||||
// Handle incorrent google recaptcha site key
|
||||
props.handleError(event, createMessage(GOOGLE_RECAPTCHA_KEY_ERROR));
|
||||
} else {
|
||||
handleRecaptchaLoading(true);
|
||||
try {
|
||||
await recaptchaRef?.current?.reset();
|
||||
const token = await recaptchaRef?.current?.executeAsync();
|
||||
if (token && typeof props.clickWithRecaptcha === "function") {
|
||||
props.clickWithRecaptcha(token);
|
||||
} else {
|
||||
// Handle incorrent google recaptcha site key
|
||||
props.handleError(event, createMessage(GOOGLE_RECAPTCHA_KEY_ERROR));
|
||||
}
|
||||
handleRecaptchaLoading(false);
|
||||
} catch (err) {
|
||||
handleRecaptchaLoading(false);
|
||||
// Handle error due to google recaptcha key of different domain
|
||||
props.handleError(event, createMessage(GOOGLE_RECAPTCHA_DOMAIN_ERROR));
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<RecaptchaWrapper onClick={handleBtnClick}>
|
||||
{props.children}
|
||||
<ReCAPTCHA
|
||||
onErrored={() => setInvalidKey(true)}
|
||||
ref={recaptchaRef}
|
||||
sitekey={props.googleRecaptchaKey || ""}
|
||||
size="invisible"
|
||||
/>
|
||||
</RecaptchaWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
function RecaptchaV3Component(
|
||||
props: {
|
||||
children: any;
|
||||
recaptchaType?: RecaptchaType;
|
||||
handleError: (event: React.MouseEvent<HTMLElement>, error: string) => void;
|
||||
} & RecaptchaProps,
|
||||
) {
|
||||
// Check if a string is a valid JSON string
|
||||
const checkValidJson = (inputString: string): boolean => {
|
||||
return !inputString.includes('"');
|
||||
};
|
||||
|
||||
const handleBtnClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
if (status === ScriptStatus.READY) {
|
||||
(window as any).grecaptcha.ready(() => {
|
||||
try {
|
||||
(window as any).grecaptcha
|
||||
.execute(props.googleRecaptchaKey, {
|
||||
action: "submit",
|
||||
})
|
||||
.then((token: any) => {
|
||||
if (typeof props.clickWithRecaptcha === "function") {
|
||||
props.clickWithRecaptcha(token);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// Handle incorrent google recaptcha site key
|
||||
props.handleError(
|
||||
event,
|
||||
createMessage(GOOGLE_RECAPTCHA_KEY_ERROR),
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
// Handle error due to google recaptcha key of different domain
|
||||
props.handleError(
|
||||
event,
|
||||
createMessage(GOOGLE_RECAPTCHA_DOMAIN_ERROR),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let validGoogleRecaptchaKey = props.googleRecaptchaKey;
|
||||
if (validGoogleRecaptchaKey && !checkValidJson(validGoogleRecaptchaKey)) {
|
||||
validGoogleRecaptchaKey = undefined;
|
||||
}
|
||||
const status = useScript(
|
||||
`https://www.google.com/recaptcha/api.js?render=${validGoogleRecaptchaKey}`,
|
||||
AddScriptTo.HEAD,
|
||||
);
|
||||
return <div onClick={handleBtnClick}>{props.children}</div>;
|
||||
}
|
||||
115
app/client/src/components/wds/Checkbox/index.tsx
Normal file
115
app/client/src/components/wds/Checkbox/index.tsx
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import styled from "styled-components";
|
||||
import { Checkbox as BlueprintCheckbox } from "@blueprintjs/core";
|
||||
|
||||
import { Colors } from "constants/Colors";
|
||||
import { lightenColor, darkenColor } from "widgets/WidgetUtils";
|
||||
|
||||
type StyledCheckboxProps = {
|
||||
checked?: boolean;
|
||||
disabled?: boolean;
|
||||
backgroundColor?: string;
|
||||
borderRadius?: string;
|
||||
indeterminate?: boolean;
|
||||
hasError?: boolean;
|
||||
inputRef?: (el: HTMLInputElement | null) => any;
|
||||
};
|
||||
|
||||
const DISABLED_ICON_SVG =
|
||||
"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill-rule='evenodd' clip-rule='evenodd' d='M11 7H5c-.55 0-1 .45-1 1s.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1z' fill='white'/%3e%3c/svg%3e";
|
||||
const CHECKED_ICON_SVG =
|
||||
"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 14 14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='14' height='14' /%3E%3Cpath d='M10.1039 3.5L11 4.40822L5.48269 10L2.5 6.97705L3.39613 6.06883L5.48269 8.18305L10.1039 3.5Z' fill='white'/%3E%3C/svg%3E%0A";
|
||||
|
||||
const Checkbox = styled(BlueprintCheckbox)<StyledCheckboxProps>`
|
||||
${({ backgroundColor, borderRadius, checked, hasError }) => `
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: ${checked ? Colors.GREY_10 : Colors.GREY_9};
|
||||
|
||||
&.bp3-control.bp3-checkbox .bp3-control-indicator {
|
||||
margin: 0;
|
||||
border: none;
|
||||
box-shadow: 0px 0px 0px 1px ${Colors.GREY_3};
|
||||
outline: none !important;
|
||||
background: transparent;
|
||||
border-radius: ${borderRadius};
|
||||
|
||||
// ERROR state ( needed when checkbox is required )
|
||||
${hasError && `box-shadow: 0px 0px 0px 1px ${Colors.ERROR_RED};`};
|
||||
}
|
||||
|
||||
&.bp3-control.bp3-checkbox input:checked ~ .bp3-control-indicator,
|
||||
&.bp3-control.bp3-checkbox input:indeterminate ~ .bp3-control-indicator {
|
||||
background: ${backgroundColor} !important;
|
||||
background-image: none;
|
||||
border: none !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
// ACTIVE
|
||||
&.bp3-control.bp3-checkbox:active .bp3-control-indicator {
|
||||
background: ${lightenColor(backgroundColor)} !important;
|
||||
box-shadow:
|
||||
0px 0px 0px 1px ${backgroundColor},
|
||||
0px 0px 0px 3px ${lightenColor(backgroundColor)} !important;
|
||||
}
|
||||
|
||||
// ACTIVE WHEN DISABLED
|
||||
&.bp3-control.bp3-checkbox:active input:disabled ~ .bp3-control-indicator {
|
||||
box-shadow: 0px 0px 0px 1px ${Colors.GREY_3} !important;
|
||||
}
|
||||
|
||||
// DISABLED
|
||||
&.bp3-control.bp3-checkbox input:disabled ~ .bp3-control-indicator {
|
||||
opacity: 0.5;
|
||||
background: ${Colors.GREY_5} !important;
|
||||
color: ${Colors.GREY_8};
|
||||
|
||||
&::before {
|
||||
background-image: url("${DISABLED_ICON_SVG}") !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.bp3-control.bp3-checkbox input:checked ~ .bp3-control-indicator {
|
||||
&::before {
|
||||
background-image: url("${CHECKED_ICON_SVG}") !important;
|
||||
}
|
||||
}
|
||||
|
||||
// CHECKED
|
||||
&.bp3-control.bp3-checkbox input:checked ~ .bp3-control-indicator {
|
||||
background: ${backgroundColor} !important;
|
||||
}
|
||||
|
||||
// HOVER WHEN CHECKED
|
||||
&.bp3-control.bp3-checkbox:hover input:checked ~ .bp3-control-indicator {
|
||||
box-shadow: none;
|
||||
background: ${darkenColor(backgroundColor)} !important;
|
||||
}
|
||||
|
||||
// HOVER WHEN UNCHECKED
|
||||
&.bp3-control.bp3-checkbox:hover :not(input:checked) ~ .bp3-control-indicator {
|
||||
box-shadow: 0px 0px 0px 1px ${Colors.GREY_5};
|
||||
}
|
||||
|
||||
// INDETERMINATE
|
||||
&.bp3-control.bp3-checkbox input:indeterminate ~ .bp3-control-indicator {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
// BLUEPRINT DEFAULT ISSUES
|
||||
&.bp3-control:not(.bp3-align-right) {
|
||||
padding-left: 0;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
Checkbox.defaultProps = {
|
||||
backgroundColor: "#553DE9",
|
||||
borderRadius: "0.375rem",
|
||||
};
|
||||
|
||||
export { Checkbox };
|
||||
53
app/client/src/components/wds/Menu/index.tsx
Normal file
53
app/client/src/components/wds/Menu/index.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Popover,
|
||||
Menu as BMenu,
|
||||
MenuItem as BMenuItem,
|
||||
IMenuProps,
|
||||
IMenuItemProps,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactElement[] | React.ReactElement;
|
||||
};
|
||||
|
||||
function Menu(props: Props) {
|
||||
const menus =
|
||||
(Array.isArray(props.children) &&
|
||||
props.children.find(
|
||||
(child: any) => child.type.displayName === "MenuList",
|
||||
)) ||
|
||||
undefined;
|
||||
|
||||
const trigger =
|
||||
Array.isArray(props.children) &&
|
||||
props.children.find(
|
||||
(child: any) => child.type.displayName === "MenuTrigger",
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover content={menus} popoverClassName="Menu-v2" transitionDuration={-1}>
|
||||
{trigger}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function MenuList(props: IMenuProps) {
|
||||
return <BMenu {...props} />;
|
||||
}
|
||||
|
||||
MenuList.displayName = "MenuList";
|
||||
|
||||
function MenuTrigger(props: any) {
|
||||
return <div {...props} />;
|
||||
}
|
||||
|
||||
MenuTrigger.displayName = "MenuTrigger";
|
||||
|
||||
function MenuItem(props: IMenuItemProps) {
|
||||
return <BMenuItem {...props} />;
|
||||
}
|
||||
|
||||
MenuItem.displayName = "MenuItem";
|
||||
|
||||
export { Menu, MenuList, MenuItem, MenuTrigger };
|
||||
57
app/client/src/components/wds/Select/index.tsx
Normal file
57
app/client/src/components/wds/Select/index.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Popover,
|
||||
Menu,
|
||||
MenuItem,
|
||||
IMenuProps,
|
||||
IMenuItemProps,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactElement[] | React.ReactElement;
|
||||
};
|
||||
|
||||
function Select(props: Props) {
|
||||
const menus =
|
||||
(Array.isArray(props.children) &&
|
||||
props.children.find(
|
||||
(child: any) => child.type.displayName === "SelectList",
|
||||
)) ||
|
||||
undefined;
|
||||
|
||||
const trigger =
|
||||
Array.isArray(props.children) &&
|
||||
props.children.find(
|
||||
(child: any) => child.type.displayName === "SelectTrigger",
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
content={menus}
|
||||
popoverClassName="Select-v2"
|
||||
transitionDuration={-1}
|
||||
>
|
||||
{trigger}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
function SelectList(props: IMenuProps) {
|
||||
return <Menu {...props} />;
|
||||
}
|
||||
|
||||
SelectList.displayName = "SelectList";
|
||||
|
||||
function SelectTrigger(props: any) {
|
||||
return <div {...props} />;
|
||||
}
|
||||
|
||||
SelectTrigger.displayName = "SelectTrigger";
|
||||
|
||||
function SelectOption(props: IMenuItemProps) {
|
||||
return <MenuItem {...props} />;
|
||||
}
|
||||
|
||||
SelectOption.displayName = "SelectOption";
|
||||
|
||||
export { Select, SelectList, SelectOption, SelectTrigger };
|
||||
149
app/client/src/components/wds/Showcase.tsx
Normal file
149
app/client/src/components/wds/Showcase.tsx
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import React, { useState } from "react";
|
||||
|
||||
import { Checkbox, Button } from "components/wds";
|
||||
import { borderRadiusOptions } from "constants/ThemeConstants";
|
||||
|
||||
function Showcase() {
|
||||
const [borderRadius, setBorderRadius] = useState("0px");
|
||||
|
||||
const theme = {
|
||||
borderRadius,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container min-h-screen pt-12 mx-auto">
|
||||
<h1 className="mt-12 space-y-8 text-3xl font-bold">
|
||||
Widgets Design System
|
||||
</h1>
|
||||
|
||||
<h1>Theme Options</h1>
|
||||
<div>Border radius</div>
|
||||
<div className="flex gap-2">
|
||||
{Object.keys(borderRadiusOptions).map((optionKey) => (
|
||||
<button
|
||||
className={`flex items-center justify-center w-8 h-8 bg-trueGray-100 ring-gray-700 cursor-pointer hover:bg-trueGray-50 ${
|
||||
borderRadius === borderRadiusOptions[optionKey] ? "ring-1" : ""
|
||||
}`}
|
||||
key={optionKey}
|
||||
onClick={() => {
|
||||
setBorderRadius(borderRadiusOptions[optionKey]);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="w-4 h-4 border-t-2 border-l-2 border-gray-600 rounded-"
|
||||
style={{ borderTopLeftRadius: borderRadiusOptions[optionKey] }}
|
||||
/>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="space-y-5">
|
||||
<div className="mt-5">
|
||||
<h2 className="my-2 text-xl font-semibold">Checkbox</h2>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-gray-500">States</h3>
|
||||
<div className="flex space-x-3">
|
||||
<Checkbox checked label="Active" {...theme} />
|
||||
<Checkbox
|
||||
checked={false}
|
||||
disabled
|
||||
label="Disabled"
|
||||
{...theme}
|
||||
/>
|
||||
<Checkbox checked={false} hasError label="Error" {...theme} />
|
||||
<Checkbox
|
||||
checked={false}
|
||||
indeterminate
|
||||
label="Indeterminate"
|
||||
{...theme}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* checkbox end */}
|
||||
|
||||
{/* buttons */}
|
||||
<div className="">
|
||||
<h2 className="my-2 text-xl font-semibold">Buttons</h2>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-gray-500">Types</h3>
|
||||
<div className="flex space-x-3">
|
||||
<Button leftIcon="download" {...theme} />
|
||||
<Button variant="solid" {...theme}>
|
||||
Solid
|
||||
</Button>
|
||||
<Button variant="outline" {...theme}>
|
||||
Outline
|
||||
</Button>
|
||||
<Button variant="ghost" {...theme}>
|
||||
Ghost
|
||||
</Button>
|
||||
<Button variant="link" {...theme}>
|
||||
Link
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-gray-500">States</h3>
|
||||
<div className="flex space-x-3">
|
||||
<Button {...theme}>Default</Button>
|
||||
<Button isDisabled {...theme}>
|
||||
Disalbed
|
||||
</Button>
|
||||
<Button isLoading {...theme}>
|
||||
Loading
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-gray-500">Icon and Alignment</h3>
|
||||
<div className="flex space-x-3">
|
||||
<Button className="w-40" leftIcon="download" {...theme}>
|
||||
With Icon
|
||||
</Button>
|
||||
<Button
|
||||
className="w-40"
|
||||
justifyContent="space-between"
|
||||
leftIcon="download"
|
||||
{...theme}
|
||||
>
|
||||
With Icon
|
||||
</Button>
|
||||
<Button
|
||||
className="w-40"
|
||||
justifyContent="flex-start"
|
||||
leftIcon="download"
|
||||
{...theme}
|
||||
>
|
||||
With Icon
|
||||
</Button>
|
||||
<Button
|
||||
className="w-40"
|
||||
justifyContent="flex-end"
|
||||
leftIcon="download"
|
||||
{...theme}
|
||||
>
|
||||
With Icon
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h3 className="text-gray-500">Misc</h3>
|
||||
<div className="flex space-x-3">
|
||||
<Button tooltip="This is tooltip content" {...theme}>
|
||||
Tooltip
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*button end */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Showcase;
|
||||
1
app/client/src/components/wds/Tooltip/index.tsx
Normal file
1
app/client/src/components/wds/Tooltip/index.tsx
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as withTooltip } from "./withTooltip";
|
||||
50
app/client/src/components/wds/Tooltip/withTooltip.tsx
Normal file
50
app/client/src/components/wds/Tooltip/withTooltip.tsx
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Tooltip from "components/ads/Tooltip";
|
||||
import { Position } from "@blueprintjs/core";
|
||||
|
||||
const ToolTipWrapper = styled.div`
|
||||
height: 100%;
|
||||
&& .bp3-popover2-target {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
& > div {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface TooltipProps {
|
||||
tooltip?: string;
|
||||
isDisabled?: boolean;
|
||||
}
|
||||
|
||||
export default function withTooltip<T extends TooltipProps = TooltipProps>(
|
||||
WrappedComponent: React.ComponentType<T>,
|
||||
) {
|
||||
const displayName =
|
||||
WrappedComponent.displayName || WrappedComponent.name || "Component";
|
||||
|
||||
function ComponentWithTooltip(props: T) {
|
||||
if (props.tooltip) {
|
||||
return (
|
||||
<ToolTipWrapper>
|
||||
<Tooltip
|
||||
content={props.tooltip}
|
||||
disabled={props.isDisabled}
|
||||
hoverOpenDelay={200}
|
||||
position={Position.TOP}
|
||||
>
|
||||
<WrappedComponent {...props} {...(props as T)} />
|
||||
</Tooltip>
|
||||
</ToolTipWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return <WrappedComponent {...props} {...(props as T)} />;
|
||||
}
|
||||
|
||||
ComponentWithTooltip.displayName = `withTooltip(${displayName})`;
|
||||
|
||||
return ComponentWithTooltip;
|
||||
}
|
||||
3
app/client/src/components/wds/index.tsx
Normal file
3
app/client/src/components/wds/index.tsx
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { Checkbox } from "./Checkbox";
|
||||
export { withTooltip } from "./Tooltip";
|
||||
export { default as Button } from "./Button";
|
||||
|
|
@ -184,4 +184,5 @@ export const Colors = {
|
|||
COD_GRAY: "#191919",
|
||||
MINE_SHAFT_2: "#333333",
|
||||
};
|
||||
|
||||
export type Color = typeof Colors[keyof typeof Colors];
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user