Makes some improvements/restructurings to the PgTable component.

pull/83/head
Aditya Toshniwal 2022-04-04 19:03:50 +05:30 committed by Akshay Joshi
parent cc5cfa0997
commit 4fff26c571
7 changed files with 231 additions and 197 deletions

View File

@ -30,7 +30,6 @@ export default class ActiveQuery extends BaseUISchema {
readonly: true, readonly: true,
mode: ['properties'], mode: ['properties'],
group: gettext('Details'), group: gettext('Details'),
disabled: true
}, },
{ {
id: 'query_start', id: 'query_start',
@ -39,8 +38,6 @@ export default class ActiveQuery extends BaseUISchema {
editable: false, editable: false,
readonly: true, readonly: true,
group: gettext('Details'), group: gettext('Details'),
disabled: true
}, },
{ {
id: 'state_change', id: 'state_change',
@ -49,7 +46,6 @@ export default class ActiveQuery extends BaseUISchema {
editable: false, editable: false,
readonly: true, readonly: true,
group: gettext('Details'), group: gettext('Details'),
disabled: true
}, },
{ {
id: 'query', id: 'query',

View File

@ -85,11 +85,11 @@ const useStyles = makeStyles((theme) => ({
}, },
panelContent: { panelContent: {
...theme.mixins.panelBorder, ...theme.mixins.panelBorder,
display: 'flex',
flexDirection: 'column', flexDirection: 'column',
overflow: 'hidden !important', overflow: 'hidden !important',
flexGrow: 1, height: '100%',
minWidth: '300px', minHeight: '400px'
minHeight: '300px'
}, },
arrowButton: { arrowButton: {
fontSize: '2rem !important', fontSize: '2rem !important',
@ -339,6 +339,7 @@ export default function Dashboard({
let canEditRow = true; let canEditRow = true;
return ( return (
<PgIconButton <PgIconButton
size="xs"
className={row.isExpanded ?classes.buttonClick : ''} className={row.isExpanded ?classes.buttonClick : ''}
icon={ icon={
row.isExpanded ? ( row.isExpanded ? (
@ -809,31 +810,34 @@ export default function Dashboard({
> >
{gettext('Server activity')}{' '} {gettext('Server activity')}{' '}
</Box> </Box>
<Tabs <Box display="flex">
value={val} <Tabs
onChange={tabChanged} value={val}
className={classes.searchInput} onChange={tabChanged}
> className={classes.searchInput}
{tab.map((tabValue, i) => { >
return <Tab key={i} label={tabValue} />; {tab.map((tabValue, i) => {
})} return <Tab key={i} label={tabValue} />;
})}
</Tabs>
<RefreshButton/> <RefreshButton/>
</Tabs> </Box>
<Box flexGrow={1}>
<PgTable <PgTable
columns={ caveTable={false}
val === 0 columns={
? activityColumns val === 0
: val === 1 ? activityColumns
? databaseLocksColumns : val === 1
: val == 2 ? databaseLocksColumns
? databasePreparedColumns : val == 2
: serverConfigColumns ? databasePreparedColumns
} : serverConfigColumns
data={dashData} }
schema={schemaDict} data={dashData}
offset={145} schema={schemaDict}
></PgTable> ></PgTable>
</Box>
</Box> </Box>
</Box> </Box>
</Box> </Box>

View File

@ -94,6 +94,7 @@ export default function(basicSettings) {
stepFg: '#000', stepFg: '#000',
toggleBtnBg: '#000', toggleBtnBg: '#000',
colorFg: '#FFFFFF', colorFg: '#FFFFFF',
emptySpaceBg: '#212121',
} }
}); });
} }

View File

@ -92,6 +92,7 @@ export default function(basicSettings) {
stepFg: '#000', stepFg: '#000',
toggleBtnBg: '#6B6B6B', toggleBtnBg: '#6B6B6B',
colorFg: '#FFFFFF', colorFg: '#FFFFFF',
emptySpaceBg: '#010B15',
} }
}); });
} }

View File

@ -103,7 +103,7 @@ export default function(basicSettings) {
toggleBtnBg: '#000', toggleBtnBg: '#000',
editorToolbarBg: '#ebeef3', editorToolbarBg: '#ebeef3',
datagridBg: '#fff', datagridBg: '#fff',
emptySpaceBg: '#ebeef3',
} }
}); });
} }

View File

