import { useEffect, useState } from 'react'; // @ts-ignore import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import { Button, Select, SelectItem, TextInput, Grid, Column, // @ts-ignore } from '@carbon/react'; import validator from '@rjsf/validator-ajv8'; import { FormField, JsonSchemaForm } from '../interfaces'; import { Form } from '../themes/carbon'; import { modifyProcessIdentifierForPathParam, slugifyString, underscorizeString, } from '../helpers'; import HttpService from '../services/HttpService'; import { Notification } from '../components/Notification'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; export default function JsonSchemaFormBuilder() { const params = useParams(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const formFieldTypes = ['textbox', 'checkbox', 'select']; const [formTitle, setFormTitle] = useState(''); const [formDescription, setFormDescription] = useState(''); const [formId, setFormId] = useState(''); const [formFields, setFormFields] = useState([]); const [showNewFormField, setShowNewFormField] = useState(false); const [formFieldSelectOptions, setFormFieldSelectOptions] = useState(''); const [formIdHasBeenUpdatedByUser, setFormIdHasBeenUpdatedByUser] = useState(false); const [formFieldIdHasBeenUpdatedByUser, setFormFieldIdHasBeenUpdatedByUser] = useState(false); const [showFormFieldSelectTextField, setShowFormFieldSelectTextField] = useState(false); const [formFieldId, setFormFieldId] = useState(''); const [formFieldTitle, setFormFieldTitle] = useState(''); const [formFieldType, setFormFieldType] = useState(''); const [requiredFields, setRequiredFields] = useState([]); const [savedJsonSchema, setSavedJsonSchema] = useState(false); const modifiedProcessModelId = modifyProcessIdentifierForPathParam( `${params.process_model_id}` ); useEffect(() => { const processResult = (result: JsonSchemaForm) => { const jsonForm = JSON.parse(result.file_contents); setFormTitle(jsonForm.title); setFormDescription(jsonForm.description); setRequiredFields(jsonForm.required); const newFormId = (searchParams.get('file_name') || '').replace( '-schema.json', '' ); setFormId(newFormId); const newFormFields: FormField[] = []; Object.keys(jsonForm.properties).forEach((propertyId: string) => { const propertyDetails = jsonForm.properties[propertyId]; newFormFields.push({ id: propertyId, title: propertyDetails.title, required: propertyDetails.required, type: propertyDetails.type, enum: propertyDetails.enum, default: propertyDetails.default, pattern: propertyDetails.pattern, }); }); setFormFields(newFormFields); }; if (searchParams.get('file_name')) { HttpService.makeCallToBackend({ path: `/process-models/${modifiedProcessModelId}/files/${searchParams.get( 'file_name' )}`, successCallback: processResult, }); } }, [modifiedProcessModelId, searchParams]); const formSubmitResultElement = () => { if (savedJsonSchema) { return ( setSavedJsonSchema(false)} > It saved ); } return null; }; const renderFormJson = () => { const formJson = { title: formTitle, description: formDescription, properties: {}, required: requiredFields, }; formFields.forEach((formField: FormField) => { let jsonSchemaFieldType = formField.type; if (['checkbox'].includes(formField.type)) { jsonSchemaFieldType = 'boolean'; } const formJsonObject: any = { type: jsonSchemaFieldType || 'string', title: formField.title, }; if (formField.enum) { formJsonObject.enum = formField.enum; } if (formField.default !== undefined) { formJsonObject.default = formField.default; } if (formField.pattern) { formJsonObject.pattern = formField.pattern; } (formJson.properties as any)[formField.id] = formJsonObject; }); return JSON.stringify(formJson, null, 2); }; const renderFormUiJson = () => { const uiOrder = formFields.map((formField: FormField) => { return formField.id; }); return JSON.stringify({ 'ui:order': uiOrder }, null, 2); }; const onFormFieldTitleChange = (newFormFieldTitle: string) => { if (!formFieldIdHasBeenUpdatedByUser) { setFormFieldId(underscorizeString(newFormFieldTitle)); } setFormFieldTitle(newFormFieldTitle); }; const onFormTitleChange = (newFormTitle: string) => { if (!formIdHasBeenUpdatedByUser) { setFormId(slugifyString(newFormTitle)); } setFormTitle(newFormTitle); }; const getFormFieldType = (indicatedType: string) => { if (indicatedType === 'checkbox') { return 'boolean'; } // undefined or 'select' or 'textbox' return 'string'; }; const addFormField = () => { const newFormField: FormField = { id: formFieldId, title: formFieldTitle, required: false, type: getFormFieldType(formFieldType), enum: showFormFieldSelectTextField ? formFieldSelectOptions.split(',') : undefined, }; setFormFieldIdHasBeenUpdatedByUser(false); setShowNewFormField(false); setFormFields([...formFields, newFormField]); }; const handleFormFieldTypeChange = (event: any) => { setFormFieldType(event.srcElement.value); if (event.srcElement.value === 'select') { setShowFormFieldSelectTextField(true); } else { setShowFormFieldSelectTextField(false); } }; const newFormFieldComponent = () => { if (showNewFormField) { return ( <> { onFormFieldTitleChange(event.srcElement.value); }} /> { setFormFieldIdHasBeenUpdatedByUser(true); setFormFieldId(event.srcElement.value); }} /> {showFormFieldSelectTextField ? ( { setFormFieldSelectOptions(event.srcElement.value); }} /> ) : null} ); } return null; }; const formFieldArea = () => { if (formFields.length > 0) { return formFields.map((formField: FormField) => { return

