UNPKG

datajunction-ui

Version:
145 lines (134 loc) 3.87 kB
/** * Custom metadata field component for nodes */ import { ErrorMessage, Field, useFormikContext } from 'formik'; import CodeMirror from '@uiw/react-codemirror'; import { langs } from '@uiw/codemirror-extensions-langs'; import { useState, useEffect } from 'react'; export const CustomMetadataField = ({ value }) => { const formik = useFormikContext(); const jsonExt = langs.json(); const [hasError, setHasError] = useState(false); useEffect(() => { if (!value || value === '') { setHasError(false); return; } const stringValue = typeof value === 'string' ? value : JSON.stringify(value, null, 2); try { JSON.parse(stringValue); setHasError(false); } catch (err) { setHasError(true); } }, [value]); const formatValue = value => { if (value === null || value === undefined) { return ''; } if (typeof value === 'string') { return value; } return JSON.stringify(value, null, 2); }; const updateFormik = val => { formik.setFieldValue('custom_metadata', val); formik.setFieldTouched('custom_metadata', true); if (!val || val.trim() === '') { setHasError(false); } else { try { JSON.parse(val); setHasError(false); } catch (err) { setHasError(true); } } }; return ( <div className="QueryInput NodeCreationInput"> <details> <summary style={{ cursor: 'pointer' }}> <label style={{ paddingLeft: '3px', display: 'inline-block', pointerEvents: 'none', }} > Custom Metadata (JSON) </label> </summary> <ErrorMessage name="custom_metadata" component="span" /> <Field type="textarea" style={{ display: 'none' }} as="textarea" name="custom_metadata" id="CustomMetadata" validate={value => { if (!value || value.trim() === '') { return undefined; } try { const parsed = JSON.parse(value); if ( typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ) { const keys = Object.keys(parsed); const originalKeyMatches = value.match(/"([^"]+)"\s*:/g); if ( originalKeyMatches && originalKeyMatches.length > keys.length ) { return 'Duplicate keys detected'; } } return undefined; } catch (err) { return 'Invalid JSON format'; } }} /> <div role="button" tabIndex={0} className={`relative flex ${ hasError ? 'bg-red-900/20' : 'bg-[#282a36]' }`} style={{ border: hasError ? '2px solid #ef4444' : 'none', borderRadius: '4px', boxShadow: hasError ? '0 0 0 1px rgba(239, 68, 68, 0.3)' : 'none', }} > <CodeMirror id={'custom_metadata'} name={'custom_metadata'} extensions={[jsonExt]} value={formatValue(value)} placeholder={'{\n "key": "value"\n}'} options={{ theme: 'default', lineNumbers: true, }} width="100%" height="200px" style={{ margin: '0 0 23px 0', flex: 1, fontSize: '110%', textAlign: 'left', }} onChange={(value, viewUpdate) => { updateFormik(value); }} /> </div> </details> </div> ); };