diff --git a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js index ecf774670d..0f149cf217 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/ThemingTests/Theme_MultiSelectWidget_spec.js @@ -1,6 +1,7 @@ const commonlocators = require("../../../../locators/commonlocators.json"); const themelocator = require("../../../../locators/ThemeLocators.json"); +import { multiSelectWidgetLocators } from "../../../../locators/WidgetLocators"; import { agHelper, locators, @@ -26,49 +27,19 @@ describe( agHelper.GetNClick(locators._canvas); appSettings.OpenAppSettings(); appSettings.GoToThemeSettings(); - //Border validation - //cy.contains("Border").click({ force: true }); - cy.get(themelocator.border).should("have.length", "3"); - cy.borderMouseover(0, "none"); - cy.borderMouseover(1, "M"); - cy.borderMouseover(2, "L"); - cy.get(themelocator.border).eq(1).click({ force: true }); - cy.wait("@updateTheme").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - cy.wait(1000); - cy.contains("Border").click({ force: true }); - //Shadow validation - //cy.contains("Shadow").click({ force: true }); - cy.wait(2000); - cy.xpath(theme.locators._boxShadow("L")).click({ force: true }); - cy.wait("@updateTheme").should( - "have.nested.property", - "response.body.responseMeta.status", - 200, - ); - cy.wait(1000); - cy.contains("Shadow").click({ force: true }); - - //Font cy.xpath( "//p[text()='App font']/following-sibling::section//div//input", ).then(($elem) => { - cy.get($elem).click({ force: true }); - cy.wait(250); - cy.fixture("fontData").then(function (testdata) { - this.testdata = testdata; - }); + agHelper.GetNClick($elem); - cy.get(themelocator.fontsSelected) - //.eq(10) + agHelper + .GetElement(themelocator.fontsSelected) .should("contain.text", "Nunito Sans"); - cy.get(".rc-virtual-list .rc-select-item-option") - .find(".leading-normal") + agHelper + .GetElement(themelocator.fontOption) + .find(themelocator.fontsSelected) .eq(3) .then(($childElem) => { cy.get($childElem).click({ force: true }); @@ -80,60 +51,46 @@ describe( themeFont = `Inter, sans-serif`; }); }); + cy.contains("Font").click({ force: true }); - //Color - Bug 23501 - hence skipping - // cy.wait(1000); - // theme.ChangeThemeColor("purple", "Primary"); - // cy.get(themelocator.inputColor).should("have.value", "purple"); - // cy.wait(1000); - - // theme.ChangeThemeColor("brown", "Background"); - // cy.get(themelocator.inputColor).should("have.value", "brown"); - // cy.wait(1000); - // cy.contains("Color").click({ force: true }); appSettings.ClosePane(); }); - //Skipping due to mentioned bug - it.skip("2. Publish the App and validate Font across the app + Bug 15007", function () { + it("2. Publish the App and validate Font across the app", function () { deployMode.DeployApp(); - cy.get(".rc-select-selection-item > .rc-select-selection-item-content") + agHelper + .GetElement( + multiSelectWidgetLocators.multiSelectWidgetSelectedOptionContent, + ) .first() .should("have.css", "font-family", themeFont); - cy.get(".rc-select-selection-item > .rc-select-selection-item-content") + agHelper + .GetElement( + multiSelectWidgetLocators.multiSelectWidgetSelectedOptionContent, + ) .last() .should("have.css", "font-family", themeFont); deployMode.NavigateBacktoEditor(); }); - it.skip("3. Validate current theme feature", function () { - cy.get("#canvas-selection-0").click({ force: true }); + it("3. Apply theme and validate the color", function () { appSettings.OpenAppSettings(); appSettings.GoToThemeSettings(); - //Change the Theme - cy.get(commonlocators.changeThemeBtn).click({ force: true }); - cy.get(themelocator.currentTheme).click({ force: true }); - cy.get(".t--theme-card main > main") - .first() - .invoke("css", "background-color") - .then(() => { - cy.get(".t--draggable-multiselectwidgetv2:contains('more')") - .last() - .invoke("css", "background-color") - .then((selectedBackgroudColor) => { - expect("rgba(0, 0, 0, 0)").to.equal(selectedBackgroudColor); - appSettings.ClosePane(); - }); - }); - - //Publish the App and validate change of Theme across the app in publish mode - deployMode.DeployApp(); - cy.xpath("//div[@id='root']//section/parent::div").should( - "have.css", - "background-color", - "rgb(165, 42, 42)", + agHelper.GetNClick(commonlocators.changeThemeBtn, 0, true); + agHelper.GetNClick( + `${themelocator.featuredThemeSection} [data-testid='t--theme-card-Sunrise']`, ); + + deployMode.DeployApp(); + + agHelper.GetNClick(multiSelectWidgetLocators.multiSelectWidgetTrigger); + agHelper + .GetElement( + multiSelectWidgetLocators.multiSelectWidgetDropdownOptionCheckbox, + ) + .first() + .should("have.css", "background-color", "rgb(239, 68, 68)"); }); }, ); diff --git a/app/client/cypress/locators/ThemeLocators.json b/app/client/cypress/locators/ThemeLocators.json index 6bf5174002..4f7b655bc9 100644 --- a/app/client/cypress/locators/ThemeLocators.json +++ b/app/client/cypress/locators/ThemeLocators.json @@ -9,5 +9,7 @@ "greenColor": "[style='background-color: rgb(21, 128, 61);']", "fontsSelected": ".leading-normal", "currentTheme": ".cursor-pointer:contains('Applied theme')", - "purpleColor": "[style='background-color: rgb(107,114,128);']" -} + "purpleColor": "[style='background-color: rgb(107,114,128);']", + "featuredThemeSection": "[data-testid='t--featured-themes']", + "fontOption": ".rc-virtual-list .rc-select-item-option" +} \ No newline at end of file diff --git a/app/client/cypress/locators/WidgetLocators.ts b/app/client/cypress/locators/WidgetLocators.ts index 8e2d368244..3f84187498 100644 --- a/app/client/cypress/locators/WidgetLocators.ts +++ b/app/client/cypress/locators/WidgetLocators.ts @@ -175,3 +175,9 @@ export const buttongroupwidgetlocators = { `//*[contains(@class,'bp3-menu-item')]//*[text()='${text}']`, button: "//*[contains(@class,'t--widget-buttongroupwidget')]//button", }; + +export const multiSelectWidgetLocators = { + multiSelectWidgetTrigger: ".t--widget-multiselectwidgetv2 .rc-select-selector", + multiSelectWidgetSelectedOptionContent: ".rc-select-selection-item > .rc-select-selection-item-content", + multiSelectWidgetDropdownOptionCheckbox: ".multi-select-dropdown .rc-select-item-option-selected .bp3-control-indicator" +}; \ No newline at end of file diff --git a/app/client/src/components/propertyControls/ColorPickerComponentV2.tsx b/app/client/src/components/propertyControls/ColorPickerComponentV2.tsx index 0c6ee76260..6c012b137e 100644 --- a/app/client/src/components/propertyControls/ColorPickerComponentV2.tsx +++ b/app/client/src/components/propertyControls/ColorPickerComponentV2.tsx @@ -367,12 +367,11 @@ const ColorPickerComponent = React.forwardRef( defaultFullColorPickerValue, ); - const debouncedOnChange = React.useCallback( - debounce((color: string, isUpdatedViaKeyboard: boolean) => { + const debouncedOnChange = useMemo(() => { + return debounce((color: string, isUpdatedViaKeyboard: boolean) => { props.changeColor(color, isUpdatedViaKeyboard); - }, DEBOUNCE_TIMER), - [], - ); + }, DEBOUNCE_TIMER); + }, [props]); useEffect(() => { setIsOpen(isOpenProp); @@ -545,13 +544,19 @@ const ColorPickerComponent = React.forwardRef( }; }, [handleKeydown]); - const handleChangeColor = (event: React.ChangeEvent) => { - const value = event.target.value; - if (isValidColor(value)) { - debouncedOnChange(value, true); - } - setColor(value); - }; + const handleChangeColor = useCallback( + (event: React.ChangeEvent) => { + const value = event.target.value; + + if (!value) return; + + if (isValidColor(value)) { + debouncedOnChange(value, true); + } + setColor(value); + }, + [debouncedOnChange], + ); // if props.color changes and state color is different, // sets the state color to props color diff --git a/app/client/src/entities/AppTheming/index.ts b/app/client/src/entities/AppTheming/index.ts index 74f785366a..b5ce82c73e 100644 --- a/app/client/src/entities/AppTheming/index.ts +++ b/app/client/src/entities/AppTheming/index.ts @@ -67,7 +67,7 @@ export interface AppThemeProperties { colors: { primaryColor: string; backgroundColor: string; - [key: string]: string; + [key: Exclude]: string; }; borderRadius: { [key: string]: string; diff --git a/app/client/src/pages/Editor/ThemePropertyPane/ThemeCard.tsx b/app/client/src/pages/Editor/ThemePropertyPane/ThemeCard.tsx index 223ca19466..fcdc40d0c1 100644 --- a/app/client/src/pages/Editor/ThemePropertyPane/ThemeCard.tsx +++ b/app/client/src/pages/Editor/ThemePropertyPane/ThemeCard.tsx @@ -177,6 +177,7 @@ export function ThemeCard(props: ThemeCard) { "overflow-hidden": !selectable, "hover:shadow-xl cursor-pointer": selectable, })} + data-testid={`t--theme-card-${theme.name}`} onClick={changeSelectedTheme} > diff --git a/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx b/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx index 1e63890a73..f6b708d09c 100644 --- a/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx +++ b/app/client/src/pages/Editor/ThemePropertyPane/ThemeEditor.tsx @@ -76,7 +76,7 @@ function ThemeEditor() { dispatch(updateSelectedAppThemeAction({ applicationId, theme })); }, - [updateSelectedAppThemeAction], + [applicationId, dispatch], ); /** @@ -91,7 +91,7 @@ function ThemeEditor() { AppThemingMode.APP_THEME_SELECTION, ]), ); - }, [setAppThemingModeStackAction]); + }, [dispatch, themingStack]); /** * resets theme diff --git a/app/client/src/pages/Editor/ThemePropertyPane/ThemeSelector.tsx b/app/client/src/pages/Editor/ThemePropertyPane/ThemeSelector.tsx index d192ffef18..3a74543d5f 100644 --- a/app/client/src/pages/Editor/ThemePropertyPane/ThemeSelector.tsx +++ b/app/client/src/pages/Editor/ThemePropertyPane/ThemeSelector.tsx @@ -76,7 +76,10 @@ function ThemeSelector() { ))} )} -
+
Featured themes {systemThemes.map((theme) => ( ("primaryColor"); const [isFullColorPicker, setFullColorPicker] = React.useState(false); + const onColorClick = useCallback( + (e: React.MouseEvent) => { + const colorName = e.currentTarget.getAttribute("data-color-name"); + if (!colorName) return; + + setAutoFocus(selectedColor === colorName ? !autoFocus : true); + setSelectedColor(colorName); + }, + [autoFocus, selectedColor], + ); + + const onChangeColor = useCallback( + (color: string) => { + updateTheme({ + ...theme, + properties: { + ...theme.properties, + colors: { + ...theme.properties.colors, + [selectedColor]: color, + }, + }, + }); + }, + [selectedColor, theme, updateTheme], + ); + return (
- {Object.keys(theme.properties.colors).map( - (colorName: string, index: number) => { - return ( - - { - setAutoFocus( - selectedColor === colorName ? !autoFocus : true, - ); - setSelectedColor(colorName); - }} - /> - - ); - }, - )} + {objectKeys(theme.properties.colors).map((colorName, index) => { + return ( + + + + ); + })}
{selectedColor && (

{capitalizeFirstLetter(startCase(selectedColor))}

{ - updateTheme({ - ...theme, - properties: { - ...theme.properties, - colors: { - ...theme.properties.colors, - [selectedColor]: color, - }, - }, - }); - }} + changeColor={onChangeColor} color={userDefinedColors[selectedColor]} + data-color={selectedColor} isFullColorPicker={isFullColorPicker} isOpen={autoFocus} key={selectedColor}