Upgrade react-data-grid fork to latest and change pgAdmin accordingly. #7705

This commit is contained in:
Aditya Toshniwal 2024-07-31 19:12:36 +05:30 committed by GitHub
parent c45fb47b08
commit c6e7ce03cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 165 additions and 184 deletions

View File

@ -126,7 +126,7 @@
"react-arborist": "^3.2.0", "react-arborist": "^3.2.0",
"react-aspen": "^1.1.0", "react-aspen": "^1.1.0",
"react-checkbox-tree": "^1.7.2", "react-checkbox-tree": "^1.7.2",
"react-data-grid": "https://github.com/pgadmin-org/react-data-grid.git#200d2f5e02de694e3e9ffbe177c279bc40240fb8", "react-data-grid": "https://github.com/pgadmin-org/react-data-grid.git#4e10a5a327ff58198ac83c7b0c62549b20b78ae5",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",

View File

@ -70,8 +70,9 @@ export function FileNameEditor({row, column, onRowChange, onClose}) {
}, []); }, []);
const onKeyDown = (e)=>{ const onKeyDown = (e)=>{
if(e.code === 'Tab' || e.code === 'Enter') { if(e.code === 'Tab' || e.code == 'Escape' || e.code == 'Enter') {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
onClose(); onClose();
} }
}; };
@ -116,20 +117,16 @@ const columns = [
{ {
key: 'Filename', key: 'Filename',
name: gettext('Name'), name: gettext('Name'),
formatter: FileNameFormatter, renderCell: FileNameFormatter,
editor: FileNameEditor, renderEditCell: FileNameEditor,
editorOptions: {
editOnClick: false,
onCellKeyDown: (e)=>e.preventDefault(),
}
},{ },{
key: 'Properties.DateModified', key: 'Properties.DateModified',
name: gettext('Date Modified'), name: gettext('Date Modified'),
formatter: ({row})=><>{row.Properties?.['Date Modified']}</> renderCell: ({row})=><>{row.Properties?.['Date Modified']}</>
},{ },{
key: 'Properties.Size', key: 'Properties.Size',
name: gettext('Size'), name: gettext('Size'),
formatter: ({row})=><>{row.file_type != 'dir' && row.Properties?.['Size']}</> renderCell: ({row})=><>{row.file_type != 'dir' && row.Properties?.['Size']}</>
} }
]; ];
@ -161,7 +158,7 @@ export default function ListView({items, operation, ...props}) {
sortable: true, sortable: true,
resizable: true resizable: true
}} }}
headerRowHeight={28} headerRowHeight={35}
rowHeight={28} rowHeight={28}
mincolumnWidthBy={25} mincolumnWidthBy={25}
enableCellSelect={false} enableCellSelect={false}

View File

@ -13,4 +13,6 @@
@import 'node_modules/rc-dock/dist/rc-dock.css'; @import 'node_modules/rc-dock/dist/rc-dock.css';
@import 'node_modules/@szhsin/react-menu/dist/index.css'; @import 'node_modules/@szhsin/react-menu/dist/index.css';
@import 'node_modules/react-data-grid/lib/styles.css';
@import './pgadmin.css'; @import './pgadmin.css';

View File

