From 4eb564d1715e870ef9363474ddf4adae1a54c4e3 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Mon, 16 Dec 2024 17:29:42 +0100 Subject: [PATCH 1/7] Adapt export UI --- .../cypress/e2e/detailPage/boreholeform.cy.js | 4 +- .../cypress/e2e/helpers/buttonHelpers.js | 9 + src/client/cypress/e2e/mainPage/export.cy.js | 12 +- .../bulkedit/BulkEditFormProps.ts | 3 +- .../bulkEditDialog.tsx} | 165 ++++++++++-------- .../src/components/export/exportDialog.tsx | 50 ++++++ src/client/src/pages/detail/detailHeader.tsx | 29 ++- .../overview/boreholeTable/bottomBar.tsx | 35 +++- .../boreholeTable/bottomBarContainer.tsx | 48 +---- .../src/pages/overview/layout/mapView.tsx | 52 +++--- 10 files changed, 230 insertions(+), 177 deletions(-) rename src/client/src/components/{legacyComponents => }/bulkedit/BulkEditFormProps.ts (84%) rename src/client/src/components/{legacyComponents/bulkedit/bulkEditForm.tsx => bulkedit/bulkEditDialog.tsx} (63%) create mode 100644 src/client/src/components/export/exportDialog.tsx diff --git a/src/client/cypress/e2e/detailPage/boreholeform.cy.js b/src/client/cypress/e2e/detailPage/boreholeform.cy.js index 0c9ef7cba..3bb360f74 100644 --- a/src/client/cypress/e2e/detailPage/boreholeform.cy.js +++ b/src/client/cypress/e2e/detailPage/boreholeform.cy.js @@ -1,4 +1,4 @@ -import { exportCSVItem, exportJsonItem, saveWithSaveBar } from "../helpers/buttonHelpers"; +import { exportCSVItem, exportItem, exportJsonItem, saveWithSaveBar } from "../helpers/buttonHelpers"; import { clickOnRowWithText, showTableAndWaitForData, sortBy } from "../helpers/dataGridHelpers"; import { evaluateInput, evaluateSelect, isDisabled, setInput, setSelect } from "../helpers/formHelpers"; import { @@ -248,7 +248,9 @@ describe("Test for the borehole form.", () => { cy.get("@borehole_id").then(id => { goToRouteAndAcceptTerms(`/${id}`); ensureEditingDisabled(); + exportItem(); exportJsonItem(); + exportItem(); exportCSVItem(); }); diff --git a/src/client/cypress/e2e/helpers/buttonHelpers.js b/src/client/cypress/e2e/helpers/buttonHelpers.js index 28e4b1247..28185f4ba 100644 --- a/src/client/cypress/e2e/helpers/buttonHelpers.js +++ b/src/client/cypress/e2e/helpers/buttonHelpers.js @@ -59,6 +59,15 @@ export const deleteItem = parent => { cy.get(selector).click({ force: true }); }; +/** + * Clicks on the Export button. + */ +export const exportItem = () => { + const selector = '[data-cy="export-button"]'; + cy.get(selector).should("not.be.disabled"); + cy.get(selector).click({ force: true }); +}; + /** * Clicks on the JSON-export button. */ diff --git a/src/client/cypress/e2e/mainPage/export.cy.js b/src/client/cypress/e2e/mainPage/export.cy.js index 5be5dcddb..c40c94344 100644 --- a/src/client/cypress/e2e/mainPage/export.cy.js +++ b/src/client/cypress/e2e/mainPage/export.cy.js @@ -1,4 +1,4 @@ -import { exportCSVItem, exportJsonItem } from "../helpers/buttonHelpers"; +import { exportCSVItem, exportItem, exportJsonItem } from "../helpers/buttonHelpers"; import { checkAllVisibleRows, checkRowWithText, showTableAndWaitForData } from "../helpers/dataGridHelpers.js"; import { createBorehole, @@ -29,7 +29,9 @@ describe("Test for exporting boreholes.", () => { deleteDownloadedFile(jsonFileName); deleteDownloadedFile(csvFileName); + exportItem(); exportJsonItem(); + exportItem(); exportCSVItem(); readDownloadedFile(jsonFileName); readDownloadedFile(csvFileName); @@ -40,14 +42,14 @@ describe("Test for exporting boreholes.", () => { showTableAndWaitForData(); checkAllVisibleRows(); deleteDownloadedFile(csvFileName); - exportCSVItem(); + exportItem(); const moreThan100SelectedPrompt = "You have selected more than 100 boreholes and a maximum of 100 boreholes can be exported. Do you want to continue?"; handlePrompt(moreThan100SelectedPrompt, "Cancel"); - cy.get("@borehole_export_csv").should("not.exist"); - exportCSVItem(); + exportItem(); handlePrompt(moreThan100SelectedPrompt, "Export 100 boreholes"); + exportCSVItem(); cy.wait("@borehole_export_csv").its("response.statusCode").should("eq", 200); readDownloadedFile(csvFileName); @@ -58,7 +60,5 @@ describe("Test for exporting boreholes.", () => { }); deleteDownloadedFile(jsonFileName); - exportJsonItem(); - handlePrompt(moreThan100SelectedPrompt, "Cancel"); }); }); diff --git a/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts b/src/client/src/components/bulkedit/BulkEditFormProps.ts similarity index 84% rename from src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts rename to src/client/src/components/bulkedit/BulkEditFormProps.ts index e7299dae1..d8bf948ab 100644 --- a/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts +++ b/src/client/src/components/bulkedit/BulkEditFormProps.ts @@ -1,9 +1,10 @@ import { GridRowSelectionModel } from "@mui/x-data-grid"; -import { FormValueType } from "../../form/form.ts"; +import { FormValueType } from "../form/form.ts"; export interface BulkEditFormProps { selected: GridRowSelectionModel; loadBoreholes: () => void; + isOpen: boolean; } export type BulkEditFormValue = string | number | boolean | undefined | null; diff --git a/src/client/src/components/legacyComponents/bulkedit/bulkEditForm.tsx b/src/client/src/components/bulkedit/bulkEditDialog.tsx similarity index 63% rename from src/client/src/components/legacyComponents/bulkedit/bulkEditForm.tsx rename to src/client/src/components/bulkedit/bulkEditDialog.tsx index a1109f6fe..6dac51530 100644 --- a/src/client/src/components/legacyComponents/bulkedit/bulkEditForm.tsx +++ b/src/client/src/components/bulkedit/bulkEditDialog.tsx @@ -7,6 +7,7 @@ import { AccordionDetails, AccordionSummary, Box, + Dialog, DialogActions, DialogContent, DialogTitle, @@ -15,20 +16,20 @@ import { Typography, } from "@mui/material"; import { ChevronDownIcon, RotateCcw } from "lucide-react"; -import { patchBoreholes } from "../../../api-lib"; -import { ReduxRootState, User } from "../../../api-lib/ReduxStateInterfaces.ts"; -import { theme } from "../../../AppTheme.ts"; -import WorkgroupSelect from "../../../pages/overview/sidePanelContent/commons/workgroupSelect.tsx"; -import { AlertContext } from "../../alert/alertContext.tsx"; -import { CancelButton, SaveButton } from "../../buttons/buttons"; -import { FormValueType } from "../../form/form.ts"; -import { FormBooleanSelect } from "../../form/formBooleanSelect.tsx"; -import { FormDomainSelect } from "../../form/formDomainSelect.tsx"; -import { FormInput } from "../../form/formInput.tsx"; -import { StackFullWidth } from "../../styledComponents.ts"; +import { patchBoreholes } from "../../api-lib"; +import { ReduxRootState, User } from "../../api-lib/ReduxStateInterfaces.ts"; +import { theme } from "../../AppTheme.ts"; +import WorkgroupSelect from "../../pages/overview/sidePanelContent/commons/workgroupSelect.tsx"; +import { AlertContext } from "../alert/alertContext.tsx"; +import { CancelButton, SaveButton } from "../buttons/buttons.tsx"; +import { FormValueType } from "../form/form.ts"; +import { FormBooleanSelect } from "../form/formBooleanSelect.tsx"; +import { FormDomainSelect } from "../form/formDomainSelect.tsx"; +import { FormInput } from "../form/formInput.tsx"; +import { StackFullWidth } from "../styledComponents.ts"; import { BulkEditFormField, BulkEditFormProps, BulkEditFormValue } from "./BulkEditFormProps.ts"; -export const BulkEditForm = ({ selected, loadBoreholes }: BulkEditFormProps) => { +export const BulkEditDialog = ({ isOpen, selected, loadBoreholes }: BulkEditFormProps) => { const [fieldsToUpdate, setFieldsToUpdate] = useState>([]); const [workgroupId, setWorkgroupId] = useState(""); const { showAlert } = useContext(AlertContext); @@ -200,68 +201,82 @@ export const BulkEditForm = ({ selected, loadBoreholes }: BulkEditFormProps) => ); return ( - - - {t("bulkEditing")} - - - - - {bulkEditFormFields.map(field => { - if (field.type != FormValueType.Workgroup || enabledWorkgroups.length > 1) { - return ( - - } - sx={{ - pl: 1, - "& .MuiAccordionSummary-content": { - m: 0, - }, - }}> - - f[0]).includes(field.api ?? field.fieldName) - ? "visible" - : "hidden", - mr: 1, - }} - onClick={e => { - e.stopPropagation(); - undoChange(field); - }}> - - - - {t(field.fieldName)} - - - - - - <>{renderInput(field)} - - - - ); - } - })} - - - - - - - - - - + + + + {t("bulkEditing")} + + + + + {bulkEditFormFields.map(field => { + if (field.type != FormValueType.Workgroup || enabledWorkgroups.length > 1) { + return ( + + } + sx={{ + pl: 1, + "& .MuiAccordionSummary-content": { + m: 0, + }, + }}> + + f[0]).includes(field.api ?? field.fieldName) + ? "visible" + : "hidden", + mr: 1, + }} + onClick={e => { + e.stopPropagation(); + undoChange(field); + }}> + + + + {t(field.fieldName)} + + + + + + <>{renderInput(field)} + + + + ); + } + })} + + + + + + + + + + + ); }; diff --git a/src/client/src/components/export/exportDialog.tsx b/src/client/src/components/export/exportDialog.tsx new file mode 100644 index 000000000..bacac8e93 --- /dev/null +++ b/src/client/src/components/export/exportDialog.tsx @@ -0,0 +1,50 @@ +import { useTranslation } from "react-i18next"; +import { Dialog, DialogActions, DialogContent, DialogTitle, Stack, Typography } from "@mui/material"; +import { GridRowSelectionModel } from "@mui/x-data-grid"; +import { exportCSVBorehole, getAllBoreholes } from "../../api/borehole.ts"; +import { downloadData } from "../../utils.ts"; +import { CancelButton, ExportButton } from "../buttons/buttons.tsx"; + +interface ExportDialogProps { + isExporting: boolean; + setIsExporting: React.Dispatch>; + selectionModel: GridRowSelectionModel; + fileName: string; +} +export const ExportDialog = ({ isExporting, setIsExporting, selectionModel, fileName }: ExportDialogProps) => { + const { t } = useTranslation(); + + const exportJson = async () => { + const paginatedResponse = await getAllBoreholes(selectionModel, 1, selectionModel.length); + const jsonString = JSON.stringify(paginatedResponse.boreholes, null, 2); + downloadData(jsonString, `${fileName}.json`, "application/json"); + setIsExporting(false); + }; + + const exportCsv = async () => { + const csvData = await exportCSVBorehole(selectionModel.slice(0, 100)); + downloadData(csvData, `${fileName}.json`, "text/csv"); + setIsExporting(false); + }; + + return ( + + + + {t("export")} + + + + + + + + + + setIsExporting(false)} /> + + + + + ); +}; diff --git a/src/client/src/pages/detail/detailHeader.tsx b/src/client/src/pages/detail/detailHeader.tsx index 37bb99850..a9bff5d58 100644 --- a/src/client/src/pages/detail/detailHeader.tsx +++ b/src/client/src/pages/detail/detailHeader.tsx @@ -1,11 +1,11 @@ -import { useContext } from "react"; +import { useContext, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; import { useHistory } from "react-router-dom"; import { Chip, Stack, Typography } from "@mui/material"; import { Check, Trash2, X } from "lucide-react"; import { deleteBorehole, lockBorehole, unlockBorehole } from "../../api-lib"; -import { BoreholeV2, exportCSVBorehole } from "../../api/borehole.ts"; +import { BoreholeV2 } from "../../api/borehole.ts"; import { useAuth } from "../../auth/useBdmsAuth.tsx"; import { DeleteButton, @@ -14,10 +14,10 @@ import { ExportButton, ReturnButton, } from "../../components/buttons/buttons.tsx"; +import { ExportDialog } from "../../components/export/exportDialog.tsx"; import DateText from "../../components/legacyComponents/dateText"; import { PromptContext } from "../../components/prompt/promptContext.tsx"; import { DetailHeaderStack } from "../../components/styledComponents.ts"; -import { downloadData } from "../../utils.ts"; import { useFormDirty } from "./useFormDirty.tsx"; interface DetailHeaderProps { @@ -35,6 +35,7 @@ const DetailHeader = ({ triggerReset, borehole, }: DetailHeaderProps) => { + const [isExporting, setIsExporting] = useState(false); const history = useHistory(); const dispatch = useDispatch(); const { t } = useTranslation(); @@ -85,19 +86,6 @@ const DetailHeader = ({ history.push("/"); }; - const getFileName = (name: string) => { - return name.replace(/\s/g, "_"); - }; - const handleJsonExport = () => { - const jsonString = JSON.stringify([borehole], null, 2); - downloadData(jsonString, getFileName(borehole.name), "application/json"); - }; - - const handleCSVExport = async () => { - const csvData = await exportCSVBorehole([borehole.id]); - downloadData(csvData, getFileName(borehole.name), "text/csv"); - }; - return ( @@ -150,12 +138,17 @@ const DetailHeader = ({ ) : ( <> - - + setIsExporting(true)} /> ))} + ); }; diff --git a/src/client/src/pages/overview/boreholeTable/bottomBar.tsx b/src/client/src/pages/overview/boreholeTable/bottomBar.tsx index ab0e3bab9..7eaa896ff 100644 --- a/src/client/src/pages/overview/boreholeTable/bottomBar.tsx +++ b/src/client/src/pages/overview/boreholeTable/bottomBar.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; import { Box, Button, Stack, Typography } from "@mui/material"; import { GridRowSelectionModel } from "@mui/x-data-grid"; -import { ChevronDown, ChevronUp, Trash2 } from "lucide-react"; +import { ArrowDownToLine, ChevronDown, ChevronUp, Trash2 } from "lucide-react"; import CopyIcon from "../../../assets/icons/copy.svg?react"; import { Boreholes, ReduxRootState, User } from "../../../api-lib/ReduxStateInterfaces.ts"; import { theme } from "../../../AppTheme.ts"; @@ -20,10 +20,9 @@ interface BottomBarProps { search: { filter: string }; onDeleteMultiple: () => void; onCopyBorehole: () => void; - onExportMultipleJson: () => void; - onExportMultipleCsv: () => void; workgroup: string; setWorkgroup: React.Dispatch>; + setIsExporting: React.Dispatch>; } const BottomBar = ({ @@ -32,11 +31,10 @@ const BottomBar = ({ onDeleteMultiple, search, onCopyBorehole, - onExportMultipleJson, - onExportMultipleCsv, boreholes, workgroup, setWorkgroup, + setIsExporting, }: BottomBarProps) => { const { t } = useTranslation(); const { showPrompt, promptIsOpen } = useContext(PromptContext); @@ -83,6 +81,30 @@ const BottomBar = ({ multipleSelected(selectionModel, search.filter); } + const showPromptExportMoreThan100 = (callback: () => void) => { + showPrompt(t("bulkExportMoreThan100"), [ + { + label: t("cancel"), + }, + { + label: t("export100Boreholes"), + icon: , + variant: "contained", + action: callback, + }, + ]); + }; + + const onExportMultiple = async () => { + if (selectionModel.length > 100) { + showPromptExportMoreThan100(() => { + setIsExporting(true); + }); + } else { + setIsExporting(true); + } + }; + return ( showCopyPromptForSelectedWorkgroup()} /> )} - - + onExportMultiple()} /> {t("selectedCount", { count: selectionModel.length })} ) : ( diff --git a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx index b6c5989bd..ac05831b2 100644 --- a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx +++ b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx @@ -3,12 +3,10 @@ import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; import { useHistory } from "react-router-dom"; import { GridRowSelectionModel, GridSortDirection, GridSortModel } from "@mui/x-data-grid"; -import { ArrowDownToLine } from "lucide-react"; import { deleteBoreholes } from "../../../api-lib"; import { Boreholes, ReduxRootState, User } from "../../../api-lib/ReduxStateInterfaces.ts"; -import { copyBorehole, exportCSVBorehole, getAllBoreholes } from "../../../api/borehole.ts"; +import { copyBorehole } from "../../../api/borehole.ts"; import { PromptContext } from "../../../components/prompt/promptContext.tsx"; -import { downloadData } from "../../../utils.ts"; import { OverViewContext } from "../overViewContext.tsx"; import { FilterContext } from "../sidePanelContent/filter/filterContext.tsx"; import { BoreholeTable } from "./boreholeTable.tsx"; @@ -31,6 +29,7 @@ interface BottomBarContainerProps { rowToHighlight: number | null; selectionModel: GridRowSelectionModel; setSelectionModel: React.Dispatch>; + setIsExporting: React.Dispatch>; } const BottomBarContainer = ({ @@ -42,6 +41,7 @@ const BottomBarContainer = ({ rowToHighlight, selectionModel, setSelectionModel, + setIsExporting, }: BottomBarContainerProps) => { const user: User = useSelector((state: ReduxRootState) => state.core_user); const history = useHistory(); @@ -94,43 +94,6 @@ const BottomBarContainer = ({ setIsBusy(false); }; - const getBulkExportFilename = (suffix: string) => { - return `bulkexport_${new Date().toISOString().split("T")[0]}.${suffix}`; - }; - - const handleExportMultipleJson = async () => { - const paginatedResponse = await getAllBoreholes(selectionModel, 1, selectionModel.length); - const jsonString = JSON.stringify(paginatedResponse.boreholes, null, 2); - downloadData(jsonString, getBulkExportFilename("json"), "application/json"); - }; - - const handleExportMultipleCsv = async () => { - const csvData = await exportCSVBorehole(selectionModel.slice(0, 100)); - downloadData(csvData, getBulkExportFilename("csv"), "text/csv"); - }; - - const showPromptExportMoreThan100 = (callback: () => void) => { - showPrompt(t("bulkExportMoreThan100"), [ - { - label: t("cancel"), - }, - { - label: t("export100Boreholes"), - icon: , - variant: "contained", - action: callback, - }, - ]); - }; - - const onExportMultiple = async (callback: () => Promise) => { - if (selectionModel.length > 100) { - showPromptExportMoreThan100(callback); - } else { - await callback(); - } - }; - return ( <> onExportMultiple(handleExportMultipleJson)} - onExportMultipleCsv={() => onExportMultiple(handleExportMultipleCsv)} + // onExportMultipleJson={() => onExportMultiple(handleExportMultipleJson)} + // onExportMultipleCsv={() => onExportMultiple(handleExportMultipleCsv)} search={search} boreholes={boreholes} workgroup={workgroupId} setWorkgroup={setWorkgroupId} + setIsExporting={setIsExporting} /> { const [hover, setHover] = useState(null); const [rowToHighlight, setRowToHighlight] = useState(null); const [selectionModel, setSelectionModel] = useState([]); + const [isExporting, setIsExporting] = useState(false); const history = useHistory(); const { filterPolygon, @@ -73,30 +75,26 @@ export const MapView = ({ displayErrorMessage }: MapViewProps) => { sx={{ flex: "1 1.5 100%", }}> - - { - loadBoreholes( - boreholes.page, - boreholes.limit, - search.filter, - boreholes.orderby, - boreholes.direction, - featureIds, - ); - }} - selected={selectionModel} - /> - + { + loadBoreholes( + boreholes.page, + boreholes.limit, + search.filter, + boreholes.orderby, + boreholes.direction, + featureIds, + ); + }} + selected={selectionModel} + /> + { setFeatureIds={setFeatureIds} displayErrorMessage={displayErrorMessage} /> - { setSelectionModel={setSelectionModel} rowToHighlight={rowToHighlight} setHover={setHover} + setIsExporting={setIsExporting} /> ); From 2a70d99235ae1cda5db695e8442e9d9fcbb21905 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 17 Dec 2024 09:00:10 +0100 Subject: [PATCH 2/7] Remove unused variables --- .../src/pages/overview/boreholeTable/bottomBarContainer.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx index ac05831b2..a97a94cf1 100644 --- a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx +++ b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx @@ -1,12 +1,10 @@ import React, { useCallback, useContext, useLayoutEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; import { useSelector } from "react-redux"; import { useHistory } from "react-router-dom"; import { GridRowSelectionModel, GridSortDirection, GridSortModel } from "@mui/x-data-grid"; import { deleteBoreholes } from "../../../api-lib"; import { Boreholes, ReduxRootState, User } from "../../../api-lib/ReduxStateInterfaces.ts"; import { copyBorehole } from "../../../api/borehole.ts"; -import { PromptContext } from "../../../components/prompt/promptContext.tsx"; import { OverViewContext } from "../overViewContext.tsx"; import { FilterContext } from "../sidePanelContent/filter/filterContext.tsx"; import { BoreholeTable } from "./boreholeTable.tsx"; @@ -45,10 +43,8 @@ const BottomBarContainer = ({ }: BottomBarContainerProps) => { const user: User = useSelector((state: ReduxRootState) => state.core_user); const history = useHistory(); - const { t } = useTranslation(); const { featureIds } = useContext(FilterContext); const { bottomDrawerOpen } = useContext(OverViewContext); - const { showPrompt } = useContext(PromptContext); const [workgroupId, setWorkgroupId] = useState(user.data.workgroups[0]?.id); const [isBusy, setIsBusy] = useState(false); const [paginationModel, setPaginationModel] = useState({ From 1d9dd0fa5cb2f50772ea85270962736bf91c8d3d Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 17 Dec 2024 09:21:30 +0100 Subject: [PATCH 3/7] Add alert for unsaved changes --- src/client/public/locale/de/common.json | 1 + src/client/public/locale/en/common.json | 1 + src/client/public/locale/fr/common.json | 1 + src/client/public/locale/it/common.json | 1 + src/client/src/pages/detail/detailHeader.tsx | 80 +++++++++++++------- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/client/public/locale/de/common.json b/src/client/public/locale/de/common.json index 5fdf5edf9..cfa7a1987 100644 --- a/src/client/public/locale/de/common.json +++ b/src/client/public/locale/de/common.json @@ -307,6 +307,7 @@ "maxValue": "Maximalwert", "member": "Member", "messageDiscardUnsavedChanges": "Es gibt ungespeicherte Änderungen. Möchten Sie alle Änderungen verwerfen?", + "messageUnsavedChangesAtExport": "Es gibt ungespeicherte Änderungen. Möchten Sie das Bohrloch ohne Speichern exportieren?", "meter": "Meter", "minValue": "Minimalwert", "minute": "Minute", diff --git a/src/client/public/locale/en/common.json b/src/client/public/locale/en/common.json index 3185533fa..0b4161c45 100644 --- a/src/client/public/locale/en/common.json +++ b/src/client/public/locale/en/common.json @@ -307,6 +307,7 @@ "maxValue": "Maximum", "member": "Member", "messageDiscardUnsavedChanges": "There are unsaved changes. Do you want to discard all changes?", + "messageUnsavedChangesAtExport": "There are unsaved changes. Do you want to export the borehole without saving?", "meter": "Meter", "minValue": "Minimum", "minute": "minute", diff --git a/src/client/public/locale/fr/common.json b/src/client/public/locale/fr/common.json index e00675dcf..e81e7c5a5 100644 --- a/src/client/public/locale/fr/common.json +++ b/src/client/public/locale/fr/common.json @@ -307,6 +307,7 @@ "maxValue": "Valeur maximale", "member": "Membre", "messageDiscardUnsavedChanges": "Il y a des modifications non enregistrées. Voulez-vous annuler toutes les modifications?", + "messageUnsavedChangesAtExport": "Il y a des modifications non enregistrées. Voulez-vous exporter le forage sans enregistrer?", "meter": "Mètres", "minValue": "Valeur minimale", "minute": "minute", diff --git a/src/client/public/locale/it/common.json b/src/client/public/locale/it/common.json index 72e596fed..b3491680e 100644 --- a/src/client/public/locale/it/common.json +++ b/src/client/public/locale/it/common.json @@ -307,6 +307,7 @@ "maxValue": "Valore massimo", "member": "Membro", "messageDiscardUnsavedChanges": "Sono presenti modifiche non salvate. Si desidera annullare tutte le modifiche?", + "messageUnsavedChangesAtExport": "Ci sono modifiche non salvate. Si desidera esportare la perforazione senza salvare?", "meter": "Metri", "minValue": "Valore minimo", "minute": "minuto", diff --git a/src/client/src/pages/detail/detailHeader.tsx b/src/client/src/pages/detail/detailHeader.tsx index a9bff5d58..94d737316 100644 --- a/src/client/src/pages/detail/detailHeader.tsx +++ b/src/client/src/pages/detail/detailHeader.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; import { useHistory } from "react-router-dom"; import { Chip, Stack, Typography } from "@mui/material"; -import { Check, Trash2, X } from "lucide-react"; +import { ArrowDownToLine, Check, Trash2, X } from "lucide-react"; import { deleteBorehole, lockBorehole, unlockBorehole } from "../../api-lib"; import { BoreholeV2 } from "../../api/borehole.ts"; import { useAuth } from "../../auth/useBdmsAuth.tsx"; @@ -81,6 +81,22 @@ const DetailHeader = ({ ]); }; + const startExportWithUnsavedChanges = () => { + showPrompt(t("messageUnsavedChangesAtExport"), [ + { + label: t("cancel"), + icon: , + variant: "outlined", + }, + { + label: t("export"), + icon: , + variant: "contained", + action: () => setIsExporting(true), + }, + ]); + }; + const handleDelete = async () => { await deleteBorehole(borehole.id); history.push("/"); @@ -113,35 +129,41 @@ const DetailHeader = ({ /> - {editableByCurrentUser && - (editingEnabled ? ( - <> - - showPrompt(t("deleteBoreholesMessage", { count: 1 }), [ - { - label: t("cancel"), - }, - { - label: t("delete"), - icon: , - variant: "contained", - action: () => { - handleDelete(); + {editableByCurrentUser && ( + <> + setIsExporting(true)} + /> + {editingEnabled ? ( + <> + + showPrompt(t("deleteBoreholesMessage", { count: 1 }), [ + { + label: t("cancel"), + }, + { + label: t("delete"), + icon: , + variant: "contained", + action: () => { + handleDelete(); + }, }, - }, - ]) - } - /> - - - ) : ( - <> - setIsExporting(true)} /> - - - ))} + ]) + } + /> + + + ) : ( + <> + + + )} + + )} Date: Tue, 17 Dec 2024 09:47:40 +0100 Subject: [PATCH 4/7] Fix file export --- src/client/src/components/export/exportDialog.tsx | 2 +- src/client/src/pages/detail/detailHeader.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/src/components/export/exportDialog.tsx b/src/client/src/components/export/exportDialog.tsx index bacac8e93..d430ae885 100644 --- a/src/client/src/components/export/exportDialog.tsx +++ b/src/client/src/components/export/exportDialog.tsx @@ -23,7 +23,7 @@ export const ExportDialog = ({ isExporting, setIsExporting, selectionModel, file const exportCsv = async () => { const csvData = await exportCSVBorehole(selectionModel.slice(0, 100)); - downloadData(csvData, `${fileName}.json`, "text/csv"); + downloadData(csvData, `${fileName}.csv`, "text/csv"); setIsExporting(false); }; diff --git a/src/client/src/pages/detail/detailHeader.tsx b/src/client/src/pages/detail/detailHeader.tsx index 94d737316..96d6a63f2 100644 --- a/src/client/src/pages/detail/detailHeader.tsx +++ b/src/client/src/pages/detail/detailHeader.tsx @@ -169,7 +169,7 @@ const DetailHeader = ({ isExporting={isExporting} setIsExporting={setIsExporting} selectionModel={[borehole.id]} - fileName={borehole.name.replace(/\s/g, "_")} + fileName={borehole.name?.replace(/\s/g, "_") ?? "export"} /> ); From f15162a81c7d39e13817e2c7a21edb7c453d9d34 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 17 Dec 2024 10:06:22 +0100 Subject: [PATCH 5/7] Fix button selectors --- src/client/cypress/e2e/helpers/buttonHelpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/cypress/e2e/helpers/buttonHelpers.js b/src/client/cypress/e2e/helpers/buttonHelpers.js index 28185f4ba..61130f3b2 100644 --- a/src/client/cypress/e2e/helpers/buttonHelpers.js +++ b/src/client/cypress/e2e/helpers/buttonHelpers.js @@ -72,7 +72,7 @@ export const exportItem = () => { * Clicks on the JSON-export button. */ export const exportJsonItem = () => { - const selector = '[data-cy="exportjson-button"]'; + const selector = '[data-cy="json-button"]'; cy.get(selector).should("not.be.disabled"); cy.get(selector).click({ force: true }); }; @@ -81,7 +81,7 @@ export const exportJsonItem = () => { * Clicks on the CSV-export button. */ export const exportCSVItem = () => { - const selector = '[data-cy="exportcsv-button"]'; + const selector = '[data-cy="csv-button"]'; cy.get(selector).should("not.be.disabled"); cy.get(selector).click({ force: true }); }; From 8f32bff45d468482b863cf73ce853e1c7c3ee598 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 17 Dec 2024 10:47:55 +0100 Subject: [PATCH 6/7] Remove commented code --- .../src/pages/overview/boreholeTable/bottomBarContainer.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx index a97a94cf1..1dbb9c00c 100644 --- a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx +++ b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx @@ -97,8 +97,6 @@ const BottomBarContainer = ({ multipleSelected={multipleSelected} onCopyBorehole={onCopyBorehole} onDeleteMultiple={onDeleteMultiple} - // onExportMultipleJson={() => onExportMultiple(handleExportMultipleJson)} - // onExportMultipleCsv={() => onExportMultiple(handleExportMultipleCsv)} search={search} boreholes={boreholes} workgroup={workgroupId} From b2e08a6186e71cdc110aab4b124200b5aa2eefbc Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 17 Dec 2024 10:53:38 +0100 Subject: [PATCH 7/7] Remove redundant fragment --- src/client/src/pages/detail/detailHeader.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/client/src/pages/detail/detailHeader.tsx b/src/client/src/pages/detail/detailHeader.tsx index 96d6a63f2..4dfefaf24 100644 --- a/src/client/src/pages/detail/detailHeader.tsx +++ b/src/client/src/pages/detail/detailHeader.tsx @@ -158,9 +158,7 @@ const DetailHeader = ({ ) : ( - <> - - + )} )}