+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+
+ {flexRender(header.column.columnDef.header, header.getContext())}
+ {header.column.getCanSort() && header.column.getIsSorted() &&
+
+ {header.column.getIsSorted() == 'desc' ?
+
+ : }
+ }
+
+ {header.column.getCanResize() && (
+
header.column.resetSize()}
+ onMouseDown={header.getResizeHandler()}
+ onTouchStart={header.getResizeHandler()}
+ className='pgrt-header-resizer'
+ />
+ )}
+
+ ))}
+
+ ))}
+
+ );
+}
+PgReactTableHeader.propTypes = {
+ table: PropTypes.object,
+};
+
+export function PgReactTableBody({children, style}) {
+ return (
+
+ {children}
+
+ );
+}
+PgReactTableBody.propTypes = {
+ style: PropTypes.object,
+ children: CustomPropTypes.children,
+};
+
+export const PgReactTable = forwardRef(({children, table, rootClassName, tableClassName, ...props}, ref)=>{
+ const columns = table.getAllColumns();
+ // Render the UI for your table
+ const maxExpandWidth = (ref.current?.getBoundingClientRect().width ?? 430) - 30; //margin,scrollbar,etc.
+
+ const columnSizeVars = React.useMemo(() => {
+ const headers = table.getFlatHeaders();
+ const colSizes = {};
+ for (let i = 0; i < headers.length; i++) {
+ const header = headers[i];
+ colSizes[`--header-${header.id}-size`] = header.getSize();
+ colSizes[`--col-${header.column.id}-size`] = header.column.getSize();
+ }
+ return colSizes;
+ }, [columns, table.getState().columnSizingInfo]);
+
+ return (
+
+
+ {children}
+
+
+ );
+});
+PgReactTable.displayName = 'PgReactTable';
+PgReactTable.propTypes = {
+ table: PropTypes.object,
+ rootClassName: PropTypes.any,
+ tableClassName: PropTypes.any,
+ children: CustomPropTypes.children,
+};
+
+export function getExpandCell({ onClick, ...props }) {
+ const Cell = ({ row }) => {
+ const onClickFinal = (e) => {
+ e.preventDefault();
+ row.toggleExpanded();
+ onClick?.(row, e);
+ };
+ return (
+
+ ) : (
+
+ )
+ }
+ noBorder
+ {...props}
+ onClick={onClickFinal}
+ aria-label={props.title}
+ />
+ );
+ };
+
+ Cell.displayName = 'ExpandCell';
+ Cell.propTypes = {
+ title: PropTypes.string,
+ row: PropTypes.any,
+ };
+
+ return Cell;
+}
+
+const ReadOnlySwitch = styled(Switch)(({theme})=>({
+ opacity: 0.75,
+ '& .MuiSwitch-track': {
+ opacity: theme.palette.action.disabledOpacity,
+ }
+}));
+export function getSwitchCell() {
+ const Cell = ({ value }) => {
+ return
;
+ };
+
+ Cell.displayName = 'SwitchCell';
+ Cell.propTypes = {
+ value: PropTypes.any,
+ };
+
+ return Cell;
+}
diff --git a/web/pgadmin/static/js/components/PgTable.jsx b/web/pgadmin/static/js/components/PgTable.jsx
index 9d03e7843..2bb0586b6 100644
--- a/web/pgadmin/static/js/components/PgTable.jsx
+++ b/web/pgadmin/static/js/components/PgTable.jsx
@@ -7,484 +7,244 @@
//
//////////////////////////////////////////////////////////////
-import React from 'react';
+import React, { useMemo, useRef } from 'react';
import {
- useTable,
- useRowSelect,
- useSortBy,
- useResizeColumns,
- useFlexLayout,
- useGlobalFilter,
- useExpanded,
-} from 'react-table';
-import { VariableSizeList } from 'react-window';
-import { makeStyles } from '@mui/styles';
-import clsx from 'clsx';
+ useReactTable,
+ getCoreRowModel,
+ getSortedRowModel,
+ getFilteredRowModel,
+ getExpandedRowModel,
+ flexRender,
+} from '@tanstack/react-table';
+import { useVirtualizer } from '@tanstack/react-virtual';
+import { styled } from '@mui/styles';
import PropTypes from 'prop-types';
-import AutoSizer from 'react-virtualized-auto-sizer';
-import { Checkbox, Box, Switch } from '@mui/material';
+import { Checkbox, Box } from '@mui/material';
import { InputText } from './FormComponents';
import _ from 'lodash';
import gettext from 'sources/gettext';
import SchemaView from '../SchemaView';
import EmptyPanelMessage from './EmptyPanelMessage';
-import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
-import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
-import ChevronRightIcon from '@mui/icons-material/ChevronRight';
-import { PgIconButton } from './Buttons';
+import { PgReactTable, PgReactTableBody, PgReactTableCell, PgReactTableHeader, PgReactTableRow, PgReactTableRowContent, PgReactTableRowExpandContent } from './PgReactTableStyled';
-/* eslint-disable react/display-name */
-const useStyles = makeStyles((theme) => ({
- root: {
+const ROW_HEIGHT = 30;
+function TableRow({ index, style, schema, row, measureElement }) {
+ const [expandComplete, setExpandComplete] = React.useState(false);
+ const rowRef = React.useRef();
+
+ React.useEffect(() => {
+ if (rowRef.current) {
+ if (!expandComplete && rowRef.current.style.height == `${ROW_HEIGHT}px`) {
+ return;
+ }
+ measureElement(rowRef.current);
+ }
+ }, [row.getIsExpanded(), expandComplete]);
+
+ return (
+
+
+ {row.getVisibleCells().map((cell) => {
+ const content = flexRender(cell.column.columnDef.cell, cell.getContext());
+
+ return (
+
+ {content}
+
+ );
+ })}
+
+
+ Promise.resolve(row.original)}
+ viewHelperProps={{ mode: 'properties' }}
+ schema={schema}
+ showFooter={false}
+ onDataChange={() => { setExpandComplete(true); }}
+ />
+
+
+ );
+}
+TableRow.propTypes = {
+ index: PropTypes.number,
+ style: PropTypes.object,
+ row: PropTypes.object,
+ schema: PropTypes.object,
+ measureElement: PropTypes.func,
+};
+
+export function Table({ columns, data, hasSelectRow, schema, sortOptions, tableProps, searchVal, ...props }) {
+ const defaultColumn = React.useMemo(
+ () => ({
+ size: 150,
+ minSize: 100,
+ maxSize: 1200,
+ }),
+ []
+ );
+
+ const finalColumns = useMemo(() => (hasSelectRow ? [{
+ id: 'selection',
+ header: ({ table }) => {
+ return (
+
+
+
+ );
+ },
+ cell: ({ row }) => (
+
+
+
+ ),
+ enableSorting: false,
+ enableResizing: false,
+ maxSize: 35,
+ }] : []).concat(
+ columns.filter((c)=>_.isUndefined(c.enableVisibility) ? true : c.enableVisibility)
+ ), [hasSelectRow, columns]);
+
+ // Render the UI for your table
+ const tableRef = useRef();
+
+ const table = useReactTable({
+ columns: finalColumns,
+ data,
+ defaultColumn,
+ autoResetAll: false,
+ initialState: {
+ sorting: sortOptions || [],
+ },
+ state: {
+ rowSelection: props.selectedRows ?? {},
+ globalFilter: searchVal,
+ },
+ columnResizeMode: 'onChange',
+ onRowSelectionChange: props.setSelectedRows,
+ enableRowSelection: (row) => (hasSelectRow && (_.isUndefined(row.original.canDrop) ? true : row.original.canDrop)),
+ getCoreRowModel: getCoreRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ getFilteredRowModel: getFilteredRowModel(),
+ getExpandedRowModel: getExpandedRowModel(),
+ ...tableProps,
+ });
+
+ const rows = table.getRowModel().rows;
+
+ const virtualizer = useVirtualizer({
+ count: rows.length,
+ getScrollElement: () => tableRef.current,
+ estimateSize: () => ROW_HEIGHT,
+ measureElement:
+ typeof window !== 'undefined' &&
+ navigator.userAgent.indexOf('Firefox') === -1
+ ? element => element?.getBoundingClientRect().height
+ : undefined,
+ overscan: 20,
+ });
+
+ return (
+
+
+ {rows.length == 0 ?
+ :
+
+ {virtualizer.getVirtualItems().map((virtualRow) => {
+ const row = rows[virtualRow.index];
+ return ;
+ })}
+ }
+
+ );
+}
+Table.propTypes = {
+ columns: PropTypes.array,
+ data: PropTypes.array,
+ hasSelectRow: PropTypes.bool,
+ schema: PropTypes.object,
+ sortOptions: PropTypes.arrayOf(PropTypes.object),
+ tableProps: PropTypes.object,
+ selectedRows: PropTypes.object,
+ setSelectedRows: PropTypes.func,
+ searchVal: PropTypes.string,
+};
+
+const StyledPgTableRoot = styled('div')(({theme})=>({
+ display: 'flex',
+ flexGrow: 1,
+ overflow: 'hidden',
+ flexDirection: 'column',
+ height: '100%',
+
+
+ '& .pgtable-header': {
display: 'flex',
- flexDirection: 'column',
- height: '100%',
- ...theme.mixins.panelBorder,
- backgroundColor: theme.palette.background.default,
+ background: theme.palette.background.default,
+ padding: '8px 2px 4px',
+
+ '& .pgtable-search-input': {
+ minWidth: '300px'
+ },
},
- autoResizerContainer: {
- flexGrow: 1,
- minHeight: 0
- },
- autoResizer: {
- width: '100% !important',
- },
- fixedSizeList: {
- direction: 'ltr',
- overflowX: 'hidden !important',
- overflow: 'overlay !important',
- },
- CustomHeader:{
- marginTop: '8px',
- marginLeft: '4px'
- },
- warning: {
- backgroundColor: theme.palette.warning.main + '!important'
- },
- alert: {
- backgroundColor: theme.palette.error.main + '!important'
- },
- searchInput: {
- minWidth: '300px'
- },
- tableContainer: {
- overflowX: 'auto',
+
+ '& .pgtable-body': {
flexGrow: 1,
minHeight: 0,
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.otherVars.emptySpaceBg,
},
- table: {
- borderSpacing: 0,
- overflow: 'hidden',
- borderRadius: theme.shape.borderRadius,
- border: '1px solid '+theme.otherVars.borderColor,
- display: 'flex',
- flexDirection: 'column',
- height: '100%',
- },
- pgTableContainer: {
- display: 'flex',
- flexGrow: 1,
- overflow: 'hidden',
- flexDirection: 'column',
- height: '100%',
- },
- pgTableHeader: {
- display: 'flex',
- background: theme.palette.background.default,
- padding: '8px 8px 4px',
- },
- tableRowContent:{
- display: 'flex',
- flexDirection: 'column',
- minHeight: 0,
- },
- expandedForm: {
- ...theme.mixins.panelBorder.all,
- margin: '8px',
- flexGrow: 1,
- },
-
- tableCell: {
- margin: 0,
- padding: theme.spacing(0.5),
- ...theme.mixins.panelBorder.bottom,
- ...theme.mixins.panelBorder.right,
- position: 'relative',
- overflow: 'hidden',
- height: '34px',
- textOverflow: 'ellipsis',
- whiteSpace: 'nowrap',
- backgroundColor: theme.otherVars.tableBg,
- userSelect: 'text'
- },
- selectCell: {
- textAlign: 'center',
- minWidth: 20
- },
- tableHeader: {
- backgroundColor: theme.otherVars.tableBg,
- },
- tableCellHeader: {
- fontWeight: theme.typography.fontWeightBold,
- padding: theme.spacing(1, 0.5),
- textAlign: 'left',
- alignContent: 'center',
- backgroundColor: theme.otherVars.tableBg,
- overflow: 'hidden',
- ...theme.mixins.panelBorder.bottom,
- ...theme.mixins.panelBorder.right,
- ...theme.mixins.panelBorder.top,
- ...theme.mixins.panelBorder.left,
- },
- resizer: {
- display: 'inline-block',
- width: '5px',
- height: '100%',
- position: 'absolute',
- right: 0,
- top: 0,
- transform: 'translateX(50%)',
- zIndex: 1,
- touchAction: 'none',
- },
- cellIcon: {
- paddingLeft: '1.8em',
- paddingTop: '0.35em',
- borderRadius: 0,
- backgroundPosition: '1%',
- },
- emptyPanel: {
- minHeight: '100%',
- minWidth: '100%',
- overflow: 'auto',
- padding: '8px',
- display: 'flex',
- },
- caveTable: {
- margin: '8px',
- },
- panelIcon: {
- width: '80%',
- margin: '0 auto',
- marginTop: '25px !important',
- position: 'relative',
- textAlign: 'center',
- },
- panelMessage: {
- marginLeft: '0.5rem',
- fontSize: '0.875rem',
- },
- expandedIconCell: {
- backgroundColor: theme.palette.grey[400],
- ...theme.mixins.panelBorder.top,
- borderBottom: 'none',
- },
- btnCell: {
- padding: theme.spacing(0.5, 0),
- textAlign: 'center',
- },
- btnExpanded: {
- backgroundColor: theme.palette.grey[400]
- },
- readOnlySwitch: {
- opacity: 0.75,
- '& .MuiSwitch-track': {
- opacity: theme.palette.action.disabledOpacity,
+ '&.pgtable-pgrt-border': {
+ '& .pgrt': {
+ border: '1px solid ' + theme.otherVars.borderColor,
}
- }
+ },
+
+ '&.pgtable-pgrt-cave': {
+ '& .pgtable-body': {
+ padding: '8px',
+ },
+ '& .pgtable-header': {
+ padding: '8px 8px 4px',
+ },
+ '& .pgrt': {
+ border: '1px solid ' + theme.otherVars.borderColor,
+ }
+ },
}));
-const IndeterminateCheckbox = React.forwardRef(
- ({ indeterminate, label, ...rest }, ref) => {
- const defaultRef = React.useRef();
- const resolvedRef = ref || defaultRef;
-
- React.useEffect(() => {
- resolvedRef.current.indeterminate = indeterminate;
- }, [resolvedRef, indeterminate]);
- return (
-
- );
- },
-);
-
-IndeterminateCheckbox.displayName = 'SelectCheckbox';
-
-IndeterminateCheckbox.propTypes = {
- indeterminate: PropTypes.bool,
- rest: PropTypes.func,
- getToggleAllRowsSelectedProps: PropTypes.func,
- row: PropTypes.object,
- label: PropTypes.string,
-};
-
-const ROW_HEIGHT = 34;
-
-function SortIcon ({column}) {
- if (column.isSorted) {
- return column.isSortedDesc ?
:
;
- }
- return '';
-}
-
-SortIcon.propTypes = {
- column: PropTypes.object
-};
-
-function RenderRow({ index, style, schema, row, prepareRow, setRowHeight, ExpandedComponent }) {
- const [expandComplete, setExpandComplete] = React.useState(false);
- const rowRef = React.useRef() ;
- const classes = useStyles();
- prepareRow(row);
-
- React.useEffect(()=>{
- if(rowRef.current) {
- if(!expandComplete && rowRef.current.style.height == `${ROW_HEIGHT}px`) {
- return;
- }
- let rowHeight;
- rowRef.current.style.height = 'unset';
- if(expandComplete) {
- rowHeight = rowRef.current.offsetHeight;
- } else {
- rowHeight = ROW_HEIGHT;
- rowRef.current.style.height = ROW_HEIGHT;
- }
- rowRef.current.style.height = rowHeight + 'px';
- setRowHeight(index, rowHeight);
- }
- }, [expandComplete]);
-
- return (
-
-
-
- {row.cells.map((cell) => {
- let classNames = [classes.tableCell];
- if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) {
- classNames.push(classes.btnCell);
- }
- if(cell.column.id == 'btn-edit' && row.isExpanded) {
- classNames.push(classes.expandedIconCell);
- }
- if (row.original.row_type === 'warning'){
- classNames.push(classes.warning);
- }
- if (row.original.row_type === 'alert'){
- classNames.push(classes.alert);
- }
- return (
-
- {cell.render('Cell')}
-
- );
- })}
-
- {!_.isUndefined(row) && row.isExpanded && (
-
- {schema && Promise.resolve(row.original)}
- viewHelperProps={{ mode: 'properties' }}
- schema={schema[row.id]??schema}
- showFooter={false}
- onDataChange={()=>{setExpandComplete(true);}}
- />}
- {ExpandedComponent && setExpandComplete(true)}/>}
-
- )}
-
-
- );
-}
-RenderRow.propTypes = {
- index: PropTypes.number,
- style: PropTypes.object,
- row: PropTypes.object,
- schema: PropTypes.object,
- prepareRow: PropTypes.func,
- setRowHeight: PropTypes.func,
- ExpandedComponent: PropTypes.node,
-};
-
-export default function PgTable({ columns, data, isSelectRow, caveTable=true, schema, ExpandedComponent, sortOptions, tableProps, ...props }) {
- // Use the state and functions returned from useTable to build your UI
- const classes = useStyles();
+export default function PgTable({ caveTable = true, tableNoBorder = true, ...props }) {
const [searchVal, setSearchVal] = React.useState('');
- const windowTableRef = React.useRef();
- const rowHeights = React.useRef({});
- // Reset Search value on tab changes.
-
- React.useEffect(()=>{
- setSearchVal(prevState => (prevState));
- setGlobalFilter(searchVal || undefined);
- rowHeights.current = {};
- windowTableRef.current?.resetAfterIndex(0);
- }, [data]);
-
- function getRowHeight(index) {
- return rowHeights.current[index] || ROW_HEIGHT;
- }
-
- const setRowHeight = (index, size) => {
- if(windowTableRef.current) {
- if(size == ROW_HEIGHT) {
- delete rowHeights.current[index];
- } else {
- rowHeights.current[index] = size;
- }
- windowTableRef.current.resetAfterIndex(index);
- }
- };
-
- const defaultColumn = React.useMemo(
- () => ({
- minWidth: 50,
- }),
- []
- );
-
- const {
- getTableProps,
- getTableBodyProps,
- headerGroups,
- rows,
- prepareRow,
- selectedFlatRows,
- state: { selectedRowIds },
- setGlobalFilter,
- setHiddenColumns,
- totalColumnsWidth
- } = useTable(
- {
- columns,
- data,
- defaultColumn,
- isSelectRow,
- autoResetSortBy: false,
- initialState: {
- sortBy: sortOptions || [],
- },
- ...tableProps,
- },
- useGlobalFilter,
- useSortBy,
- useExpanded,
- useRowSelect,
- useResizeColumns,
- useFlexLayout,
- (hooks) => {
- hooks.visibleColumns.push((CLOUMNS) => {
- if (isSelectRow) {
- return [
- // Let's make a column for selection
- {
- id: 'selection',
- resizable: false,
- // The header can use the table's getToggleAllRowsSelectedProps method
- // to render a checkbox
- Header: ({ getToggleAllRowsSelectedProps, toggleRowSelected, isAllRowsSelected, rows }) => {
-
- const modifiedOnChange = (event) => {
- rows.forEach((row) => {
- //check each row if it is not disabled
- !(!_.isUndefined(row.original.canDrop) && !(row.original.canDrop)) && toggleRowSelected(row.id, event.currentTarget.checked);
-
- });
- };
-
- let allTableRows = 0;
- let selectedTableRows = 0;
- rows.forEach((row) => {
- row.isSelected && selectedTableRows++;
- (_.isUndefined(row.original.canDrop) || row.original.canDrop) && allTableRows++;
- });
- const disabled = allTableRows === 0;
- const checked =
- (isAllRowsSelected ||
- allTableRows === selectedTableRows) &&
- !disabled;
- return(
-
-
-
- );},
- // The cell can use the individual row's getToggleRowSelectedProps method
- // to the render a checkbox
- Cell: ({ row }) => (
-
-
-
- ),
- sortable: false,
- disableResizing: true,
- width: 35,
- maxWidth: 35,
- minWidth: 35
- },
- ...CLOUMNS,
- ];
- } else {
- return [...CLOUMNS];
- }
- });
- }
- );
-
- React.useEffect(() => {
- setHiddenColumns(
- columns
- .filter((column) => {
- return !(column.isVisible === undefined || column.isVisible === true);
- }
- )
- .map((column) => column.accessor)
- );
- }, [setHiddenColumns, columns]);
-
- React.useEffect(() => {
- if (props.setSelectedRows) {
- props.setSelectedRows(selectedFlatRows);
- }
- }, [selectedRowIds]);
-
- React.useEffect(() => {
- if (props.getSelectedRows) {
- props.getSelectedRows(selectedFlatRows);
- }
- }, [selectedRowIds]);
-
- React.useEffect(() => {
- setGlobalFilter(searchVal || undefined);
- }, [searchVal]);
-
- // Render the UI for your table
return (
-
-
- {props.CustomHeader && ( )}
+
+
+ {props.CustomHeader && ( )}
{
setSearchVal(val);
@@ -492,149 +252,16 @@ export default function PgTable({ columns, data, isSelectRow, caveTable=true, sc
/>
-
-
-
- {headerGroups.map((headerGroup) => (
-
({
- style: {
- ...column.style,
- height: '40px',
- }
- }))}>
- {headerGroup.headers.map((column) => (
-
-
- {column.render('Header')}
-
-
-
-
- {column.resizable && (
-
- )}
-
- ))}
-
- ))}
-
- {
- data.length > 0 ? (
-
-
- {({ height }) => (
-
- {({index, style})=>(
-
- )}
- )}
-
-
- ) : (
-
- )
- }
-
+
-
+
);
}
PgTable.propTypes = {
- stepId: PropTypes.number,
- height: PropTypes.number,
CustomHeader: PropTypes.func,
- className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
caveTable: PropTypes.bool,
- fixedSizeList: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
- children: PropTypes.oneOfType([
- PropTypes.arrayOf(PropTypes.node),
- PropTypes.node,
- ]),
- getToggleAllRowsSelectedProps: PropTypes.func,
- toggleRowSelected: PropTypes.func,
- columns: PropTypes.array,
- data: PropTypes.array,
- isSelectRow: PropTypes.bool,
- isAllRowsSelected: PropTypes.bool,
- row: PropTypes.func,
- setSelectedRows: PropTypes.func,
- getSelectedRows: PropTypes.func,
- searchText: PropTypes.string,
- sortOptions: PropTypes.array,
- schema: PropTypes.object,
- rows: PropTypes.object,
- ExpandedComponent: PropTypes.node,
- tableProps: PropTypes.object,
+ tableNoBorder: PropTypes.bool,
'data-test': PropTypes.string
-};
-
-
-export function getExpandCell({onClick, ...props}) {
- const Cell = ({ row }) => {
- const classes = useStyles();
- const onClickFinal = (e)=>{
- e.preventDefault();
- row.toggleRowExpanded(!row.isExpanded);
- onClick?.(row, e);
- };
- return (
-
- ) : (
-
- )
- }
- noBorder
- {...props}
- onClick={onClickFinal}
- aria-label={props.title}
- />
- );
- };
-
- Cell.displayName = 'ExpandCell';
- Cell.propTypes = {
- title: PropTypes.string,
- row: PropTypes.any,
- };
-
- return Cell;
-}
-
-export function getSwitchCell() {
- const Cell = ({value})=>{
- const classes = useStyles();
- return
;
- };
-
- Cell.displayName = 'SwitchCell';
- Cell.propTypes = {
- value: PropTypes.any,
- };
-
- return Cell;
-}
+};
\ No newline at end of file
diff --git a/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx b/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
index 8804e4798..5ee44910f 100644
--- a/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
+++ b/web/pgadmin/tools/grant_wizard/static/js/GrantWizard.jsx
@@ -10,7 +10,7 @@
import gettext from 'sources/gettext';
import _ from 'lodash';
import url_for from 'sources/url_for';
-import React from 'react';
+import React, { useEffect } from 'react';
import { Box } from '@mui/material';
import { makeStyles } from '@mui/styles';
import Wizard from '../../../../static/js/helpers/wizard/Wizard';
@@ -63,63 +63,64 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
let columns = [
{
- Header: 'Object Type',
- accessor: 'object_type',
- sortable: true,
- resizable: false,
- disableGlobalFilter: true
+ header: 'Object Type',
+ accessorKey: 'object_type',
+ enableSorting: true,
+ enableResizing: false,
+ enableFilters: false
},
{
- Header: 'Schema',
- accessor: 'nspname',
- sortable: true,
- resizable: false,
- disableGlobalFilter: true
+ header: 'Schema',
+ accessorKey: 'nspname',
+ enableSorting: true,
+ enableResizing: false,
+ enableFilters: false
},
{
- Header: 'Name',
- accessor: 'name_with_args',
- sortable: true,
- resizable: true,
- disableGlobalFilter: false,
- minWidth: 280
+ header: 'Name',
+ accessorKey: 'name_with_args',
+ enableSorting: true,
+ enableResizing: true,
+ enableFilters: true,
+ minSize: 280
},
{
- Header: 'parameters',
- accessor: 'proargs',
- sortable: false,
- resizable: false,
- disableGlobalFilter: false,
+ header: 'parameters',
+ accessorKey: 'proargs',
+ enableSorting: false,
+ enableResizing: false,
+ enableFilters: true,
+ enableVisibility: false,
minWidth: 280,
- isVisible: false
},
{
- Header: 'Name',
- accessor: 'name',
- sortable: false,
- resizable: false,
- disableGlobalFilter: false,
+ header: 'Name',
+ accessorKey: 'name',
+ enableSorting: false,
+ enableResizing: false,
+ enableFilters: true,
+ enableVisibility: false,
minWidth: 280,
- isVisible: false
},
{
- Header: 'ID',
- accessor: 'oid',
- sortable: false,
- resizable: false,
- disableGlobalFilter: false,
+ header: 'ID',
+ accessorKey: 'oid',
+ enableSorting: false,
+ enableResizing: false,
+ enableFilters: true,
+ enableVisibility: false,
minWidth: 280,
- isVisible: false
}
];
let steps = [gettext('Object Selection'), gettext('Privilege Selection'), gettext('Review')];
- const [selectedObject, setSelectedObject] = React.useState([]);
+ const [selectedRows, setSelectedRows] = React.useState({});
const [selectedAcl, setSelectedAcl] = React.useState({});
const [msqlData, setMSQLData] = React.useState('');
const [loaderText, setLoaderText] = React.useState('');
const [tableData, setTableData] = React.useState([]);
const [privOptions, setPrivOptions] = React.useState({});
- const [privileges, setPrivileges] = React.useState([]);
+ const selectedObject = React.useRef([]);
+ const privileges = React.useRef([]);
const [privSchemaInstance, setPrivSchemaInstance] = React.useState();
const [errMsg, setErrMsg] = React.useState('');
const pgAdmin = usePgAdmin();
@@ -135,11 +136,6 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
return !isValid;
};
-
- React.useEffect(() => {
- privSchemaInstance?.privilegeRoleSchema.updateSupportedPrivs(privileges);
- }, [privileges]);
-
React.useEffect(() => {
const privSchema = new PrivilegeSchema((privs) => getNodePrivilegeRoleSchema('', nodeInfo, nodeData, privs));
setPrivSchemaInstance(privSchema);
@@ -197,7 +193,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
});
let post_data = {
acl: selectedAcl.privilege,
- objects: selectedObject
+ objects: selectedObject.current
};
api.post(msql_url, post_data)
.then(res => {
@@ -219,7 +215,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
});
const post_data = {
acl: selectedAcl.privilege,
- objects: selectedObject
+ objects: selectedObject.current
};
api.post(_url, post_data)
.then(() => {
@@ -233,7 +229,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
};
const disableNextCheck = (stepId) => {
- if (selectedObject.length > 0 && stepId === 0) {
+ if (Object.keys(selectedRows).length > 0 && stepId === 0) {
return false;
}
@@ -244,14 +240,14 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
window.open(url_for('help.static', { 'filename': 'grant_wizard.html' }), 'pgadmin_help');
};
- const getTableSelectedRows = (selRows) => {
+ useEffect(()=>{
let selObj = [];
let objectTypes = new Set();
- if (selRows.length > 0) {
-
- selRows.forEach((row) => {
+ if (Object.keys(selectedRows).length > 0) {
+ Object.keys(selectedRows).forEach((rowId) => {
+ const row = tableData[rowId];
let object_type = '';
- switch (row.values.object_type) {
+ switch (row.object_type) {
case 'Function':
object_type = 'function';
break;
@@ -284,7 +280,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
}
objectTypes.add(object_type);
- selObj.push(row.values);
+ selObj.push(row);
});
}
let privs = new Set();
@@ -293,10 +289,11 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
privs.add(priv);
});
});
- setPrivileges(Array.from(privs));
- setSelectedObject(selObj);
+ privileges.current = Array.from(privs);
+ selectedObject.current = selObj;
+ privSchemaInstance?.privilegeRoleSchema.updateSupportedPrivs(privileges.current);
setErrMsg(selObj.length === 0 ? gettext('Please select any database object.') : '');
- };
+ }, [selectedRows]);
const onErrClose = React.useCallback(()=>{
setErrMsg('');
@@ -316,13 +313,15 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
-
+ hasSelectRow={true}
+ selectedRows={selectedRows}
+ setSelectedRows={setSelectedRows}
+ />
@@ -330,17 +329,17 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData, onClose }) {
stepId={1}
className={clsx(classes.privilegeStep)}>
{privSchemaInstance &&
-
{/*This is intentional (SonarQube)*/}}
- viewHelperProps={{ mode: 'create' }}
- schema={privSchemaInstance}
- showFooter={false}
- isTabView={false}
- onDataChange={(isChanged, changedData) => {
- setSelectedAcl(changedData);
- }}
- />
+ {/*This is intentional (SonarQube)*/}}
+ viewHelperProps={{ mode: 'create' }}
+ schema={privSchemaInstance}
+ showFooter={false}
+ isTabView={false}
+ onDataChange={(isChanged, changedData) => {
+ setSelectedAcl(changedData);
+ }}
+ />
}
{
return obj.isEditable(state);
}
@@ -137,7 +137,7 @@ class UserManagementCollection extends BaseUISchema {
return obj.isEditable(state) && state.auth_source == AUTH_METHODS['INTERNAL'];
}
}, {
- id: 'locked', label: gettext('Locked'), cell: 'switch', width: 60, disableResizing: true,
+ id: 'locked', label: gettext('Locked'), cell: 'switch', width: 60, enableResizing: false,
editable: (state)=> {
return state.locked;
}
diff --git a/web/regression/feature_tests/pg_utilities_backup_restore_test.py b/web/regression/feature_tests/pg_utilities_backup_restore_test.py
index 943ab3701..888848679 100644
--- a/web/regression/feature_tests/pg_utilities_backup_restore_test.py
+++ b/web/regression/feature_tests/pg_utilities_backup_restore_test.py
@@ -294,10 +294,11 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
if serv == 'pg' and server_version is not None and \
default_binary_path['pg'] != '':
path_input = \
- self.page.find_by_xpath(
- "//div[span[text()='PostgreSQL {}']]"
- "/following-sibling::div//div/input".format(
- server_version))
+ self.page.find_by_css_selector(
+ "div[class='pgrd-row-cell'][title='PostgreSQL {}']"
+ "+div[class='pgrd-row-cell'] input"
+ .format(server_version)
+ )
existing_path = path_input.get_property("value")
if existing_path != default_binary_path['pg']:
path_already_set = False
diff --git a/web/regression/python_test_utils/test_gui_helper.py b/web/regression/python_test_utils/test_gui_helper.py
index f6b5d6321..8d5440e25 100644
--- a/web/regression/python_test_utils/test_gui_helper.py
+++ b/web/regression/python_test_utils/test_gui_helper.py
@@ -54,8 +54,8 @@ def open_process_details(tester):
time.sleep(3)
tester.page.find_by_css_selector(
"div[data-test='processes'] "
- "div[data-test='row-container']:nth-child(1) "
- "div[role='row'] div[role='cell']:nth-child(3) button").click()
+ "div[role='row']:nth-child(1) "
+ "div[role='cell']:nth-child(3) button").click()
tester.page.wait_for_element_to_disappear(
lambda driver: driver.find_element(
diff --git a/web/yarn.lock b/web/yarn.lock
index db63c1f1e..7bb0c4854 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -3173,6 +3173,44 @@ __metadata:
languageName: node
linkType: hard
+"@tanstack/react-table@npm:^8.16.0":
+ version: 8.16.0
+ resolution: "@tanstack/react-table@npm:8.16.0"
+ dependencies:
+ "@tanstack/table-core": 8.16.0
+ peerDependencies:
+ react: ">=16.8"
+ react-dom: ">=16.8"
+ checksum: 9a80668ba7531b49425d3c08fe34fbd4bbcdf936fbca120114d2d090013242c3ea1b573c1381719289600bc866f2ded9e3e13c7c4923285d2cf4eee1c1d489e7
+ languageName: node
+ linkType: hard
+
+"@tanstack/react-virtual@npm:^3.4.0":
+ version: 3.4.0
+ resolution: "@tanstack/react-virtual@npm:3.4.0"
+ dependencies:
+ "@tanstack/virtual-core": 3.4.0
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ checksum: 73c272d4a6242d1e49e37e56cec3985d8ff3108e8cd33d2f0c8c3f6ec3d84fece50813e875ee15ee025de4c47f051fcdf8829b1a9c824fd360ae0a569eddb1f5
+ languageName: node
+ linkType: hard
+
+"@tanstack/table-core@npm:8.16.0":
+ version: 8.16.0
+ resolution: "@tanstack/table-core@npm:8.16.0"
+ checksum: c2c33c542c60788eb90806feb8f1f0340aa565ef9bb031bc5562d43598394a4089d61007f55ed6ab1fa16bbe93228cb2673b564ecf90b416bf463f42a56f3d85
+ languageName: node
+ linkType: hard
+
+"@tanstack/virtual-core@npm:3.4.0":
+ version: 3.4.0
+ resolution: "@tanstack/virtual-core@npm:3.4.0"
+ checksum: dee878179e504bb2d62ffb36a97e1c37e777af1802cadb03566b732099b13d7d053590997e3c17ce098bcb2adf527f53f69795d38cb607e308cde21dc809702e
+ languageName: node
+ linkType: hard
+
"@testing-library/dom@npm:^8.0.0":
version: 8.20.1
resolution: "@testing-library/dom@npm:8.20.1"
@@ -13769,15 +13807,6 @@ __metadata:
languageName: node
linkType: hard
-"react-table@npm:^7.6.3":
- version: 7.8.0
- resolution: "react-table@npm:7.8.0"
- peerDependencies:
- react: ^16.8.3 || ^17.0.0-0 || ^18.0.0
- checksum: 44ca0fb848c6869cd793cede8dc33072b38ebb8f8d2833565afe7cf3eac5d1fa455ac5fb9d06838b16fab0523d5d03e3e82f7645032f71245096e67b892313b9
- languageName: node
- linkType: hard
-
"react-timer-hook@npm:^3.0.5":
version: 3.0.7
resolution: "react-timer-hook@npm:3.0.7"
@@ -13822,7 +13851,7 @@ __metadata:
languageName: node
linkType: hard
-"react-window@npm:^1.3.1, react-window@npm:^1.8.10, react-window@npm:^1.8.5":
+"react-window@npm:^1.3.1, react-window@npm:^1.8.10":
version: 1.8.10
resolution: "react-window@npm:1.8.10"
dependencies:
@@ -14265,6 +14294,8 @@ __metadata:
"@simonwep/pickr": ^1.5.1
"@svgr/webpack": ^8.1.0
"@szhsin/react-menu": ^2.2.0
+ "@tanstack/react-table": ^8.16.0
+ "@tanstack/react-virtual": ^3.4.0
"@testing-library/jest-dom": ^6.1.2
"@testing-library/react": 12
"@testing-library/user-event": ^14.4.3
@@ -14356,10 +14387,8 @@ __metadata:
react-resize-detector: ^9.1.0
react-rnd: ^10.3.5
react-select: ^5.7.2
- react-table: ^7.6.3
react-timer-hook: ^3.0.5
react-virtualized-auto-sizer: ^1.0.6
- react-window: ^1.8.5
resize-observer-polyfill: ^1.5.1
shim-loader: ^1.0.1
snapsvg-cjs: ^0.0.6