|
11 | 11 | // See the License for the specific language governing permissions and |
12 | 12 | // limitations under the License. |
13 | 13 |
|
| 14 | +import { Box, Theme, Typography, useTheme } from '@mui/material'; |
| 15 | +import { Table, TableCellConfigs, TableColumnConfig, useSelection } from '@perses-dev/components'; |
| 16 | +import { formatValue, Labels, QueryDataType, TimeSeries, TimeSeriesData, transformData } from '@perses-dev/core'; |
| 17 | +import { useSelectionItemActions } from '@perses-dev/dashboards'; |
14 | 18 | import { |
| 19 | + ActionOptions, |
15 | 20 | PanelData, |
16 | 21 | PanelProps, |
17 | 22 | replaceVariablesInString, |
18 | 23 | useAllVariableValues, |
19 | 24 | VariableStateMap, |
20 | 25 | } from '@perses-dev/plugin-system'; |
21 | | -import { Table, TableCellConfigs, TableColumnConfig } from '@perses-dev/components'; |
22 | | -import { ReactElement, useEffect, useMemo, useState } from 'react'; |
23 | | -import { formatValue, Labels, QueryDataType, TimeSeries, TimeSeriesData, transformData } from '@perses-dev/core'; |
24 | | -import { PaginationState, SortingState, ColumnFiltersState } from '@tanstack/react-table'; |
25 | | -import { useTheme, Theme, Typography, Box } from '@mui/material'; |
26 | | -import { ColumnSettings, TableOptions, evaluateConditionalFormatting } from '../models'; |
| 26 | +import { ColumnFiltersState, PaginationState, RowSelectionState, SortingState } from '@tanstack/react-table'; |
| 27 | +import { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'; |
| 28 | +import { ColumnSettings, evaluateConditionalFormatting, TableOptions } from '../models'; |
27 | 29 | import { EmbeddedPanel } from './EmbeddedPanel'; |
28 | 30 |
|
29 | 31 | function generateCellContentConfig( |
@@ -211,6 +213,50 @@ export function TablePanel({ contentDimensions, spec, queryResults }: TableProps |
211 | 213 | const theme = useTheme(); |
212 | 214 | const allVariables = useAllVariableValues(); |
213 | 215 |
|
| 216 | + const selectionEnabled = spec.selection?.enabled ?? false; |
| 217 | + const { selectionMap, setSelection, clearSelection } = useSelection<Record<string, unknown>, string>(); |
| 218 | + |
| 219 | + const itemActionsConfig = spec.actions ? (spec.actions as ActionOptions) : undefined; |
| 220 | + const itemActionsListConfig = |
| 221 | + itemActionsConfig?.enabled && itemActionsConfig.displayWithItem ? itemActionsConfig.actionsList : []; |
| 222 | + |
| 223 | + const { getItemActionButtons, confirmDialog, actionButtons } = useSelectionItemActions({ |
| 224 | + actions: itemActionsListConfig, |
| 225 | + variableState: allVariables, |
| 226 | + }); |
| 227 | + |
| 228 | + const filteredDataRef = useRef<Array<Record<string, unknown>>>([]); |
| 229 | + |
| 230 | + // Convert selectionMap to TanStack's RowSelectionState format |
| 231 | + const rowSelection = useMemo((): RowSelectionState => { |
| 232 | + const result: RowSelectionState = {}; |
| 233 | + selectionMap.forEach((_, id) => { |
| 234 | + result[id] = true; |
| 235 | + }); |
| 236 | + return result; |
| 237 | + }, [selectionMap]); |
| 238 | + |
| 239 | + const handleRowSelectionChange = useCallback( |
| 240 | + (newRowSelection: RowSelectionState) => { |
| 241 | + const newSelection: Array<{ id: string; item: Record<string, unknown> }> = []; |
| 242 | + for (const [id, isSelected] of Object.entries(newRowSelection)) { |
| 243 | + if (isSelected) { |
| 244 | + const index = parseInt(id, 10); |
| 245 | + if (filteredDataRef.current[index] !== undefined) { |
| 246 | + newSelection.push({ id, item: filteredDataRef.current[index] }); |
| 247 | + } |
| 248 | + } |
| 249 | + } |
| 250 | + |
| 251 | + if (newSelection.length === 0) { |
| 252 | + clearSelection(); |
| 253 | + } else { |
| 254 | + setSelection(newSelection); |
| 255 | + } |
| 256 | + }, |
| 257 | + [setSelection, clearSelection] |
| 258 | + ); |
| 259 | + |
214 | 260 | // TODO: handle other query types |
215 | 261 | const queryMode = getTablePanelQueryOptions(spec).mode; |
216 | 262 | const rawData: Array<Record<string, unknown>> = useMemo(() => { |
@@ -452,6 +498,9 @@ export function TablePanel({ contentDimensions, spec, queryResults }: TableProps |
452 | 498 | return filtered; |
453 | 499 | }, [data, columnFilters, spec.enableFiltering]); |
454 | 500 |
|
| 501 | + // Keep ref in sync with filtered data for use in selection handler |
| 502 | + filteredDataRef.current = filteredData; |
| 503 | + |
455 | 504 | const [pagination, setPagination] = useState<PaginationState | undefined>( |
456 | 505 | spec.pagination ? { pageIndex: 0, pageSize: 10 } : undefined |
457 | 506 | ); |
@@ -486,6 +535,7 @@ export function TablePanel({ contentDimensions, spec, queryResults }: TableProps |
486 | 535 |
|
487 | 536 | return ( |
488 | 537 | <> |
| 538 | + {confirmDialog} |
489 | 539 | {spec.enableFiltering && ( |
490 | 540 | <div |
491 | 541 | style={{ |
@@ -592,6 +642,11 @@ export function TablePanel({ contentDimensions, spec, queryResults }: TableProps |
592 | 642 | onSortingChange={setSorting} |
593 | 643 | pagination={pagination} |
594 | 644 | onPaginationChange={setPagination} |
| 645 | + checkboxSelection={selectionEnabled} |
| 646 | + rowSelection={rowSelection} |
| 647 | + onRowSelectionChange={handleRowSelectionChange} |
| 648 | + getItemActions={({ id, data }) => getItemActionButtons({ id, data: data as Record<string, unknown> })} |
| 649 | + hasItemActions={actionButtons && actionButtons.length > 0} |
595 | 650 | /> |
596 | 651 | </> |
597 | 652 | ); |
|
0 commit comments