Enhance ObjectTable component by adding support for action handling with new props for row actions and visibility of action buttons. Refactor skeleton data creation and improve loading logic for better performance and user experience during data fetching.

This commit is contained in:
Tom Butcher 2026-07-20 02:07:10 +01:00
parent 46fd3b0c8e
commit 8dc74f1a8e

View File

@ -106,7 +106,9 @@ const ObjectTable = forwardRef(
size = 'middle', size = 'middle',
onStateChange, onStateChange,
showFilterSidebar = false, showFilterSidebar = false,
expandHeight = false expandHeight = false,
showActions = true,
onRowAction
}, },
ref ref
) => { ) => {
@ -186,14 +188,17 @@ const ObjectTable = forwardRef(
const rowActions = const rowActions =
model.actions?.filter((action) => action.row == true) || [] model.actions?.filter((action) => action.row == true) || []
const createSkeletonData = useCallback((pageNum) => { const createSkeletonData = useCallback(
return Array(pageSize) (pageNum) => {
.fill(null) return Array(pageSize)
.map((_, index) => ({ .fill(null)
_id: `skeleton-${pageNum}-${index}`, .map((_, index) => ({
isSkeleton: true _id: `skeleton-${pageNum}-${index}`,
})) isSkeleton: true
}, [pageSize]) }))
},
[pageSize]
)
const createSkeletonPage = useCallback( const createSkeletonPage = useCallback(
(pageNum) => ({ (pageNum) => ({
@ -236,6 +241,12 @@ const ObjectTable = forwardRef(
type={'text'} type={'text'}
size={'small'} size={'small'}
onClick={() => { onClick={() => {
if (
onRowAction &&
onRowAction(action, objectData) !== false
) {
return
}
if (action.url) { if (action.url) {
navigate(action.url(objectData._id)) navigate(action.url(objectData._id))
} }
@ -314,9 +325,7 @@ const ObjectTable = forwardRef(
hasMore: result.hasMore hasMore: result.hasMore
} }
setPages((prev) => setPages((prev) =>
prev.map((page) => prev.map((page) => (page.pageNum === pageNum ? loadedPage : page))
page.pageNum === pageNum ? loadedPage : page
)
) )
setLoading(false) setLoading(false)
return result.data || [] return result.data || []
@ -330,9 +339,9 @@ const ObjectTable = forwardRef(
const findRenderedRow = useCallback((scrollTarget, id) => { const findRenderedRow = useCallback((scrollTarget, id) => {
if (!scrollTarget || id == null) return null if (!scrollTarget || id == null) return null
return Array.from( return Array.from(scrollTarget.querySelectorAll('tr[data-row-key]')).find(
scrollTarget.querySelectorAll('tr[data-row-key]') (row) => row.getAttribute('data-row-key') === String(id)
).find((row) => row.getAttribute('data-row-key') === String(id)) )
}, []) }, [])
const captureScrollAnchor = useCallback( const captureScrollAnchor = useCallback(
@ -360,9 +369,7 @@ const ObjectTable = forwardRef(
} }
const placeholderAnchor = closestRow(placeholderPage.items) const placeholderAnchor = closestRow(placeholderPage.items)
const loadedPages = currentPages.filter( const loadedPages = currentPages.filter((page) => !page.isSkeletonPage)
(page) => !page.isSkeletonPage
)
const retainedPage = const retainedPage =
direction === 'previous' direction === 'previous'
? loadedPages[0] ? loadedPages[0]
@ -380,8 +387,7 @@ const ObjectTable = forwardRef(
(scrollTarget, anchor, loadedPage) => { (scrollTarget, anchor, loadedPage) => {
if (!scrollTarget || !anchor) return if (!scrollTarget || !anchor) return
const loadedItem = const loadedItem = loadedPage.items[anchor.placeholderAnchor?.index]
loadedPage.items[anchor.placeholderAnchor?.index]
const anchorId = loadedItem?._id ?? anchor.fallbackAnchor?.id const anchorId = loadedItem?._id ?? anchor.fallbackAnchor?.id
const previousTop = loadedItem const previousTop = loadedItem
? anchor.placeholderAnchor?.top ? anchor.placeholderAnchor?.top
@ -463,11 +469,7 @@ const ObjectTable = forwardRef(
} }
} }
}, },
[ [captureScrollAnchor, createPageWindow, fetchPage]
captureScrollAnchor,
createPageWindow,
fetchPage
]
) )
const loadNextPage = useCallback( const loadNextPage = useCallback(
@ -726,10 +728,7 @@ const ObjectTable = forwardRef(
] ]
if (firstResult.hasMore) { if (firstResult.hasMore) {
setPages([ setPages([...loadedPages, createSkeletonPage(pageNum + 1)])
...loadedPages,
createSkeletonPage(pageNum + 1)
])
const secondResult = await fetchPage(pageNum + 1) const secondResult = await fetchPage(pageNum + 1)
loadedPages.push({ loadedPages.push({
pageNum: pageNum + 1, pageNum: pageNum + 1,
@ -1004,7 +1003,11 @@ const ObjectTable = forwardRef(
} }
}) })
if (rowActions.length > 0 && tableData.some((item) => !item?.isSkeleton)) { if (
showActions &&
rowActions.length > 0 &&
tableData.some((item) => !item?.isSkeleton)
) {
columnsWithSkeleton.push({ columnsWithSkeleton.push({
title: ( title: (
<Flex gap='small' align='center' justify='center'> <Flex gap='small' align='center' justify='center'>
@ -1185,7 +1188,9 @@ ObjectTable.propTypes = {
size: PropTypes.string, size: PropTypes.string,
onStateChange: PropTypes.func, onStateChange: PropTypes.func,
showFilterSidebar: PropTypes.bool, showFilterSidebar: PropTypes.bool,
expandHeight: PropTypes.bool expandHeight: PropTypes.bool,
showActions: PropTypes.bool,
onRowAction: PropTypes.func
} }
export default ObjectTable export default ObjectTable