@@ -2,8 +2,9 @@ import { faGear, faPlus } from "@fortawesome/free-solid-svg-icons";
22import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
33import { Form , Formik , useField , useFormikContext } from "formik" ;
44import { JSONSchema7 } from "json-schema" ;
5- import { useEffect , useMemo , useState } from "react" ;
5+ import { useMemo , useState } from "react" ;
66import { FormattedMessage , useIntl } from "react-intl" ;
7+ import { useEffectOnce } from "react-use" ;
78import * as yup from "yup" ;
89
910import { Button } from "components/ui/Button" ;
@@ -97,8 +98,10 @@ export const InputsView: React.FC = () => {
9798 // make sure key can only occur once
9899 key : yup
99100 . string ( )
100- . required ( "form.empty.error" )
101- . notOneOf ( inputInEditing ?. isNew ? usedKeys : usedKeys . filter ( ( key ) => key !== inputInEditing ?. key ) ) ,
101+ . notOneOf (
102+ inputInEditing ?. isNew ? usedKeys : usedKeys . filter ( ( key ) => key !== inputInEditing ?. key ) ,
103+ "connectorBuilder.duplicateFieldID"
104+ ) ,
102105 required : yup . bool ( ) ,
103106 definition : yup . object ( ) . shape ( {
104107 title : yup . string ( ) . required ( "form.empty.error" ) ,
@@ -116,36 +119,10 @@ export const InputsView: React.FC = () => {
116119 < Card withPadding className = { styles . inputsCard } >
117120 < ol className = { styles . list } >
118121 { inferredInputs . map ( ( input ) => (
119- < li className = { styles . listItem } key = { input . key } >
120- < div className = { styles . itemLabel } > { input . definition . title || input . key } </ div >
121- < Button
122- className = { styles . itemButton }
123- size = "sm"
124- variant = "secondary"
125- aria-label = "Edit"
126- onClick = { ( ) => {
127- setInputInEditing ( formInputToInputInEditing ( input , true ) ) ;
128- } }
129- >
130- < FontAwesomeIcon className = { styles . icon } icon = { faGear } />
131- </ Button >
132- </ li >
122+ < InputItem input = { input } setInputInEditing = { setInputInEditing } isInferredInput />
133123 ) ) }
134124 { inputs . value . map ( ( input ) => (
135- < li className = { styles . listItem } key = { input . key } >
136- < div className = { styles . itemLabel } > { input . definition . title || input . key } </ div >
137- < Button
138- className = { styles . itemButton }
139- size = "sm"
140- variant = "secondary"
141- aria-label = "Edit"
142- onClick = { ( ) => {
143- setInputInEditing ( formInputToInputInEditing ( input , false ) ) ;
144- } }
145- >
146- < FontAwesomeIcon className = { styles . icon } icon = { faGear } />
147- </ Button >
148- </ li >
125+ < InputItem input = { input } setInputInEditing = { setInputInEditing } isInferredInput = { false } />
149126 ) ) }
150127 </ ol >
151128 </ Card >
@@ -197,6 +174,7 @@ export const InputsView: React.FC = () => {
197174 </ BuilderConfigView >
198175 ) ;
199176} ;
177+
200178const InputModal = ( {
201179 inputInEditing,
202180 onClose,
@@ -207,14 +185,13 @@ const InputModal = ({
207185 onClose : ( ) => void ;
208186} ) => {
209187 const isInferredInputOverride = inputInEditing . isInferredInputOverride ;
210- const { isValid, values, setFieldValue } = useFormikContext < InputInEditing > ( ) ;
188+ const { isValid, values, setFieldValue, setTouched } = useFormikContext < InputInEditing > ( ) ;
189+
211190 const { formatMessage } = useIntl ( ) ;
212- const [ title , titleMeta ] = useField < string | undefined > ( "definition.title" ) ;
213- useEffect ( ( ) => {
214- if ( titleMeta . touched && ! isInferredInputOverride ) {
215- setFieldValue ( "key" , sluggify ( title . value || "" ) ) ;
216- }
217- } , [ setFieldValue , title . value , titleMeta . touched , isInferredInputOverride ] ) ;
191+ useEffectOnce ( ( ) => {
192+ // key input is always touched so errors are shown right away as it will be auto-set by the user changing the title
193+ setTouched ( { key : true } ) ;
194+ } ) ;
218195
219196 return (
220197 < Modal
@@ -231,6 +208,11 @@ const InputModal = ({
231208 < BuilderField
232209 path = "definition.title"
233210 type = "string"
211+ onChange = { ( newValue ) => {
212+ if ( ! isInferredInputOverride ) {
213+ setFieldValue ( "key" , sluggify ( newValue || "" ) , true ) ;
214+ }
215+ } }
234216 label = { formatMessage ( { id : "connectorBuilder.inputModal.inputName" } ) }
235217 tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.inputNameTooltip" } ) }
236218 />
@@ -242,7 +224,7 @@ const InputModal = ({
242224 tooltip = { formatMessage (
243225 { id : "connectorBuilder.inputModal.fieldIdTooltip" } ,
244226 {
245- syntaxExample : "{{ my_input}}" ,
227+ syntaxExample : `{{config[' ${ values . key || " my_input" } ']}}` ,
246228 }
247229 ) }
248230 />
@@ -253,27 +235,26 @@ const InputModal = ({
253235 label = { formatMessage ( { id : "connectorBuilder.inputModal.description" } ) }
254236 tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.descriptionTooltip" } ) }
255237 />
256- { values . type !== "unknown" ? (
238+ { values . type !== "unknown" && ! isInferredInputOverride ? (
257239 < >
258- { ! isInferredInputOverride && (
259- < >
260- < BuilderField
261- path = "type"
262- type = "enum"
263- options = { [ "string" , "number" , "integer" , "array" , "boolean" , "enum" ] }
264- label = { formatMessage ( { id : "connectorBuilder.inputModal.type" } ) }
265- tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.typeTooltip" } ) }
266- />
267- { values . type === "enum" && (
268- < BuilderField
269- path = "definition.enum"
270- type = "array"
271- optional
272- label = { formatMessage ( { id : "connectorBuilder.inputModal.enum" } ) }
273- tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.enumTooltip" } ) }
274- />
275- ) }
276- </ >
240+ < BuilderField
241+ path = "type"
242+ type = "enum"
243+ options = { [ "string" , "number" , "integer" , "array" , "boolean" , "enum" ] }
244+ onChange = { ( ) => {
245+ setFieldValue ( "definition.default" , undefined ) ;
246+ } }
247+ label = { formatMessage ( { id : "connectorBuilder.inputModal.type" } ) }
248+ tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.typeTooltip" } ) }
249+ />
250+ { values . type === "enum" && (
251+ < BuilderField
252+ path = "definition.enum"
253+ type = "array"
254+ optional
255+ label = { formatMessage ( { id : "connectorBuilder.inputModal.enum" } ) }
256+ tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.enumTooltip" } ) }
257+ />
277258 ) }
278259 < BuilderField
279260 path = "definition.airbyte_secret"
@@ -282,15 +263,13 @@ const InputModal = ({
282263 label = { formatMessage ( { id : "connectorBuilder.inputModal.secret" } ) }
283264 tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.secretTooltip" } ) }
284265 />
285- { ! isInferredInputOverride && (
286- < BuilderField
287- path = "required"
288- type = "boolean"
289- optional
290- label = { formatMessage ( { id : "connectorBuilder.inputModal.required" } ) }
291- tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.requiredTooltip" } ) }
292- />
293- ) }
266+ < BuilderField
267+ path = "required"
268+ type = "boolean"
269+ optional
270+ label = { formatMessage ( { id : "connectorBuilder.inputModal.required" } ) }
271+ tooltip = { formatMessage ( { id : "connectorBuilder.inputModal.requiredTooltip" } ) }
272+ />
294273 < BuilderField
295274 path = "showDefaultValueField"
296275 type = "boolean"
@@ -317,7 +296,11 @@ const InputModal = ({
317296 </ >
318297 ) : (
319298 < InfoBox >
320- < FormattedMessage id = "connectorBuilder.inputModal.unsupportedInput" />
299+ { isInferredInputOverride ? (
300+ < FormattedMessage id = "connectorBuilder.inputModal.inferredInputMessage" />
301+ ) : (
302+ < FormattedMessage id = "connectorBuilder.inputModal.unsupportedInput" />
303+ ) }
321304 </ InfoBox >
322305 ) }
323306 </ ModalBody >
@@ -340,3 +323,30 @@ const InputModal = ({
340323 </ Modal >
341324 ) ;
342325} ;
326+
327+ const InputItem = ( {
328+ input,
329+ setInputInEditing,
330+ isInferredInput,
331+ } : {
332+ input : BuilderFormInput ;
333+ setInputInEditing : ( inputInEditing : InputInEditing ) => void ;
334+ isInferredInput : boolean ;
335+ } ) : JSX . Element => {
336+ return (
337+ < li className = { styles . listItem } key = { input . key } >
338+ < div className = { styles . itemLabel } > { input . definition . title || input . key } </ div >
339+ < Button
340+ className = { styles . itemButton }
341+ size = "sm"
342+ variant = "secondary"
343+ aria-label = "Edit"
344+ onClick = { ( ) => {
345+ setInputInEditing ( formInputToInputInEditing ( input , isInferredInput ) ) ;
346+ } }
347+ >
348+ < FontAwesomeIcon className = { styles . icon } icon = { faGear } />
349+ </ Button >
350+ </ li >
351+ ) ;
352+ } ;
0 commit comments