diff --git a/src/components/dialog/faultEvent/FaultEventCreation.tsx b/src/components/dialog/faultEvent/FaultEventCreation.tsx index 6b09be21..522088ec 100644 --- a/src/components/dialog/faultEvent/FaultEventCreation.tsx +++ b/src/components/dialog/faultEvent/FaultEventCreation.tsx @@ -38,7 +38,7 @@ const FaultEventCreation = ({ register, } = useFormMethods; - const faultEvents = useReusableFaultEvents(); + const faultEvents = disabled ? [] : useReusableFaultEvents(); const [newEvent, setNewEvent] = useState(null); const [selectedEvent, setSelectedEvent] = useState(null); const [showCreateEvent, setShowCreateEvent] = useState(false); @@ -49,9 +49,13 @@ const FaultEventCreation = ({ const gateTypeWatch = watch("gateType"); useEffect(() => { + reset(); if (selectedEvent) { setValue("name", selectedEvent.name); - setValue("existingEvent", selectedEvent.iri ? selectedEvent : null); + setValue( + "existingEvent", + selectedEvent?.supertypes ? selectedEvent?.supertypes[0] : selectedEvent.iri ? selectedEvent : null, + ); if (existingEventSelected) { setValue("eventType", selectedEvent.eventType); } @@ -59,8 +63,6 @@ const FaultEventCreation = ({ setValue("eventType", EventType.INTERMEDIATE); setValue("gateType", GateType.OR); } - } else { - reset(); } }, [isRootEvent, selectedEvent, setValue, existingEventSelected, isCreatedEvent, reset]); @@ -83,12 +85,20 @@ const FaultEventCreation = ({ const handleEventSelect = (data: any) => { setSelectedEvent(data); - setIsCreatedEvent(false); + if (!data) { + reset(); + return; + } + setIsCreatedEvent(!data.iri); }; function renderEventSelect() { const eventVal = asArray(eventValue?.supertypes)?.[0] || eventValue; - const defaultValue = eventVal ? { name: eventVal.name, iri: eventVal.iri } : null; + const _eventVal = eventVal ? { name: eventVal.name, iri: eventVal.iri } : null; + if (_eventVal && !faultEvents.some((evt) => evt.iri === _eventVal.iri)) { + faultEvents.push(_eventVal); + updatedFHAEventTypes.push(_eventVal); + } return ( <> @@ -97,8 +107,15 @@ const FaultEventCreation = ({ { + return { + iri: null, + name: name, + }; + }} onChangeCallback={handleEventSelect} onInputChangeCallback={handleFilterOptions} onCreateEventClick={handleOnCreateEventClick} @@ -107,7 +124,6 @@ const FaultEventCreation = ({ renderInput={(params) => ( )} - defaultValue={defaultValue} disabled={disabled} /> diff --git a/src/components/dialog/faultEvent/FaultEventDialog.tsx b/src/components/dialog/faultEvent/FaultEventDialog.tsx index 4a313686..77e8dd89 100644 --- a/src/components/dialog/faultEvent/FaultEventDialog.tsx +++ b/src/components/dialog/faultEvent/FaultEventDialog.tsx @@ -28,16 +28,21 @@ const FaultEventDialog = ({ open, eventIri, treeUri, onCreated, onClose }: Props const [selectedSystem] = useSelectedSystemSummaries(); const useFormMethods = useForm({ resolver: yupResolver(faultEventSchema) }); - const { handleSubmit, formState } = useFormMethods; + const { handleSubmit, formState, reset } = useFormMethods; const { isSubmitting } = formState; + const handleClose = () => { + onClose(); + reset(); + }; + const handleCreateEvent = async (values: any) => { const requestEvent = eventFromHookFormValues(values); faultEventService .addEvent(eventIri, requestEvent) .then((value) => { - onClose(); + handleClose(); onCreated(value); }) .catch((reason) => showSnackbar(reason, SnackbarType.ERROR)); @@ -45,10 +50,8 @@ const FaultEventDialog = ({ open, eventIri, treeUri, onCreated, onClose }: Props return (
- - - Create Event - + + Create Event diff --git a/src/components/materialui/ControlledAutocomplete.tsx b/src/components/materialui/ControlledAutocomplete.tsx index 53445f78..31999a44 100644 --- a/src/components/materialui/ControlledAutocomplete.tsx +++ b/src/components/materialui/ControlledAutocomplete.tsx @@ -1,12 +1,14 @@ import React, { useState } from "react"; import { Controller } from "react-hook-form"; -import { Autocomplete, Grid, Link, Typography } from "@mui/material"; +import { Autocomplete, createFilterOptions, Grid, Link, Tooltip, Typography } from "@mui/material"; import { simplifyReferences } from "@utils/utils"; import { useTranslation } from "react-i18next"; +import { AddCircle } from "@mui/icons-material"; interface Props { name: string; options: any[]; + newOption?: (string) => any; getOptionKey: (any) => string; getOptionLabel: (any) => string; renderInput; @@ -48,6 +50,7 @@ const ControlledAutocomplete = ({ options = [], name, renderInput, + newOption = null, getOptionKey, getOptionLabel, control, @@ -64,6 +67,7 @@ const ControlledAutocomplete = ({ // TODO - refactor use SafeAutocomplete instead of the implementation here const [_options, _defaultValue, getOptionValue] = prepareOptions(useSafeOptions, options, defaultValue); const [menuOpen, setMenuOpen] = useState(false); + const [newOptionValue, setNewOptionValue] = useState(null); const { t } = useTranslation(); const handleOnClick = (e) => { @@ -86,6 +90,48 @@ const ControlledAutocomplete = ({ ); }; + const defaultFilter = createFilterOptions(); + const newOptionFilter = (options, state) => { + const filtered = defaultFilter(options, state); + const { inputValue } = state; + const isExisting = filtered.some((option) => inputValue === getOptionLabel(option)); + if (inputValue !== "" && !isExisting) { + const inputOption = newOption(inputValue); + inputOption.newOption = true; + filtered.splice(0, 0, inputOption); + } + return filtered; + }; + + const renderNewOption = (params, option) => { + const { key, ...optionProps } = params; + + return ( +
  • + + {getOptionLabel(option)} + + {option?.newOption && ( + + + + )} + + +
  • + ); + }; + + const getNewOptionLabel = (option) => { + // Value selected with enter, right from the input + if (typeof option === "string") { + return option; + } + + // Regular option + return getOptionLabel(option); + }; + return ( ( @@ -93,21 +139,30 @@ const ControlledAutocomplete = ({ fullWidth options={_options} getOptionKey={getOptionKey} - getOptionLabel={getOptionLabel} - renderOption={renderOption} + getOptionLabel={newOption ? getNewOptionLabel : getOptionLabel} + renderOption={renderNewOption} renderInput={renderInput} clearOnBlur={clearOnBlur} + freeSolo onChange={(e, data) => { let _data = getOptionValue(data); + if (!data || data.newOption) setNewOptionValue(data); onChangeCallback(_data); onChange(data); }} + filterOptions={newOption ? newOptionFilter : defaultFilter} onBlur={onBlur} - value={value} + value={newOptionValue ? newOptionValue : value} ref={ref} onInputChange={(e, inputValue) => { + if (!inputValue) onChangeCallback(null); onInputChangeCallback(inputValue); }} + isOptionEqualToValue={ + getOptionKey + ? (option, value) => value && (value?.newOption || getOptionKey(option) === getOptionKey(value)) + : null + } open={menuOpen} onClose={() => setMenuOpen(false)} onOpen={() => setMenuOpen(true)}