Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6449bea
feat(datagrid-web): add multipage selection to dg2
rahmanunver Sep 19, 2025
1e9406d
feat(datagrid-web): add untracked shared files, version bump, changel…
rahmanunver Sep 19, 2025
bfda763
test(datagrid-web): fix tests with new SelectActionHelper arguments
rahmanunver Sep 22, 2025
f7b8f43
feat(datagrid-web): refactor, remove duplicate logic, move new contro…
rahmanunver Sep 25, 2025
4b0f6c1
feat(datagrid-web): refactor shared packages
rahmanunver Sep 25, 2025
259d6ea
chore(datagrid-web): cleanup unused prop properties
rahmanunver Sep 26, 2025
f393da7
chore(datagrid-web): unused class properties
rahmanunver Sep 26, 2025
d6f049d
feat(datagrid-web): wip:refactor, MultiPageSelectionController
rahmanunver Sep 26, 2025
11e2297
refactor: change store logic and design
iobuhov Oct 2, 2025
6889997
chore: start controller integration
iobuhov Oct 3, 2025
04cfad2
feat: add select all host
iobuhov Oct 8, 2025
87001b9
refactor: minor fixes
iobuhov Oct 8, 2025
f6e81de
refactor: change getter to method
iobuhov Oct 8, 2025
fee08ff
feat: add execution time measurements
iobuhov Oct 8, 2025
166c612
refactor: implement ds reset
iobuhov Oct 9, 2025
e3b34f2
refactor: use gate to avoid computations
iobuhov Oct 9, 2025
c7860fb
feat: change xml groups
iobuhov Oct 10, 2025
d1953ae
feat: add sab vm
iobuhov Oct 13, 2025
92caf48
feat: add spd vm
iobuhov Oct 13, 2025
9123777
feat: select all v1
iobuhov Oct 13, 2025
ce6273a
refactor: change texts & etc
iobuhov Oct 15, 2025
888f444
fix: pass dg settings flag
iobuhov Oct 15, 2025
6780058
feat: use css variable
iobuhov Oct 15, 2025
692515b
feat: fix ts issues
iobuhov Oct 15, 2025
0471555
feat: set delay for 1.5s
iobuhov Oct 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@ $root: ".widget-datagrid";
align-items: center;
}

