Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/5955 on enter composer bug #6009

Open
wants to merge 2 commits into
base: iso7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelogs/unreleased/5955-onEnter-composer-bug.yml
Original file line number Diff line number Diff line change
@@ -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}}"
124 changes: 102 additions & 22 deletions src/UI/Components/Diagram/components/FormModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand All @@ -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<PossibleForm[]>([]);
const [fields, setFields] = useState<Field[]>([]);
const [formState, setFormState] = useState<InstanceAttributeModel>({});
const [isSelectOpen, setIsSelectOpen] = useState(false);
const [selected, setSelected] = useState<Selected | undefined>(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<MenuToggleElement>) => (
/**
* pass a MenuToggle component to Select Component with specified properties.
*
* @param {React.Ref<MenuToggleElement>} toggleRef - The reference to the MenuToggle element.
* @returns {JSX.Element} The MenuToggle component.
*/
const toggleComponent = (
toggleRef: React.Ref<MenuToggleElement>,
): JSX.Element => (
<MenuToggle
ref={toggleRef}
onClick={(val) => setIsSelectOpen(val)}
Expand All @@ -89,8 +116,41 @@ const FormModal = ({
</MenuToggle>
);

/**
* 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<HTMLButtonElement, MouseEvent> | React.FormEvent<HTMLFormElement>} event - The event triggered by submitting the form or clicking the confirm button.
* @returns {void}
*/
const onSubmit = (
event:
| React.MouseEvent<HTMLButtonElement, MouseEvent>
| React.FormEvent<HTMLFormElement>,
): 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,
);
Expand All @@ -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));
}
}
Expand All @@ -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);
});
}
Expand Down Expand Up @@ -252,7 +332,7 @@ const FormModal = ({
<Select
isScrollable
selected={selected?.name}
toggle={toggle}
toggle={toggleComponent}
onOpenChange={(isOpen) => setIsSelectOpen(isOpen)}
isOpen={isSelectOpen}
onSelect={(_evt, value) => {
Expand All @@ -267,7 +347,7 @@ const FormModal = ({
</Select>
</FlexItem>
<FlexItem>
<Form>
<Form onSubmit={onSubmit}>
{fields.map((field) => (
<FieldInput
originalState={{}} //TODO: change it to actual state in the PR that solely focus on form
Expand Down