@wandelbots/wandelbots-js-react-components 2.32.0-pr.feature-robot-precondition-list.372.5bce944 → 2.32.0-pr.feature-robot-precondition-list.372.8bd8d01

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wandelbots/wandelbots-js-react-components",
3
- "version": "2.32.0-pr.feature-robot-precondition-list.372.5bce944",
3
+ "version": "2.32.0-pr.feature-robot-precondition-list.372.8bd8d01",
4
4
  "description": "React UI toolkit for building applications on top of the Wandelbots platform",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -139,6 +139,7 @@
139
139
  "dependencies": {
140
140
  "@monaco-editor/react": "^4.7.0",
141
141
  "@mui/x-charts": "^8.9.0",
142
+ "@mui/x-data-grid": "^8.10.1",
142
143
  "@shikijs/monaco": "^3.1.0",
143
144
  "i18next-browser-languagedetector": "^8.0.4",
144
145
  "lodash-es": "^4.17.21",
@@ -0,0 +1,454 @@
1
+ import ClearIcon from "@mui/icons-material/Clear"
2
+ import FilterListIcon from "@mui/icons-material/FilterList"
3
+ import SearchIcon from "@mui/icons-material/Search"
4
+ import { Box, Divider, Typography } from "@mui/material"
5
+ import {
6
+ DataGrid,
7
+ type DataGridProps,
8
+ FilterPanelTrigger,
9
+ type GridColDef,
10
+ type GridRowParams,
11
+ QuickFilter,
12
+ QuickFilterClear,
13
+ QuickFilterControl,
14
+ QuickFilterTrigger,
15
+ Toolbar,
16
+ ToolbarButton,
17
+ } from "@mui/x-data-grid"
18
+ import { observer } from "mobx-react-lite"
19
+ import { useMemo, useState } from "react"
20
+ import { externalizeComponent } from "../externalizeComponent"
21
+
22
+ export interface WandelbotsDataGridProps<T = Record<string, unknown>> {
23
+ /**
24
+ * Array of data items to display in the grid
25
+ */
26
+ data: T[]
27
+
28
+ /**
29
+ * Column definitions for the DataGrid
30
+ */
31
+ columns: GridColDef[]
32
+
33
+ /**
34
+ * Function to transform data items into DataGrid rows
35
+ * Should return an object with an 'id' field and other fields matching column definitions
36
+ */
37
+ getRowData: (item: T) => Record<string, unknown> & { id: string | number }
38
+
39
+ /**
40
+ * Callback when a row is clicked
41
+ */
42
+ onRowClick?: (item: T, params: GridRowParams) => void
43
+
44
+ /**
45
+ * Currently selected item (for highlighting)
46
+ */
47
+ selectedItem?: T | null
48
+
49
+ /**
50
+ * Function to get the ID of an item (used for selection highlighting)
51
+ */
52
+ getItemId?: (item: T) => string | number
53
+
54
+ /**
55
+ * Title displayed in the toolbar
56
+ */
57
+ title?: string
58
+
59
+ /**
60
+ * Show item count in title
61
+ * @default true
62
+ */
63
+ showCount?: boolean
64
+
65
+ /**
66
+ * Placeholder text for the search input
67
+ * @default "Search"
68
+ */
69
+ searchPlaceholder?: string
70
+
71
+ /**
72
+ * Additional DataGrid props to pass through
73
+ */
74
+ dataGridProps?: Partial<DataGridProps>
75
+
76
+ /**
77
+ * Custom toolbar component to replace the default one
78
+ */
79
+ CustomToolbar?: React.ComponentType
80
+
81
+ /**
82
+ * Select the first item by default
83
+ * @default false
84
+ */
85
+ selectFirstByDefault?: boolean
86
+ }
87
+
88
+ export const WandelbotsDataGrid = externalizeComponent(
89
+ observer(
90
+ <T,>({
91
+ data,
92
+ columns,
93
+ getRowData,
94
+ onRowClick,
95
+ selectedItem,
96
+ getItemId,
97
+ title,
98
+ showCount = true,
99
+ searchPlaceholder = "Search",
100
+ dataGridProps,
101
+ CustomToolbar,
102
+ selectFirstByDefault = false,
103
+ }: WandelbotsDataGridProps<T>) => {
104
+ // Internal state for selection when not controlled
105
+ const [internalSelectedItem, setInternalSelectedItem] =
106
+ useState<T | null>(null)
107
+
108
+ // Prepare rows for the DataGrid
109
+ const rows = useMemo(() => data.map(getRowData), [data, getRowData])
110
+
111
+ // Handle default selection - only use if no selectedItem is explicitly provided
112
+ const effectiveSelectedItem = useMemo(() => {
113
+ // If selectedItem is explicitly provided, use it (including null)
114
+ if (selectedItem !== undefined) {
115
+ return selectedItem
116
+ }
117
+ // If we have an internal selection, use it
118
+ if (internalSelectedItem !== null) {
119
+ return internalSelectedItem
120
+ }
121
+ // Otherwise, use first item if selectFirstByDefault is true
122
+ if (selectFirstByDefault && data.length > 0) {
123
+ const firstItem = data[0]
124
+ // Set internal state to first item on initial load
125
+ setInternalSelectedItem(firstItem)
126
+ return firstItem
127
+ }
128
+ return null
129
+ }, [selectFirstByDefault, data, selectedItem, internalSelectedItem])
130
+
131
+ // Handle row click
132
+ const handleRowClick = (params: GridRowParams) => {
133
+ const item = data.find((item) => {
134
+ const rowData = getRowData(item)
135
+ return rowData.id === params.id
136
+ })
137
+
138
+ if (item) {
139
+ // Update internal selection state if not controlled by props
140
+ if (selectedItem === undefined) {
141
+ setInternalSelectedItem(item)
142
+ }
143
+
144
+ // Call the user's onRowClick callback
145
+ if (onRowClick) {
146
+ onRowClick(item, params)
147
+ }
148
+ }
149
+ }
150
+
151
+ // Get selected row ID for highlighting
152
+ const selectedRowId = useMemo(() => {
153
+ if (!effectiveSelectedItem || !getItemId) return null
154
+ return getItemId(effectiveSelectedItem)
155
+ }, [effectiveSelectedItem, getItemId])
156
+
157
+ // Default toolbar with filter and quick filter
158
+ function DefaultToolbar() {
159
+ return (
160
+ <Toolbar>
161
+ <Box
162
+ sx={{
163
+ display: "flex",
164
+ width: "100%",
165
+ gap: 1,
166
+ p: 1,
167
+ alignItems: "center",
168
+ }}
169
+ >
170
+ {title && (
171
+ <Typography
172
+ variant="h6"
173
+ sx={{
174
+ fontWeight: 500,
175
+ color: "white",
176
+ }}
177
+ >
178
+ {title}
179
+ {showCount && ` (${data.length})`}
180
+ </Typography>
181
+ )}
182
+ <Box
183
+ sx={{
184
+ ml: "auto",
185
+ display: "flex",
186
+ gap: 1,
187
+ alignItems: "center",
188
+ }}
189
+ >
190
+ <FilterPanelTrigger
191
+ render={
192
+ <ToolbarButton aria-label="Show filters">
193
+ <FilterListIcon fontSize="small" />
194
+ </ToolbarButton>
195
+ }
196
+ />
197
+ <Divider
198
+ orientation="vertical"
199
+ flexItem
200
+ sx={{
201
+ height: "24px",
202
+ alignSelf: "center",
203
+ }}
204
+ />
205
+ <QuickFilter
206
+ render={(props, state) => (
207
+ <Box
208
+ {...props}
209
+ sx={{
210
+ display: "flex",
211
+ overflow: "hidden",
212
+ }}
213
+ >
214
+ <Box
215
+ sx={{
216
+ borderRadius: state.expanded ? "4px 0 0 4px" : "4px",
217
+ borderRight: state.expanded ? "none" : undefined,
218
+ }}
219
+ >
220
+ <QuickFilterTrigger
221
+ render={
222
+ <ToolbarButton aria-label="Search">
223
+ <SearchIcon fontSize="small" />
224
+ </ToolbarButton>
225
+ }
226
+ />
227
+ </Box>
228
+ <Box
229
+ sx={{
230
+ display: "flex",
231
+ overflow: "hidden",
232
+ transition: "all 0.3s ease-in-out",
233
+ width: state.expanded ? "192px" : "0px",
234
+ }}
235
+ >
236
+ <Box
237
+ sx={{
238
+ flex: 1,
239
+ "& .MuiInputBase-root": {
240
+ height: "32px",
241
+ borderRadius:
242
+ state.expanded && state.value !== ""
243
+ ? "0"
244
+ : "0 4px 4px 0",
245
+ },
246
+ }}
247
+ >
248
+ <QuickFilterControl placeholder={searchPlaceholder} />
249
+ </Box>
250
+ {state.expanded && state.value !== "" && (
251
+ <QuickFilterClear
252
+ render={
253
+ <Box sx={{ borderRadius: "0 4px 4px 0" }}>
254
+ <ToolbarButton aria-label="Clear">
255
+ <ClearIcon fontSize="small" />
256
+ </ToolbarButton>
257
+ </Box>
258
+ }
259
+ />
260
+ )}
261
+ </Box>
262
+ </Box>
263
+ )}
264
+ />
265
+ </Box>
266
+ </Box>
267
+ </Toolbar>
268
+ )
269
+ }
270
+
271
+ const ToolbarComponent = CustomToolbar || DefaultToolbar
272
+
273
+ return (
274
+ <Box
275
+ sx={{
276
+ height: "100%",
277
+ display: "flex",
278
+ flexDirection: "column",
279
+ background: "var(--background-paper-elevation-5, #202233)",
280
+ }}
281
+ >
282
+ <DataGrid
283
+ rows={rows}
284
+ columns={columns}
285
+ onRowClick={handleRowClick}
286
+ disableColumnMenu={false}
287
+ disableRowSelectionOnClick={true}
288
+ disableMultipleRowSelection={true}
289
+ hideFooterSelectedRowCount={true}
290
+ filterMode="client"
291
+ sortingOrder={["desc", "asc"]}
292
+ hideFooter={false}
293
+ showToolbar={true}
294
+ slots={{
295
+ toolbar: ToolbarComponent,
296
+ }}
297
+ initialState={{
298
+ sorting: {
299
+ sortModel: [],
300
+ },
301
+ filter: {
302
+ filterModel: {
303
+ items: [],
304
+ },
305
+ },
306
+ ...dataGridProps?.initialState,
307
+ }}
308
+ {...dataGridProps}
309
+ // Ensure autosize properties are not overridden by dataGridProps
310
+ autosizeOnMount={dataGridProps?.autosizeOnMount ?? true}
311
+ autosizeOptions={{
312
+ includeOutliers: true,
313
+ includeHeaders: true,
314
+ expand: true,
315
+ ...dataGridProps?.autosizeOptions,
316
+ }}
317
+ sx={{
318
+ border: "none",
319
+ backgroundColor: "transparent",
320
+ width: "100%",
321
+ "& .MuiDataGrid-main": {
322
+ border: "none",
323
+ backgroundColor: "transparent",
324
+ },
325
+ "& .MuiDataGrid-container--top [role=row]": {
326
+ backgroundColor: "transparent !important",
327
+ },
328
+ "& .MuiDataGrid-topContainer": {
329
+ borderBottom: "none !important",
330
+ },
331
+ "& .MuiDataGrid-columnHeaders": {
332
+ border: "none",
333
+ borderBottom: "none !important",
334
+ backgroundColor: "var(--background-paper-elevation-5, #202233)",
335
+ },
336
+ "& .MuiDataGrid-row": {
337
+ cursor: onRowClick ? "pointer" : "default",
338
+ border: "none",
339
+ margin: "0px 0",
340
+ position: "relative",
341
+ "&:hover": {
342
+ backgroundColor: "transparent !important",
343
+ "&::before": {
344
+ content: '""',
345
+ position: "absolute",
346
+ top: 0,
347
+ left: "16px",
348
+ right: "16px",
349
+ bottom: 0,
350
+ backgroundColor: "action.hover",
351
+ borderRadius: "16px",
352
+ zIndex: 0,
353
+ },
354
+ },
355
+ // Disable MUI's built-in selection styling completely
356
+ "&.Mui-selected": {
357
+ backgroundColor: "transparent !important",
358
+ "&:hover": {
359
+ backgroundColor: "transparent !important",
360
+ },
361
+ },
362
+ // Highlight selected row with a distinct color using data attribute
363
+ ...(selectedRowId !== null && {
364
+ [`&[data-id="${selectedRowId}"]`]: {
365
+ "&::before": {
366
+ content: '""',
367
+ position: "absolute",
368
+ top: 0,
369
+ left: "16px",
370
+ right: "16px",
371
+ bottom: 0,
372
+ backgroundColor: "rgba(255, 255, 255, 0.08) !important",
373
+ borderRadius: "16px",
374
+ zIndex: 0,
375
+ },
376
+ "&:hover::before": {
377
+ backgroundColor: "rgba(255, 255, 255, 0.12) !important",
378
+ },
379
+ },
380
+ }),
381
+ },
382
+ "& .MuiDataGrid-cell--textLeft": {
383
+ paddingLeft: "40px",
384
+ },
385
+ "& .MuiDataGrid-cell": {
386
+ border: "none",
387
+ position: "relative",
388
+ zIndex: 1,
389
+ "&:focus": {
390
+ outline: "none",
391
+ },
392
+ "&:focus-within": {
393
+ outline: "none",
394
+ },
395
+ },
396
+ "& .MuiDataGrid-columnHeader": {
397
+ border: "none",
398
+ paddingLeft: "40px",
399
+ paddingRight: "40px",
400
+ backgroundColor: "transparent !important",
401
+ "& .MuiDataGrid-columnHeaderTitle": {
402
+ color: "rgba(255, 255, 255, 0.6)",
403
+ },
404
+ },
405
+ "& .MuiDataGrid-toolbarContainer": {
406
+ padding: "8px",
407
+ border: "none !important",
408
+ borderBottom: "none !important",
409
+ "& .MuiBox-root": {
410
+ backgroundColor: "transparent !important",
411
+ },
412
+ "& .MuiFormControl-root": {
413
+ backgroundColor: "transparent !important",
414
+ },
415
+ "& .MuiInputBase-root": {
416
+ backgroundColor: "transparent !important",
417
+ },
418
+ "& *": {
419
+ borderBottom: "none !important",
420
+ },
421
+ },
422
+ "& .MuiDataGrid-toolbar": {
423
+ borderBottom: "none !important",
424
+ },
425
+ "& .MuiDataGrid-toolbarFilterList": {
426
+ border: "none",
427
+ },
428
+ "& .MuiDataGrid-withBorderColor": {
429
+ borderColor: "transparent !important",
430
+ },
431
+ "& .MuiDataGrid-columnSeparator": {
432
+ display: "none",
433
+ },
434
+ "& .MuiDataGrid-footerContainer": {
435
+ display: "none",
436
+ },
437
+ "& .MuiDataGrid-filler": {
438
+ border: "none !important",
439
+ borderTop: "none !important",
440
+ borderBottom: "none !important",
441
+ borderLeft: "none !important",
442
+ borderRight: "none !important",
443
+ "--rowBorderColor": "none !important",
444
+ },
445
+ ...dataGridProps?.sx,
446
+ }}
447
+ />
448
+ </Box>
449
+ )
450
+ },
451
+ ),
452
+ )
453
+
454
+ WandelbotsDataGrid.displayName = "WandelbotsDataGrid"
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./components/3d-viewport/PresetEnvironment"
2
2
  export * from "./components/3d-viewport/SafetyZonesRenderer"
3
3
  export * from "./components/3d-viewport/TrajectoryRenderer"
4
4
  export * from "./components/CycleTimer"
5
+ export * from "./components/DataGrid"
5
6
  export * from "./components/jogging/JoggingCartesianAxisControl"
6
7
  export * from "./components/jogging/JoggingJointRotationControl"
7
8
  export * from "./components/jogging/JoggingPanel"