&-exporting {
&-exporting,
&-selecting-all-pages {
.widget-datagrid-top-bar,
.widget-datagrid-header,
.widget-datagrid-content,
Expand Down Expand Up @@ -480,7 +481,10 @@ $root: ".widget-datagrid";

&-spinner {
justify-content: center;
width: 100%;

&-full-width {
width: 100%;
}

&-margin {
margin: 52px 0;
Expand Down Expand Up @@ -555,16 +559,36 @@ $root: ".widget-datagrid";
:where(#{$root}-pb-start) {
margin-block: var(--spacing-medium);
padding-inline: var(--spacing-medium);
display: flex;
align-items: center;
}

#{$root}-clear-selection {
#{$root}-btn-invisible {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not really invisible, it makes them look like a link, I would call it btn-link or something.

cursor: pointer;
background: transparent;
border: none;
text-decoration: underline;
color: var(--link-color);
padding: 0;
padding: 0.3em 0.5em;
border-radius: 6px;
display: inline-block;

&:hover,
&:focus-visible {
background-color: var(--brand-primary-50, #e6e7f2);
}
}

:where(#{$root}-select-all-bar) {
grid-column: 1 / -1;
background-color: #f0f1f2;
display: flex;
flex-flow: row nowrap;
align-items: center;
padding: var(--spacing-smaller, 8px) var(--spacing-medium, 16px);

#{$root}-spinner {
padding: 6.2px;
}
}

@keyframes skeleton-loading {
Expand Down
4 changes: 4 additions & 0 deletions packages/pluggableWidgets/datagrid-web/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

### Added

- We added multi-page select all functionality for Datagrid widget with configurable batch processing, progress tracking, and page restoration to allow users to select all items across multiple pages with a single click.

## [3.6.1] - 2025-10-14

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import {
hideNestedPropertiesIn,
hidePropertiesIn,
hidePropertyIn,
Properties,
transformGroupsIntoTabs
Properties
} from "@mendix/pluggable-widgets-tools";
import {
container,
Expand All @@ -22,7 +21,7 @@ import { ColumnsPreviewType, DatagridPreviewProps } from "../typings/DatagridPro
export function getProperties(
values: DatagridPreviewProps,
defaultProperties: Properties,
platform: "web" | "desktop"
_: "web" | "desktop"
): Properties {
values.columns.forEach((column, index) => {
if (column.showContentAs !== "attribute" && !column.sortable && !values.columnsFilterable) {
Expand Down Expand Up @@ -65,15 +64,6 @@ export function getProperties(
if (column.minWidth !== "manual") {
hidePropertyIn(defaultProperties, values, "columns", index, "minWidthLimit");
}
if (!values.advanced && platform === "web") {
hideNestedPropertiesIn(defaultProperties, values, "columns", index, [
"columnClass",
"sortable",
"resizable",
"draggable",
"hidable"
]);
}
});
if (values.pagination === "buttons") {
hidePropertyIn(defaultProperties, values, "showNumberOfRows");
Expand Down Expand Up @@ -124,28 +114,6 @@ export function getProperties(
"columns"
);

if (platform === "web") {
if (!values.advanced) {
hidePropertiesIn(defaultProperties, values, [
"pagination",
"pagingPosition",
"showEmptyPlaceholder",
"rowClass",
"columnsSortable",
"columnsDraggable",
"columnsResizable",
"columnsHidable",
"configurationAttribute",
"onConfigurationChange",
"filterSectionTitle"
]);
}

transformGroupsIntoTabs(defaultProperties);
} else {
hidePropertyIn(defaultProperties, values, "advanced");
}

if (values.configurationStorageType === "localStorage") {
hidePropertiesIn(defaultProperties, values, ["configurationAttribute", "onConfigurationChange"]);
}
Expand All @@ -170,6 +138,7 @@ function hideSelectionProperties(defaultProperties: Properties, values: Datagrid

if (itemSelection !== "Multi") {
hidePropertyIn(defaultProperties, values, "keepSelection");
hidePropertyIn(defaultProperties, values, "enableSelectAll");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { enableStaticRendering } from "mobx-react-lite";
enableStaticRendering(true);

import { useFocusTargetController } from "@mendix/widget-plugin-grid/keyboard-navigation/useFocusTargetController";
import { DatasourceController } from "@mendix/widget-plugin-grid/query/DatasourceController";
import { SelectAllController } from "@mendix/widget-plugin-grid/selection";
import { ProgressStore } from "@mendix/widget-plugin-grid/stores/ProgressStore";
import { SelectionCountStore } from "@mendix/widget-plugin-grid/stores/SelectionCountStore";
import { BaseControllerHost } from "@mendix/widget-plugin-mobx-kit/BaseControllerHost";
import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider";
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
import { parseStyle } from "@mendix/widget-plugin-platform/preview/parse-style";
Expand All @@ -15,11 +20,11 @@ import { ColumnsPreviewType, DatagridPreviewProps } from "typings/DatagridProps"
import { Cell } from "./components/Cell";
import { Widget } from "./components/Widget";
import { ColumnPreview } from "./helpers/ColumnPreview";
import { DatagridContext } from "./helpers/root-context";
import { DatagridContext, DatagridRootScope } from "./helpers/root-context";
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
import { GridBasicData } from "./helpers/state/GridBasicData";

import { SelectionCountStore } from "@mendix/widget-plugin-grid/selection/stores/SelectionCountStore";
import { SelectAllBarViewModel } from "./helpers/state/SelectAllBarViewModel";
import { SelectionProgressDialogViewModel } from "./helpers/state/SelectionProgressDialogViewModel";
import "./ui/DatagridPreview.scss";

// Fix type definition for Selectable
Expand Down Expand Up @@ -61,6 +66,8 @@ const initColumns: ColumnsPreviewType[] = [

const numberOfItems = 3;

class Host extends BaseControllerHost {}

export function preview(props: DatagridPreviewProps): ReactElement {
const EmptyPlaceholder = props.emptyPlaceholder.renderer;
const data: ObjectItem[] = Array.from({ length: numberOfItems }).map((_, index) => ({
Expand All @@ -87,18 +94,35 @@ export function preview(props: DatagridPreviewProps): ReactElement {
const eventsController = { getProps: () => Object.create({}) };

const ctx = useConst(() => {
const gateProvider = new GateProvider({});
const basicData = new GridBasicData(gateProvider.gate);
const selectionCountStore = new SelectionCountStore(gateProvider.gate);
const host = new Host();
const gateProvider = new GateProvider({ datasource: {} as any, itemSelection: undefined });
const basicData = new GridBasicData(gateProvider.gate as any);
const query = new DatasourceController(host, { gate: gateProvider.gate });
const selectionCountStore = new SelectionCountStore(gateProvider.gate as any);
const selectAllController = new SelectAllController(host, gateProvider.gate, query);
const selectAllProgressStore = new ProgressStore();
return {
basicData,
selectionHelper: undefined,
selectActionHelper,
cellEventsController: eventsController,
checkboxEventsController: eventsController,
focusController,
selectionCountStore
};
selectionCountStore,
selectAllProgressStore,
selectAllBarViewModel: new SelectAllBarViewModel(
host,
gateProvider.gate as any,
selectAllController,
selectionCountStore
),
selectionProgressDialogViewModel: new SelectionProgressDialogViewModel(
host,
gateProvider.gate as any,
selectAllProgressStore,
selectAllController
)
} satisfies DatagridRootScope;
});

return (
Expand Down
43 changes: 17 additions & 26 deletions packages/pluggableWidgets/datagrid-web/src/Datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,31 @@ import { DatagridContainerProps } from "../typings/DatagridProps";
import { Cell } from "./components/Cell";
import { Widget } from "./components/Widget";
import { WidgetHeaderContext } from "./components/WidgetHeaderContext";
import { ProgressStore } from "./features/data-export/ProgressStore";
import { useDataExport } from "./features/data-export/useDataExport";
import { useCellEventsController } from "./features/row-interaction/CellEventsController";
import { useCheckboxEventsController } from "./features/row-interaction/CheckboxEventsController";
import { DatagridContext } from "./helpers/root-context";
import { DatagridContext, DatagridRootScope } from "./helpers/root-context";
import { useSelectActionHelper } from "./helpers/SelectActionHelper";
import { IColumnGroupStore } from "./helpers/state/ColumnGroupStore";
import { RootGridStore } from "./helpers/state/RootGridStore";
import { useRootStore } from "./helpers/state/useRootStore";
import { useDataGridJSActions } from "./helpers/useDataGridJSActions";

interface Props extends DatagridContainerProps {
columnsStore: IColumnGroupStore;
rootStore: RootGridStore;
progressStore: ProgressStore;
}

const Container = observer((props: Props): ReactElement => {
const { columnsStore, rootStore } = props;
const { paginationCtrl } = rootStore;
const { rootStore } = props;
const { paginationCtrl, gate, query, columnsStore, exportProgressStore } = rootStore;

const items = props.datasource.items ?? [];
const items = query.items ?? [];

const [exportProgress, abortExport] = useDataExport(props, props.columnsStore, props.progressStore);
const [exportProgress, abortExport] = useDataExport(props, columnsStore, exportProgressStore);

const selectionHelper = useSelectionHelper(
props.itemSelection,
props.datasource,
props.onSelectionChange,
gate.props.itemSelection,
gate.props.datasource,
gate.props.onSelectionChange,
props.keepSelection ? "always keep" : "always clear"
);

Expand Down Expand Up @@ -65,16 +61,20 @@ const Container = observer((props: Props): ReactElement => {
const checkboxEventsController = useCheckboxEventsController(selectActionHelper, focusController);

const ctx = useConst(() => {
rootStore.basicData.setSelectionHelper(selectionHelper);
return {
const scope: DatagridRootScope = {
basicData: rootStore.basicData,
selectionHelper,
selectActionHelper,
cellEventsController,
checkboxEventsController,
focusController,
selectionCountStore: rootStore.selectionCountStore
selectionCountStore: rootStore.selectionCountStore,
selectAllProgressStore: rootStore.selectAllProgressStore,
selectAllBarViewModel: rootStore.selectAllBarViewModel,
selectionProgressDialogViewModel: rootStore.selectionProgressDialogViewModel
};

return scope;
});

return (
Expand Down Expand Up @@ -123,7 +123,7 @@ const Container = observer((props: Props): ReactElement => {
rowClass={useCallback((value: any) => props.rowClass?.get(value)?.value ?? "", [props.rowClass])}
setPage={paginationCtrl.setPage}
styles={props.style}
exporting={exportProgress.exporting}
exporting={exportProgress.inProgress}
processedRows={exportProgress.loaded}
visibleColumns={columnsStore.visibleColumns}
availableColumns={columnsStore.availableColumns}
Expand All @@ -146,14 +146,5 @@ const Container = observer((props: Props): ReactElement => {
Container.displayName = "DatagridComponent";

export default function Datagrid(props: DatagridContainerProps): ReactElement | null {
const rootStore = useRootStore(props);

return (
<Container
{...props}
rootStore={rootStore}
columnsStore={rootStore.columnsStore}
progressStore={rootStore.exportProgressCtrl}
/>
);
return <Container {...props} rootStore={useRootStore(props)} />;
}
Loading
Loading