Form Field: {formField.id}

; }); } return null; }; const handleSaveCallback = () => { setSavedJsonSchema(true); }; const uploadFile = (file: File) => { const url = `/process-models/${modifiedProcessModelId}/files`; const httpMethod = 'POST'; const formData = new FormData(); formData.append('file', file); formData.append('fileName', file.name); HttpService.makeCallToBackend({ path: url, successCallback: handleSaveCallback, httpMethod, postBody: formData, }); }; const saveFile = () => { setSavedJsonSchema(false); let formJsonFileName = `${formId}-schema.json`; let formUiJsonFileName: string | null = `${formId}-uischema.json`; if (searchParams.get('file_name')) { formJsonFileName = searchParams.get('file_name') as any; if (formJsonFileName.match(/-schema\.json$/)) { formUiJsonFileName = (searchParams.get('file_name') as any).replace( '-schema.json', '-uischema.json' ); } else { formUiJsonFileName = null; } } uploadFile(new File([renderFormJson()], formJsonFileName)); if (formUiJsonFileName) { uploadFile(new File([renderFormUiJson()], formUiJsonFileName)); } }; const deleteFile = () => { const url = `/process-models/${modifiedProcessModelId}/files/${params.file_name}`; const httpMethod = 'DELETE'; const navigateToProcessModelShow = (_httpResult: any) => { navigate(`/admin/process-models/${modifiedProcessModelId}`); }; HttpService.makeCallToBackend({ path: url, successCallback: navigateToProcessModelShow, httpMethod, }); }; const formIdTextField = () => { if (searchParams.get('file_name')) { return null; } return ( { setFormIdHasBeenUpdatedByUser(true); setFormId(event.srcElement.value); }} /> ); }; const jsonFormButton = () => { if (!searchParams.get('file_name')) { return null; } return ( <> ); }; const processModelFileName = searchParams.get('file_name') || ''; const topOfPageElements = () => { return ( <>

Process Model File{processModelFileName ? ': ' : ''} {processModelFileName}

); }; const jsonFormArea = () => { return ( <> {formSubmitResultElement()} {jsonFormButton()} { onFormTitleChange(event.srcElement.value); }} /> {formIdTextField()} { setFormDescription(event.srcElement.value); }} /> {formFieldArea()} {newFormFieldComponent()} ); }; const schemaString = renderFormJson(); const uiSchemaString = renderFormUiJson(); const schema = JSON.parse(schemaString); const uiSchema = JSON.parse(uiSchemaString); return ( <> {topOfPageElements()} {jsonFormArea()}

Form Preview

); }