diff --git a/packages/react/.changeset/clean-flies-provide.md b/packages/react/.changeset/clean-flies-provide.md new file mode 100644 index 000000000..621266944 --- /dev/null +++ b/packages/react/.changeset/clean-flies-provide.md @@ -0,0 +1,5 @@ +--- +"@gadgetinc/react": patch +--- + +Updated `AutoInput` to accept an optional `label?: string` input diff --git a/packages/react/cypress/component/auto/form/AutoFormInputLabels.cy.tsx b/packages/react/cypress/component/auto/form/AutoFormInputLabels.cy.tsx new file mode 100644 index 000000000..73c081152 --- /dev/null +++ b/packages/react/cypress/component/auto/form/AutoFormInputLabels.cy.tsx @@ -0,0 +1,87 @@ +/* eslint-disable jest/valid-expect */ +import React from "react"; +import { MUIAutoInput } from "../../../../src/auto/mui/inputs/MUIAutoInput.js"; +import { PolarisAutoInput } from "../../../../src/auto/polaris/inputs/PolarisAutoInput.js"; +import { humanizeCamelCase } from "../../../../src/utils.js"; +import { api } from "../../../support/api.js"; +import { describeForEachAutoAdapter } from "../../../support/auto.js"; + +const AutoInput = (props: { suiteName: string; field: string; label?: string }) => { + if (props.suiteName === "Polaris") { + return ; + } + + if (props.suiteName === "MUI") { + return ; + } + + throw new Error("Invalid suite name"); +}; + +const widgetFieldApiIds = [ + "name", + "inventoryCount", + "gizmos", + "anything", + "description", + "category", + "startsAt", + "isChecked", + "metafields", + "roles", + "secretKey", + "section", + "mustBeLongString", +]; + +describeForEachAutoAdapter("AutoForm - input labels", ({ name, adapter: { AutoForm }, wrapper }) => { + beforeEach(() => { + cy.viewport("macbook-13"); + }); + + it("renders AutoInputs with custom labels", () => { + cy.mountWithWrapper( + + {widgetFieldApiIds.map((fieldApiId) => ( + + ))} + , + wrapper + ); + + for (const fieldApiId of widgetFieldApiIds) { + cy.contains(fieldApiId + "_CustomLabel").should("exist"); + } + }); + + it("renders AutoInputs with default labels", () => { + cy.mountWithWrapper( + + {widgetFieldApiIds.map((fieldApiId) => ( + + ))} + , + wrapper + ); + + for (const fieldName of widgetFieldNames) { + cy.contains(humanizeCamelCase(fieldName)).should("exist"); + } + }); +}); + +const widgetFieldNames = [ + "Name", + "Inventory count", + "Gizmos", + "Anything", + "Description", + "Category", + "Starts at", + "Is checked", + "Metafields", + "Roles", + "Secret key", + "Section", + "Must be long string", +]; diff --git a/packages/react/src/auto/interfaces/AutoRelationshipInputProps.tsx b/packages/react/src/auto/interfaces/AutoRelationshipInputProps.tsx index 491475525..24349b97a 100644 --- a/packages/react/src/auto/interfaces/AutoRelationshipInputProps.tsx +++ b/packages/react/src/auto/interfaces/AutoRelationshipInputProps.tsx @@ -5,6 +5,7 @@ export interface AutoRelationshipInputProps { field: string; control?: Control; optionLabel?: OptionLabel; + label?: string; } /** diff --git a/packages/react/src/auto/mui/MUIAutoForm.tsx b/packages/react/src/auto/mui/MUIAutoForm.tsx index 37833b847..b32269688 100644 --- a/packages/react/src/auto/mui/MUIAutoForm.tsx +++ b/packages/react/src/auto/mui/MUIAutoForm.tsx @@ -81,12 +81,19 @@ export const MUIAutoFormComponent = < return props.successContent; } + if (fetchingMetadata) { + return ( + + + + ); + } + const formContent = props.children ?? ( <> {formTitle && {formTitle}} {!props.onSuccess && } {!props.onFailure && } - {fetchingMetadata && } {!metadataError && ( <> {fields.map(({ metadata }) => ( diff --git a/packages/react/src/auto/mui/inputs/MUIAutoBooleanInput.tsx b/packages/react/src/auto/mui/inputs/MUIAutoBooleanInput.tsx index 9563d5882..d4eb1259f 100644 --- a/packages/react/src/auto/mui/inputs/MUIAutoBooleanInput.tsx +++ b/packages/react/src/auto/mui/inputs/MUIAutoBooleanInput.tsx @@ -5,8 +5,8 @@ import { useController, type Control } from "react-hook-form"; import { useFieldMetadata } from "../../hooks/useFieldMetadata.js"; import { MUIAutoFormControl } from "./MUIAutoFormControl.js"; -export const MUIAutoBooleanInput = (props: { field: string; control?: Control } & Partial) => { - const { field: fieldApiIdentifier, control, ...rest } = props; +export const MUIAutoBooleanInput = (props: { field: string; control?: Control; label?: string } & Partial) => { + const { field: fieldApiIdentifier, label, control, ...rest } = props; const { path } = useFieldMetadata(fieldApiIdentifier); @@ -18,7 +18,7 @@ export const MUIAutoBooleanInput = (props: { field: string; control?: Control + ); diff --git a/packages/react/src/auto/mui/inputs/MUIAutoDateTimePicker.tsx b/packages/react/src/auto/mui/inputs/MUIAutoDateTimePicker.tsx index 0fdf76cd5..cf4692925 100644 --- a/packages/react/src/auto/mui/inputs/MUIAutoDateTimePicker.tsx +++ b/packages/react/src/auto/mui/inputs/MUIAutoDateTimePicker.tsx @@ -6,7 +6,13 @@ import { zonedTimeToUtc } from "../../../dateTimeUtils.js"; import type { GadgetDateTimeConfig } from "../../../internal/gql/graphql.js"; import { useFieldMetadata } from "../../hooks/useFieldMetadata.js"; -export const MUIAutoDateTimePicker = (props: { field: string; value?: Date; onChange?: (value: Date) => void; error?: string }) => { +export const MUIAutoDateTimePicker = (props: { + field: string; + value?: Date; + onChange?: (value: Date) => void; + error?: string; + label?: string; +}) => { const localTz = Intl.DateTimeFormat().resolvedOptions().timeZone; const { path, metadata } = useFieldMetadata(props.field); const config = metadata.configuration; @@ -17,7 +23,7 @@ export const MUIAutoDateTimePicker = (props: { field: string; value?: Date; onCh return ( { props.onChange?.(zonedTimeToUtc(new Date(newValue ?? ""), localTz)); fieldProps.onChange(zonedTimeToUtc(new Date(newValue ?? ""), localTz)); diff --git a/packages/react/src/auto/mui/inputs/MUIAutoEnumInput.tsx b/packages/react/src/auto/mui/inputs/MUIAutoEnumInput.tsx index 9ad99bd17..e98e40ea5 100644 --- a/packages/react/src/auto/mui/inputs/MUIAutoEnumInput.tsx +++ b/packages/react/src/auto/mui/inputs/MUIAutoEnumInput.tsx @@ -10,7 +10,7 @@ export const MUIAutoEnumInput = < FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"] >( - props: { field: string } & Partial> + props: { field: string; label?: string } & Partial> ) => { const { allowMultiple, selectedOptions, onSelectionChange, allOptions, label } = useEnumInputController(props); @@ -19,7 +19,7 @@ export const MUIAutoEnumInput = < disablePortal multiple={allowMultiple} options={allOptions} - renderInput={(params) => } + renderInput={(params) => } value={allowMultiple ? selectedOptions : selectedOptions[0]} onChange={(event, value) => { if (value === null || (Array.isArray(value) && value.length === 0)) { diff --git a/packages/react/src/auto/mui/inputs/MUIAutoFileInput.tsx b/packages/react/src/auto/mui/inputs/MUIAutoFileInput.tsx index 314eb7d8b..efe8f3ab8 100644 --- a/packages/react/src/auto/mui/inputs/MUIAutoFileInput.tsx +++ b/packages/react/src/auto/mui/inputs/MUIAutoFileInput.tsx @@ -21,8 +21,8 @@ const VisuallyHiddenInput = styled("input")({ width: 1, }); -export const MUIAutoFileInput = (props: { field: string; control?: Control }) => { - const { field: fieldApiIdentifier, control } = props; +export const MUIAutoFileInput = (props: { field: string; control?: Control; label?: string }) => { + const { field: fieldApiIdentifier, control, label } = props; const { onFileUpload, metadata } = useFileInputController({ field: fieldApiIdentifier, control, @@ -31,7 +31,7 @@ export const MUIAutoFileInput = (props: { field: string; control?: Control return (