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:
parent
d59e91680a
commit
dbb677f818
@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user