1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-16 22:50:10 +03:00

F OpenNebula/one#5422: Fix table component

This commit is contained in:
Sergio Betanzos 2021-06-22 09:16:48 +02:00
parent d59e91680a
commit dbb677f818
No known key found for this signature in database
GPG Key ID: E3E704F097737136
2 changed files with 96 additions and 173 deletions

View File

@ -1,7 +1,7 @@
/* eslint-disable react/prop-types */
import * as React from 'react'
import { makeStyles, Box, CircularProgress, useMediaQuery } from '@material-ui/core'
import { makeStyles, Box, LinearProgress } from '@material-ui/core'
import {
useGlobalFilter,
usePagination,
@ -9,9 +9,8 @@ import {
useTable
} from 'react-table'
import SplitPane from 'client/components/SplitPane'
import Toolbar from 'client/components/Tables/Virtualized/toolbar'
import Header from 'client/components/Tables/Virtualized/header'
import Row from 'client/components/Tables/Enhanced/row'
import Pagination from 'client/components/Tables/Enhanced/pagination'
import { addOpacityToColor } from 'client/utils'
@ -22,90 +21,48 @@ const useStyles = makeStyles(({ palette, typography, breakpoints }) => ({
display: 'flex',
flexDirection: 'column'
},
table: {
height: '100%',
overflow: 'auto',
[breakpoints.up('md')]: {
border: `1px solid ${palette.action.disabledBackground}`,
borderRadius: 6
},
// includes header row
'& *[role=row]': {
padding: '0.8em',
textAlign: 'start',
overflowWrap: 'break-word',
lineHeight: '1rem',
color: palette.text.primary,
[breakpoints.up('md')]: {
display: 'grid',
gridAutoFlow: 'column',
gridTemplateColumns: ({ columnsWidth }) => columnsWidth.join(' ')
}
}
},
header: {
position: 'sticky',
top: 0,
zIndex: 2,
textTransform: 'uppercase',
fontSize: '0.9em',
fontWeight: 700,
letterSpacing: '0.05em',
borderBottom: 'transparent',
backgroundColor: palette.grey[palette.type === 'light' ? 200 : 600],
[breakpoints.down('sm')]: {
display: 'none'
}
},
body: {
[breakpoints.only('sm')]: {
display: 'grid',
gap: '1em',
gridTemplateColumns: '1fr 1fr'
},
[breakpoints.only('xm')]: {
display: 'grid',
gap: '1em',
gridTemplateColumns: '1fr'
},
'& *[role=row]': {
fontSize: '1em',
fontWeight: typography.fontWeightMedium,
borderTop: `1px solid ${palette.action.disabledBackground}`,
overflow: 'auto',
display: 'grid',
gap: '1em',
gridTemplateColumns: '1fr',
'& > [role=row]': {
padding: '0.8em',
cursor: 'pointer',
color: palette.text.primary,
backgroundColor: palette.background.paper,
fontWeight: typography.fontWeightMedium,
fontSize: '1em',
borderRadius: 6,
display: 'flex',
gap: 8,
'&:hover': {
backgroundColor: palette.action.hover
},
'&:first-of-type': {
borderTopColor: 'transparent'
},
'&.selected': {
backgroundColor: addOpacityToColor(palette.secondary.main, 0.7)
backgroundColor: addOpacityToColor(palette.secondary.main, 0.2),
border: `1px solid ${palette.secondary.main}`
}
},
'& *[role=cell]': {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}
},
toolbar: {
...typography.body1,
color: palette.text.hint,
marginBottom: 16,
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
justifyContent: 'space-between',
gap: '1em'
gap: '1em',
'& > div:first-child': {
flexGrow: 1
}
},
total: {
pagination: {
display: 'flex',
alignItems: 'center',
gap: '1em',
transition: 200
transition: '200ms'
}
}))
@ -118,17 +75,14 @@ const EnhancedTable = ({
pageSize = 10,
isLoading,
showPageCount,
getRowId,
RowComponent,
renderDetail,
renderAllSelected = true,
fetchMore,
canFetchMore,
MobileComponentRow
canFetchMore
}) => {
const columnsWidth = React.useMemo(() =>
columns.map(({ width = '1fr' }) => {
return Number.isInteger(width) ? `${width}px` : width
}), [])
const isMobile = useMediaQuery(theme => theme.breakpoints.down('sm'))
const classes = useStyles({ columnsWidth })
const classes = useStyles()
const defaultColumn = React.useMemo(() => ({
// Filter: DefaultFilter,
@ -140,6 +94,7 @@ const EnhancedTable = ({
columns,
data,
defaultColumn,
getRowId,
autoResetPage: false,
initialState: {
pageSize
@ -157,9 +112,12 @@ const EnhancedTable = ({
page,
gotoPage,
pageCount,
selectedFlatRows,
state: { pageIndex }
} = useTableProps
const justOneSelected = selectedFlatRows.length === 1
const handleChangePage = newPage => {
gotoPage(newPage)
@ -169,59 +127,58 @@ const EnhancedTable = ({
}
return (
<Box {...getTableProps()} className={classes.root}>
<div className={classes.toolbar}>
<Toolbar useTableProps={useTableProps} />
<div className={classes.total}>
{isLoading && <CircularProgress size='1em' color='secondary' />}
Total loaded: {rows.length}
<SplitPane>
<Box {...getTableProps()} className={classes.root}>
<div className={classes.toolbar}>
<Toolbar useTableProps={useTableProps} />
<div className={classes.pagination}>
{page?.length > 0 && (
<Pagination
handleChangePage={handleChangePage}
useTableProps={useTableProps}
count={rows.length}
showPageCount={showPageCount}
/>
)}
</div>
</div>
</div>
<div className={classes.table}>
<div className={classes.header}>
<Header useTableProps={useTableProps} />
</div>
{isLoading && <LinearProgress size='1em' color='secondary' />}
<div className={classes.body}>
{
page.map(row => {
prepareRow(row)
{page.map(row => {
prepareRow(row)
/** @type {import('react-table').UseRowSelectRowProps} */
const { getRowProps, original, toggleRowSelected, isSelected } = row
/** @type {import('react-table').UseRowSelectRowProps} */
const { getRowProps, original, toggleRowSelected, isSelected } = row
const { key, ...rowProps } = getRowProps()
const key = getRowProps().key
const handleSelect = () => toggleRowSelected(!isSelected)
return isMobile && MobileComponentRow ? (
<MobileComponentRow
key={key}
value={original}
isSelected={isSelected}
handleClick={handleSelect}
/>
) : (
<Row
key={key}
row={row}
handleClick={handleSelect}
/>
)
})}
return (
<RowComponent
{...rowProps}
key={key}
value={original}
className={isSelected ? 'selected' : ''}
onClick={() => toggleRowSelected(!isSelected)}
/>
)
})}
</div>
</div>
{page?.length > 0 && (
<Pagination
handleChangePage={handleChangePage}
useTableProps={useTableProps}
count={rows.length}
showPageCount={showPageCount}
/>
)}
</Box>
</Box>
<div style={{ display: 'flex', flexDirection: 'column', overflow: 'auto' }}>
{justOneSelected && renderDetail
? renderDetail(selectedFlatRows[0]?.original)
: renderAllSelected && (
<pre>
<code>
{JSON.stringify(selectedFlatRows?.map(({ id }) => id)?.join(', '), null, 2)}
</code>
</pre>
)
}
</div>
</SplitPane>
)
}

View File

@ -1,20 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { makeStyles, IconButton } from '@material-ui/core'
import { Button } from '@material-ui/core'
import { NavArrowLeft, NavArrowRight } from 'iconoir-react'
import {
FastArrowLeft as FirstPageIcon,
NavArrowLeft as PreviousPageIcon,
NavArrowRight as NextPageIcon,
FastArrowRight as LastPageIcon
} from 'iconoir-react'
const useStyles = makeStyles(theme => ({
root: {
margin: '10px auto'
}
}))
import { T } from 'client/constants'
const Pagination = ({
count = 0,
@ -22,17 +12,11 @@ const Pagination = ({
useTableProps,
showPageCount = true
}) => {
const classes = useStyles()
/** @type {import('react-table').UsePaginationState} */
const { pageIndex, pageSize } = useTableProps.state
const pageCount = React.useMemo(() => Math.ceil(count / pageSize), [count])
const handleFirstPageButtonClick = () => {
handleChangePage(0)
}
const handleBackButtonClick = () => {
handleChangePage(pageIndex - 1)
}
@ -41,46 +25,28 @@ const Pagination = ({
handleChangePage(pageIndex + 1)
}
const handleLastPageButtonClick = () => {
handleChangePage(Math.max(0, pageCount - 1))
}
return (
<div className={classes.root}>
{/* <IconButton
onClick={handleFirstPageButtonClick}
disabled={pageIndex === 0}
aria-label="first page"
>
<FirstPageIcon />
</IconButton> */}
<IconButton
<>
<Button
onClick={handleBackButtonClick}
disabled={pageIndex === 0}
aria-label="previous page"
aria-label='previous page'
>
<PreviousPageIcon />
</IconButton>
{showPageCount &&
<span style={{ marginInline: '1em' }}>
{`${pageIndex + 1} / ${pageCount}`}
</span>
}
<IconButton
<NavArrowLeft />
{T.Previous}
</Button>
<span style={{ marginInline: '1em' }}>
{`${pageIndex + 1} of ${showPageCount ? pageCount : 'many'}`}
</span>
<Button
onClick={handleNextButtonClick}
disabled={pageIndex >= Math.ceil(count / pageSize) - 1}
aria-label="next page"
aria-label='next page'
>
<NextPageIcon />
</IconButton>
{/* <IconButton
onClick={handleLastPageButtonClick}
disabled={pageIndex >= Math.ceil(count / pageSize) - 1}
aria-label="last page"
>
<LastPageIcon />
</IconButton> */}
</div>
{T.Next}
<NavArrowRight />
</Button>
</>
)
}