diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd4ab568..861de5c53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - No scrollbar was displayed in the side drawer when many additional layers were added. - There was no appropriate error message when the drawn box did not contain extractable coordinates. - The responsive design of the coordinate segment in the detail view was broken. +- When clicking the select all checkbox in the borehole table, only the boreholes on the current page were selected. ## v2.1.870 - 2024-09-27 diff --git a/src/api-legacy/v1/borehole/editinglist.py b/src/api-legacy/v1/borehole/editinglist.py index 58720d0cd..86832effa 100644 --- a/src/api-legacy/v1/borehole/editinglist.py +++ b/src/api-legacy/v1/borehole/editinglist.py @@ -26,15 +26,6 @@ async def execute( where, params = self.filterBorehole(filter) - if limit is not None and page is not None: - paging = """ - LIMIT %s - OFFSET %s - """ % (self.getIdx(), self.getIdx()) - params += [ - limit, (int(limit) * (int(page) - 1)) - ] - rowsSql = f""" SELECT borehole.id_bho as id, @@ -446,11 +437,17 @@ async def execute( rec = await self.conn.fetchrow( sql, *(layer_params + chronostratigraphy_params + lithostratigraphy_params + params) ) + + data = self.decode(rec[0]) if rec[0] is not None else [] + offset = (page - 1) * limit if page is not None and limit is not None else 0 + paginated_data = data[offset:offset + limit] if limit is not None else data + borehole_ids = [borehole['id'] for borehole in data if borehole.get('lock') is None] return { - "data": self.decode(rec[0]) if rec[0] is not None else [], + "data": paginated_data, "orderby": orderby, "direction": direction, "page": page if page is not None else 1, "pages": math.ceil(rec[1]/limit) if limit is not None else 1, - "rows": rec[1] + "rows": rec[1], + "filtered_borehole_ids": borehole_ids, } diff --git a/src/client/cypress/e2e/helpers/dataGridHelpers.js b/src/client/cypress/e2e/helpers/dataGridHelpers.js index 14654134d..81474aa6b 100644 --- a/src/client/cypress/e2e/helpers/dataGridHelpers.js +++ b/src/client/cypress/e2e/helpers/dataGridHelpers.js @@ -35,6 +35,10 @@ export const checkRowWithText = text => { cy.contains(".MuiDataGrid-row", text).find('.MuiCheckbox-root input[type="checkbox"]').check({ force: true }); }; +export const unCheckRowWithText = text => { + cy.contains(".MuiDataGrid-row", text).find('.MuiCheckbox-root input[type="checkbox"]').uncheck({ force: true }); +}; + export const clickOnRowWithText = text => { cy.contains(".MuiDataGrid-row", text).click(); }; diff --git a/src/client/cypress/e2e/mainPage/boreholeTable.cy.js b/src/client/cypress/e2e/mainPage/boreholeTable.cy.js index 88c3fa75c..8c6540a79 100644 --- a/src/client/cypress/e2e/mainPage/boreholeTable.cy.js +++ b/src/client/cypress/e2e/mainPage/boreholeTable.cy.js @@ -2,6 +2,7 @@ import { clickOnRowWithText, showTableAndWaitForData, sortBy, + unCheckRowWithText, verifyPaginationText, verifyRowContains, waitForTableData, @@ -77,4 +78,39 @@ describe("Borehole editor table tests", () => { verifyPaginationText("401–500 of 1626"); verifyRowContains("Nichole VonRueden", 0); }); + + it("verifies all rows are selected on header checkbox click", () => { + loginAsAdmin(); + cy.get('[data-cy="boreholes-number-preview"]').should("have.text", "1'626"); + showTableAndWaitForData(); + cy.get('[data-cy="boreholes-number-preview"]').should("have.text", "1'626"); + + // check all rows + cy.get('[data-cy="table-header-checkbox"]').click(); + cy.contains("1'626").should("not.exist"); + cy.contains("1478 selected").should("be.visible"); // does not select locked rows + + // uncheck one row + unCheckRowWithText("Aaliyah Casper"); + cy.contains("1477 selected").should("be.visible"); + + // uncheck all rows + cy.get('[data-cy="table-header-checkbox"]').click(); + cy.get('[data-cy="boreholes-number-preview"]').should("have.text", "1'626"); + + // verify select all rows with filtered data + cy.get('[data-cy="show-filter-button"]').click(); + cy.contains("Registration").click(); + cy.contains("Show all fields").children(".checkbox").click(); + + // input value + cy.contains("Created by").next().find("input").type("v_ U%r"); + cy.wait("@edit_list"); + verifyPaginationText("1–100 of 329"); + + // check all rows + cy.get('[data-cy="table-header-checkbox"]').click(); + cy.contains("1'626").should("not.exist"); + cy.contains("298 selected").should("be.visible"); // does not select locked rows + }); }); diff --git a/src/client/src/api-lib/ReduxStateInterfaces.ts b/src/client/src/api-lib/ReduxStateInterfaces.ts index bd85927f5..08520075a 100644 --- a/src/client/src/api-lib/ReduxStateInterfaces.ts +++ b/src/client/src/api-lib/ReduxStateInterfaces.ts @@ -1,3 +1,4 @@ +import { GridRowSelectionModel } from "@mui/x-data-grid"; import { ReferenceSystemCode } from "../pages/detail/form/location/coordinateSegmentInterfaces.ts"; export interface ReduxRootState { @@ -119,6 +120,7 @@ export interface BoreholeAttributes { } export interface Boreholes { + filtered_borehole_ids: GridRowSelectionModel; limit: number; isFetching: boolean; length: number; diff --git a/src/client/src/api-lib/reducers/index.js b/src/client/src/api-lib/reducers/index.js index eec7111ae..3ce6449af 100644 --- a/src/client/src/api-lib/reducers/index.js +++ b/src/client/src/api-lib/reducers/index.js @@ -601,6 +601,7 @@ export function boreholeEditorList() { isFetching: false, fetchTime: new Date().getTime() - state.fetchTime, data: action.json.data, + filtered_borehole_ids: action.json.filtered_borehole_ids, // eslint-disable-next-line no-prototype-builtins pages: action.json.hasOwnProperty("pages") ? action.json.pages : null, page: Object.prototype.hasOwnProperty.call(action.json, "page") ? action.json.page : null, diff --git a/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts b/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts index 1305cfdd4..e7299dae1 100644 --- a/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts +++ b/src/client/src/components/legacyComponents/bulkedit/BulkEditFormProps.ts @@ -1,7 +1,8 @@ +import { GridRowSelectionModel } from "@mui/x-data-grid"; import { FormValueType } from "../../form/form.ts"; export interface BulkEditFormProps { - selected: number[]; + selected: GridRowSelectionModel; loadBoreholes: () => void; } diff --git a/src/client/src/pages/overview/boreholeTable/boreholeTable.tsx b/src/client/src/pages/overview/boreholeTable/boreholeTable.tsx index 45daf8e8f..a395ae125 100644 --- a/src/client/src/pages/overview/boreholeTable/boreholeTable.tsx +++ b/src/client/src/pages/overview/boreholeTable/boreholeTable.tsx @@ -5,8 +5,11 @@ import { useHistory } from "react-router-dom"; import { Box } from "@mui/system"; import { DataGrid, + GridCellCheckboxRenderer, GridColDef, + GridColumnHeaderParams, GridEventListener, + GridHeaderCheckbox, GridPaginationModel, GridRowParams, GridRowSelectionModel, @@ -68,7 +71,45 @@ export const BoreholeTable: FC = ({ return rowCountRef.current; }, [boreholes?.length]); + const renderHeaderCheckbox = useMemo(() => { + return (params: GridColumnHeaderParams) => { + const handleHeaderCheckboxClick = (event: React.ChangeEvent) => { + if (event.target.checked) { + setSelectionModel(boreholes.filtered_borehole_ids); + } else { + setSelectionModel([]); + } + }; + + return ( + + ); + }; + }, [boreholes.filtered_borehole_ids, setSelectionModel]); + const columns: GridColDef[] = [ + { + field: "__check__", + width: 10, + resizable: false, + sortable: false, + filterable: false, + disableColumnMenu: true, + disableReorder: true, + disableExport: true, + renderHeader: renderHeaderCheckbox, + renderCell: params => ( + + + + ), + }, { field: "alternate_name", headerName: t("name"), flex: 1 }, { field: "borehole_type", @@ -130,6 +171,12 @@ export const BoreholeTable: FC = ({ field: "lock", headerName: "", width: 20, + resizable: false, + sortable: false, + filterable: false, + disableColumnMenu: true, + disableReorder: true, + disableExport: true, renderCell: value => { if (value.row.lock) { return ( @@ -144,7 +191,7 @@ export const BoreholeTable: FC = ({ // Add workgroup column if not in anonymous mode !auth.anonymousModeEnabled && - columns.splice(1, 0, { + columns.splice(2, 0, { field: "workgroup", valueGetter: (value: { name: string }) => { return value.name; diff --git a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx index 0ade70b15..663164872 100644 --- a/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx +++ b/src/client/src/pages/overview/boreholeTable/bottomBarContainer.tsx @@ -25,6 +25,8 @@ interface BottomBarContainerProps { ) => void; multipleSelected: (selection: GridRowSelectionModel, filter: string) => void; rowToHighlight: number | null; + selectionModel: GridRowSelectionModel; + setSelectionModel: React.Dispatch>; } const BottomBarContainer = ({ @@ -34,6 +36,8 @@ const BottomBarContainer = ({ search, setHover, rowToHighlight, + selectionModel, + setSelectionModel, }: BottomBarContainerProps) => { const user: User = useSelector((state: ReduxRootState) => state.core_user); const history = useHistory(); @@ -45,7 +49,6 @@ const BottomBarContainer = ({ pageSize: boreholes.limit ?? 100, page: boreholes.page ? boreholes.page - 1 : 0, // MUI pagination starts at 0, whereas server pagination starts at 1 }); - const [selectionModel, setSelectionModel] = useState([]); const [sortModel, setSortModel] = useState([ { field: boreholes.orderby ?? "alternate_name", diff --git a/src/client/src/pages/overview/layout/mapView.tsx b/src/client/src/pages/overview/layout/mapView.tsx index 6ced7a2fe..8cdffa3b5 100644 --- a/src/client/src/pages/overview/layout/mapView.tsx +++ b/src/client/src/pages/overview/layout/mapView.tsx @@ -18,6 +18,7 @@ interface MapViewProps { export const MapView = ({ displayErrorMessage }: MapViewProps) => { const [hover, setHover] = useState(null); const [rowToHighlight, setRowToHighlight] = useState(null); + const [selectionModel, setSelectionModel] = useState([]); const history = useHistory(); const { filterPolygon, @@ -93,7 +94,7 @@ export const MapView = ({ displayErrorMessage }: MapViewProps) => { featureIds, ); }} - selected={editorStore.mselected} + selected={selectionModel} /> { loadEditingBoreholes={loadBoreholes} multipleSelected={multipleSelected} search={search} + selectionModel={selectionModel} + setSelectionModel={setSelectionModel} rowToHighlight={rowToHighlight} setHover={setHover} />