-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(DateTimeControl): add control, tests and stories
- Loading branch information
Showing
7 changed files
with
313 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { test, expect } from "vitest" | ||
import { screen, waitFor } from "@testing-library/react" | ||
import { userEvent } from "@testing-library/user-event" | ||
|
||
import { render } from "../common/test-render" | ||
import { dateTimeSchema } from "../testSchemas/dateTimeSchema" | ||
|
||
const EXAMPLE_DATESTRING = "2021-08-09 12:34:56" | ||
const USER_DATESTRING = EXAMPLE_DATESTRING.replace(" ", "") | ||
const TITLE = dateTimeSchema.properties.dateTime.title | ||
|
||
test("renders the date that the user selects", async () => { | ||
render({ | ||
schema: dateTimeSchema, | ||
}) | ||
const input = await screen.findByLabelText(TITLE) | ||
await userEvent.type(input, USER_DATESTRING) | ||
|
||
await waitFor(() => expect(input).toHaveValue(EXAMPLE_DATESTRING)) | ||
}) | ||
|
||
test("renders default date when present", async () => { | ||
render({ | ||
schema: { | ||
...dateTimeSchema, | ||
properties: { | ||
dateTime: { | ||
...dateTimeSchema.properties.dateTime, | ||
default: EXAMPLE_DATESTRING, | ||
}, | ||
}, | ||
}, | ||
}) | ||
const input = await screen.findByLabelText(TITLE) | ||
expect(input).toHaveValue(EXAMPLE_DATESTRING) | ||
}) | ||
|
||
test("updates jsonforms data as expected", async () => { | ||
let data: Record<string, unknown> = {} | ||
render({ | ||
schema: dateTimeSchema, | ||
data, | ||
onChange: (result) => { | ||
data = result.data as Record<string, unknown> | ||
}, | ||
}) | ||
const input = await screen.findByLabelText(TITLE) | ||
await userEvent.type(input, USER_DATESTRING) | ||
await userEvent.click(screen.getByText("Submit")) | ||
await waitFor(() => { | ||
expect(data).toEqual({ | ||
dateTime: EXAMPLE_DATESTRING, | ||
}) | ||
}) | ||
}) | ||
|
||
test("renders required message if no value and interaction", async () => { | ||
render({ | ||
schema: { | ||
...dateTimeSchema, | ||
required: ["dateTime"], | ||
}, | ||
}) | ||
const input = await screen.findByLabelText(TITLE) | ||
await userEvent.clear(input) | ||
await userEvent.tab() | ||
await screen.findByText(`${TITLE} is required`) | ||
}) | ||
|
||
test(" does not show required message if not requried", async () => { | ||
render({ | ||
schema: dateTimeSchema, | ||
}) | ||
const input = await screen.findByLabelText(TITLE) | ||
await userEvent.clear(input) | ||
await userEvent.tab() | ||
await waitFor(() => { | ||
expect(screen.queryByText(`${TITLE} is required`)).toBeNull() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { memo } from "react" | ||
import type { ControlProps as JSFControlProps } from "@jsonforms/core" | ||
import { withJsonFormsControlProps } from "@jsonforms/react" | ||
import { DatePicker, type DatePickerProps, Form } from "antd" | ||
import type { Rule } from "antd/es/form" | ||
import dayjs from "dayjs" | ||
|
||
import { | ||
ControlUISchema, | ||
DateTimeControlOptions, | ||
isDateTimeControlOptions, | ||
} from "../ui-schema" | ||
|
||
type ControlProps = Omit<JSFControlProps, "uischema"> & { | ||
uischema: ControlUISchema<unknown> | JSFControlProps["uischema"] | ||
} | ||
// initialize once | ||
const DEFAULT_PROPS: DateTimeControlOptions = { | ||
format: { format: "YYYY-MM-DD HH:mm:ss", type: "mask" }, | ||
} as const | ||
|
||
function getProps(options: unknown): DateTimeControlOptions { | ||
if (isDateTimeControlOptions(options)) { | ||
return options | ||
} | ||
return DEFAULT_PROPS | ||
} | ||
|
||
export function DateTimeControl({ | ||
handleChange, | ||
path, | ||
label, | ||
id, | ||
required, | ||
schema, | ||
uischema, | ||
visible, | ||
}: ControlProps) { | ||
if (!visible) return null | ||
|
||
const initialValue = | ||
typeof schema.default === "string" ? dayjs(schema.default) : undefined | ||
|
||
const rules: Rule[] = [{ required, message: `${label} is required` }] | ||
|
||
const formItemProps = | ||
"formItemProps" in uischema ? uischema.formItemProps : {} | ||
|
||
const onChange: DatePickerProps["onChange"] = (_dateObj, dateString) => { | ||
handleChange(path, dateString) | ||
} | ||
|
||
const options = getProps(uischema.options) | ||
|
||
return ( | ||
<Form.Item | ||
label={label} | ||
id={id} | ||
name={path} | ||
required={required} | ||
validateTrigger={["onBlur"]} | ||
rules={rules} | ||
initialValue={initialValue} | ||
{...formItemProps} | ||
> | ||
<DatePicker | ||
format={DEFAULT_PROPS.format} | ||
onChange={onChange} | ||
{...options} | ||
/> | ||
</Form.Item> | ||
) | ||
} | ||
|
||
export const DateTimeRenderer = withJsonFormsControlProps(memo(DateTimeControl)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { Meta, StoryObj } from "@storybook/react" | ||
import { StorybookAntDJsonForm } from "../../common/StorybookAntDJsonForm" | ||
import { | ||
dateTimeSchema, | ||
dateTimeShowTimeUISchema, | ||
dateTimeUISchema, | ||
dateTimeOverrideDefaultFormatUISchema, | ||
dateTimeShowMillisecondHideNowUISchema, | ||
dateTimeDefaultValueSchema, | ||
} from "../../testSchemas/dateTimeSchema" | ||
|
||
const meta: Meta<typeof StorybookAntDJsonForm> = { | ||
title: "Control/DateTime", | ||
component: StorybookAntDJsonForm, | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeSchema, | ||
uiSchema: dateTimeUISchema, | ||
}, | ||
argTypes: {}, | ||
} | ||
|
||
export default meta | ||
|
||
type Story = StoryObj<typeof StorybookAntDJsonForm> | ||
|
||
export const RequiredDatetime: Story = { | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeSchema, | ||
uiSchema: dateTimeUISchema, | ||
}, | ||
} | ||
|
||
export const ShowTime: Story = { | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeSchema, | ||
uiSchema: dateTimeShowTimeUISchema, | ||
}, | ||
} | ||
|
||
export const ShowMillisecondHideNow: Story = { | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeSchema, | ||
uiSchema: dateTimeShowMillisecondHideNowUISchema, | ||
}, | ||
} | ||
|
||
export const OverrideDefaultFormat: Story = { | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeSchema, | ||
uiSchema: dateTimeOverrideDefaultFormatUISchema, | ||
}, | ||
} | ||
|
||
export const DefaultValue: Story = { | ||
tags: ["autodocs"], | ||
args: { | ||
jsonSchema: dateTimeDefaultValueSchema, | ||
uiSchema: dateTimeUISchema, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { JSONSchema } from "json-schema-to-ts" | ||
import { UISchema } from "../ui-schema" | ||
|
||
export const dateTimeSchema = { | ||
type: "object", | ||
properties: { | ||
dateTime: { | ||
title: "Date Time", | ||
type: "string", | ||
format: "date-time", | ||
}, | ||
}, | ||
required: ["dateTime"], | ||
} as const satisfies JSONSchema | ||
|
||
export const dateTimeDefaultValueSchema = { | ||
type: "object", | ||
properties: { | ||
dateTime: { | ||
title: "Date Time", | ||
type: "string", | ||
format: "date-time", | ||
default: "2021-08-09 12:34:56", | ||
}, | ||
}, | ||
} as const satisfies JSONSchema | ||
|
||
export const dateTimeUISchema = { | ||
type: "VerticalLayout", | ||
elements: [ | ||
{ | ||
type: "Control", | ||
scope: "#/properties/dateTime", | ||
label: "Date Time", | ||
}, | ||
], | ||
} satisfies UISchema<typeof dateTimeSchema> | ||
|
||
export const dateTimeShowTimeUISchema = { | ||
type: "VerticalLayout", | ||
elements: [ | ||
{ | ||
type: "Control", | ||
scope: "#/properties/dateTime", | ||
label: "Date Time", | ||
options: { | ||
showTime: true, | ||
}, | ||
}, | ||
], | ||
} satisfies UISchema<typeof dateTimeSchema> | ||
|
||
export const dateTimeShowMillisecondHideNowUISchema = { | ||
type: "VerticalLayout", | ||
elements: [ | ||
{ | ||
type: "Control", | ||
scope: "#/properties/dateTime", | ||
label: "Date Time", | ||
options: { | ||
showTime: true, | ||
showMillisecond: true, | ||
showNow: false, | ||
}, | ||
}, | ||
], | ||
} satisfies UISchema<typeof dateTimeSchema> | ||
|
||
export const dateTimeOverrideDefaultFormatUISchema = { | ||
type: "VerticalLayout", | ||
elements: [ | ||
{ | ||
type: "Control", | ||
scope: "#/properties/dateTime", | ||
label: "Date Time", | ||
options: { | ||
format: { | ||
format: "MM/DD", | ||
}, | ||
}, | ||
}, | ||
], | ||
} satisfies UISchema<typeof dateTimeSchema> |