From 1eecbdaeb4ccbcdd63c3dd44954e6510d9bcef33 Mon Sep 17 00:00:00 2001 From: Mateusz Borowczyk Date: Thu, 24 Oct 2024 14:14:35 +0200 Subject: [PATCH] Fix onEnter bug in the Instance Composer --- .../unreleased/5955-onEnter-composer-bug.yml | 6 + .../Diagram/components/FormModal.tsx | 124 ++++++++++++++---- 2 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 changelogs/unreleased/5955-onEnter-composer-bug.yml diff --git a/changelogs/unreleased/5955-onEnter-composer-bug.yml b/changelogs/unreleased/5955-onEnter-composer-bug.yml new file mode 100644 index 000000000..3fc9d7449 --- /dev/null +++ b/changelogs/unreleased/5955-onEnter-composer-bug.yml @@ -0,0 +1,6 @@ +description: Resolve issue for Instance Composer form when is confirmed by pressing enter it will navigate to the home page and interrupt the flow. +issue-nr: 5955 +change-type: patch +destination-branches: [iso7] +sections: + bugfix: "{{description}}" diff --git a/src/UI/Components/Diagram/components/FormModal.tsx b/src/UI/Components/Diagram/components/FormModal.tsx index a8e9b2e71..ac6584e14 100644 --- a/src/UI/Components/Diagram/components/FormModal.tsx +++ b/src/UI/Components/Diagram/components/FormModal.tsx @@ -44,13 +44,7 @@ interface Selected { holderName: string; } -const FormModal = ({ - isOpen, - toggleIsOpen, - services, - cellView, - onConfirm, -}: { +interface Props { isOpen: boolean; toggleIsOpen: (value: boolean) => void; services: ServiceModel[]; @@ -60,21 +54,54 @@ const FormModal = ({ entity: InstanceAttributeModel, selected: Selected, ) => void; -}) => { +} + +/** + * Component representing a form modal. + * + * @param {Props} props - The properties passed to the component. + * @param {boolean} isOpen - Indicates if the modal is open. + * @param {(value: boolean): void} toggleIsOpen - Function to toggle the modal open state. + * @param {ServiceModel[]} services - List of service models. + * @param {dia.CellView | null} cellView - The cell view that is being edited - null means that we are creating new one. + * @param {(fields: Field[], entity: InstanceAttributeModel, selected: Selected): void} onConfirm - function to handle form confirmation. + * @returns {JSX.Element} The FormModal component. + */ +const FormModal = ({ + isOpen, + toggleIsOpen, + services, + cellView, + onConfirm, +}: Props) => { const [possibleForms, setPossibleForms] = useState([]); const [fields, setFields] = useState([]); const [formState, setFormState] = useState({}); const [isSelectOpen, setIsSelectOpen] = useState(false); const [selected, setSelected] = useState(undefined); - const clearStates = () => { + /** + * Clears the form states. + * + * Resets the select open state, fields, form state, and selected item to their initial values. + * @returns {void} + */ + const clearStates = (): void => { setIsSelectOpen(false); setFields([]); setFormState({}); setSelected(undefined); }; - const toggle = (toggleRef: React.Ref) => ( + /** + * pass a MenuToggle component to Select Component with specified properties. + * + * @param {React.Ref} toggleRef - The reference to the MenuToggle element. + * @returns {JSX.Element} The MenuToggle component. + */ + const toggleComponent = ( + toggleRef: React.Ref, + ): JSX.Element => ( setIsSelectOpen(val)} @@ -89,8 +116,41 @@ const FormModal = ({ ); + /** + * Handles the submit action for the form. + * Prevents the default form submission behavior. + * If an item is selected, calls the onConfirm callback with the current fields, form state, and selected item. + * Clears the form states and closes the form modal. + * + * @param {React.MouseEvent | React.FormEvent} event - The event triggered by submitting the form or clicking the confirm button. + * @returns {void} + */ + const onSubmit = ( + event: + | React.MouseEvent + | React.FormEvent, + ): void => { + event.preventDefault(); + if (selected) onConfirm(fields, formState, selected); + clearStates(); + toggleIsOpen(false); + }; + + /** + * useCallback hook that Handles the selection of an entity. + * Finds the chosen model from the possible forms and sets the selected item to the chosen model. + * Creates a field creator with the appropriate modifier handler based on whether the cell view is in edit mode. + * Converts the attributes of the chosen model to fields and sets the fields state to the selected fields. + * If a cell view is present, sets the form state to the instance attributes of the cell view model. + * Otherwise, creates a new form state based on the selected fields. + * Closes the select component. + * + * @param {string} value - The value of the selected entity. + * @param {PossibleForm[]} possibleForms - The possible forms to choose from. + * @returns {void} + */ const onEntityChosen = useCallback( - (value: string, possibleForms: PossibleForm[]) => { + (value: string, possibleForms: PossibleForm[]): void => { const chosenModel = possibleForms.find( (service) => service.value === value, ); @@ -102,20 +162,25 @@ const FormModal = ({ holderName: chosenModel.holderName, }); - const fieldCreator = new FieldCreator( - cellView?.model.get("isInEditMode") - ? new EditModifierHandler() - : new CreateModifierHandler(), - ); - const selectedFields = fieldCreator.attributesToFields( - chosenModel.model.attributes, - ); - setFields(selectedFields); if (cellView) { + const fieldCreator = new FieldCreator( + cellView.model.get("isInEditMode") + ? new EditModifierHandler() + : new CreateModifierHandler(), + ); + const selectedFields = fieldCreator.attributesToFields( + chosenModel.model.attributes, + ); + setFields(selectedFields); setFormState( (cellView.model as ServiceEntityBlock).get("instanceAttributes"), ); } else { + const fieldCreator = new FieldCreator(new CreateModifierHandler()); + const selectedFields = fieldCreator.attributesToFields( + chosenModel.model.attributes, + ); + setFields(selectedFields); setFormState(createFormState(selectedFields)); } } @@ -124,23 +189,38 @@ const FormModal = ({ [cellView], ); + /** + * useCallback hook that Handles updates to the form state. + * If the multi flag is true, updates the form state by toggling the value in the form state at the specified path. + * Otherwise, updates the form state by setting the value at the specified path. + * + * @param {string} path - The path to the value to update. + * @param {unknown} value - The value to update. + * @param {boolean} multi - A flag indicating whether the value is a multi-value. + * @returns {void} + */ const getUpdate = (path: string, value: unknown, multi = false): void => { + //if multi is true, it means the field is a multi-select field and we need to update the array of values if (multi) { setFormState((prev) => { const clone = { ...prev }; let selection = (clone[path] as string[]) || []; + //if the value is already in the array, remove it, otherwise add it if (selection.includes(value as string)) { selection = selection.filter((item) => item !== (value as string)); } else { selection.push(value as string); } + //update the form state with the new selection property with help of _lodash set function return set(clone, path, selection); }); } else { setFormState((prev) => { const clone = { ...prev }; + + //update the form state with the new value with help of _lodash set function return set(clone, path, value); }); } @@ -252,7 +332,7 @@ const FormModal = ({ -
+ {fields.map((field) => (