@ -24,9 +24,9 @@ import PropTypes from 'prop-types';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
import { Checkbox, Box } from '@material-ui/core'; import { Checkbox, Box } from '@material-ui/core';
import { InputText } from './FormComponents'; import { InputText } from './FormComponents';
import FormView from 'sources/SchemaView';
import _ from 'lodash'; import _ from 'lodash';
import gettext from 'sources/gettext'; import gettext from 'sources/gettext';
import SchemaView from '../SchemaView';
/* eslint-disable react/display-name */ /* eslint-disable react/display-name */
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
@ -37,8 +37,11 @@ const useStyles = makeStyles((theme) => ({
...theme.mixins.panelBorder, ...theme.mixins.panelBorder,
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
}, },
autoResizerContainer: {
flexGrow: 1,
minHeight: 0
},
autoResizer: { autoResizer: {
height: '100% !important',
width: '100% !important', width: '100% !important',
}, },
fixedSizeList: { fixedSizeList: {
@ -51,7 +54,6 @@ const useStyles = makeStyles((theme) => ({
marginLeft: '4px' marginLeft: '4px'
}, },
searchBox: { searchBox: {
marginBottom: '5px',
display: 'flex', display: 'flex',
background: theme.palette.background.default background: theme.palette.background.default
}, },
@ -61,10 +63,6 @@ const useStyles = makeStyles((theme) => ({
alert: { alert: {
backgroundColor: theme.palette.error.main + '!important' backgroundColor: theme.palette.error.main + '!important'
}, },
tableContentWidth: {
width: 'calc(100% - 3px)',
},
searchPadding: { searchPadding: {
flex: 2.5 flex: 2.5
}, },
@ -77,14 +75,22 @@ const useStyles = makeStyles((theme) => ({
marginBottom: 8, marginBottom: 8,
}, },
table: { tableContainer: {
overflowX: 'auto',
flexGrow: 1, flexGrow: 1,
minHeight: 0, minHeight: 0,
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.otherVars.emptySpaceBg,
},
table: {
borderSpacing: 0, borderSpacing: 0,
width: '100%',
overflow: 'hidden', overflow: 'hidden',
borderRadius: theme.shape.borderRadius, borderRadius: theme.shape.borderRadius,
border: '1px solid'+ theme.palette.grey[400] border: '1px solid '+theme.otherVars.borderColor,
display: 'flex',
flexDirection: 'column',
height: '100%',
}, },
pgTableHeadar: { pgTableHeadar: {
display: 'flex', display: 'flex',
@ -94,11 +100,16 @@ const useStyles = makeStyles((theme) => ({
flexDirection: 'column' flexDirection: 'column'
}, },
tableRowContent:{
display: 'flex',
flexDirection: 'column',
minHeight: 0,
},
expandedForm: { expandedForm: {
...theme.mixins.panelBorder, ...theme.mixins.panelBorder.all,
margin: '8px', margin: '8px',
paddingBottom: '12px', flexGrow: 1,
marginRight: '15px',
}, },
tableCell: { tableCell: {
@ -155,6 +166,9 @@ const useStyles = makeStyles((theme) => ({
overflow: 'auto', overflow: 'auto',
padding: '7.5px', padding: '7.5px',
}, },
caveTable: {
margin: '8px',
},
panelIcon: { panelIcon: {
width: '80%', width: '80%',
margin: '0 auto', margin: '0 auto',
@ -177,30 +191,63 @@ const useStyles = makeStyles((theme) => ({
}, },
})); }));
export default function PgTable({ columns, data, isSelectRow, offset=105, ...props }) { const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef();
const resolvedRef = ref || defaultRef;
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate;
}, [resolvedRef, indeterminate]);
return (
<>
<Checkbox
color="primary"
ref={resolvedRef} {...rest}
/>
</>
);
},
);
IndeterminateCheckbox.displayName = 'SelectCheckbox';
IndeterminateCheckbox.propTypes = {
indeterminate: PropTypes.bool,
rest: PropTypes.func,
getToggleAllRowsSelectedProps: PropTypes.func,
row: PropTypes.object,
};
const ROW_HEIGHT = 35;
export default function PgTable({ columns, data, isSelectRow, caveTable=true, ...props }) {
// Use the state and functions returned from useTable to build your UI // Use the state and functions returned from useTable to build your UI
const classes = useStyles(); const classes = useStyles();
const [searchVal, setSearchVal] = React.useState(''); const [searchVal, setSearchVal] = React.useState('');
const tableRef = React.useRef(); const tableRef = React.useRef();
const rowHeights = React.useRef({}); const rowHeights = React.useRef({});
const rowRef = React.useRef({});
// Reset Search vakue in tab changed. // Reset Search vakue in tab changed.
React.useEffect(()=>{ React.useEffect(()=>{
setSearchVal(''); setSearchVal('');
},[columns]); rowHeights.current = {};
function getRowHeight(index, size) { tableRef.current?.resetAfterIndex(0);
return rowHeights.current[index] + size || 35; }, [columns]);
function getRowHeight(index) {
return rowHeights.current[index] || ROW_HEIGHT;
} }
const setRowHeight = React.useCallback((index, size) => { const setRowHeight = (index, size) => {
if(tableRef.current) { if(tableRef.current) {
tableRef.current.resetAfterIndex(index); if(size == ROW_HEIGHT) {
if (!(rowHeights.current.hasOwnProperty(index))){ delete rowHeights.current[index];
rowHeights.current = { ...rowHeights.current, [index]: size }; } else {
rowHeights.current[index] = size;
} }
tableRef.current.resetAfterIndex(index);
} }
}, []); };
const defaultColumn = React.useMemo( const defaultColumn = React.useMemo(
() => ({ () => ({
@ -209,34 +256,6 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
[] []
); );
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef();
const resolvedRef = ref || defaultRef;
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate;
}, [resolvedRef, indeterminate]);
return (
<>
<Checkbox
color="primary"
ref={resolvedRef} {...rest}
/>
</>
);
},
);
IndeterminateCheckbox.displayName = 'SelectCheckbox';
IndeterminateCheckbox.propTypes = {
indeterminate: PropTypes.bool,
rest: PropTypes.func,
getToggleAllRowsSelectedProps: PropTypes.func,
row: PropTypes.object,
};
const { const {
getTableProps, getTableProps,
getTableBodyProps, getTableBodyProps,
@ -244,7 +263,7 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
rows, rows,
prepareRow, prepareRow,
selectedFlatRows, selectedFlatRows,
state: { selectedRowIds, expanded }, state: { selectedRowIds },
setGlobalFilter, setGlobalFilter,
setHiddenColumns, setHiddenColumns,
} = useTable( } = useTable(
@ -327,11 +346,6 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
} }
); );
React.useEffect(()=>{
tableRef.current?.resetAfterIndex(0);
},[expanded]);
React.useEffect(() => { React.useEffect(() => {
setHiddenColumns( setHiddenColumns(
columns columns
@ -365,45 +379,72 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
const RenderRow = React.useCallback( const RenderRow = React.useCallback(
({ index, style }) => { ({ index, style }) => {
const row = rows[index]; const row = rows[index];
const [expandComplete, setExpandComplete] = React.useState(null);
const rowRef = React.useRef() ;
prepareRow(row); prepareRow(row);
React.useEffect(()=>{
if(expandComplete && !row.isExpanded) {
setExpandComplete(false);
}
}, [row.isExpanded]);
React.useEffect(()=>{
if(rowRef.current) {
if(expandComplete == null) {
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 ( return (
<div className={classes.tableContentWidth} style={style} key={row.id}> <div style={style} key={row.id} ref={rowRef}>
<div {...row.getRowProps()} className={classes.tr}> <div className={classes.tableRowContent}>
{row.cells.map((cell) => { <div {...row.getRowProps()} className={classes.tr}>
let classNames = [classes.tableCell]; {row.cells.map((cell) => {
if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) { let classNames = [classes.tableCell];
classNames.push(classes.btnCell); 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(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 === 'warning'){
} classNames.push(classes.warning);
if (row.original.row_type === 'alert'){ }
classNames.push(classes.alert); if (row.original.row_type === 'alert'){
} classNames.push(classes.alert);
return ( }
<div key={cell.column.id} {...cell.getCellProps()} className={clsx(classNames, row.original.icon && row.original.icon[cell.column.id], row.original.icon[cell.column.id] && classes.cellIcon)} return (
title={_.isUndefined(cell.value) || _.isNull(cell.value) ? '': String(cell.value)}> <div key={cell.column.id} {...cell.getCellProps()} className={clsx(classNames, row.original.icon && row.original.icon[cell.column.id], row.original.icon[cell.column.id] && classes.cellIcon)}
{cell.render('Cell')} title={_.isUndefined(cell.value) || _.isNull(cell.value) ? '': String(cell.value)}>
</div> {cell.render('Cell')}
); </div>
})} );
})}
</div>
{!_.isUndefined(row) && row.isExpanded && (
<Box key={row.id} className={classes.expandedForm}>
<SchemaView
getInitData={()=>Promise.resolve({})}
viewHelperProps={{ mode: 'properties' }}
schema={props.schema[row.id]}
showFooter={false}
onDataChange={()=>{setExpandComplete(true);}}
/>
</Box>
)}
</div> </div>
{!_.isUndefined(row) && row.isExpanded && (
<Box key={row.id} className={classes.expandedForm} ref={rowRef} style={{height: rowHeights.current[index]}}>
<FormView
getInitData={() => {
/*This is intentional (SonarQube)*/
}}
viewHelperProps={{ mode: 'properties' }}
schema={props.schema[row.id]}
showFooter={false}
onDataChange={() => { }}
/>
</Box>
)}
</div> </div>
); );
}, },
@ -424,80 +465,70 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
}} }}
/> />
</Box> </Box>
<AutoSizer <div className={classes.tableContainer}>
className={props.type === 'panel' ? props.className : classes.autoResizer} <div {...getTableProps()} className={clsx(classes.table, caveTable ? classes.caveTable : '')}>
> <div>
{({ height }) => ( {headerGroups.map((headerGroup) => (
<div {...getTableProps()} className={classes.table}> <div key={''} {...headerGroup.getHeaderGroupProps()}>
<div> {headerGroup.headers.map((column) => (
{headerGroups.map((headerGroup) => ( <div
<div key={''} {...headerGroup.getHeaderGroupProps()}> key={column.id}
{headerGroup.headers.map((column) => ( {...column.getHeaderProps()}
<div className={clsx(classes.tableCellHeader, column.className)}
key={column.id}
{...column.getHeaderProps()}
className={clsx(classes.tableCellHeader, column.className)}
>
<div
{...(column.sortble ? column.getSortByToggleProps() : {})}
>
{column.render('Header')}
<span>
{column.isSorted
? column.isSortedDesc
? ' 🔽'
: ' 🔼'
: ''}
</span>
{column.resizable && (
<div
{...column.getResizerProps()}
className={classes.resizer}
/>
)}
</div>
</div>
))}
</div>
))}
</div>
{
data.length > 0 ? (
<div {...getTableBodyProps()} >
<VariableSizeList
ref={tableRef}
className={props.type === 'dashboard' ? props.fixedSizeList : classes.fixedSizeList}
height={height - offset}
itemCount={rows.length}
itemSize={(i) => {
if (_.isUndefined(rows[i].isExpanded)) {
rows[i].isExpanded = false;
}
if (rowRef.current && rows[i].isExpanded) {
setRowHeight(i, rowRef.current.offsetHeight + 35);
}
return rows[i].isExpanded ? getRowHeight(i, 35) : 35;
}}
sorted={props?.sortOptions}
> >
{RenderRow} <div
{...(column.sortble ? column.getSortByToggleProps() : {})}
</VariableSizeList> >
</div> {column.render('Header')}
) : ( <span>
{column.isSorted
<div className={classes.emptyPanel}> ? column.isSortedDesc
<div className={classes.panelIcon}> ? ' 🔽'
<i className="fa fa-exclamation-circle"></i> : ' 🔼'
<span className={classes.panelMessage}>{gettext('No record found')}</span> : ''}
</span>
{column.resizable && (
<div
{...column.getResizerProps()}
className={classes.resizer}
/>
)}
</div>
</div> </div>
))}
</div> </div>
)} ))}
</div> </div>
)} {
</AutoSizer> data.length > 0 ? (
<div {...getTableBodyProps()} className={classes.autoResizerContainer}>
<AutoSizer
className={classes.autoResizer}
>
{({ height }) => (
<VariableSizeList
ref={tableRef}
className={classes.fixedSizeList}
height={height}
itemCount={rows.length}
itemSize={getRowHeight}
sorted={props?.sortOptions}
>
{RenderRow}
</VariableSizeList>)}
</AutoSizer>
</div>
) : (
<div className={classes.emptyPanel}>
<div className={classes.panelIcon}>
<i className="fa fa-exclamation-circle"></i>
<span className={classes.panelMessage}>{gettext('No record found')}</span>
</div>
</div>
)
}
</div>
</div>
</Box> </Box>
); );
} }
@ -505,9 +536,9 @@ export default function PgTable({ columns, data, isSelectRow, offset=105, ...pro
PgTable.propTypes = { PgTable.propTypes = {
stepId: PropTypes.number, stepId: PropTypes.number,
height: PropTypes.number, height: PropTypes.number,
offset: PropTypes.number,
customHeader: PropTypes.func, customHeader: PropTypes.func,
className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), className: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
caveTable: PropTypes.bool,
fixedSizeList: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), fixedSizeList: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
children: PropTypes.oneOfType([ children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),

View File

@ -315,6 +315,7 @@ export default function GrantWizard({ sid, did, nodeInfo, nodeData }) {
<WizardStep stepId={0}> <WizardStep stepId={0}>
<Box className={classes.panelContent}> <Box className={classes.panelContent}>
<PgTable <PgTable
caveTable={false}
className={classes.table} className={classes.table}
height={window.innerHeight - 450} height={window.innerHeight - 450}
columns={columns} columns={columns}