feat: disabledWhenInvalid in ButtonGroupWidget (#38656)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: rahul.barwal@appsmith.com <rahul.barwal@appsmith.com>
This commit is contained in:
parent
4e7a2a013d
commit
b3e5e431b2
|
|
@ -1,6 +1,7 @@
|
|||
import type { RefObject } from "react";
|
||||
import React, { createRef } from "react";
|
||||
import { sortBy } from "lodash";
|
||||
import { objectKeys } from "@appsmith/utils";
|
||||
import {
|
||||
Alignment,
|
||||
Icon,
|
||||
|
|
@ -45,7 +46,7 @@ interface ButtonData {
|
|||
const getButtonData = (
|
||||
groupButtons: Record<string, GroupButtonProps>,
|
||||
): ButtonData[] => {
|
||||
const buttonData = Object.keys(groupButtons).reduce(
|
||||
const buttonData = objectKeys(groupButtons).reduce(
|
||||
(acc: ButtonData[], id) => {
|
||||
return [
|
||||
...acc,
|
||||
|
|
@ -344,7 +345,7 @@ interface PopoverContentProps {
|
|||
function PopoverContent(props: PopoverContentProps) {
|
||||
const { buttonId, menuItems, onItemClicked } = props;
|
||||
|
||||
let items = Object.keys(menuItems)
|
||||
let items = objectKeys(menuItems)
|
||||
.map((itemKey) => menuItems[itemKey])
|
||||
.filter((item) => item.isVisible === true);
|
||||
|
||||
|
|
@ -490,7 +491,7 @@ class ButtonGroupComponent extends React.Component<
|
|||
|
||||
// Get widths of menu buttons
|
||||
getMenuButtonWidths = () =>
|
||||
Object.keys(this.props.groupButtons).reduce((acc, id) => {
|
||||
objectKeys(this.props.groupButtons).reduce((acc, id) => {
|
||||
if (this.props.groupButtons[id].buttonType === "MENU") {
|
||||
return {
|
||||
...acc,
|
||||
|
|
@ -503,7 +504,7 @@ class ButtonGroupComponent extends React.Component<
|
|||
|
||||
// Create refs of menu buttons
|
||||
createMenuButtonRefs = () =>
|
||||
Object.keys(this.props.groupButtons).reduce((acc, id) => {
|
||||
objectKeys(this.props.groupButtons).reduce((acc, id) => {
|
||||
if (this.props.groupButtons[id].buttonType === "MENU") {
|
||||
return {
|
||||
...acc,
|
||||
|
|
@ -540,6 +541,7 @@ class ButtonGroupComponent extends React.Component<
|
|||
buttonVariant,
|
||||
groupButtons,
|
||||
isDisabled,
|
||||
isFormValid,
|
||||
minPopoverWidth,
|
||||
orientation,
|
||||
widgetId,
|
||||
|
|
@ -547,7 +549,7 @@ class ButtonGroupComponent extends React.Component<
|
|||
const { loadedBtnId } = this.state;
|
||||
const isHorizontal = orientation === "horizontal";
|
||||
|
||||
let items = Object.keys(groupButtons)
|
||||
let items = objectKeys(groupButtons)
|
||||
.map((itemKey) => groupButtons[itemKey])
|
||||
.filter((item) => item.isVisible === true);
|
||||
|
||||
|
|
@ -574,7 +576,11 @@ class ButtonGroupComponent extends React.Component<
|
|||
{items.map((button) => {
|
||||
const isLoading = button.id === loadedBtnId;
|
||||
const isButtonDisabled =
|
||||
button.isDisabled || isDisabled || !!loadedBtnId || isLoading;
|
||||
button.isDisabled ||
|
||||
isDisabled ||
|
||||
!!loadedBtnId ||
|
||||
isLoading ||
|
||||
(button.disabledWhenInvalid && isFormValid === false);
|
||||
|
||||
if (button.buttonType === "MENU" && !isButtonDisabled) {
|
||||
const { menuItems } = button;
|
||||
|
|
@ -703,6 +709,7 @@ interface GroupButtonProps {
|
|||
index: number;
|
||||
isVisible?: boolean;
|
||||
isDisabled?: boolean;
|
||||
disabledWhenInvalid?: boolean;
|
||||
label?: string;
|
||||
buttonType?: string;
|
||||
buttonColor?: string;
|
||||
|
|
@ -718,6 +725,7 @@ interface GroupButtonProps {
|
|||
index: number;
|
||||
isVisible?: boolean;
|
||||
isDisabled?: boolean;
|
||||
disabledWhenInvalid?: boolean;
|
||||
label?: string;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
|
|
@ -746,6 +754,7 @@ export interface ButtonGroupComponentProps {
|
|||
widgetId: string;
|
||||
buttonMinWidth?: number;
|
||||
minHeight?: number;
|
||||
isFormValid?: boolean;
|
||||
}
|
||||
|
||||
export interface ButtonGroupComponentState {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import { render } from "@testing-library/react";
|
||||
import React from "react";
|
||||
import ButtonGroupWidget from "../index";
|
||||
import { RenderModes } from "constants/WidgetConstants";
|
||||
import type { ButtonGroupWidgetProps } from "../index";
|
||||
import { klona } from "klona";
|
||||
|
||||
describe("ButtonGroupWidget disabledWhenInvalid", () => {
|
||||
const defaultProps: ButtonGroupWidgetProps = {
|
||||
widgetId: "test-button-group",
|
||||
renderMode: RenderModes.CANVAS,
|
||||
version: 1,
|
||||
parentColumnSpace: 1,
|
||||
parentRowSpace: 1,
|
||||
leftColumn: 0,
|
||||
rightColumn: 0,
|
||||
topRow: 0,
|
||||
bottomRow: 0,
|
||||
isLoading: false,
|
||||
orientation: "horizontal",
|
||||
isDisabled: false,
|
||||
buttonVariant: "PRIMARY",
|
||||
type: "BUTTON_GROUP_WIDGET",
|
||||
widgetName: "ButtonGroup1",
|
||||
groupButtons: {
|
||||
groupButton1: {
|
||||
label: "Test Button 1",
|
||||
id: "groupButton1",
|
||||
widgetId: "",
|
||||
buttonType: "SIMPLE",
|
||||
placement: "CENTER",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: true,
|
||||
index: 0,
|
||||
menuItems: {},
|
||||
},
|
||||
groupButton2: {
|
||||
label: "Test Button 2",
|
||||
id: "groupButton2",
|
||||
widgetId: "",
|
||||
buttonType: "SIMPLE",
|
||||
placement: "CENTER",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: true,
|
||||
index: 1,
|
||||
menuItems: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("disables buttons when disabledWhenInvalid is true and form is invalid", () => {
|
||||
const props = klona(defaultProps);
|
||||
|
||||
props.isFormValid = false;
|
||||
|
||||
const { container } = render(<ButtonGroupWidget {...props} />);
|
||||
const buttons = container.querySelectorAll("button");
|
||||
|
||||
buttons.forEach((button) => {
|
||||
expect(button.hasAttribute("disabled")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("enables buttons when disabledWhenInvalid is true but form is valid", () => {
|
||||
const props = klona(defaultProps);
|
||||
|
||||
props.isFormValid = true;
|
||||
|
||||
const { container } = render(<ButtonGroupWidget {...props} />);
|
||||
const buttons = container.querySelectorAll("button");
|
||||
|
||||
buttons.forEach((button) => {
|
||||
expect(button.hasAttribute("disabled")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("enables buttons when disabledWhenInvalid is false regardless of form validity", () => {
|
||||
const props = klona(defaultProps);
|
||||
|
||||
props.groupButtons = {
|
||||
...defaultProps.groupButtons,
|
||||
groupButton1: {
|
||||
...defaultProps.groupButtons.groupButton1,
|
||||
disabledWhenInvalid: false,
|
||||
},
|
||||
groupButton2: {
|
||||
...defaultProps.groupButtons.groupButton2,
|
||||
disabledWhenInvalid: false,
|
||||
},
|
||||
};
|
||||
|
||||
const { container } = render(<ButtonGroupWidget {...props} />);
|
||||
const buttons = container.querySelectorAll("button");
|
||||
|
||||
buttons.forEach((button) => {
|
||||
expect(button.hasAttribute("disabled")).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -65,6 +65,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
placement: "CENTER",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 0,
|
||||
menuItems: {},
|
||||
},
|
||||
|
|
@ -77,6 +78,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
widgetId: "",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 1,
|
||||
menuItems: {},
|
||||
},
|
||||
|
|
@ -89,6 +91,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
widgetId: "",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 2,
|
||||
menuItems: {
|
||||
menuItem1: {
|
||||
|
|
@ -99,6 +102,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
onClick: "",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 0,
|
||||
},
|
||||
menuItem2: {
|
||||
|
|
@ -109,6 +113,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
onClick: "",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 1,
|
||||
},
|
||||
menuItem3: {
|
||||
|
|
@ -123,6 +128,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
onClick: "",
|
||||
isVisible: true,
|
||||
isDisabled: false,
|
||||
disabledWhenInvalid: false,
|
||||
index: 2,
|
||||
},
|
||||
},
|
||||
|
|
@ -517,6 +523,22 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
sectionName: "Form settings",
|
||||
children: [
|
||||
{
|
||||
propertyName: "disabledWhenInvalid",
|
||||
label: "Disabled invalid forms",
|
||||
helpText:
|
||||
"Disables this button if the form is invalid, if this button exists directly within a Form widget",
|
||||
controlType: "SWITCH",
|
||||
isJSConvertible: true,
|
||||
isBindProperty: true,
|
||||
isTriggerProperty: false,
|
||||
validation: { type: ValidationTypes.BOOLEAN },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
sectionName: "Events",
|
||||
hidden: (
|
||||
|
|
@ -825,6 +847,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
buttonVariant={this.props.buttonVariant}
|
||||
groupButtons={this.props.groupButtons}
|
||||
isDisabled={this.props.isDisabled}
|
||||
isFormValid={this.props.isFormValid}
|
||||
minHeight={this.isAutoLayoutMode ? this.props.minHeight : undefined}
|
||||
minPopoverWidth={minPopoverWidth}
|
||||
orientation={this.props.orientation}
|
||||
|
|
@ -839,6 +862,7 @@ class ButtonGroupWidget extends BaseWidget<
|
|||
export interface ButtonGroupWidgetProps extends WidgetProps {
|
||||
orientation: string;
|
||||
isDisabled: boolean;
|
||||
isFormValid?: boolean;
|
||||
borderRadius?: string;
|
||||
boxShadow?: string;
|
||||
buttonVariant: ButtonVariant;
|
||||
|
|
@ -850,6 +874,7 @@ export interface ButtonGroupWidgetProps extends WidgetProps {
|
|||
index: number;
|
||||
isVisible?: boolean;
|
||||
isDisabled?: boolean;
|
||||
disabledWhenInvalid?: boolean;
|
||||
label?: string;
|
||||
buttonType?: string;
|
||||
buttonColor?: string;
|
||||
|
|
@ -865,6 +890,7 @@ export interface ButtonGroupWidgetProps extends WidgetProps {
|
|||
index: number;
|
||||
isVisible?: boolean;
|
||||
isDisabled?: boolean;
|
||||
disabledWhenInvalid?: boolean;
|
||||
label?: string;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user