Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
agHelper,
draggableWidgets,
entityExplorer,
propPane,
} from "../../../../../support/Objects/ObjectsCore";

const commonlocators = require("../../../../../locators/commonlocators.json");
const widgetsPage = require("../../../../../locators/Widgets.json");

// this spec will have a json form with two textinput fields and one is updated to switch field
// We will check the position property by clicking on the left and right position buttons
// here only alignment changes and the fields order in the dom changes so no assertions were added

describe(
"JSON Form Widget Custom Field",
{ tags: ["@tag.Widget", "@tag.JSONForm"] },
() => {
const schema = {
name: "John",
education: "1",
};

it("verifies the label position and alignment", () => {
entityExplorer.DragDropWidgetNVerify(draggableWidgets.JSONFORM, 300, 100);
propPane.EnterJSContext(
"sourcedata",
JSON.stringify(schema),
true,
false,
);
propPane.ChangeJsonFormFieldType("Education", "Switch");
agHelper.AssertClassExists(
widgetsPage.switchlabel,
widgetsPage.switchAlignRight,
);
agHelper
.GetNClick(commonlocators.optionposition)
.last()
.click({ force: true });
agHelper.GetNClick(widgetsPage.rightAlign).first().click({ force: true });
agHelper.AssertClassExists(
widgetsPage.switchlabel,
widgetsPage.switchAlignLeft,
);
agHelper
.GetNClick(commonlocators.optionpositionL)
.last()
.click({ force: true });
agHelper.AssertClassExists(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Harshithazemoso Do we need only class assert here? Just want to clarify this case is need from cypress side or unit testing can also help here.

widgetsPage.switchlabel,
widgetsPage.switchAlignRight,
);
propPane.NavigateBackToPropertyPane();
});
},
);
3 changes: 3 additions & 0 deletions app/client/cypress/locators/Widgets.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@
"codeScannerNewScanButton": "//*[text()='Scan Code']/parent::button",
"codeScannerClose": ".code-scanner-close",
"codeScannerModal": ".code-scanner-content",
"switchlabel": "label.bp3-switch",
"switchAlignRight": "bp3-align-right",
"switchAlignLeft": "bp3-align-left",
"showResult": ".t--property-control-showresult input[type='checkbox']",
"infiniteLoading": ".t--property-control-infiniteloading input[type='checkbox']",
"counterclockwise": ".t--property-control-counterclockwise input[type='checkbox']",
Expand Down
6 changes: 6 additions & 0 deletions app/client/packages/dsl/src/migrate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import { migrateDefaultValuesForCustomEChart } from "./migrations/085-migrate-de
import { migrateTableServerSideFiltering } from "./migrations/086-migrate-table-server-side-filtering";
import { migrateChartwidgetCustomEchartConfig } from "./migrations/087-migrate-chart-widget-customechartdata";
import { migrateCustomWidgetDynamicHeight } from "./migrations/088-migrate-custom-widget-dynamic-height";
import { migrateJsonFormWidgetLabelPositonAndAlignment } from "./migrations/089-migrate-jsonformwidget-labelposition-and-alignment";
import type { DSLWidget } from "./types";

