@xyo-network/react-payload-table 2.32.0-rc.8 → 2.32.1

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.
Files changed (45) hide show
  1. package/dist/cjs/components/DynamicTable/DynamicTableRow.d.ts.map +1 -1
  2. package/dist/cjs/components/DynamicTable/DynamicTableRow.js +4 -2
  3. package/dist/cjs/components/DynamicTable/DynamicTableRow.js.map +1 -1
  4. package/dist/cjs/components/DynamicTable/Table.d.ts +1 -0
  5. package/dist/cjs/components/DynamicTable/Table.d.ts.map +1 -1
  6. package/dist/cjs/components/DynamicTable/Table.js +46 -4
  7. package/dist/cjs/components/DynamicTable/Table.js.map +1 -1
  8. package/dist/cjs/components/Table/Table.d.ts +2 -1
  9. package/dist/cjs/components/Table/Table.d.ts.map +1 -1
  10. package/dist/cjs/components/Table/Table.js +50 -4
  11. package/dist/cjs/components/Table/Table.js.map +1 -1
  12. package/dist/cjs/components/Table/TableRow.d.ts.map +1 -1
  13. package/dist/cjs/components/Table/TableRow.js +6 -2
  14. package/dist/cjs/components/Table/TableRow.js.map +1 -1
  15. package/dist/cjs/components/index.d.ts +1 -0
  16. package/dist/cjs/components/index.d.ts.map +1 -1
  17. package/dist/cjs/components/index.js +1 -0
  18. package/dist/cjs/components/index.js.map +1 -1
  19. package/dist/docs.json +1077 -110
  20. package/dist/esm/components/DynamicTable/DynamicTableRow.d.ts.map +1 -1
  21. package/dist/esm/components/DynamicTable/DynamicTableRow.js +4 -2
  22. package/dist/esm/components/DynamicTable/DynamicTableRow.js.map +1 -1
  23. package/dist/esm/components/DynamicTable/Table.d.ts +1 -0
  24. package/dist/esm/components/DynamicTable/Table.d.ts.map +1 -1
  25. package/dist/esm/components/DynamicTable/Table.js +47 -5
  26. package/dist/esm/components/DynamicTable/Table.js.map +1 -1
  27. package/dist/esm/components/Table/Table.d.ts +2 -1
  28. package/dist/esm/components/Table/Table.d.ts.map +1 -1
  29. package/dist/esm/components/Table/Table.js +51 -5
  30. package/dist/esm/components/Table/Table.js.map +1 -1
  31. package/dist/esm/components/Table/TableRow.d.ts.map +1 -1
  32. package/dist/esm/components/Table/TableRow.js +7 -3
  33. package/dist/esm/components/Table/TableRow.js.map +1 -1
  34. package/dist/esm/components/index.d.ts +1 -0
  35. package/dist/esm/components/index.d.ts.map +1 -1
  36. package/dist/esm/components/index.js +1 -0
  37. package/dist/esm/components/index.js.map +1 -1
  38. package/package.json +16 -14
  39. package/src/components/DynamicTable/DynamicTable.stories.tsx +34 -4
  40. package/src/components/DynamicTable/DynamicTableRow.tsx +7 -4
  41. package/src/components/DynamicTable/Table.tsx +110 -4
  42. package/src/components/Table/Table.stories.tsx +21 -4
  43. package/src/components/Table/Table.tsx +102 -5
  44. package/src/components/Table/TableRow.tsx +14 -11
  45. package/src/components/index.ts +1 -0
@@ -1,7 +1,26 @@
1
- import { Alert, Table, TableBody, TableCell, TableHead, TableProps, TableRow, Typography } from '@mui/material'
1
+ import FirstPageIcon from '@mui/icons-material/FirstPage'
2
+ import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'
3
+ import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'
4
+ import LastPageIcon from '@mui/icons-material/LastPage'
5
+ import {
6
+ Alert,
7
+ Box,
8
+ IconButton,
9
+ Table,
10
+ TableBody,
11
+ TableCell,
12
+ TableFooter,
13
+ TableHead,
14
+ TablePagination,
15
+ TableProps,
16
+ TableRow,
17
+ Typography,
18
+ useTheme,
19
+ } from '@mui/material'
2
20
  import { useBreakpoint } from '@xylabs/react-shared'
