diff --git a/src/client/cypress/e2e/detailPage/boreholeform.cy.js b/src/client/cypress/e2e/detailPage/boreholeform.cy.js index 671e3f59a..118da0f8c 100644 --- a/src/client/cypress/e2e/detailPage/boreholeform.cy.js +++ b/src/client/cypress/e2e/detailPage/boreholeform.cy.js @@ -1,5 +1,6 @@ -import { evaluateSelect, isDisabled, setSelect } from "../helpers/formHelpers"; -import { createBorehole, goToRouteAndAcceptTerms, newEditableBorehole } from "../helpers/testHelpers"; +import { clickOnRowWithText, showTableAndWaitForData, sortBy } from "../helpers/dataGridHelpers"; +import { evaluateInput, evaluateSelect, isDisabled, setSelect } from "../helpers/formHelpers"; +import { createBorehole, goToRouteAndAcceptTerms, newEditableBorehole, returnToOverview } from "../helpers/testHelpers"; describe("Test for the borehole form.", () => { it("Creates a borehole and fills dropdowns.", () => { @@ -58,6 +59,37 @@ describe("Test for the borehole form.", () => { }); }); + it("Checks if form values are updated when borehole changes", () => { + showTableAndWaitForData(); + // sort by Name descending + sortBy("Name"); + clickOnRowWithText("Zena Rath"); + + evaluateSelect("restriction", ""); + evaluateSelect("national_interest", "0"); // No + evaluateSelect("spatial_reference_system", "20104002"); // LV03 + evaluateSelect("location_precision", "20113005"); + + evaluateInput("elevation_z", "3'519.948980314633"); + evaluateInput("reference_elevation", "3'554.9389396584306"); + evaluateSelect("elevation_precision", ""); + evaluateSelect("qt_reference_elevation", ""); + evaluateSelect("reference_elevation_type", ""); + + returnToOverview(); + clickOnRowWithText("Zena Mraz"); + evaluateSelect("restriction", ""); + evaluateSelect("national_interest", "1"); // Yes + evaluateSelect("spatial_reference_system", "20104002"); // LV03 + evaluateSelect("location_precision", "20113007"); // not specified + + evaluateInput("elevation_z", "3'062.9991330499756"); + evaluateInput("reference_elevation", "3'478.1368118609007"); + evaluateSelect("elevation_precision", "20114003"); // 1 + evaluateSelect("qt_reference_elevation", "20114005"); // 0.1 + evaluateSelect("reference_elevation_type", "30000013"); // kelly bushing + }); + it("switches tabs", () => { let boreholeId; createBorehole({ "extended.original_name": "LSENALZE" }).as("borehole_id"); diff --git a/src/client/public/locale/de/common.json b/src/client/public/locale/de/common.json index 5769ee4ae..1e978bec9 100644 --- a/src/client/public/locale/de/common.json +++ b/src/client/public/locale/de/common.json @@ -174,7 +174,6 @@ "errorMissingBedrockSolution": "Tiefe Top Fels automatisch aus der Bohrdaten übernehmen", "errorOverlap": "Überlappende Schichten", "errorStartEditing": "Sie sollten die Schaltfläche 'Bearbeitung beginnen' drücken", - "errorStartEditingWrongStatus": "Bohrung mit dem Status {{status}} kann nicht editiert werden.", "errorStartWrong": "Erste Schicht beginnt nicht auf dem Referenzniveau", "errorToDepthTooHigh": "bis Tiefe ist zu gross", "errorWrongDepth": "Falsche Bohrendteufe", diff --git a/src/client/public/locale/en/common.json b/src/client/public/locale/en/common.json index cbe4c15f2..fb14961eb 100644 --- a/src/client/public/locale/en/common.json +++ b/src/client/public/locale/en/common.json @@ -174,7 +174,6 @@ "errorMissingBedrockSolution": "Take the top bedrock depth automatically from the borehole data", "errorOverlap": "Overlapping layers", "errorStartEditing": "You should press the 'start editing' button", - "errorStartEditingWrongStatus": "Borehole with status {{status}} not editable", "errorStartWrong": "First layer does not start at the reference level", "errorToDepthTooHigh": "to depth is too high", "errorWrongDepth": "Incorrect borehole end depth", diff --git a/src/client/public/locale/fr/common.json b/src/client/public/locale/fr/common.json index 6bef113d6..950a90b61 100644 --- a/src/client/public/locale/fr/common.json +++ b/src/client/public/locale/fr/common.json @@ -174,7 +174,6 @@ "errorMissingBedrockSolution": "Reprendre automatiquement la profondeur du toit du rocher à partir de la page des données de forage", "errorOverlap": "Des couches se recouvrent", "errorStartEditing": "Veuillez appuyer sur le bouton 'Commencer l'édition'", - "errorStartEditingWrongStatus": "Forage avec le statut {{status}} non modifiable", "errorStartWrong": "La première couche ne débute pas au niveau de la référence altitudinale", "errorToDepthTooHigh": "de la profondeur est trop élevée", "errorWrongDepth": "Profondeur finale erronée", diff --git a/src/client/public/locale/it/common.json b/src/client/public/locale/it/common.json index be293cf32..14f35a386 100644 --- a/src/client/public/locale/it/common.json +++ b/src/client/public/locale/it/common.json @@ -174,7 +174,6 @@ "errorMissingBedrockSolution": "Crea automaticamente la profondità del substrato roccioso attingendo dai dati inseriti della perforazione", "errorOverlap": "Sovrapposizione di strati", "errorStartEditing": "Per favore premere il pulsante 'iniziare la modifica'", - "errorStartEditingWrongStatus": "Perforazione con stato {{status}} non modificabile", "errorStartWrong": "Il primo strato non inizia dalla riferimento della quota", "errorToDepthTooHigh": "la profondità è troppo alta", "errorWrongDepth": "Profondità di perforazione finale errata", diff --git a/src/client/src/components/form/simpleBooleanSelect.tsx b/src/client/src/components/form/simpleBooleanSelect.tsx new file mode 100644 index 000000000..492609001 --- /dev/null +++ b/src/client/src/components/form/simpleBooleanSelect.tsx @@ -0,0 +1,81 @@ +import { FC } from "react"; +import { useTranslation } from "react-i18next"; +import { MenuItem, SxProps } from "@mui/material"; +import { TextField } from "@mui/material/"; +import { FormSelectMenuItem } from "./formSelect.tsx"; + +// This component is needed as an intermediate step to refactor borehole input. +// The standard form components are not usable with autosave components as they are now. +// Once the saving mechanism is refactored, this component can be replaced. + +interface SimpleBooleanSelectProps { + fieldName: string; + label: string; + required?: boolean; + disabled?: boolean; + readonly?: boolean; + selected?: number | boolean | null; + sx?: SxProps; + className?: string; + onUpdate?: (value: number | boolean | string | null) => void; +} + +export const SimpleBooleanSelect: FC = ({ + fieldName, + label, + required, + disabled, + readonly, + selected, + sx, + className, + onUpdate, +}) => { + const { t } = useTranslation(); + + const menuItems: FormSelectMenuItem[] = []; + if (!required) { + menuItems.push({ key: 0, value: undefined, label: t("reset"), italic: true }); + } + + const value = selected === true ? 1 : selected === false ? 0 : 2; + + const values = [ + { key: 1, name: t("yes") }, + { key: 0, name: t("no") }, + { key: 2, name: t("np") }, + ]; + + values.forEach(v => + menuItems.push({ + key: v.key, + value: v.key, + label: v.name, + }), + ); + + return ( + + onUpdate + ? onUpdate(parseInt(e.target.value) === 1 ? true : parseInt(e.target.value) === 0 ? false : null) + : null + } + value={value} + disabled={disabled ?? false} + data-cy={fieldName + "-formSelect"} + InputProps={{ readOnly: readonly, disabled: disabled }}> + {menuItems.map(item => ( + + {item.italic ? {item.label} : item.label} + + ))} + + ); +}; diff --git a/src/client/src/components/form/simpleDomainSelect.tsx b/src/client/src/components/form/simpleDomainSelect.tsx new file mode 100644 index 000000000..a63ef76c2 --- /dev/null +++ b/src/client/src/components/form/simpleDomainSelect.tsx @@ -0,0 +1,80 @@ +import { FC } from "react"; +import { useTranslation } from "react-i18next"; +import { MenuItem, SxProps } from "@mui/material"; +import { TextField } from "@mui/material/"; +import { useDomains } from "../../api/fetchApiV2"; +import { Codelist } from "../legacyComponents/domain/domainInterface.ts"; +import { FormSelectMenuItem } from "./formSelect.tsx"; + +// This component is needed as an intermediate step to refactor borehole input. +// The standard form components are not usable with autosave components as they are now. +// Once the saving mechanism is refactored, this component can be replaced. + +interface SimpleDomainSelectProps { + fieldName: string; + schemaName: string; + label: string; + required?: boolean; + disabled?: boolean; + readonly?: boolean; + selected?: number | boolean | null; + sx?: SxProps; + className?: string; + onUpdate?: (value: number | boolean | string | null) => void; +} + +export const SimpleDomainSelect: FC = ({ + fieldName, + label, + required, + disabled, + readonly, + selected, + schemaName, + sx, + className, + onUpdate, +}) => { + const { t, i18n } = useTranslation(); + const { data: domains } = useDomains(); + + const menuItems: FormSelectMenuItem[] = []; + if (!required) { + menuItems.push({ key: 0, value: undefined, label: t("reset"), italic: true }); + } + domains + ?.filter((d: Codelist) => d.schema === schemaName) + .sort((a: Codelist, b: Codelist) => a.order - b.order) + .forEach((d: Codelist) => + menuItems.push({ + key: d.id, + value: d.id, + label: d[i18n.language] as string, + }), + ); + + return ( + { + if (onUpdate) { + onUpdate(e.target.value); + } + }} + value={selected} + disabled={disabled ?? false} + data-cy={fieldName + "-formSelect"} + InputProps={{ readOnly: readonly, disabled: disabled }}> + {menuItems.map(item => ( + + {item.italic ? {item.label} : item.label} + + ))} + + ); +}; diff --git a/src/client/src/components/form/simpleFormInput.tsx b/src/client/src/components/form/simpleFormInput.tsx new file mode 100644 index 000000000..815338a81 --- /dev/null +++ b/src/client/src/components/form/simpleFormInput.tsx @@ -0,0 +1,68 @@ +import { FC } from "react"; +import { useTranslation } from "react-i18next"; +import { InputProps, SxProps, TextField } from "@mui/material"; +import { FormValueType } from "./form.ts"; +import { NumericFormatWithThousandSeparator } from "./numericFormatWithThousandSeparator.tsx"; + +interface SimpleInputProps { + label: string; + required?: boolean; + disabled?: boolean; + readonly?: boolean; + type?: FormValueType; + multiline?: boolean; + rows?: number; + value?: string | number | Date | null; + sx?: SxProps; + className?: string; + inputProps?: InputProps; + onUpdate?: (value: string) => void; + withThousandSeparator?: boolean; +} + +// This component is needed as an intermediate step to refactor borehole input. +// The standard form components are not usable with autosave components as they are now. +// Once the saving mechanism is refactored, this component can be replaced. + +export const SimpleFormInput: FC = ({ + value, + className, + required, + readonly, + rows, + onUpdate, + label, + type, + multiline, + withThousandSeparator, + inputProps, + disabled, + sx, +}) => { + const { t } = useTranslation(); + + return ( + { + if (onUpdate) { + onUpdate(e.target.value); + } + }} + InputProps={{ + ...inputProps /* eslint-disable @typescript-eslint/no-explicit-any */, + ...(withThousandSeparator && { inputComponent: NumericFormatWithThousandSeparator as any }), + readOnly: readonly, + disabled: disabled, + }} + /> + ); +}; diff --git a/src/client/src/pages/detail/detailPageContent.jsx b/src/client/src/pages/detail/detailPageContent.jsx index 31cf9554f..c0543ca80 100644 --- a/src/client/src/pages/detail/detailPageContent.jsx +++ b/src/client/src/pages/detail/detailPageContent.jsx @@ -108,12 +108,6 @@ class DetailPageContent extends React.Component { checkLock() { const { t, editingEnabled, editableByCurrentUser } = this.props; if (this.props.borehole.data.role !== "EDIT") { - this.context.showAlert( - t("common:errorStartEditingWrongStatus", { - status: this.props.borehole.data.role, - }), - "error", - ); return false; } if (!editingEnabled) { diff --git a/src/client/src/pages/detail/form/location/coordinatesSegment.tsx b/src/client/src/pages/detail/form/location/coordinatesSegment.tsx index b170bbe88..8d71a3271 100644 --- a/src/client/src/pages/detail/form/location/coordinatesSegment.tsx +++ b/src/client/src/pages/detail/form/location/coordinatesSegment.tsx @@ -5,7 +5,7 @@ import { Card, CardContent, CardHeader } from "@mui/material"; import { fetchApiV2 } from "../../../../api/fetchApiV2.js"; import { LabelingButton } from "../../../../components/buttons/labelingButton.tsx"; import { FormContainer, FormCoordinate, FormSelect } from "../../../../components/form/form"; -import { FormDomainSelect } from "../../../../components/form/formDomainSelect.tsx"; +import { SimpleDomainSelect } from "../../../../components/form/simpleDomainSelect.tsx"; import { getPrecisionFromString, parseFloatWithThousandsSeparator, @@ -474,7 +474,7 @@ const CoordinatesSegment: React.FC = ({ /> - = ({ borehole, updateChange, updateNumber, editingEnabled }) => { const { data: domains } = useDomains(); - const formMethods = useForm({ - mode: "all", - defaultValues: borehole.data, - }); - - useEffect(() => { - formMethods.reset(borehole.data); - }, [borehole, formMethods]); - return ( - - - - updateNumber("elevation_z", e === "" ? null : parseFloatWithThousandsSeparator(e))} - /> - { - updateChange("elevation_precision", e ?? null, false); - }} - /> - - - updateNumber("reference_elevation", e === "" ? null : parseFloatWithThousandsSeparator(e))} - /> - { - updateChange("qt_reference_elevation", e ?? null, false); - }} - /> - - - { - updateChange("reference_elevation_type", e ?? null, false); - }} - /> - d.id === borehole.data.height_reference_system)?.code} - type={FormValueType.Text} - /> - + + + updateNumber("elevation_z", e === "" ? null : parseFloatWithThousandsSeparator(e))} + /> + updateChange("elevation_precision", e ?? null, false)} + /> + + + updateNumber("reference_elevation", e === "" ? null : parseFloatWithThousandsSeparator(e))} + /> + updateChange("qt_reference_elevation", e ?? null, false)} + /> + + + updateChange("reference_elevation_type", e ?? null, false)} + /> + d.id === borehole.data.height_reference_system)?.code} + /> - + ); }; diff --git a/src/client/src/pages/detail/form/location/restrictionSegment.tsx b/src/client/src/pages/detail/form/location/restrictionSegment.tsx index 02b33791f..8c2857edb 100644 --- a/src/client/src/pages/detail/form/location/restrictionSegment.tsx +++ b/src/client/src/pages/detail/form/location/restrictionSegment.tsx @@ -1,62 +1,68 @@ -import { FormProvider, useForm } from "react-hook-form"; +import { useEffect, useState } from "react"; import { Card } from "@mui/material"; -import { FormContainer, FormInput, FormValueType } from "../../../../components/form/form.ts"; -import { FormBooleanSelect } from "../../../../components/form/formBooleanSelect.tsx"; -import { FormDomainSelect } from "../../../../components/form/formDomainSelect.tsx"; +import { FormContainer, FormValueType } from "../../../../components/form/form.ts"; +import { SimpleBooleanSelect } from "../../../../components/form/simpleBooleanSelect.tsx"; +import { SimpleDomainSelect } from "../../../../components/form/simpleDomainSelect.tsx"; +import { SimpleFormInput } from "../../../../components/form/simpleFormInput.tsx"; import { FormSegmentBox } from "../../../../components/styledComponents"; import { SegmentProps } from "./segmentInterface.ts"; +const restrictionUntilCode = 20111003; + const RestrictionSegment = ({ borehole, updateChange, editingEnabled }: SegmentProps) => { - const formMethods = useForm({ - mode: "all", - }); + const [restrictionUntilEnabled, setRestrictionUntilEnabled] = useState( + borehole.data.restriction === restrictionUntilCode, + ); - const restriction = formMethods.watch("restriction"); - const restrictionUntilCode = 20111003; + useEffect(() => { + if (borehole.data.restriction !== restrictionUntilCode) { + setRestrictionUntilEnabled(false); + } else { + setRestrictionUntilEnabled(true); + } + }, [borehole.data.restriction]); return ( - - - - - { - if (e !== restrictionUntilCode) { - formMethods.setValue("restriction_until", null); - } - updateChange("restriction", e ?? null, false); - }} - /> - { - updateChange("restriction_until", selected, false); - }} - /> - { - updateChange("national_interest", e, false); - }} - /> - - - - + + + + { + if (e !== restrictionUntilCode) { + setRestrictionUntilEnabled(false); + updateChange("restriction_until", "", false); + } + updateChange("restriction", e ?? null, false); + }} + /> + { + updateChange("restriction_until", selected, false); + }} + /> + { + updateChange("national_interest", e, false); + }} + /> + + + ); };