export const LATEST_DSL_VERSION = 89;
Expand Down Expand Up @@ -592,6 +593,11 @@ const migrateVersionedDSL = (currentDSL: DSLWidget, newPage = false) => {

if (currentDSL.version === 88) {
currentDSL = migrateCustomWidgetDynamicHeight(currentDSL);
currentDSL.version = 89;
}

if (currentDSL.version === 89) {
currentDSL = migrateJsonFormWidgetLabelPositonAndAlignment(currentDSL);
currentDSL.version = LATEST_DSL_VERSION;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";

export const migrateJsonFormWidgetLabelPositonAndAlignment = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type == "JSON_FORM_WIDGET") {
const jsonFormWidgetProps = widget;
Object.keys(jsonFormWidgetProps.schema).forEach((key) => {
const field = jsonFormWidgetProps.schema[key];
if (field.children) {
Object.keys(field.children).forEach((childKey) => {
const childField = field.children[childKey];

if (
childField.fieldType === "Switch" &&
childField.alignWidget === "RIGHT"
) {
childField.alignWidget = "LEFT";
}

if (
childField.fieldType === "Checkbox" &&
childField.alignWidget === "LEFT"
) {
field.children[childKey] = {
...childField,
labelPosition: "Right",
};
}
if (
childField.fieldType === "Checkbox" &&
childField.alignWidget === "RIGHT"
) {
childField.alignWidget = "LEFT";
field.children[childKey] = {
...childField,
labelPosition: "Left",
};
}
});
}
});
}
});
};
2 changes: 2 additions & 0 deletions app/client/src/widgets/JSONFormWidget/component/Field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function Field<TValue>({
inlineLabel = false,
isRequiredField,
label,
labelPosition,
labelStyle,
labelTextColor,
labelTextSize,
Expand Down Expand Up @@ -81,6 +82,7 @@ function Field<TValue>({
direction={direction}
isRequiredField={isRequiredField}
label={label}
labelPosition={labelPosition}
labelStyle={labelStyle}
labelTextColor={labelTextColor}
labelTextSize={labelTextSize}
Expand Down
115 changes: 88 additions & 27 deletions app/client/src/widgets/JSONFormWidget/component/FieldLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { Colors } from "constants/Colors";
import { IconWrapper } from "constants/IconConstants";
import { FontStyleTypes } from "constants/WidgetConstants";
import { THEMEING_TEXT_SIZES } from "constants/ThemeConstants";
import type { AlignWidget } from "WidgetProvider/constants";
import { AlignWidgetTypes, type AlignWidget } from "WidgetProvider/constants";
import { importSvg } from "design-system-old";
import { LabelPosition } from "components/constants";

const HelpIcon = importSvg(async () => import("assets/icons/control/help.svg"));

Expand Down Expand Up @@ -36,11 +37,14 @@ export type FieldLabelProps = PropsWithChildren<
label: string;
tooltip?: string;
alignField?: AlignField;
labelPosition?: LabelPosition;
}
>;

interface StyledLabelTextWrapperProps {
direction: FieldLabelProps["direction"];
labelPosition?: LabelPosition;
alignField?: AlignWidget;
}

interface StyledLabelProps {
Expand Down Expand Up @@ -75,6 +79,26 @@ const StyledLabelTextWrapper = styled.div<StyledLabelTextWrapperProps>`
}
`;

const InlineStyledLabelTextWrapper = styled.div<StyledLabelTextWrapperProps>`
align-items: center;
display: flex;
margin-bottom: ${({ direction }) =>
direction === "row" ? 0 : LABEL_TEXT_WRAPPER_MARGIN_BOTTOM}px;

& .${TOOLTIP_CLASSNAME} {
line-height: 0;
}
${({ alignField, labelPosition }) =>
labelPosition === LabelPosition.Left &&
alignField === AlignWidgetTypes.LEFT &&
"width: 100%;"}
${({ alignField, labelPosition }) =>
alignField === AlignWidgetTypes.RIGHT &&
(labelPosition === LabelPosition.Right ||
labelPosition === LabelPosition.Left) &&
"margin-left: auto;"}
`;

const StyledRequiredMarker = styled.div`
color: ${Colors.CRIMSON};
margin-right: ${DEFAULT_GAP}px;
Expand Down Expand Up @@ -116,6 +140,7 @@ function FieldLabel({
direction = "column",
isRequiredField = false,
label,
labelPosition = LabelPosition.Left,
labelStyle,
labelTextColor = "",
labelTextSize,
Expand All @@ -136,35 +161,71 @@ function FieldLabel({
}, [labelStyle, labelTextColor, labelTextSize]);

/**
* If field and label are to be displayed horizontally then we consider the alignField
* If field and label are to be displayed horizontally then we consider based on the labelposition
* prop else we always want to have label then field in case of vertical alignment (direction === "column")
*/
const align = direction === "row" ? alignField : "RIGHT";

return (
<StyledLabel direction={direction}>
{align === "LEFT" && children}
<StyledLabelTextWrapper direction={direction}>
<StyledLabelText isRequiredField={isRequiredField} {...labelStyleProps}>
{label}
</StyledLabelText>
{isRequiredField && <StyledRequiredMarker>*</StyledRequiredMarker>}
{tooltip && (
<StyledTooltip
className={TOOLTIP_CLASSNAME}
content={tooltip}
hoverOpenDelay={200}
position="top"

if (direction !== "row") {
return (
<StyledLabel direction={direction}>
<StyledLabelTextWrapper direction={direction}>
<StyledLabelText
isRequiredField={isRequiredField}
{...labelStyleProps}
>
{label}
</StyledLabelText>
{isRequiredField && <StyledRequiredMarker>*</StyledRequiredMarker>}
{tooltip && (
<StyledTooltip
className={TOOLTIP_CLASSNAME}
content={tooltip}
hoverOpenDelay={200}
position="top"
>
<ToolTipIcon color={Colors.SILVER_CHALICE} height={14} width={14}>
<HelpIcon className="t--input-widget-tooltip" />
</ToolTipIcon>
</StyledTooltip>
)}
</StyledLabelTextWrapper>
{children}
</StyledLabel>
);
} else {
return (
<StyledLabel direction={direction}>
{labelPosition === LabelPosition.Right && children}
<InlineStyledLabelTextWrapper
alignField={alignField}
data-testid="inlinelabel"
direction={direction}
labelPosition={labelPosition}
>
<StyledLabelText
isRequiredField={isRequiredField}
{...labelStyleProps}
>
<ToolTipIcon color={Colors.SILVER_CHALICE} height={14} width={14}>
<HelpIcon className="t--input-widget-tooltip" />
</ToolTipIcon>
</StyledTooltip>
)}
</StyledLabelTextWrapper>
{align === "RIGHT" && children}
</StyledLabel>
);
{label}
</StyledLabelText>
{isRequiredField && <StyledRequiredMarker>*</StyledRequiredMarker>}
{tooltip && (
<StyledTooltip
className={TOOLTIP_CLASSNAME}
content={tooltip}
hoverOpenDelay={200}
position="top"
>
<ToolTipIcon color={Colors.SILVER_CHALICE} height={14} width={14}>
<HelpIcon className="t--input-widget-tooltip" />
</ToolTipIcon>
</StyledTooltip>
)}
</InlineStyledLabelTextWrapper>
{labelPosition === LabelPosition.Left && children}
</StyledLabel>
);
}
}

export default FieldLabel;
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type CheckboxComponentProps = FieldComponentBaseProps &
accentColor?: string;
borderRadius?: string;
boxShadow?: string;
labelPosition: LabelPosition;
};

type CheckboxFieldProps = BaseFieldComponentProps<CheckboxComponentProps>;
Expand All @@ -45,6 +46,7 @@ const COMPONENT_DEFAULT_VALUES: CheckboxComponentProps = {
labelTextSize: BASE_LABEL_TEXT_SIZE,
isVisible: true,
label: "",
labelPosition: LabelPosition.Left,
};

const isValid = (
Expand Down Expand Up @@ -114,7 +116,7 @@ function CheckboxField({
isRequired={schemaItem.isRequired}
isValid={isDirty ? isValueValid : true}
label=""
labelPosition={LabelPosition.Left}
labelPosition={schemaItem.labelPosition}
noContainerPadding
onCheckChange={onCheckChange}
widgetId=""
Expand All @@ -133,6 +135,7 @@ function CheckboxField({
inlineLabel
isRequiredField={schemaItem.isRequired}
label={schemaItem.label}
labelPosition={schemaItem.labelPosition}
labelStyle={schemaItem.labelStyle}
labelTextColor={schemaItem.labelTextColor}
labelTextSize={schemaItem.labelTextSize}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type SwitchComponentOwnProps = FieldComponentBaseProps &
alignWidget: AlignWidget;
accentColor?: string;
onChange?: string;
labelPosition: LabelPosition;
};

type SwitchFieldProps = BaseFieldComponentProps<SwitchComponentOwnProps>;
Expand All @@ -36,6 +37,7 @@ const COMPONENT_DEFAULT_VALUES: SwitchComponentOwnProps = {
isVisible: true,
labelTextSize: BASE_LABEL_TEXT_SIZE,
label: "",
labelPosition: LabelPosition.Left,
};

const isValid = (value: boolean, schemaItem: SwitchFieldProps["schemaItem"]) =>
Expand Down Expand Up @@ -99,7 +101,7 @@ function SwitchField({
isLoading={false}
isSwitchedOn={value ?? false}
label=""
labelPosition={LabelPosition.Left}
labelPosition={schemaItem.labelPosition}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assignment within the expression should be avoided as it can lead to confusion and potential bugs. Consider restructuring this part of the code to separate the assignment from the expression.

- labelPosition={schemaItem.labelPosition}
+ const labelPos = schemaItem.labelPosition;
+ labelPosition={labelPos}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
labelPosition={schemaItem.labelPosition}
const labelPos = schemaItem.labelPosition;
labelPosition={labelPos}

onChange={onSwitchChange}
widgetId=""
/>
Expand All @@ -109,18 +111,21 @@ function SwitchField({
schemaItem.accentColor,
schemaItem.isDisabled,
onSwitchChange,
schemaItem.labelPosition,
value,
],
);

return (
<Field
accessor={schemaItem.accessor}
alignField={schemaItem.alignWidget}
defaultValue={passedDefaultValue ?? schemaItem.defaultValue}
fieldClassName={fieldClassName}
inlineLabel
isRequiredField={schemaItem.isRequired}
label={schemaItem.label}
labelPosition={schemaItem.labelPosition}
labelStyle={schemaItem.labelStyle}
labelTextColor={schemaItem.labelTextColor}
labelTextSize={schemaItem.labelTextSize}
Expand Down
Loading