3
21
  import { XyoPayload, XyoPayloadWrapper } from '@xyo-network/payload'
4
22
  import { XyoApiThrownErrorBoundary } from '@xyo-network/react-auth-service'
23
+ import { useEffect, useState } from 'react'
5
24
 
6
25
  import { PayloadDynamicTableRow } from './DynamicTableRow'
7
26
  import { PayloadDynamicTableColumnConfig, payloadDynamicTableColumnConfigDefaults } from './PayloadDynamicTableColumnConfig'
@@ -10,22 +29,88 @@ export interface PayloadDynamicTableProps extends TableProps {
10
29
  exploreDomain?: string
11
30
  archive?: string
12
31
  onRowClick?: (value: XyoPayload) => void
32
+ rowsPerPage?: number
13
33
  payloads?: XyoPayload[] | null
14
34
  columns?: PayloadDynamicTableColumnConfig
15
35
  }
16
36
 
37
+ interface TablePaginationActionsProps {
38
+ count: number
39
+ page: number
40
+ rowsPerPage: number
41
+ onPageChange: (event: React.MouseEvent<HTMLButtonElement>, newPage: number) => void
42
+ }
43
+
44
+ function TablePaginationActions(props: TablePaginationActionsProps) {
45
+ const theme = useTheme()
46
+ const { count, page, rowsPerPage, onPageChange } = props
47
+
48
+ const handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
49
+ onPageChange(event, 0)
50
+ }
51
+
52
+ const handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
53
+ onPageChange(event, page - 1)
54
+ }
55
+
56
+ const handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
57
+ onPageChange(event, page + 1)
58
+ }
59
+
60
+ const handleLastPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
61
+ onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
62
+ }
63
+
64
+ return (
65
+ <Box sx={{ flexShrink: 0, ml: 2.5 }}>
66
+ <IconButton onClick={handleFirstPageButtonClick} disabled={page === 0} aria-label="first page">
67
+ {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
68
+ </IconButton>
69
+ <IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
70
+ {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
71
+ </IconButton>
72
+ <IconButton onClick={handleNextButtonClick} disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label="next page">
73
+ {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
74
+ </IconButton>
75
+ <IconButton onClick={handleLastPageButtonClick} disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label="last page">
76
+ {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
77
+ </IconButton>
78
+ </Box>
79
+ )
80
+ }
81
+
17
82
  export const PayloadDynamicTable: React.FC<PayloadDynamicTableProps> = ({
18
83
  exploreDomain,
19
84
  archive,
20
85
  onRowClick,
86
+ rowsPerPage: rowsPerPageProp = 10,
21
87
  payloads,
22
88
  children,
23
89
  columns = payloadDynamicTableColumnConfigDefaults(),
24
90
  ...props
25
91
  }) => {
26
92
  const breakPoint = useBreakpoint()
93
+ const [page, setPage] = useState(0)
94
+ const [rowsPerPage, setRowsPerPage] = useState(rowsPerPageProp)
95
+ const payloadCount = payloads ? payloads.length : 0
96
+ // Avoid a layout jump when reaching the last page with empty rows.
97
+ const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - payloadCount) : 0
98
+
99
+ useEffect(() => {
100
+ setRowsPerPage(rowsPerPageProp)
101
+ }, [rowsPerPageProp])
102
+
103
+ const handleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, newPage: number) => {
104
+ setPage(newPage)
105
+ }
106
+
107
+ const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
108
+ setRowsPerPage(parseInt(event.target.value, 10))
109
+ setPage(0)
110
+ }
111
+
27
112
  return breakPoint ? (
28
- <Table {...props} stickyHeader>
113
+ <Table stickyHeader {...props}>
29
114
  <TableHead>
30
115
  <TableRow>
31
116
  {columns[breakPoint]?.map((column, index) => {
@@ -39,8 +124,8 @@ export const PayloadDynamicTable: React.FC<PayloadDynamicTableProps> = ({
39
124
  })}
40
125
  </TableRow>
41
126
  </TableHead>
42
- <TableBody>
43
- {payloads?.map((payload, index) => {
127
+ <TableBody sx={{ overflowY: 'scroll ' }}>
128
+ {payloads?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((payload, index) => {
44
129
  const wrapper = new XyoPayloadWrapper(payload)
45
130
  return (
46
131
  <XyoApiThrownErrorBoundary
@@ -67,7 +152,28 @@ export const PayloadDynamicTable: React.FC<PayloadDynamicTableProps> = ({
67
152
  )
68
153
  })}
69
154
  {children}
155
+ {emptyRows > 0 && Array(emptyRows).fill(<PayloadDynamicTableRow />)}
70
156
  </TableBody>
157
+ <TableFooter>
158
+ <TableRow>
159
+ <TablePagination
160
+ rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
161
+ colSpan={5}
162
+ count={payloadCount}
163
+ rowsPerPage={rowsPerPage}
164
+ page={page}
165
+ SelectProps={{
166
+ inputProps: {
167
+ 'aria-label': 'rows per page',
168
+ },
169
+ native: true,
170
+ }}
171
+ onPageChange={handleChangePage}
172
+ onRowsPerPageChange={handleChangeRowsPerPage}
173
+ ActionsComponent={TablePaginationActions}
174
+ />
175
+ </TableRow>
176
+ </TableFooter>
71
177
  </Table>
72
178
  ) : null
73
179
  }
@@ -1,5 +1,5 @@
1
1
  import { ComponentMeta, ComponentStory } from '@storybook/react'
2
- import { samplePayload, useAppThemeDecorator } from '@xyo-network/react-storybook'
2
+ import { sampleIdPayload, sampleSystemInfoBrowserPayload, useAppThemeDecorator } from '@xyo-network/react-storybook'
3
3
  import { BrowserRouter } from 'react-router-dom'
4
4
 
5
5
  import { PayloadTable } from './Table'
@@ -26,16 +26,33 @@ Default.args = {}
26
26
  Default.decorators = [useAppThemeDecorator]
27
27
 
28
28
  const WithData = Template.bind({})
29
- WithData.args = { payloads: [samplePayload, samplePayload] }
29
+ WithData.args = {
30
+ payloads: [
31
+ sampleIdPayload,
32
+ sampleSystemInfoBrowserPayload,
33
+ sampleIdPayload,
34
+ sampleSystemInfoBrowserPayload,
35
+ sampleIdPayload,
36
+ sampleSystemInfoBrowserPayload,
37
+ sampleIdPayload,
38
+ sampleSystemInfoBrowserPayload,
39
+ sampleIdPayload,
40
+ sampleSystemInfoBrowserPayload,
41
+ sampleIdPayload,
42
+ sampleSystemInfoBrowserPayload,
43
+ sampleIdPayload,
44
+ sampleSystemInfoBrowserPayload,
45
+ ],
46
+ }
30
47
  WithData.decorators = [useAppThemeDecorator]
31
48
 
32
49
  const WithError = Template.bind({})
33
50
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
34
- const { _hash, ...badPayload } = samplePayload
51
+ const { ...badPayload } = sampleIdPayload
35
52
 
36
53
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
54
  //@ts-ignore
38
- WithError.args = { payloads: [samplePayload, badPayload] }
55
+ WithError.args = { payloads: [sampleIdPayload, badPayload] }
39
56
 
40
57
  export { Default, WithData, WithError }
41
58
 
@@ -1,7 +1,16 @@
1
- import { Alert, Table, TableBody, TableCell, TableHead, TableProps, TableRow, Typography } from '@mui/material'
1
+ import FirstPageIcon from '@mui/icons-material/FirstPage'
2
+ import KeyboardArrowLeft from '@mui/icons-material/KeyboardArrowLeft'
3
+ import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'
4
+ import LastPageIcon from '@mui/icons-material/LastPage'
5
+ import { Alert, Table, TableBody, TableCell, TableFooter, TableHead, TablePagination, TableProps, TableRow, Typography } from '@mui/material'
6
+ import Box from '@mui/material/Box'
7
+ import IconButton from '@mui/material/IconButton'
8
+ import { useTheme } from '@mui/material/styles'
2
9
  import { useBreakpoint } from '@xylabs/react-shared'
3
10
  import { XyoPayload, XyoPayloadWrapper } from '@xyo-network/payload'
4
11
  import { XyoApiThrownErrorBoundary } from '@xyo-network/react-auth-service'
12
+ import * as React from 'react'
13
+ import { useEffect, useState } from 'react'
5
14
 
6
15
  import { payloadColumnNames, PayloadTableColumnConfig, payloadTableColumnConfigDefaults } from './PayloadTableColumnConfig'
7
16
  import { PayloadTableRow } from './TableRow'
@@ -10,22 +19,88 @@ export interface PayloadTableProps extends TableProps {
10
19
  exploreDomain?: string
11
20
  archive?: string
12
21
  onRowClick?: (value: XyoPayload) => void
22
+ rowsPerPage?: number
13
23
  payloads?: XyoPayload[] | null
14
24
  columns?: PayloadTableColumnConfig
15
25
  }
16
26
 
27
+ interface TablePaginationActionsProps {
28
+ count: number
29
+ page: number
30
+ rowsPerPage: number
31
+ onPageChange: (event: React.MouseEvent<HTMLButtonElement>, newPage: number) => void
32
+ }
33
+
34
+ function TablePaginationActions(props: TablePaginationActionsProps) {
35
+ const theme = useTheme()
36
+ const { count, page, rowsPerPage, onPageChange } = props
37
+
38
+ const handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
39
+ onPageChange(event, 0)
40
+ }
41
+
42
+ const handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
43
+ onPageChange(event, page - 1)
44
+ }
45
+
46
+ const handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
47
+ onPageChange(event, page + 1)
48
+ }
49
+
50
+ const handleLastPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
51
+ onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
52
+ }
53
+
54
+ return (
55
+ <Box sx={{ flexShrink: 0, ml: 2.5 }}>
56
+ <IconButton onClick={handleFirstPageButtonClick} disabled={page === 0} aria-label="first page">
57
+ {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
58
+ </IconButton>
59
+ <IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
60
+ {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
61
+ </IconButton>
62
+ <IconButton onClick={handleNextButtonClick} disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label="next page">
63
+ {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
64
+ </IconButton>
65
+ <IconButton onClick={handleLastPageButtonClick} disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label="last page">
66
+ {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
67
+ </IconButton>
68
+ </Box>
69
+ )
70
+ }
71
+
17
72
  export const PayloadTable: React.FC<PayloadTableProps> = ({
18
73
  exploreDomain,
19
74
  archive,
20
75
  onRowClick,
76
+ rowsPerPage: rowsPerPageProp = 10,
21
77
  payloads,
22
78
  children,
23
79
  columns = payloadTableColumnConfigDefaults(),
24
80
  ...props
25
81
  }) => {
26
82
  const breakPoint = useBreakpoint()
83
+ const [page, setPage] = useState(0)
84
+ const [rowsPerPage, setRowsPerPage] = useState(rowsPerPageProp)
85
+ const payloadCount = payloads ? payloads.length : 0
86
+ // Avoid a layout jump when reaching the last page with empty rows.
87
+ const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - payloadCount) : 0
88
+
89
+ useEffect(() => {
90
+ setRowsPerPage(rowsPerPageProp)
91
+ }, [rowsPerPageProp])
92
+
93
+ const handleChangePage = (event: React.MouseEvent<HTMLButtonElement> | null, newPage: number) => {
94
+ setPage(newPage)
95
+ }
96
+
97
+ const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
98
+ setRowsPerPage(parseInt(event.target.value, 10))
99
+ setPage(0)
100
+ }
101
+
27
102
  return breakPoint ? (
28
- <Table {...props}>
103
+ <Table stickyHeader {...props}>
29
104
  <TableHead>
30
105
  <TableRow>
31
106
  {columns[breakPoint]?.map((column, index) => {
@@ -39,13 +114,14 @@ export const PayloadTable: React.FC<PayloadTableProps> = ({
39
114
  })}
40
115
  </TableRow>
41
116
  </TableHead>
42
- <TableBody>
43
- {payloads?.map((payload, index) => {
117
+ <TableBody sx={{ overflowY: 'scroll ' }}>
118
+ {payloads?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((payload, index) => {
119
+ // {payloads?.map((payload, index) => {
44
120
  const wrapper = new XyoPayloadWrapper(payload)
45
121
  return (
46
122
  <XyoApiThrownErrorBoundary
47
123
  key={`${wrapper.hash}-${index}`}
48
- errorComponent={(e) => (
124
+ errorComponent={(e: Error) => (
49
125
  <Alert severity="error">
50
126
  Error Loading Payload: <Typography fontWeight="bold">{e.message}</Typography>
51
127
  </Alert>
@@ -67,7 +143,28 @@ export const PayloadTable: React.FC<PayloadTableProps> = ({
67
143
  )
68
144
  })}
69
145
  {children}
146
+ {emptyRows > 0 && Array(emptyRows).fill(<PayloadTableRow />)}
70
147
  </TableBody>
148
+ <TableFooter>
149
+ <TableRow>
150
+ <TablePagination
151
+ rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
152
+ colSpan={3}
153
+ count={payloadCount}
154
+ rowsPerPage={rowsPerPage}
155
+ page={page}
156
+ SelectProps={{
157
+ inputProps: {
158
+ 'aria-label': 'rows per page',
159
+ },
160
+ native: true,
161
+ }}
162
+ onPageChange={handleChangePage}
163
+ onRowsPerPageChange={handleChangeRowsPerPage}
164
+ ActionsComponent={TablePaginationActions}
165
+ />
166
+ </TableRow>
167
+ </TableFooter>
71
168
  </Table>
72
169
  ) : null
73
170
  }
@@ -1,9 +1,11 @@
1
- import { TableCell, TableCellProps, TableRow, TableRowProps, Typography } from '@mui/material'
1
+ import CheckCircleOutlineRoundedIcon from '@mui/icons-material/CheckCircleOutlineRounded'
2
+ import ErrorOutlineRoundedIcon from '@mui/icons-material/ErrorOutlineRounded'
3
+ import WarningAmberRoundedIcon from '@mui/icons-material/WarningAmberRounded'
4
+ import { alpha, TableCell, TableCellProps, TableRow, TableRowProps, Typography } from '@mui/material'
2
5
  import { useBreakpoint } from '@xylabs/react-shared'
3
6
  import { XyoPayload, XyoPayloadValidator, XyoPayloadWrapper } from '@xyo-network/payload'
4
7
  import { useNetwork } from '@xyo-network/react-network'
5
8
  import { HashTableCell } from '@xyo-network/react-shared'
6
- import { MdClear, MdDone } from 'react-icons/md'
7
9
 
8
10
  import { PayloadTableColumnConfig, payloadTableColumnConfigDefaults, PayloadTableColumnSlug } from './PayloadTableColumnConfig'
9
11
 
@@ -52,15 +54,16 @@ export const PayloadTableRow: React.FC<PayloadTableRowProps> = ({
52
54
 
53
55
  const valid: React.FC<TableCellProps> = (props) => (
54
56
  <TableCell key="valid" align="center" {...props}>
55
- <Typography fontFamily="monospace" variant="body2" noWrap>
56
- {isValid === undefined ? (
57
- <MdDone fontSize={18} color="yellow" />
58
- ) : isValid ? (
59
- <MdDone fontSize={18} color="green" />
60
- ) : (
61
- <MdClear color="red" fontSize={18} />
62
- )}
63
- </Typography>
57
+ {isValid === undefined && payload != undefined ? (
58
+ <WarningAmberRoundedIcon fontSize="small" color="warning" />
59
+ ) : isValid === true ? (
60
+ <CheckCircleOutlineRoundedIcon fontSize="small" color="success" />
61
+ ) : isValid === false ? (
62
+ <ErrorOutlineRoundedIcon color="error" fontSize="small" />
63
+ ) : (
64
+ //to keep row height consistent when no data provided, may need fix later
65
+ <ErrorOutlineRoundedIcon sx={{ color: alpha('#fff', 0) }} fontSize="small" />
66
+ )}
64
67
  </TableCell>
65
68
  )
66
69
 
@@ -1 +1,2 @@
1
+ export * from './DynamicTable'
1
2
  export * from './Table'