diff --git a/src/client/cypress/e2e/filters/filter.cy.js b/src/client/cypress/e2e/filters/filter.cy.js index ac679ab18..dc55751b0 100644 --- a/src/client/cypress/e2e/filters/filter.cy.js +++ b/src/client/cypress/e2e/filters/filter.cy.js @@ -69,7 +69,7 @@ describe("Search filter tests", () => { cy.wait("@setting"); // check visibility of filters - cy.contains("h3", "Done").click(); + returnToOverview(); cy.get('[data-cy="show-filter-button"]').click(); cy.contains("Registration").click(); cy.contains("Created by"); diff --git a/src/client/cypress/e2e/filters/srsFilter.cy.js b/src/client/cypress/e2e/filters/srsFilter.cy.js index 1034e0686..72e12fd07 100644 --- a/src/client/cypress/e2e/filters/srsFilter.cy.js +++ b/src/client/cypress/e2e/filters/srsFilter.cy.js @@ -18,7 +18,7 @@ describe("Tests for filtering data by reference system.", () => { cy.get("@checkbox").check({ force: true }); cy.get("@checkbox").should("be.checked"); - cy.contains("h3", "Done").click(); + returnToOverview(); cy.get('[data-cy="show-filter-button"]').click(); cy.contains("h6", "Location").click(); cy.get('[data-cy="spatial-reference-filter"]').should("exist"); @@ -27,7 +27,7 @@ describe("Tests for filtering data by reference system.", () => { cy.get("@checkbox").uncheck({ force: true }); cy.get("@checkbox").should("not.be.checked"); - cy.contains("h3", "Done").click(); + returnToOverview(); cy.get('[data-cy="show-filter-button"]').click(); cy.contains("h6", "Location").click(); cy.get('[data-cy="spatial-reference-filter"]').should("not.exist"); diff --git a/src/client/cypress/e2e/mainPage/map.cy.js b/src/client/cypress/e2e/mainPage/map.cy.js index 7e5a42d4d..ecbd37298 100644 --- a/src/client/cypress/e2e/mainPage/map.cy.js +++ b/src/client/cypress/e2e/mainPage/map.cy.js @@ -1,4 +1,4 @@ -import { loginAsEditor } from "../helpers/testHelpers.js"; +import { loginAsEditor, returnToOverview } from "../helpers/testHelpers.js"; describe("Map tests", () => { it("map preserves zoom level and center", () => { @@ -28,7 +28,7 @@ describe("Map tests", () => { cy.get('[data-cy="settings-button"]').click(); // return to map - cy.contains("h3", "Done").click(); + returnToOverview(); // verify resolution and map center cy.window().then(win => { diff --git a/src/client/cypress/e2e/settings/fieldSettings.cy.js b/src/client/cypress/e2e/settings/fieldSettings.cy.js new file mode 100644 index 000000000..87c02e26f --- /dev/null +++ b/src/client/cypress/e2e/settings/fieldSettings.cy.js @@ -0,0 +1,99 @@ +import { goToRouteAndAcceptTerms, loginAsAdmin, returnToOverview } from "../helpers/testHelpers"; + +it("checks that the field settings control the field visibility.", () => { + loginAsAdmin("/"); + + const waitForSettings = () => { + cy.wait(["@setting", "@codes", "@codelist_GET"]); + }; + cy.get('[data-cy="settings-button"]').click(); + cy.contains("Lithology fields").click(); + cy.contains("Select all").click(); + cy.wait("@setting"); + waitForSettings(); + + goToRouteAndAcceptTerms("/1001140/stratigraphy/lithology"); + cy.get('[data-cy="styled-layer-9"]').click(); + cy.contains("From depth [m MD]").should("exist"); + cy.contains("To depth [m MD]").should("exist"); + cy.contains("End of borehole").should("exist"); + cy.contains("Completeness of entries").should("exist"); + cy.contains("Lithology").should("exist"); + cy.contains("Original lithology").should("exist"); + cy.contains("USCS original classification").should("exist"); + cy.contains("USCS way of determination").should("exist"); + cy.contains("USCS 1").should("exist"); + cy.contains("Grain size 1").should("exist"); + cy.contains("USCS 2").should("exist"); + cy.contains("Grain size 2").should("exist"); + cy.contains("USCS 3").should("exist"); + cy.contains("Grain shape").should("exist"); + cy.contains("Grain angularity").should("exist"); + cy.contains("Organic components").should("exist"); + cy.contains("Debris").should("exist"); + cy.contains("Debris lithology").should("exist"); + cy.contains("Striations").should("exist"); + cy.contains("Colour").should("exist"); + cy.contains("Consistency").should("exist"); + cy.contains("Plasticity").should("exist"); + cy.contains("Compactness").should("exist"); + cy.contains("Cohesion").should("exist"); + cy.contains("Gradation").should("exist"); + cy.contains("Humidity").should("exist"); + cy.contains("Alteration").should("exist"); + cy.contains("Notes").should("exist"); + + returnToOverview(); + cy.get('[data-cy="settings-button"]').click(); + cy.contains("Lithology fields").click(); + cy.contains("Unselect all").click(); + waitForSettings(); + + goToRouteAndAcceptTerms("/1001140/stratigraphy/lithology"); + cy.get('[data-cy="styled-layer-9"]').click(); + cy.contains("From depth [m MD]").should("exist"); + cy.contains("To depth [m MD]").should("exist"); + cy.contains("End of borehole").should("not.exist"); + cy.contains("Completeness of entries").should("not.exist"); + cy.contains("Original lithology").should("not.exist"); + cy.contains("USCS original classification").should("not.exist"); + cy.contains("USCS way of determination").should("not.exist"); + cy.contains("USCS 1").should("not.exist"); + cy.contains("Grain size 1").should("not.exist"); + cy.contains("USCS 2").should("not.exist"); + cy.contains("Grain size 2").should("not.exist"); + cy.contains("USCS 3").should("not.exist"); + cy.contains("Grain shape").should("not.exist"); + cy.contains("Grain angularity").should("not.exist"); + cy.contains("Organic components").should("not.exist"); + cy.contains("Debris").should("not.exist"); + cy.contains("Debris lithology").should("not.exist"); + cy.contains("Colour").should("not.exist"); + cy.contains("Consistency").should("not.exist"); + cy.contains("Plasticity").should("not.exist"); + cy.contains("Compactness").should("not.exist"); + cy.contains("Cohesion").should("not.exist"); + cy.contains("Gradation").should("not.exist"); + cy.contains("Humidity").should("not.exist"); + cy.contains("Alteration").should("not.exist"); + cy.contains("Notes").should("not.exist"); + + returnToOverview(); + cy.get('[data-cy="settings-button"]').click(); + cy.contains("Lithology fields").click(); + waitForSettings(); + cy.wait(500); + + // manually check some and verify states + cy.get('[data-cy="checkbox-original_lithology"]').click(); + cy.get('[data-cy="checkbox-plasticity"]').click(); + cy.get('[data-cy="checkbox-uscs_1"]').click(); + cy.get('[data-cy="checkbox-plasticity"] input').should("be.checked"); + cy.get('[data-cy="checkbox-original_lithology"] input').should("be.checked"); + cy.get('[data-cy="checkbox-uscs_1"] input').should("be.checked"); + + cy.get('[data-cy="checkbox-humidity"] input').should("not.be.checked"); + cy.get('[data-cy="checkbox-gradation"] input').should("not.be.checked"); + cy.get('[data-cy="checkbox-cohesion"] input').should("not.be.checked"); + cy.get('[data-cy="checkbox-compactness"] input').should("not.be.checked"); +}); diff --git a/src/client/cypress/e2e/settings/mapSettings.cy.js b/src/client/cypress/e2e/settings/mapSettings.cy.js index a6bbc7b61..2a5df0db0 100644 --- a/src/client/cypress/e2e/settings/mapSettings.cy.js +++ b/src/client/cypress/e2e/settings/mapSettings.cy.js @@ -1,4 +1,4 @@ -import { goToRouteAndAcceptTerms } from "../helpers/testHelpers.js"; +import { goToRouteAndAcceptTerms, returnToOverview } from "../helpers/testHelpers.js"; describe("map settings", () => { it("Adds wms and wmts to user maps", () => { @@ -28,7 +28,7 @@ describe("map settings", () => { cy.get('[data-cy="maps-for-user-box"]').contains(wmtsName); // Verify layers are added to overview map - cy.contains("h3", "Done").click(); + returnToOverview(); cy.get('[data-cy="layers-button"]').click(); cy.contains(wmsName); cy.contains(wmtsName); diff --git a/src/client/src/components/buttons/buttons.tsx b/src/client/src/components/buttons/buttons.tsx index 14a9bda49..7d2eaf770 100644 --- a/src/client/src/components/buttons/buttons.tsx +++ b/src/client/src/components/buttons/buttons.tsx @@ -1,8 +1,8 @@ import { forwardRef } from "react"; import { useTranslation } from "react-i18next"; import CloseIcon from "@mui/icons-material/Close"; -import { Button } from "@mui/material"; -import { ArrowDownToLine, Check, Pencil, Plus, Save, Trash2 } from "lucide-react"; +import { Button, IconButton } from "@mui/material"; +import { ArrowDownToLine, Check, ChevronLeft, Pencil, Plus, Save, Trash2 } from "lucide-react"; import CopyIcon from "../../assets/icons/copy.svg?react"; import { capitalizeFirstLetter } from "../../utils.ts"; import { ButtonProps } from "./buttonsInterface"; @@ -131,3 +131,20 @@ export const ExportButton = forwardRef((props, r /> ); }); + +export const ReturnButton = ({ onClick }: { onClick: () => void }) => { + return ( + + + + ); +}; diff --git a/src/client/src/components/legacyComponents/listItem/listItem.jsx b/src/client/src/components/legacyComponents/listItem/listItem.jsx index f10245d70..1b7bff9c6 100644 --- a/src/client/src/components/legacyComponents/listItem/listItem.jsx +++ b/src/client/src/components/legacyComponents/listItem/listItem.jsx @@ -14,8 +14,7 @@ const ListItem = props => { style={{ padding: "1em", borderRadius: "inherit", - borderLeft: - location.pathname.indexOf(path) >= 0 && name !== "done" ? "0.25em solid rgb(237, 29, 36)" : null, + borderLeft: location.pathname.indexOf(path) >= 0 ? "0.25em solid rgb(237, 29, 36)" : null, }}> diff --git a/src/client/src/components/styledComponents.ts b/src/client/src/components/styledComponents.ts index 3aa1c9bac..5a9c97fa0 100644 --- a/src/client/src/components/styledComponents.ts +++ b/src/client/src/components/styledComponents.ts @@ -63,3 +63,9 @@ export const DialogFooterContainer = styled(Box)({ borderTop: "1px solid " + theme.palette.border, padding: theme.spacing(3), }); + +export const DetailHeaderStack = styled(Stack)({ + borderBottom: "1px solid " + theme.palette.boxShadow, + height: "84px", + padding: "16px", +}); diff --git a/src/client/src/pages/detail/detailHeader.tsx b/src/client/src/pages/detail/detailHeader.tsx index ea654d3ca..80f02a000 100644 --- a/src/client/src/pages/detail/detailHeader.tsx +++ b/src/client/src/pages/detail/detailHeader.tsx @@ -2,15 +2,21 @@ import { useContext } from "react"; import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; import { useHistory } from "react-router-dom"; -import { Chip, IconButton, Stack, Typography } from "@mui/material"; -import { Check, ChevronLeft, Trash2, X } from "lucide-react"; +import { Chip, Stack, Typography } from "@mui/material"; +import { Check, Trash2, X } from "lucide-react"; import { deleteBorehole, lockBorehole, unlockBorehole } from "../../api-lib"; import { BoreholeV2 } from "../../api/borehole.ts"; -import { theme } from "../../AppTheme.ts"; import { useAuth } from "../../auth/useBdmsAuth.tsx"; -import { DeleteButton, EditButton, EndEditButton, ExportButton } from "../../components/buttons/buttons.tsx"; +import { + DeleteButton, + EditButton, + EndEditButton, + ExportButton, + ReturnButton, +} from "../../components/buttons/buttons.tsx"; import DateText from "../../components/legacyComponents/dateText"; import { PromptContext } from "../../components/prompt/promptContext.tsx"; +import { DetailHeaderStack } from "../../components/styledComponents.ts"; interface DetailHeaderProps { editingEnabled: boolean; @@ -93,32 +99,16 @@ const DetailHeader = ({ }; return ( - + - { { editingEnabled && (isFormDirty ? stopEditingWithUnsavedChanges() : stopEditing()); history.push("/"); } }} - sx={{ - width: "36px", - height: "36px", - marginRight: "18px", - borderRadius: "2px", - }}> - - + /> {borehole?.alternateName} {!auth.anonymousModeEnabled && ( @@ -165,7 +155,7 @@ const DetailHeader = ({ ))} - + ); }; diff --git a/src/client/src/pages/detail/detailHeaderSettings.tsx b/src/client/src/pages/detail/detailHeaderSettings.tsx new file mode 100644 index 000000000..03e233bcf --- /dev/null +++ b/src/client/src/pages/detail/detailHeaderSettings.tsx @@ -0,0 +1,20 @@ +import { useHistory } from "react-router-dom"; +import { Stack } from "@mui/material"; +import { ReturnButton } from "../../components/buttons/buttons.tsx"; +import { DetailHeaderStack } from "../../components/styledComponents.ts"; + +export const DetailHeaderSettings = () => { + const history = useHistory(); + + return ( + + + { + history.push("/"); + }} + /> + + + ); +}; diff --git a/src/client/src/pages/settings/components/editorSettingList/editorSettingList.jsx b/src/client/src/pages/settings/components/editorSettingList/editorSettingList.jsx index 9846c2c98..639a2228f 100644 --- a/src/client/src/pages/settings/components/editorSettingList/editorSettingList.jsx +++ b/src/client/src/pages/settings/components/editorSettingList/editorSettingList.jsx @@ -1,34 +1,36 @@ +import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { Button } from "@mui/material"; +import { Button, Checkbox } from "@mui/material"; import { Segment } from "semantic-ui-react"; -import _ from "lodash"; import TranslationText from "../../../../components/legacyComponents/translationText.jsx"; import * as Styled from "./styles"; const EditorSettingList = props => { const { data, toggleFilter, attribute, toggleField, listName, codes, toggleFieldArray, toggleFilterArray } = props; - const { t } = useTranslation(); + const [checkedStates, setCheckedStates] = useState({}); - const isChecked = item => { - return listName === "lithologyfields" - ? isVisible(item.value) - : item.value.split(".").length > 1 - ? data?.[item.value.split(".")[0]]?.[item.value.split(".")[1]] - : data?.[item.value]; - }; - const isVisible = field => { - if (_.has(codes, "data.layer_kind") && _.isArray(codes.data.layer_kind)) { - for (let idx = 0; idx < codes.data.layer_kind.length; idx++) { - const element = codes.data.layer_kind[idx]; + useEffect(() => { + const isChecked = item => { + const isVisible = field => { + const layerKindConfigEntry = codes?.find(c => c.schema === "layer_kind"); - if (element.code === "Geol") { - return element.conf.fields[field]; - } - } - } - return false; - }; + const conf = layerKindConfigEntry?.conf ? JSON.parse(layerKindConfigEntry?.conf) : ""; + return conf?.fields?.[field] ?? false; + }; + return listName === "lithologyfields" + ? isVisible(item.value) + : item.value.split(".").length > 1 + ? data?.[item.value.split(".")[0]]?.[item.value.split(".")[1]] + : data?.[item.value]; + }; + + const initialState = {}; + attribute.forEach(item => { + initialState[item.value] = isChecked(item); + }); + setCheckedStates(initialState); + }, [attribute, codes, data, listName]); const sendSelectAll = value => { const newData = []; @@ -39,12 +41,35 @@ const EditorSettingList = props => { if (listName === "lithologyfields") { toggleFieldArray(newData, value); } else toggleFilterArray(newData, value); + + setCheckedStates(prevState => { + const newState = { ...prevState }; + attribute.forEach(item => { + newState[item.value] = value; + }); + return newState; + }); }; + + const handleCheckboxChange = (item, value) => { + setCheckedStates(prevState => ({ + ...prevState, + [item.value]: value, + })); + + if (listName === "lithologyfields") { + toggleField(item.value, value); + } else { + toggleFilter(item.value, value); + } + }; + return (