@xyo-network/react-payload-table 2.37.24 → 2.37.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Table/Table.d.ts +8 -4
- package/dist/cjs/components/Table/Table.d.ts.map +1 -1
- package/dist/cjs/components/Table/Table.js +23 -18
- package/dist/cjs/components/Table/Table.js.map +1 -1
- package/dist/cjs/components/Table/TablePagination.d.ts.map +1 -1
- package/dist/cjs/components/Table/TablePagination.js +9 -1
- package/dist/cjs/components/Table/TablePagination.js.map +1 -1
- package/dist/cjs/components/Table/index.d.ts +2 -0
- package/dist/cjs/components/Table/index.d.ts.map +1 -1
- package/dist/cjs/components/Table/index.js +2 -0
- package/dist/cjs/components/Table/index.js.map +1 -1
- package/dist/cjs/components/Table/types/PaginationEventNouns.d.ts +2 -0
- package/dist/cjs/components/Table/types/PaginationEventNouns.d.ts.map +1 -0
- package/dist/cjs/components/Table/types/PaginationEventNouns.js +3 -0
- package/dist/cjs/components/Table/types/PaginationEventNouns.js.map +1 -0
- package/dist/cjs/components/Table/types/index.d.ts +2 -0
- package/dist/cjs/components/Table/types/index.d.ts.map +1 -0
- package/dist/cjs/components/Table/types/index.js +5 -0
- package/dist/cjs/components/Table/types/index.js.map +1 -0
- package/dist/docs.json +2732 -231
- package/dist/esm/components/Table/Table.d.ts +8 -4
- package/dist/esm/components/Table/Table.d.ts.map +1 -1
- package/dist/esm/components/Table/Table.js +22 -15
- package/dist/esm/components/Table/Table.js.map +1 -1
- package/dist/esm/components/Table/TablePagination.d.ts.map +1 -1
- package/dist/esm/components/Table/TablePagination.js +7 -1
- package/dist/esm/components/Table/TablePagination.js.map +1 -1
- package/dist/esm/components/Table/index.d.ts +2 -0
- package/dist/esm/components/Table/index.d.ts.map +1 -1
- package/dist/esm/components/Table/index.js +2 -0
- package/dist/esm/components/Table/index.js.map +1 -1
- package/dist/esm/components/Table/types/PaginationEventNouns.d.ts +2 -0
- package/dist/esm/components/Table/types/PaginationEventNouns.d.ts.map +1 -0
- package/dist/esm/components/Table/types/PaginationEventNouns.js +2 -0
- package/dist/esm/components/Table/types/PaginationEventNouns.js.map +1 -0
- package/dist/esm/components/Table/types/index.d.ts +2 -0
- package/dist/esm/components/Table/types/index.d.ts.map +1 -0
- package/dist/esm/components/Table/types/index.js +2 -0
- package/dist/esm/components/Table/types/index.js.map +1 -0
- package/package.json +7 -6
- package/src/components/Table/FetchMoreTable.stories.tsx +26 -9
- package/src/components/Table/Table.tsx +134 -116
- package/src/components/Table/TablePagination.tsx +15 -2
- package/src/components/Table/index.ts +2 -0
- package/src/components/Table/types/PaginationEventNouns.ts +1 -0
- package/src/components/Table/types/index.ts +1 -0
|
@@ -3,7 +3,7 @@ import { useBreakpoint } from '@xylabs/react-shared'
|
|
|
3
3
|
import { PayloadWrapper, XyoPayload } from '@xyo-network/payload'
|
|
4
4
|
import { XyoApiThrownErrorBoundary } from '@xyo-network/react-auth-service'
|
|
5
5
|
import { TableEx, TableExProps, TableFooterEx } from '@xyo-network/react-table'
|
|
6
|
-
import {
|
|
6
|
+
import { forwardRef, useEffect, useState } from 'react'
|
|
7
7
|
|
|
8
8
|
import { payloadColumnNames, PayloadTableColumnConfig, payloadTableColumnConfigDefaults } from './PayloadTableColumnConfig'
|
|
9
9
|
import { TablePaginationActions } from './TablePagination'
|
|
@@ -13,140 +13,158 @@ export interface PayloadTableProps extends TableExProps {
|
|
|
13
13
|
exploreDomain?: string
|
|
14
14
|
archive?: string
|
|
15
15
|
onRowClick?: (value: XyoPayload) => void
|
|
16
|
-
fetchMorePayloads?: () => boolean
|
|
17
16
|
rowsPerPage?: number
|
|
18
17
|
payloads?: XyoPayload[] | null
|
|
18
|
+
loading?: boolean
|
|
19
19
|
columns?: PayloadTableColumnConfig
|
|
20
|
+
/** External trigger to fetch more payloads */
|
|
21
|
+
fetchMorePayloads?: () => void
|
|
22
|
+
/** set number of schema parts to display starting from the end */
|
|
20
23
|
maxSchemaDepth?: number
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
/** Total number of payloads passed */
|
|
25
|
+
count?: number
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
export const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
28
|
+
export const PayloadTableWithRef = forwardRef<HTMLTableElement, PayloadTableProps>(
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
exploreDomain,
|
|
32
|
+
archive,
|
|
33
|
+
onRowClick,
|
|
34
|
+
fetchMorePayloads,
|
|
35
|
+
rowsPerPage: rowsPerPageProp = 25,
|
|
36
|
+
payloads,
|
|
37
|
+
children,
|
|
38
|
+
columns = payloadTableColumnConfigDefaults(),
|
|
39
|
+
maxSchemaDepth,
|
|
40
|
+
count = 0,
|
|
41
|
+
loading = false,
|
|
42
|
+
variant = 'scrollable',
|
|
43
|
+
...props
|
|
44
|
+
},
|
|
45
|
+
ref,
|
|
46
|
+
) => {
|
|
47
|
+
const breakPoint = useBreakpoint()
|
|
48
|
+
const [page, setPage] = useState(0)
|
|
49
|
+
const [rowsPerPage, setRowsPerPage] = useState(rowsPerPageProp)
|
|
50
|
+
const [visiblePayloads, setVisiblePayloads] = useState<XyoPayload[]>([])
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - payloadCount || 0) : 0
|
|
52
|
+
// Avoid a layout jump when reaching the last page with empty rows.
|
|
53
|
+
const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - count || 0) : 0
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}, [count, payloads])
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
setRowsPerPage(rowsPerPageProp)
|
|
57
|
+
}, [rowsPerPageProp])
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
// React to various prop changes to derive new visible payloads
|
|
60
|
+
// count is needed to show initial payloads added async to the same payloads reference
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (payloads) {
|
|
63
|
+
setVisiblePayloads(payloads.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage))
|
|
64
|
+
}
|
|
65
|
+
}, [count, page, payloads, rowsPerPage])
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
// If the payload reference changes, assume we have a new list and reset current page
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
setPage(0)
|
|
70
|
+
}, [payloads])
|
|
62
71
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
const handleAdditionalPayloads = () => {
|
|
73
|
+
if (fetchMorePayloads && payloads) {
|
|
74
|
+
const buffer = rowsPerPage * 2
|
|
75
|
+
const lastVisiblePayload = visiblePayloads?.at(-1)
|
|
76
|
+
if (lastVisiblePayload) {
|
|
77
|
+
const lastVisibleIndex = payloads?.indexOf(lastVisiblePayload)
|
|
78
|
+
if (lastVisibleIndex !== undefined && payloads.length - (lastVisibleIndex + 1) <= buffer) {
|
|
79
|
+
fetchMorePayloads()
|
|
80
|
+
}
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
}
|
|
74
|
-
setPage(newPage)
|
|
75
|
-
}
|
|
76
84
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
const handleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, newPage: number) => {
|
|
86
|
+
handleAdditionalPayloads()
|
|
87
|
+
setPage(newPage)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
91
|
+
setRowsPerPage(parseInt(event.target.value, 10))
|
|
92
|
+
setPage(0)
|
|
93
|
+
}
|
|
81
94
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
return breakPoint ? (
|
|
96
|
+
<TableEx variant={variant} ref={ref} {...props}>
|
|
97
|
+
<TableHead>
|
|
98
|
+
<TableRow>
|
|
99
|
+
{columns[breakPoint]?.map((column, index) => {
|
|
100
|
+
return (
|
|
101
|
+
<TableCell key={index} width={index === 0 ? '100%' : undefined} align={index === 0 ? 'left' : 'center'}>
|
|
102
|
+
<Typography variant="body2" noWrap>
|
|
103
|
+
{payloadColumnNames[column]}
|
|
104
|
+
</Typography>
|
|
105
|
+
</TableCell>
|
|
106
|
+
)
|
|
107
|
+
})}
|
|
108
|
+
</TableRow>
|
|
109
|
+
</TableHead>
|
|
110
|
+
<TableBody>
|
|
111
|
+
{visiblePayloads?.map((payload, index) => {
|
|
112
|
+
const wrapper = new PayloadWrapper(payload)
|
|
87
113
|
return (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
114
|
+
<XyoApiThrownErrorBoundary
|
|
115
|
+
key={`${wrapper.hash}-${index}`}
|
|
116
|
+
errorComponent={(e: Error) => (
|
|
117
|
+
<Alert severity="error">
|
|
118
|
+
Error Loading Payload: <Typography fontWeight="bold">{e.message}</Typography>
|
|
119
|
+
</Alert>
|
|
120
|
+
)}
|
|
121
|
+
>
|
|
122
|
+
<PayloadTableRow
|
|
123
|
+
maxSchemaDepth={maxSchemaDepth}
|
|
124
|
+
archive={archive}
|
|
125
|
+
onClick={
|
|
126
|
+
onRowClick
|
|
127
|
+
? () => {
|
|
128
|
+
onRowClick(payload)
|
|
129
|
+
}
|
|
130
|
+
: undefined
|
|
131
|
+
}
|
|
132
|
+
exploreDomain={exploreDomain}
|
|
133
|
+
payload={payload}
|
|
134
|
+
/>
|
|
135
|
+
</XyoApiThrownErrorBoundary>
|
|
93
136
|
)
|
|
94
137
|
})}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{children}
|
|
126
|
-
{emptyRows > 0 && Array(emptyRows).fill(<PayloadTableRow />)}
|
|
127
|
-
</TableBody>
|
|
128
|
-
<TableFooterEx variant={variant}>
|
|
129
|
-
<TableRow>
|
|
130
|
-
<StyledTablePagination
|
|
131
|
-
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
|
|
132
|
-
count={payloadCount}
|
|
133
|
-
rowsPerPage={rowsPerPage}
|
|
134
|
-
page={page}
|
|
135
|
-
SelectProps={{
|
|
136
|
-
inputProps: {
|
|
137
|
-
'aria-label': 'rows per page',
|
|
138
|
-
},
|
|
139
|
-
native: true,
|
|
140
|
-
}}
|
|
141
|
-
onPageChange={handleChangePage}
|
|
142
|
-
onRowsPerPageChange={handleChangeRowsPerPage}
|
|
143
|
-
ActionsComponent={(props) => <TablePaginationActions enableNextPage={!!fetchMorePayloads} loading={loading} {...props} />}
|
|
144
|
-
/>
|
|
145
|
-
</TableRow>
|
|
146
|
-
</TableFooterEx>
|
|
147
|
-
</TableEx>
|
|
148
|
-
) : null
|
|
149
|
-
}
|
|
138
|
+
{children}
|
|
139
|
+
{emptyRows > 0 && Array(emptyRows).fill(<PayloadTableRow />)}
|
|
140
|
+
</TableBody>
|
|
141
|
+
<TableFooterEx variant={variant}>
|
|
142
|
+
<TableRow>
|
|
143
|
+
<StyledTablePagination
|
|
144
|
+
rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
|
|
145
|
+
count={count ?? 0}
|
|
146
|
+
rowsPerPage={rowsPerPage}
|
|
147
|
+
page={page}
|
|
148
|
+
SelectProps={{
|
|
149
|
+
inputProps: {
|
|
150
|
+
'aria-label': 'rows per page',
|
|
151
|
+
},
|
|
152
|
+
native: true,
|
|
153
|
+
}}
|
|
154
|
+
onPageChange={handleChangePage}
|
|
155
|
+
onRowsPerPageChange={handleChangeRowsPerPage}
|
|
156
|
+
ActionsComponent={(props) => <TablePaginationActions enableNextPage={!!fetchMorePayloads} loading={loading} {...props} />}
|
|
157
|
+
/>
|
|
158
|
+
</TableRow>
|
|
159
|
+
</TableFooterEx>
|
|
160
|
+
</TableEx>
|
|
161
|
+
) : null
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
PayloadTableWithRef.displayName = 'PayloadTable'
|
|
166
|
+
|
|
167
|
+
export const PayloadTable = PayloadTableWithRef
|
|
150
168
|
|
|
151
169
|
const StyledTablePagination = styled(TablePagination)(({ theme }) => ({
|
|
152
170
|
'& > .MuiToolbar-root': {
|
|
@@ -3,6 +3,9 @@ import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'
|
|
|
3
3
|
import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'
|
|
4
4
|
import LastPageIcon from '@mui/icons-material/LastPage'
|
|
5
5
|
import { Box, CircularProgress, IconButton, useTheme } from '@mui/material'
|
|
6
|
+
import { useXyoEvent } from '@xyo-network/react-event'
|
|
7
|
+
|
|
8
|
+
import { PaginationNouns } from './types'
|
|
6
9
|
|
|
7
10
|
interface TablePaginationActionsProps {
|
|
8
11
|
count: number
|
|
@@ -15,20 +18,25 @@ interface TablePaginationActionsProps {
|
|
|
15
18
|
|
|
16
19
|
export function TablePaginationActions({ count, page, rowsPerPage, onPageChange, enableNextPage, loading }: TablePaginationActionsProps) {
|
|
17
20
|
const theme = useTheme()
|
|
21
|
+
const [paginationRef, paginationDispatch] = useXyoEvent<HTMLButtonElement, PaginationNouns>()
|
|
18
22
|
|
|
19
23
|
const handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
24
|
+
paginationDispatch('firstPage', 'click', 'true')
|
|
20
25
|
onPageChange(event, 0)
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
const handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
29
|
+
paginationDispatch('previousPage', 'click', (page - 1)?.toString())
|
|
24
30
|
onPageChange(event, page - 1)
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
const handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
34
|
+
paginationDispatch('nextPage', 'click', (page + 1)?.toString())
|
|
28
35
|
onPageChange(event, page + 1)
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
const handleLastPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
39
|
+
paginationDispatch('lastPage', 'click', 'true')
|
|
32
40
|
onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
|
|
33
41
|
}
|
|
34
42
|
|
|
@@ -39,10 +47,15 @@ export function TablePaginationActions({ count, page, rowsPerPage, onPageChange,
|
|
|
39
47
|
<IconButton onClick={handleFirstPageButtonClick} disabled={page === 0} aria-label="first page">
|
|
40
48
|
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
|
|
41
49
|
</IconButton>
|
|
42
|
-
<IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
|
|
50
|
+
<IconButton ref={paginationRef} onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
|
|
43
51
|
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
|
|
44
52
|
</IconButton>
|
|
45
|
-
<IconButton
|
|
53
|
+
<IconButton
|
|
54
|
+
ref={paginationRef}
|
|
55
|
+
onClick={handleNextButtonClick}
|
|
56
|
+
disabled={!enableNextPage && page >= Math.ceil(count / rowsPerPage) - 1}
|
|
57
|
+
aria-label="next page"
|
|
58
|
+
>
|
|
46
59
|
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
|
|
47
60
|
</IconButton>
|
|
48
61
|
<IconButton onClick={handleLastPageButtonClick} disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label="last page">
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type PaginationNouns = 'nextPage' | 'previousPage' | 'firstPage' | 'lastPage'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './PaginationEventNouns'
|