@ -6,7 +6,7 @@
// This software is released under the PostgreSQL Licence // This software is released under the PostgreSQL Licence
// //
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import React, { useContext, useEffect, useMemo } from 'react'; import React, { useCallback, useContext, useEffect, useMemo } from 'react';
import ReactDataGrid, { Row } from 'react-data-grid'; import ReactDataGrid, { Row } from 'react-data-grid';
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -23,6 +23,7 @@ const StyledReactDataGrid = styled(ReactDataGrid)(({theme})=>({
backgroundColor: theme.otherVars.qtDatagridBg, backgroundColor: theme.otherVars.qtDatagridBg,
fontSize: '12px', fontSize: '12px',
border: 'none', border: 'none',
userSelect: 'none',
'--rdg-selection-color': theme.palette.primary.main, '--rdg-selection-color': theme.palette.primary.main,
'& .rdg-cell': { '& .rdg-cell': {
...theme.mixins.panelBorder.right, ...theme.mixins.panelBorder.right,
@ -35,10 +36,17 @@ const StyledReactDataGrid = styled(ReactDataGrid)(({theme})=>({
'&[aria-selected=true]:not([role="columnheader"])': { '&[aria-selected=true]:not([role="columnheader"])': {
outlineWidth: '0px', outlineWidth: '0px',
outlineOffset: '0px', outlineOffset: '0px',
},
'& .rdg-cell-value': {
height: '100%',
} }
}, },
'& .rdg-header-row .rdg-cell': { '& .rdg-header-row .rdg-cell': {
padding: 0, padding: 0,
'& .rdg-header-sort-name': {
margin: 'auto 0',
}
}, },
'& .rdg-header-row': { '& .rdg-header-row': {
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
@ -61,20 +69,6 @@ const StyledReactDataGrid = styled(ReactDataGrid)(({theme})=>({
} }
}, },
}, },
'&.ReactGrid-hasSelectColumn': {
'& .rdg-cell': {
'&[aria-selected=true][aria-colindex="1"]': {
outlineWidth: '2px',
outlineOffset: '-2px',
backgroundColor: theme.otherVars.qtDatagridBg,
color: theme.palette.text.primary,
}
},
'& .rdg-row[aria-selected=true] .rdg-cell:nth-of-type(1)': {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
}
}
})); }));
export const GridContextUtils = React.createContext(); export const GridContextUtils = React.createContext();
@ -110,12 +104,18 @@ export function CustomRow({inTest=false, ...props}) {
if(inTest) { if(inTest) {
return <div data-test='test-div' tabIndex={-1} onKeyDown={handleKeyDown}></div>; return <div data-test='test-div' tabIndex={-1} onKeyDown={handleKeyDown}></div>;
} }
const onRowClick = (...args)=>{
gridUtils.onItemClick?.(props.rowIdx); const onCellClick = (args) => {
props.onRowClick?.(...args); gridUtils.onItemClick?.(args.row.rowIdx);
props.onRowClick?.(args.row);
}; };
const onCellDoubleClick = (args) => {
gridUtils.onItemEnter?.(args.row);
};
return ( return (
<Row {...props} onKeyDown={handleKeyDown} onRowClick={onRowClick} onRowDoubleClick={(row)=>gridUtils.onItemEnter?.(row)} <Row {...props} onKeyDown={handleKeyDown} onCellClick={onCellClick} onCellDoubleClick={onCellDoubleClick}
selectCell={(row, column)=>props.selectCell(row, column)} aria-selected={isRowSelected}/> selectCell={(row, column)=>props.selectCell(row, column)} aria-selected={isRowSelected}/>
); );
} }
@ -136,14 +136,23 @@ export default function PgReactDataGrid({gridRef, className, hasSelectColumn=tru
props.enableCellSelect && finalClassName.push('ReactGrid-cellSelection'); props.enableCellSelect && finalClassName.push('ReactGrid-cellSelection');
finalClassName.push(className); finalClassName.push(className);
const valObj = useMemo(() => ({onItemEnter, onItemSelect, onItemClick}), [onItemEnter, onItemSelect, onItemClick]); const valObj = useMemo(() => ({onItemEnter, onItemSelect, onItemClick}), [onItemEnter, onItemSelect, onItemClick]);
const renderRow = useCallback((key, props) => {
return <CustomRow key={key} {...props} />;
}, []);
const renderSortStatus = useCallback((props) => {
return <CutomSortIcon {...props} />;
}, []);
return ( return (
<GridContextUtils.Provider value={valObj}> <GridContextUtils.Provider value={valObj}>
<StyledReactDataGrid <StyledReactDataGrid
ref={gridRef} ref={gridRef}
className={finalClassName.join(' ')} className={finalClassName.join(' ')}
components={{ renderers={{
sortIcon: CutomSortIcon, renderRow,
rowRenderer: CustomRow, renderSortStatus,
noRowsFallback: <Box textAlign="center" gridColumn="1/-1" p={1}>{noRowsIcon}{noRowsText || gettext('No rows found.')}</Box>, noRowsFallback: <Box textAlign="center" gridColumn="1/-1" p={1}>{noRowsIcon}{noRowsText || gettext('No rows found.')}</Box>,
}} }}
{...props} {...props}

View File

@ -35,12 +35,9 @@ const StyledBox = styled(Box)(({theme}) => ({
fontSize: '13px', fontSize: '13px',
'--rdg-background-color': theme.palette.default.main, '--rdg-background-color': theme.palette.default.main,
'--rdg-selection-color': theme.palette.primary.main, '--rdg-selection-color': theme.palette.primary.main,
'& .ResultGridComponent-gridPanel': { '& .ResultGridComponent-grid.ReactGrid-root': {
'--rdg-background-color': theme.palette.default.main + ' !important', fontSize: '13px',
'&.ResultGridComponent-grid': { '--rdg-selection-color': 'none',
fontSize: '13px',
'--rdg-selection-color': 'none'
},
'& .rdg-header-row': { '& .rdg-header-row': {
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
'& .rdg-cell': { '& .rdg-cell': {
@ -57,13 +54,29 @@ const StyledBox = styled(Box)(({theme}) => ({
}, },
'& .rdg-row': { '& .rdg-row': {
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
'&[aria-selected=true]': { '&[aria-selected=false]': {
backgroundColor: theme.palette.primary.light, '&.ResultGridComponent-selectedRow': {
color: theme.otherVars.qtDatagridSelectFg, paddingLeft: '0.5rem',
'& .rdg-cell:nth-of-type(1)': { backgroundColor: theme.palette.primary.light,
backgroundColor: 'transparent', },
outlineColor: 'transparent', '&.ResultGridComponent-source': {
color: theme.palette.primary.contrastText, backgroundColor: theme.otherVars.schemaDiff.sourceRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'&.ResultGridComponent-target': {
backgroundColor: theme.otherVars.schemaDiff.targetRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'&.ResultGridComponent-different': {
backgroundColor: theme.otherVars.schemaDiff.diffRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'&.ResultGridComponent-identical': {
paddingLeft: '0.5rem',
color: theme.otherVars.schemaDiff.diffColorFg,
}, },
}, },
'& .rdg-cell': { '& .rdg-cell': {
@ -74,19 +87,15 @@ const StyledBox = styled(Box)(({theme}) => ({
...theme.mixins.panelBorder.bottom, ...theme.mixins.panelBorder.bottom,
'&[aria-colindex="1"]': { '&[aria-colindex="1"]': {
padding: 0, padding: 0,
textAlign: 'center',
}, },
'&[aria-selected=true]:not([role="columnheader"]):not([aria-colindex="1"])': { '& .ResultGridComponent-rowIcon': {
outlineWidth: '0', display: 'inline-block !important',
outlineOffset: '-1px', height: '1.3rem',
color: theme.otherVars.qtDatagridSelectFg, width: '1.3rem'
},
'&[aria-selected=true][aria-colindex="1"]': {
outlineWidth: 0,
backgroundColor: theme.palette.default.main + ' !important'
}, },
'& .ResultGridComponent-cellExpand': { '& .ResultGridComponent-cellExpand': {
display: 'table', width: '100%',
blockSize: '100%',
'& > span': { '& > span': {
verticalAlign: 'middle', verticalAlign: 'middle',
cursor: 'pointer', cursor: 'pointer',
@ -97,11 +106,7 @@ const StyledBox = styled(Box)(({theme}) => ({
}, },
'& .ResultGridComponent-subRow': { '& .ResultGridComponent-subRow': {
paddingLeft: '1rem', paddingLeft: '1rem',
'& .ResultGridComponent-rowIcon': {
display: 'inline-block !important',
height: '1.3rem',
width: '1.3rem'
},
'& .ResultGridComponent-count': { '& .ResultGridComponent-count': {
display: 'inline-block !important', display: 'inline-block !important',
'& .ResultGridComponent-countLabel': { '& .ResultGridComponent-countLabel': {
@ -115,29 +120,6 @@ const StyledBox = styled(Box)(({theme}) => ({
} }
} }
}, },
'& .ResultGridComponent-selectedRow': {
paddingLeft: '0.5rem',
backgroundColor: theme.palette.primary.light,
},
'& .ResultGridComponent-source': {
backgroundColor: theme.otherVars.schemaDiff.sourceRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'& .ResultGridComponent-target': {
backgroundColor: theme.otherVars.schemaDiff.targetRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'& .ResultGridComponent-different': {
backgroundColor: theme.otherVars.schemaDiff.diffRowColor,
color: theme.otherVars.schemaDiff.diffSelectFG,
paddingLeft: '0.5rem',
},
'& .ResultGridComponent-identical': {
paddingLeft: '0.5rem',
color: theme.otherVars.schemaDiff.diffColorFg,
},
'& .ResultGridComponent-recordRow': { '& .ResultGridComponent-recordRow': {
marginLeft: '2.7rem', marginLeft: '2.7rem',
height: '1.3rem', height: '1.3rem',
@ -146,15 +128,9 @@ const StyledBox = styled(Box)(({theme}) => ({
marginRight: '0.3rem', marginRight: '0.3rem',
paddingLeft: '0.5rem', paddingLeft: '0.5rem',
}, },
'& .ResultGridComponent-selectCell': { '&.ResultGridComponent-selectCell': {
padding: '0 0.3rem' padding: '0 0.3rem'
}, },
'& .ResultGridComponent-selectedRowCheckBox': {
backgroundColor: theme.otherVars.schemaDiff.diffSelCheckbox,
},
'& .ResultGridComponent-selChBox': {
paddingLeft: 0,
}
} }
}, },
'& .ResultGridComponent-noRowsIcon': { '& .ResultGridComponent-noRowsIcon': {
@ -456,33 +432,31 @@ function selectHeaderRenderer({selectedRows, setSelectedRows, rootSelection, set
Cell.displayName = 'Cell'; Cell.displayName = 'Cell';
return Cell; return Cell;
} }
function selectFormatter({selectedRows, setSelectedRows, setRootSelection, activeRow, setActiveRow, allRowIds, selectedRowIds, selectedResultRows, deselectResultRows, getStyleClassName}) { function selectFormatter({selectedRows, setSelectedRows, setRootSelection, setActiveRow, allRowIds, selectedRowIds, selectedResultRows, deselectResultRows}) {
const Cell = ({ row, isCellSelected }) => { const Cell = ({ row, isCellSelected }) => {
isCellSelected && setActiveRow(row.id); isCellSelected && setActiveRow(row.id);
return ( return (
<Box className={!row?.children && getStyleClassName(row, selectedRows, isCellSelected, activeRow, true) + ' ResultGridComponent-selChBox'}> <InputCheckbox
<InputCheckbox className='ResultGridComponent-selectCell'
className='ResultGridComponent-selectCell' cid={`${row.id}`}
cid={`${row.id}`} value={selectedRows.includes(`${row.id}`)}
value={selectedRows.includes(`${row.id}`)} size='small'
size='small' onChange={(e) => {
onChange={(e) => { setSelectedRows((prev) => {
setSelectedRows((prev) => { let tempSelectedRows = [...prev];
let tempSelectedRows = [...prev]; if (!prev.includes(e.target.id)) {
if (!prev.includes(e.target.id)) { selectedResultRows(row, tempSelectedRows);
selectedResultRows(row, tempSelectedRows); tempSelectedRows.length === allRowIds.length && setRootSelection(true);
tempSelectedRows.length === allRowIds.length && setRootSelection(true); } else {
} else { deselectResultRows(row, tempSelectedRows);
deselectResultRows(row, tempSelectedRows); }
} tempSelectedRows = new Set(tempSelectedRows);
tempSelectedRows = new Set(tempSelectedRows); selectedRowIds([...tempSelectedRows]);
selectedRowIds([...tempSelectedRows]); return [...tempSelectedRows];
return [...tempSelectedRows]; });
}); }
} }
} ></InputCheckbox>
></InputCheckbox>
</Box>
); );
}; };
@ -494,7 +468,7 @@ function selectFormatter({selectedRows, setSelectedRows, setRootSelection, activ
return Cell; return Cell;
} }
function expandFormatter({activeRow, setActiveRow, filterParams, gridData, selectedRows, dispatch, getStyleClassName}) { function expandFormatter({setActiveRow, filterParams, gridData, selectedRows, dispatch}) {
const Cell = ({ row, isCellSelected })=>{ const Cell = ({ row, isCellSelected })=>{
const hasChildren = row.children !== undefined; const hasChildren = row.children !== undefined;
isCellSelected && setActiveRow(row.id); isCellSelected && setActiveRow(row.id);
@ -510,15 +484,12 @@ function expandFormatter({activeRow, setActiveRow, filterParams, gridData, selec
onCellExpand={() => dispatch({ id: row.id, type: 'toggleSubRow', filterParams: filterParams, gridData: gridData, selectedRows: selectedRows })} onCellExpand={() => dispatch({ id: row.id, type: 'toggleSubRow', filterParams: filterParams, gridData: gridData, selectedRows: selectedRows })}
/> />
)} )}
<div className="rdg-cell-value"> {!hasChildren && (
<Box>
{!hasChildren && ( <span className={'ResultGridComponent-recordRow ' + row.icon}></span>
<Box className={getStyleClassName(row, selectedRows, isCellSelected, activeRow)}> {row.label}
<span className={'ResultGridComponent-recordRow ' + row.icon}></span> </Box>
{row.label} )}
</Box>
)}
</div>
</> </>
); );
}; };
@ -531,12 +502,12 @@ function expandFormatter({activeRow, setActiveRow, filterParams, gridData, selec
return Cell; return Cell;
} }
function resultFormatter({selectedRows, activeRow, setActiveRow, getStyleClassName}) { function resultFormatter({setActiveRow}) {
const Cell = ({ row, isCellSelected })=>{ const Cell = ({ row, isCellSelected })=>{
isCellSelected && setActiveRow(row.id); isCellSelected && setActiveRow(row.id);
return ( return (
<Box className={getStyleClassName(row, selectedRows, isCellSelected, activeRow)}> <Box>
{row.status} {row.status}
</Box> </Box>
); );
@ -648,10 +619,10 @@ export function ResultGridComponent({ gridData, allRowIds, filterParams, selecte
} }
} }
function getStyleClassName(row, selectedRowIds, isCellSelected, activeRowId, isCheckbox = false) { function getStyleClassName(row, selectedRowIds, activeRowId) {
let clsName = null; let clsName = null;
if (selectedRowIds.includes(`${row.id}`) || isCellSelected || row.id == activeRowId) { if (selectedRowIds.includes(`${row.id}`) || row.id == activeRowId) {
clsName = isCheckbox ? 'ResultGridComponent-selectedRowCheckBox' : 'ResultGridComponent-selectedRow'; clsName = 'ResultGridComponent-selectedRow';
} else if (row.status == FILTER_NAME.DIFFERENT) { } else if (row.status == FILTER_NAME.DIFFERENT) {
clsName = 'ResultGridComponent-different'; clsName = 'ResultGridComponent-different';
} else if (row.status == FILTER_NAME.SOURCE_ONLY) { } else if (row.status == FILTER_NAME.SOURCE_ONLY) {
@ -671,14 +642,14 @@ export function ResultGridComponent({ gridData, allRowIds, filterParams, selecte
...SelectColumn, ...SelectColumn,
minWidth: 30, minWidth: 30,
width: 30, width: 30,
headerRenderer: selectHeaderRenderer({ renderHeaderCell: selectHeaderRenderer({
selectedRows, setSelectedRows, rootSelection, selectedRows, setSelectedRows, rootSelection,
setRootSelection, allRowIds, selectedRowIds setRootSelection, allRowIds, selectedRowIds
}), }),
formatter: selectFormatter({ renderCell: selectFormatter({
selectedRows, setSelectedRows, setRootSelection, selectedRows, setSelectedRows, setRootSelection,
activeRow, setActiveRow, allRowIds, selectedRowIds, setActiveRow, allRowIds, selectedRowIds,
selectedResultRows, deselectResultRows, getStyleClassName selectedResultRows, deselectResultRows
}), }),
}, },
{ {
@ -692,15 +663,15 @@ export function ResultGridComponent({ gridData, allRowIds, filterParams, selecte
return 1; return 1;
}, },
formatter: expandFormatter({ renderCell: expandFormatter({
activeRow, setActiveRow, filterParams, gridData, setActiveRow, filterParams, gridData,
selectedRows, dispatch, getStyleClassName selectedRows, dispatch
}), }),
}, },
{ {
key: 'status', key: 'status',
name: 'Comparison Result', name: 'Comparison Result',
formatter: resultFormatter({selectedRows, activeRow, setActiveRow, getStyleClassName}), renderCell: resultFormatter({setActiveRow}),
}, },
]; ];
@ -768,7 +739,7 @@ export function ResultGridComponent({ gridData, allRowIds, filterParams, selecte
<PgReactDataGrid <PgReactDataGrid
id="schema-diff-result-grid" id="schema-diff-result-grid"
columns={columns} rows={rows} columns={columns} rows={rows}
className={'ResultGridComponent-gridPanel ResultGridComponent-grid'} className='ResultGridComponent-grid'
treeDepth={2} treeDepth={2}
enableRowSelect={true} enableRowSelect={true}
defaultColumnOptions={{ defaultColumnOptions={{
@ -782,6 +753,9 @@ export function ResultGridComponent({ gridData, allRowIds, filterParams, selecte
direction={'vertical-lr'} direction={'vertical-lr'}
noRowsText={gettext('No difference found')} noRowsText={gettext('No difference found')}
noRowsIcon={<InfoIcon className='ResultGridComponent-noRowsIcon' />} noRowsIcon={<InfoIcon className='ResultGridComponent-noRowsIcon' />}
rowClass={(row) =>
getStyleClassName(row, selectedRows, activeRow)
}
/> />
: :
<> <>

View File

@ -134,17 +134,17 @@ const columns = [
key: 'name', key: 'name',
name: gettext('Object name'), name: gettext('Object name'),
width: 250, width: 250,
formatter: ObjectNameFormatter, renderCell: ObjectNameFormatter,
},{ },{
key: 'type', key: 'type',
name: gettext('Type'), name: gettext('Type'),
width: 30, width: 70,
formatter: TypePathFormatter, renderCell: TypePathFormatter,
},{ },{
key: 'path', key: 'path',
name: gettext('Object path'), name: gettext('Object path'),
enableSorting: false, enableSorting: false,
formatter: TypePathFormatter, renderCell: TypePathFormatter,
} }
]; ];
@ -416,10 +416,10 @@ export default function SearchObjects({nodeData}) {
columns={columns} columns={columns}
rows={sortedItems} rows={sortedItems}
defaultColumnOptions={{ defaultColumnOptions={{
enableSorting: true, sortable: true,
enableResizing: true resizable: true
}} }}
headerRowHeight={28} headerRowHeight={35}
rowHeight={28} rowHeight={28}
mincolumnWidthBy={25} mincolumnWidthBy={25}
enableCellSelect={false} enableCellSelect={false}

View File

@ -9,7 +9,7 @@
import { Box } from '@mui/material'; import { Box } from '@mui/material';
import { styled } from '@mui/material/styles'; import { styled } from '@mui/material/styles';
import _ from 'lodash'; import _ from 'lodash';
import React, {useState, useEffect, useContext, useRef, useLayoutEffect, useMemo} from 'react'; import React, {useState, useEffect, useContext, useRef, useLayoutEffect, useMemo, useCallback} from 'react';
import {Row, useRowSelection} from 'react-data-grid'; import {Row, useRowSelection} from 'react-data-grid';
import LockIcon from '@mui/icons-material/Lock'; import LockIcon from '@mui/icons-material/Lock';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
@ -74,7 +74,6 @@ function CustomRow(props) {
const dataGridExtras = useContext(DataGridExtrasContext); const dataGridExtras = useContext(DataGridExtrasContext);
const rowInfoValue = useMemo(()=>({ const rowInfoValue = useMemo(()=>({
rowIdx: props.rowIdx,
getCellElement: (colIdx)=>{ getCellElement: (colIdx)=>{
return rowRef.current?.querySelector(`.rdg-cell[aria-colindex="${colIdx+1}"]`); return rowRef.current?.querySelector(`.rdg-cell[aria-colindex="${colIdx+1}"]`);
} }
@ -114,15 +113,14 @@ function getCopyShortcutHandler(handleCopy) {
}; };
} }
function SelectAllHeaderRenderer({onAllRowsSelectionChange, isCellSelected}) { function SelectAllHeaderRenderer({isCellSelected}) {
const [checked, setChecked] = useState(false); const [isRowSelected, onRowSelectionChange] = useRowSelection();
const cellRef = useRef(); const cellRef = useRef();
const eventBus = useContext(QueryToolEventsContext); const eventBus = useContext(QueryToolEventsContext);
const dataGridExtras = useContext(DataGridExtrasContext); const dataGridExtras = useContext(DataGridExtrasContext);
const onClick = ()=>{ const onClick = ()=>{
eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, true, ()=>{ eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, true, ()=>{
setChecked(!checked); onRowSelectionChange({ type: 'HEADER', checked: !isRowSelected });
onAllRowsSelectionChange(!checked);
}); });
}; };
@ -198,24 +196,24 @@ SelectableHeaderRenderer.propTypes = {
function setEditorFormatter(col) { function setEditorFormatter(col) {
// If grid is editable then add editor else make it readonly // If grid is editable then add editor else make it readonly
if (col.cell == 'oid' && col.name == 'oid') { if (col.cell == 'oid' && col.name == 'oid') {
col.editor = null; col.renderEditCell = null;
col.formatter = Formatters.TextFormatter; col.renderCell = Formatters.TextFormatter;
} else if (col.cell == 'Json') { } else if (col.cell == 'Json') {
col.editor = Editors.JsonTextEditor; col.renderEditCell = Editors.JsonTextEditor;
col.formatter = Formatters.TextFormatter; col.renderCell = Formatters.TextFormatter;
} else if (['number', 'oid'].indexOf(col.cell) != -1 || ['xid', 'real'].indexOf(col.type) != -1) { } else if (['number', 'oid'].indexOf(col.cell) != -1 || ['xid', 'real'].indexOf(col.type) != -1) {
col.formatter = Formatters.NumberFormatter; col.renderCell = Formatters.NumberFormatter;
col.editor = Editors.NumberEditor; col.renderEditCell = Editors.NumberEditor;
} else if (col.cell == 'boolean') { } else if (col.cell == 'boolean') {
col.editor = Editors.CheckboxEditor; col.renderEditCell = Editors.CheckboxEditor;
col.formatter = Formatters.TextFormatter; col.renderCell = Formatters.TextFormatter;
} else if (col.cell == 'binary') { } else if (col.cell == 'binary') {
// We do not support editing binary data in SQL editor and data grid. // We do not support editing binary data in SQL editor and data grid.
col.editor = null; col.renderEditCell = null;
col.formatter = Formatters.BinaryFormatter; col.renderCell = Formatters.BinaryFormatter;
} else { } else {
col.editor = Editors.TextEditor; col.renderEditCell = Editors.TextEditor;
col.formatter = Formatters.TextFormatter; col.renderCell = Formatters.TextFormatter;
} }
} }
@ -251,7 +249,7 @@ function initialiseColumns(columns, rows, totalRowCount, columnWidthBy) {
for(const col of retColumns) { for(const col of retColumns) {
col.width = getTextWidth(col, rows, canvasContext, columnWidthBy); col.width = getTextWidth(col, rows, canvasContext, columnWidthBy);
col.resizable = true; col.resizable = true;
col.editorOptions = { col.renderEditCellOptions = {
commitOnOutsideClick: false, commitOnOutsideClick: false,
onCellKeyDown: (e)=>{ onCellKeyDown: (e)=>{
// global keyboard shortcuts will work now and will open the the editor for the cell once pgAdmin reopens // global keyboard shortcuts will work now and will open the the editor for the cell once pgAdmin reopens
@ -276,12 +274,9 @@ function initialiseColumns(columns, rows, totalRowCount, columnWidthBy) {
canvas.remove(); canvas.remove();
return retColumns; return retColumns;
} }
function RowNumColFormatter({row, rowKeyGetter, rowIdx, dataChangeStore, onSelectedColumnsChange}) {
function RowNumColFormatter({row, rowKeyGetter, dataChangeStore, onSelectedColumnsChange}) {
const {rowIdx} = useContext(RowInfoContext);
const [isRowSelected, onRowSelectionChange] = useRowSelection(); const [isRowSelected, onRowSelectionChange] = useRowSelection();
let rowKey = rowKeyGetter(row); let rowKey = rowKeyGetter(row);
let rownum = rowIdx+1; let rownum = rowIdx+1;
if(rowKey in (dataChangeStore?.added || {})) { if(rowKey in (dataChangeStore?.added || {})) {
@ -291,7 +286,7 @@ function RowNumColFormatter({row, rowKeyGetter, dataChangeStore, onSelectedColum
} }
return (<div className='QueryTool-rowNumCell' onClick={()=>{ return (<div className='QueryTool-rowNumCell' onClick={()=>{
onSelectedColumnsChange(new Set()); onSelectedColumnsChange(new Set());
onRowSelectionChange({ row: row, checked: !isRowSelected, isShiftClick: false}); onRowSelectionChange({ type: 'ROW', row: row, checked: !isRowSelected, isShiftClick: false});
}} onKeyDown={()=>{/* already taken care by parent */}}> }} onKeyDown={()=>{/* already taken care by parent */}}>
{rownum} {rownum}
</div>); </div>);
@ -313,13 +308,13 @@ function formatColumns(columns, dataChangeStore, selectedColumns, onSelectedColu
}; };
for(const [idx, col] of retColumns.entries()) { for(const [idx, col] of retColumns.entries()) {
col.headerRenderer = HeaderRenderer; col.renderHeaderCell = HeaderRenderer;
col.cellClass = cellClassGetter(col, selectedColumns.has(idx), dataChangeStore, rowKeyGetter); col.cellClass = cellClassGetter(col, selectedColumns.has(idx), dataChangeStore, rowKeyGetter);
} }
let rowNumCol = retColumns[0]; let rowNumCol = retColumns[0];
rowNumCol.headerRenderer = SelectAllHeaderRenderer; rowNumCol.renderHeaderCell = SelectAllHeaderRenderer;
rowNumCol.formatter = (props)=>{ rowNumCol.renderCell = (props)=>{
return <RowNumColFormatter {...props} rowKeyGetter={rowKeyGetter} dataChangeStore={dataChangeStore} onSelectedColumnsChange={onSelectedColumnsChange} />; return <RowNumColFormatter {...props} rowKeyGetter={rowKeyGetter} dataChangeStore={dataChangeStore} onSelectedColumnsChange={onSelectedColumnsChange} />;
}; };
@ -372,6 +367,10 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha
eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_COPY_DATA); eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_COPY_DATA);
} }
const renderCustomRow = useCallback((key, props) => {
return <CustomRow key={key} {...props} />;
}, []);
const dataGridExtras = useMemo(()=>({ const dataGridExtras = useMemo(()=>({
onSelectedCellChange, handleCopy onSelectedCellChange, handleCopy
}), [onSelectedCellChange]); }), [onSelectedCellChange]);
@ -399,8 +398,8 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha
enableCellSelect={true} enableCellSelect={true}
onCopy={handleCopy} onCopy={handleCopy}
onMultiCopy={handleCopy} onMultiCopy={handleCopy}
components={{ renderers={{
rowRenderer: CustomRow, renderRow: renderCustomRow,
}} }}
enableRangeSelection={true} enableRangeSelection={true}
rangeLeftBoundaryColIdx={0} rangeLeftBoundaryColIdx={0}

View File

@ -5389,7 +5389,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"clsx@npm:^2.1.0, clsx@npm:^2.1.1": "clsx@npm:^2.0.0, clsx@npm:^2.1.0, clsx@npm:^2.1.1":
version: 2.1.1 version: 2.1.1
resolution: "clsx@npm:2.1.1" resolution: "clsx@npm:2.1.1"
checksum: acd3e1ab9d8a433ecb3cc2f6a05ab95fe50b4a3cfc5ba47abb6cbf3754585fcb87b84e90c822a1f256c4198e3b41c7f6c391577ffc8678ad587fc0976b24fd57 checksum: acd3e1ab9d8a433ecb3cc2f6a05ab95fe50b4a3cfc5ba47abb6cbf3754585fcb87b84e90c822a1f256c4198e3b41c7f6c391577ffc8678ad587fc0976b24fd57
@ -13251,15 +13251,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-data-grid@https://github.com/pgadmin-org/react-data-grid.git#200d2f5e02de694e3e9ffbe177c279bc40240fb8": "react-data-grid@https://github.com/pgadmin-org/react-data-grid.git#4e10a5a327ff58198ac83c7b0c62549b20b78ae5":
version: 7.0.0-beta.14 version: 7.0.0-beta.44
resolution: "react-data-grid@https://github.com/pgadmin-org/react-data-grid.git#commit=200d2f5e02de694e3e9ffbe177c279bc40240fb8" resolution: "react-data-grid@https://github.com/pgadmin-org/react-data-grid.git#commit=4e10a5a327ff58198ac83c7b0c62549b20b78ae5"
dependencies: dependencies:
clsx: ^1.1.1 clsx: ^2.0.0
peerDependencies: peerDependencies:
react: ^16.14 || ^17.0 || ^18.0 react: ^18.0 || ^19.0
react-dom: ^16.14 || ^17.0 || ^18.0 react-dom: ^18.0 || ^19.0
checksum: ee77fcd8b689e664824f24ed91c82263158e5fb77214f8b5e6bc88d13deb30bd8bd381e6901bc508f1152745dbb8b858f57d605f13bb936275137d01e81a0ae7 checksum: 75e8910f9b69c60c28223e82647cb8323e08d13d1b56eec94e918e7feadc50f5f4257205a3cd628b9fba019577c3ffab62bdecda7d950e7647ba75988de28261
languageName: node languageName: node
linkType: hard linkType: hard
@ -14038,7 +14038,7 @@ __metadata:
react-arborist: ^3.2.0 react-arborist: ^3.2.0
react-aspen: ^1.1.0 react-aspen: ^1.1.0
react-checkbox-tree: ^1.7.2 react-checkbox-tree: ^1.7.2
react-data-grid: "https://github.com/pgadmin-org/react-data-grid.git#200d2f5e02de694e3e9ffbe177c279bc40240fb8" react-data-grid: "https://github.com/pgadmin-org/react-data-grid.git#4e10a5a327ff58198ac83c7b0c62549b20b78ae5"
react-dnd: ^16.0.1 react-dnd: ^16.0.1
react-dnd-html5-backend: ^16.0.1 react-dnd-html5-backend: ^16.0.1
react-dom: ^18.2.0 react-dom: ^18.2.0