Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -35,9 +35,9 @@ describe('CustomInput', () => {

it('forwards name, placeholder and disabled props to the input', () => {
renderInput({
name: 'email',
type: 'text',
disabled: true,
'name': 'email',
'type': 'text',
'disabled': true,
'data-testid': 'email',
})
const input = screen.getByTestId('email') as HTMLInputElement
Expand Down
4 changes: 3 additions & 1 deletion admin-ui/app/components/GluuDatePicker/GluuDatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const GluuDatePicker = memo(
onAccept={props.onAccept}
minDate={props.minDate}
maxDate={props.maxDate}
disabled={props.disabled ?? false}
slotProps={effectiveSlotProps}
sx={datePickerSx}
{...(props.showTime ? { closeOnSelect: false } : {})}
Expand Down Expand Up @@ -123,7 +124,8 @@ const GluuDatePicker = memo(
prev.textColor === next.textColor &&
prev.backgroundColor === next.backgroundColor &&
prev.minDate === next.minDate &&
prev.maxDate === next.maxDate
prev.maxDate === next.maxDate &&
prev.disabled === next.disabled
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,24 @@ describe('GluuDatePicker (single mode)', () => {

it('displays the passed value formatted with the default US format (MM/DD/YYYY)', () => {
const { container } = render(
<GluuDatePicker mode="single" label="When" value={createDate('2024-01-15')} onChange={jest.fn()} />,
<GluuDatePicker
mode="single"
label="When"
value={createDate('2024-01-15')}
onChange={jest.fn()}
/>,
{ wrapper: Wrapper },
)
expect(getInputs(container)[0].value).toBe('01/15/2024')
})

it('renders an empty field when no value is provided', () => {
const { container } = render(<GluuDatePicker mode="single" label="When" onChange={jest.fn()} />, {
wrapper: Wrapper,
})
const { container } = render(
<GluuDatePicker mode="single" label="When" onChange={jest.fn()} />,
{
wrapper: Wrapper,
},
)
expect(getInputs(container)[0].value).toBe('')
})

Expand All @@ -75,7 +83,12 @@ describe('GluuDatePicker (single mode)', () => {
it('fires onChange when a day is selected from the calendar', () => {
const onChange = jest.fn()
render(
<GluuDatePicker mode="single" label="When" value={createDate('2024-01-15')} onChange={onChange} />,
<GluuDatePicker
mode="single"
label="When"
value={createDate('2024-01-15')}
onChange={onChange}
/>,
{ wrapper: Wrapper },
)
openCalendarAndPickDay('20')
Expand Down
1 change: 1 addition & 0 deletions admin-ui/app/components/GluuDatePicker/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type GluuDatePickerSingleProps = GluuDatePickerBase & {
minDate?: Dayjs
maxDate?: Dayjs
labelShrink?: boolean
disabled?: boolean
}

export type GluuDatePickerRangeProps = GluuDatePickerBase & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,9 @@ describe('GluuDropdown', () => {

it('fires onOpenChange when toggling open and closed', () => {
const onOpenChange = jest.fn()
render(
<GluuDropdown trigger="Choose fruit" options={options} onOpenChange={onOpenChange} />,
{ wrapper: Wrapper },
)
render(<GluuDropdown trigger="Choose fruit" options={options} onOpenChange={onOpenChange} />, {
wrapper: Wrapper,
})

fireEvent.click(getTrigger())
expect(onOpenChange).toHaveBeenLastCalledWith(true)
Expand Down Expand Up @@ -169,10 +168,9 @@ describe('GluuDropdown', () => {
})

it('renders the empty message when there are no options', () => {
render(
<GluuDropdown trigger="Choose fruit" options={[]} emptyMessage="Nothing available" />,
{ wrapper: Wrapper },
)
render(<GluuDropdown trigger="Choose fruit" options={[]} emptyMessage="Nothing available" />, {
wrapper: Wrapper,
})

fireEvent.click(getTrigger())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ const renderList = (overrides: Partial<GluuDynamicListProps> = {}) =>
const getRowInputs = (): HTMLInputElement[] =>
screen
.queryAllByRole('textbox')
.filter((el): el is HTMLInputElement =>
el.classList.contains('gluu-dynamic-list-input'),
)
.filter((el): el is HTMLInputElement => el.classList.contains('gluu-dynamic-list-input'))

describe('GluuDynamicList', () => {
it('renders the title and add button when there are no items', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ describe('GluuSearchToolbar', () => {
it('renders the primary action and calls its onClick', () => {
const onClick = jest.fn()
render(
<GluuSearchToolbar
searchPlaceholder="Find"
primaryAction={{ label: 'Apply', onClick }}
/>,
<GluuSearchToolbar searchPlaceholder="Find" primaryAction={{ label: 'Apply', onClick }} />,
{ wrapper: Wrapper },
)
const applyButton = screen.getByRole('button', { name: /Apply/i })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ const Providers = ({ children, pageConfig }: ProvidersProps) => (
const renderSidebar = (
children: React.ReactNode,
pageConfig: PageConfig = makePageConfig({ animationsDisabled: true }),
) => render(<Providers pageConfig={pageConfig}><Sidebar>{children}</Sidebar></Providers>)
) =>
render(
<Providers pageConfig={pageConfig}>
<Sidebar>{children}</Sidebar>
</Providers>,
)

const getSidebar = (): HTMLElement => {
const el = document.querySelector<HTMLElement>('.sidebar.custom-sidebar-container')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ const renderEditor = (props: GluuInputEditorProps<FormikValues>) =>
</AppTestWrapper>,
)

const getEditor = (): HTMLTextAreaElement =>
screen.getByTestId('ace') as HTMLTextAreaElement
const getEditor = (): HTMLTextAreaElement => screen.getByTestId('ace') as HTMLTextAreaElement

describe('GluuInputEditor', () => {
it('renders the label and the editor', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ describe('GluuThemeFormFooter', () => {
})

it('disables both Apply and Cancel when isLoading is true', () => {
renderFooter(
baseProps({ showBack: true, showApply: true, showCancel: true, isLoading: true }),
)
renderFooter(baseProps({ showBack: true, showApply: true, showCancel: true, isLoading: true }))
expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled()
expect(screen.getByRole('button', { name: 'Cancel' })).toBeDisabled()
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,32 @@ describe('SsaForm', () => {
})

describe('expiration date', () => {
it('does not render the date picker until is_expirable is enabled', () => {
it('renders the expiration date field with a title', () => {
render(<SsaForm {...defaultProps} />, { wrapper: Wrapper })
expect(screen.getByText('Expiration Date')).toBeInTheDocument()
})

it('disables the date picker until is_expirable is enabled', async () => {
render(<SsaForm {...defaultProps} />, { wrapper: Wrapper })
expect(screen.getByRole('button', { name: /choose date/i })).toBeDisabled()

const expirableToggle = document.querySelector(
'input#is_expirable[type="checkbox"]',
) as HTMLInputElement
expect(expirableToggle.checked).toBe(false)
fireEvent.click(expirableToggle)
await waitFor(() => {
expect(screen.getByRole('button', { name: /choose date/i })).toBeEnabled()
})
})

it('shows the date picker after toggling is_expirable on', async () => {
it('surfaces a validation message when is_expirable is on without a date', async () => {
render(<SsaForm {...defaultProps} />, { wrapper: Wrapper })
const expirableToggle = document.querySelector(
'input#is_expirable[type="checkbox"]',
) as HTMLInputElement
fireEvent.click(expirableToggle)
await waitFor(() => {
expect(expirableToggle.checked).toBe(true)
expect(screen.getByText(/Expiration date is required/i)).toBeInTheDocument()
})
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { useFormik, type FormikProps } from 'formik'
import type { JsonValue } from 'Routes/Apps/Gluu/types/common'
import { Form, Col, FormGroup } from 'Components'
import { GluuDatePicker } from '@/components/GluuDatePicker'
import { createDate, DATE_FORMATS } from '@/utils/dayjsUtils'
import { addDate, createDate, DATE_FORMATS } from '@/utils/dayjsUtils'
import type { Dayjs } from '@/utils/dayjsUtils'
import GluuInputRow from 'Routes/Apps/Gluu/GluuInputRow'
import GluuToggleRow from 'Routes/Apps/Gluu/GluuToggleRow'
import GluuRemovableInputRow from 'Routes/Apps/Gluu/GluuRemovableInputRow'
import GluuLabel from 'Routes/Apps/Gluu/GluuLabel'
import GluuText from 'Routes/Apps/Gluu/GluuText'
import GluuAutocomplete from 'Routes/Apps/Gluu/GluuAutocomplete'
import GluuThemeFormFooter from 'Routes/Apps/Gluu/GluuThemeFormFooter'
import GluuCommitDialog from 'Routes/Apps/Gluu/GluuCommitDialog'
import { SSA } from 'Utils/ApiResources'
import { CEDARLING_CONFIG_SPACING } from '@/constants'
import { useTheme } from '@/context/theme/themeContext'
import getThemeColor from '@/context/theme/config'
import { DEFAULT_THEME, THEME_DARK } from '@/context/theme/constants'
Expand Down Expand Up @@ -168,6 +170,8 @@ const SsaForm: React.FC<SsaFormProps> = ({
[isSubmitting, formik.dirty, formik.isValid, modifiedFields, selectedAttributes],
)

const minExpirationDate = useMemo(() => addDate(createDate(), 1, 'day'), [])

const enterHerePlaceholder = useMemo(() => t('placeholders.enter_here'), [t])

const softwareRolesPlaceholder = useMemo(
Expand All @@ -192,6 +196,7 @@ const SsaForm: React.FC<SsaFormProps> = ({
const handleExpirationDateChange = useCallback(
(date: Dayjs | null) => {
formik.setFieldValue('expirationDate', date)
formik.setFieldTouched('expirationDate', true, false)
},
[formik],
)
Expand Down Expand Up @@ -310,17 +315,30 @@ const SsaForm: React.FC<SsaFormProps> = ({
doc_category={SSA}
/>

<div className={classes.toggleCell}>
<GluuToggleRow
name="one_time_use"
formik={formik}
label="fields.one_time_use"
lsize={12}
rsize={12}
value={formik.values.one_time_use}
<div className={classes.datePickerCell}>
<GluuLabel
label="fields.expiration_date"
size={12}
isDark={isDark}
doc_category={SSA}
doc_entry="expiration"
/>
<GluuDatePicker
format={DATE_FORMATS.DATE_PICKER_DISPLAY_US}
label=""
value={formik.values.expirationDate as Dayjs | null}
onChange={handleExpirationDateChange}
minDate={minExpirationDate}
disabled={!formik.values.is_expirable}
textColor={themeColors.fontColor}
backgroundColor={themeColors.background}
inputHeight={CEDARLING_CONFIG_SPACING.INPUT_HEIGHT}
/>
{validationState.expirationDateError && (
<GluuText disableThemeColor className={classes.datePickerError}>
{validationState.expirationDateErrorMessage}
</GluuText>
)}
</div>

<div className={classes.toggleCell}>
Expand Down Expand Up @@ -349,19 +367,18 @@ const SsaForm: React.FC<SsaFormProps> = ({
/>
</div>

{formik.values.is_expirable && (
<div className={classes.datePickerCell}>
<GluuDatePicker
format={DATE_FORMATS.DATE_PICKER_DISPLAY_US}
value={formik.values.expirationDate as Dayjs | null}
onChange={handleExpirationDateChange}
minDate={createDate()}
textColor={themeColors.fontColor}
backgroundColor={themeColors.background}
inputHeight={50}
/>
</div>
)}
<div className={classes.toggleCell}>
<GluuToggleRow
name="one_time_use"
formik={formik}
label="fields.one_time_use"
lsize={12}
rsize={12}
value={formik.values.one_time_use}
isDark={isDark}
doc_category={SSA}
/>
</div>
</div>

<div className={classes.dynamicClaimsWrap}>
Expand All @@ -374,10 +391,6 @@ const SsaForm: React.FC<SsaFormProps> = ({
value={formik.values[attribute] as string}
modifiedFields={modifiedFields}
setModifiedFields={setModifiedFields}
// GluuRemovableInputRow constrains FormikProps to Record<string, JsonValue>;
// SsaFormValues includes a Dayjs `expirationDate` (not JsonValue), but this row
// only ever reads the dynamic string-valued custom attribute fields, so the cast
// is safe at runtime.
formik={formik as object as FormikProps<Record<string, JsonValue>>}
lsize={12}
handler={() => handleAttributeRemove(attribute)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,47 @@ export const useStyles = makeStyles<SsaFormStylesParams>()((_, { isDark, themeCo
margin: '1px 2px',
},
datePickerCell: {
'position': 'relative' as const,
'minWidth': 0,
'boxSizing': 'border-box' as const,
'display': 'flex',
'alignItems': 'center',
'flexDirection': 'column',
'alignItems': 'stretch',
'& .MuiInputBase-root': {
backgroundColor: `${inputBg} !important`,
},
'& .MuiPickersInputBase-root.Mui-disabled': {
opacity: OPACITY.DISABLED,
cursor: 'not-allowed',
},
'& .MuiInputLabel-root, & .MuiPickersInputBase-root .MuiInputLabel-root': {
display: 'none',
},
'& .MuiOutlinedInput-notchedOutline legend, & .MuiPickersOutlinedInput-notchedOutline legend':
{
display: 'none',
width: 0,
maxWidth: 0,
},
'& label': {
flex: '0 0 auto',
display: 'block',
width: '100%',
maxWidth: '100%',
paddingTop: 0,
paddingBottom: 0,
paddingLeft: 0,
paddingRight: 0,
marginBottom: '4px !important',
},
},
datePickerError: {
position: 'absolute' as const,
top: '100%',
left: 0,
marginTop: 2,
color: themeColors.errorColor,
fontSize: fontSizes.sm,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
claimsPanelWrap: {
flex: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const getSsaValidationSchema = () =>
return false
}

return dateValue.isAfter(dayjs())
return dateValue.isAfter(dayjs(), 'day')
},
),
}) as Yup.ObjectSchema<SsaFormValues>
Loading
Loading