Skip to content

Commit 2e64134

Browse files
authored
RI-7212: replace EuiFormFieldset with FormFieldset (#4739)
* RI-7212: replace EuiFormFieldset with FormFieldset * update display legend logic * add FormFieldset unit tests
1 parent 65736aa commit 2e64134

File tree

7 files changed

+264
-15
lines changed

7 files changed

+264
-15
lines changed
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/* eslint-disable jsx-a11y/label-has-associated-control */
2+
import React from 'react'
3+
import { render, screen } from 'uiSrc/utils/test-utils'
4+
import { FormFieldset, FormFieldsetProps } from './FormFieldset'
5+
6+
const defaultProps: FormFieldsetProps = {
7+
children: <div data-testid="fieldset-content">Test content</div>,
8+
}
9+
10+
describe('FormFieldset', () => {
11+
it('should render', () => {
12+
expect(render(<FormFieldset {...defaultProps} />)).toBeTruthy()
13+
})
14+
15+
it('should render children', () => {
16+
render(<FormFieldset {...defaultProps} />)
17+
18+
expect(screen.getByTestId('fieldset-content')).toBeInTheDocument()
19+
expect(screen.getByText('Test content')).toBeInTheDocument()
20+
})
21+
22+
it('should render as fieldset element', () => {
23+
render(<FormFieldset {...defaultProps} />)
24+
25+
const fieldset = screen.getByRole('group')
26+
expect(fieldset.tagName).toBe('FIELDSET')
27+
})
28+
29+
it('should render without legend when legend prop is not provided', () => {
30+
render(<FormFieldset {...defaultProps} />)
31+
32+
expect(screen.queryByRole('legend')).not.toBeInTheDocument()
33+
})
34+
35+
it('should render legend when legend prop is provided', () => {
36+
render(
37+
<FormFieldset {...defaultProps} legend={{ children: 'Test Legend' }} />,
38+
)
39+
40+
expect(screen.getByText('Test Legend')).toBeInTheDocument()
41+
})
42+
43+
it('should render legend with custom content', () => {
44+
const legendContent = (
45+
<span data-testid="custom-legend">Custom Legend Content</span>
46+
)
47+
48+
render(
49+
<FormFieldset {...defaultProps} legend={{ children: legendContent }} />,
50+
)
51+
52+
expect(screen.getByTestId('custom-legend')).toBeInTheDocument()
53+
expect(screen.getByText('Custom Legend Content')).toBeInTheDocument()
54+
})
55+
56+
it('should not render legend when display is hidden', () => {
57+
render(
58+
<FormFieldset
59+
{...defaultProps}
60+
legend={{
61+
children: 'Hidden Legend',
62+
display: 'hidden',
63+
}}
64+
/>,
65+
)
66+
67+
expect(screen.queryByText('Hidden Legend')).not.toBeInTheDocument()
68+
})
69+
70+
it('should render legend when display is visible', () => {
71+
render(
72+
<FormFieldset
73+
{...defaultProps}
74+
legend={{
75+
children: 'Visible Legend',
76+
display: 'visible',
77+
}}
78+
/>,
79+
)
80+
81+
expect(screen.getByText('Visible Legend')).toBeInTheDocument()
82+
})
83+
84+
it('should render legend when display is not specified (defaults to visible)', () => {
85+
render(
86+
<FormFieldset
87+
{...defaultProps}
88+
legend={{ children: 'Default Legend' }}
89+
/>,
90+
)
91+
92+
expect(screen.getByText('Default Legend')).toBeInTheDocument()
93+
})
94+
95+
it('should pass through HTML attributes to fieldset element', () => {
96+
render(
97+
<FormFieldset
98+
{...defaultProps}
99+
data-testid="custom-fieldset"
100+
className="custom-class"
101+
id="custom-id"
102+
/>,
103+
)
104+
105+
const fieldset = screen.getByTestId('custom-fieldset')
106+
expect(fieldset).toHaveClass('custom-class')
107+
expect(fieldset).toHaveAttribute('id', 'custom-id')
108+
})
109+
110+
it('should pass through HTML attributes to legend element', () => {
111+
render(
112+
<FormFieldset
113+
{...defaultProps}
114+
legend={{
115+
children: 'Legend with attributes',
116+
// @ts-ignore
117+
'data-testid': 'custom-legend',
118+
className: 'legend-class',
119+
id: 'legend-id',
120+
}}
121+
/>,
122+
)
123+
124+
const legend = screen.getByTestId('custom-legend')
125+
expect(legend).toHaveClass('legend-class')
126+
expect(legend).toHaveAttribute('id', 'legend-id')
127+
})
128+
129+
it('should handle multiple children', () => {
130+
render(
131+
<FormFieldset>
132+
<div data-testid="child-1">Child 1</div>
133+
<div data-testid="child-2">Child 2</div>
134+
<input data-testid="input-field" type="text" />
135+
</FormFieldset>,
136+
)
137+
138+
expect(screen.getByTestId('child-1')).toBeInTheDocument()
139+
expect(screen.getByTestId('child-2')).toBeInTheDocument()
140+
expect(screen.getByTestId('input-field')).toBeInTheDocument()
141+
})
142+
143+
it('should handle form elements as children', () => {
144+
render(
145+
<FormFieldset legend={{ children: 'Form Fields' }}>
146+
<label htmlFor="name">Name:</label>
147+
<input id="name" type="text" data-testid="name-input" />
148+
<label htmlFor="email">Email:</label>
149+
<input id="email" type="email" data-testid="email-input" />
150+
</FormFieldset>,
151+
)
152+
153+
expect(screen.getByText('Form Fields')).toBeInTheDocument()
154+
expect(screen.getByLabelText('Name:')).toBeInTheDocument()
155+
expect(screen.getByLabelText('Email:')).toBeInTheDocument()
156+
expect(screen.getByTestId('name-input')).toBeInTheDocument()
157+
expect(screen.getByTestId('email-input')).toBeInTheDocument()
158+
})
159+
160+
it('should handle empty children', () => {
161+
render(<FormFieldset />)
162+
163+
const fieldset = screen.getByRole('group')
164+
expect(fieldset).toBeInTheDocument()
165+
expect(fieldset).toBeEmptyDOMElement()
166+
})
167+
168+
it('should handle null children', () => {
169+
render(<FormFieldset>{null}</FormFieldset>)
170+
171+
const fieldset = screen.getByRole('group')
172+
expect(fieldset).toBeInTheDocument()
173+
})
174+
175+
it('should handle undefined children', () => {
176+
render(<FormFieldset>{undefined}</FormFieldset>)
177+
178+
const fieldset = screen.getByRole('group')
179+
expect(fieldset).toBeInTheDocument()
180+
})
181+
182+
it('should handle complex legend with multiple elements', () => {
183+
const complexLegend = (
184+
<div>
185+
<strong>Important:</strong>
186+
<span> Please fill all required fields</span>
187+
</div>
188+
)
189+
190+
render(
191+
<FormFieldset {...defaultProps} legend={{ children: complexLegend }} />,
192+
)
193+
194+
expect(screen.getByText('Important:')).toBeInTheDocument()
195+
expect(
196+
screen.getByText('Please fill all required fields'),
197+
).toBeInTheDocument()
198+
})
199+
})
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* eslint-disable sonarjs/no-nested-template-literals */
2+
import { HTMLAttributes } from 'react'
3+
import styled, { css } from 'styled-components'
4+
import { Theme } from '@redis-ui/styles'
5+
6+
export type StyledFieldsetProps = HTMLAttributes<HTMLFieldSetElement>
7+
8+
export const StyledFieldset = styled.fieldset`
9+
border: none;
10+
margin: 0;
11+
padding: 0;
12+
min-width: 0;
13+
`
14+
15+
export interface StyledLegendProps extends HTMLAttributes<HTMLLegendElement> {
16+
display?: 'visible' | 'hidden'
17+
}
18+
19+
export const StyledLegend = styled.legend<StyledLegendProps>`
20+
${({ theme }: { theme: Theme } & StyledLegendProps) => css`
21+
margin-bottom: ${theme.core.space.space100};
22+
`}
23+
padding: 0;
24+
`
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react'
2+
3+
import {
4+
StyledFieldset,
5+
StyledFieldsetProps,
6+
StyledLegend,
7+
StyledLegendProps,
8+
} from './FormFieldset.styles'
9+
10+
export interface FormFieldsetProps extends StyledFieldsetProps {
11+
legend?: StyledLegendProps
12+
}
13+
14+
export const FormFieldset = ({
15+
legend,
16+
children,
17+
...props
18+
}: FormFieldsetProps) => (
19+
<StyledFieldset {...props}>
20+
{legend && legend.display !== 'hidden' && <StyledLegend {...legend} />}
21+
{children}
22+
</StyledFieldset>
23+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './FormFieldset'

redisinsight/ui/src/packages/redistimeseries-app/src/components/Chart/ChartConfigForm.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React, { useState } from 'react'
22
import {
33
EuiFieldText,
4-
EuiFormFieldset,
54
EuiButtonGroup,
65
EuiAccordion,
76
EuiButtonGroupProps,
87
} from '@elastic/eui'
98
import { SwitchInput } from 'uiSrc/components/base/inputs'
9+
import { FormFieldset } from 'uiSrc/components/base/forms/fieldset'
1010
import { AxisScale, GraphMode, ChartConfigFormProps } from './interfaces'
1111
import {
1212
X_LABEL_MAX_LENGTH,
@@ -71,24 +71,24 @@ export default function ChartConfigForm(props: ChartConfigFormProps) {
7171
{moreOptions && (
7272
<div className="more-options">
7373
<section>
74-
<EuiFormFieldset legend={{ children: 'Title' }}>
74+
<FormFieldset legend={{ children: 'Title' }}>
7575
<EuiFieldText
7676
placeholder="Title"
7777
value={value.title}
7878
onChange={(e) => onChange('title', e.target.value)}
7979
aria-label="Title"
8080
maxLength={parseInt(TITLE_MAX_LENGTH)}
8181
/>
82-
</EuiFormFieldset>
83-
<EuiFormFieldset legend={{ children: 'X axis Label' }}>
82+
</FormFieldset>
83+
<FormFieldset legend={{ children: 'X axis Label' }}>
8484
<EuiFieldText
8585
placeholder="X axis label"
8686
value={value.xlabel}
8787
onChange={(e) => onChange('xlabel', e.target.value)}
8888
aria-label="X Label"
8989
maxLength={parseInt(X_LABEL_MAX_LENGTH)}
9090
/>
91-
</EuiFormFieldset>
91+
</FormFieldset>
9292
</section>
9393
<section>
9494
<div className="right-y-axis">
@@ -151,16 +151,16 @@ export default function ChartConfigForm(props: ChartConfigFormProps) {
151151

152152
const YAxisConfigForm = ({ value, onChange, label }: any) => (
153153
<div>
154-
<EuiFormFieldset legend={{ children: `${label} Label` }}>
154+
<FormFieldset legend={{ children: `${label} Label` }}>
155155
<EuiFieldText
156156
placeholder="Label"
157157
value={value.label}
158158
onChange={(e) => onChange({ ...value, label: e.target.value })}
159159
aria-label="label"
160160
maxLength={parseInt(Y_LABEL_MAX_LENGTH)}
161161
/>
162-
</EuiFormFieldset>
163-
<EuiFormFieldset legend={{ children: `${label} Scale` }}>
162+
</FormFieldset>
163+
<FormFieldset legend={{ children: `${label} Scale` }}>
164164
<EnumSelect
165165
inputLabel="Scale"
166166
onChange={(e) =>
@@ -169,7 +169,7 @@ const YAxisConfigForm = ({ value, onChange, label }: any) => (
169169
value={value.scale}
170170
enumType={AxisScale}
171171
/>
172-
</EuiFormFieldset>
172+
</FormFieldset>
173173
</div>
174174
)
175175

redisinsight/ui/src/pages/browser/components/add-key/AddKeyCommonFields/AddKeyCommonFields.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { ChangeEvent } from 'react'
22
import { toNumber } from 'lodash'
3-
import { EuiFieldText, EuiFormFieldset } from '@elastic/eui'
3+
import { EuiFieldText } from '@elastic/eui'
44
import { MAX_TTL_NUMBER, Maybe, validateTTLNumberForAddKey } from 'uiSrc/utils'
55

66
import { FlexItem, Row } from 'uiSrc/components/base/layout/flex'
77
import { FormField } from 'uiSrc/components/base/forms/FormField'
88
import { RiSelect } from 'uiSrc/components/base/forms/select/RiSelect'
9+
import { FormFieldset } from 'uiSrc/components/base/forms/fieldset'
910
import { AddCommonFieldsFormConfig as config } from '../constants/fields-config'
1011

1112
import styles from './styles.module.scss'
@@ -48,7 +49,7 @@ const AddKeyCommonFields = (props: Props) => {
4849
<div className={styles.wrapper}>
4950
<Row className={styles.container}>
5051
<FlexItem grow>
51-
<EuiFormFieldset
52+
<FormFieldset
5253
legend={{ children: 'Select key type', display: 'hidden' }}
5354
>
5455
<FormField label="Key Type*">
@@ -63,7 +64,7 @@ const AddKeyCommonFields = (props: Props) => {
6364
data-testid="select-key-type"
6465
/>
6566
</FormField>
66-
</EuiFormFieldset>
67+
</FormFieldset>
6768
</FlexItem>
6869
<FlexItem grow>
6970
<FormField label={config.keyTTL.label}>

redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EuiFieldText, EuiFormFieldset } from '@elastic/eui'
1+
import { EuiFieldText } from '@elastic/eui'
22
import { EuiComboBoxOptionOption } from '@elastic/eui/src/components/combo_box/types'
33
import cx from 'classnames'
44
import React, { ChangeEvent, useEffect, useRef, useState } from 'react'
@@ -23,6 +23,7 @@ import {
2323
SecondaryButton,
2424
} from 'uiSrc/components/base/forms/buttons'
2525
import { AutoTag } from 'uiSrc/components/base/forms/combo-box/AutoTag'
26+
import { FormFieldset } from 'uiSrc/components/base/forms/fieldset'
2627
import { InfoIcon } from 'uiSrc/components/base/icons'
2728
import { FormField } from 'uiSrc/components/base/forms/FormField'
2829
import { HealthText, Text } from 'uiSrc/components/base/text'
@@ -225,7 +226,7 @@ const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => {
225226
</FormField>
226227
</FlexItem>
227228
<FlexItem grow>
228-
<EuiFormFieldset
229+
<FormFieldset
229230
legend={{ children: 'Select key type', display: 'hidden' }}
230231
>
231232
<FormField label="Key Type*">
@@ -241,7 +242,7 @@ const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => {
241242
data-testid="key-type"
242243
/>
243244
</FormField>
244-
</EuiFormFieldset>
245+
</FormFieldset>
245246
</FlexItem>
246247
</Row>
247248
<Row className={styles.row} style={{ maxWidth: '100%' }}>

0 commit comments

Comments
 (0)