@@ -590,6 +590,7 @@ export function TableGrid({
590590 rows,
591591 rowTotal,
592592 isLoadingRows,
593+ rowsError,
593594 fetchNextPage,
594595 hasNextPage,
595596 isFetchingNextPage,
@@ -4973,104 +4974,114 @@ export function TableGrid({
49734974 ) }
49744975 </ thead >
49754976 < tbody ref = { tbodyRef } >
4976- { isLoadingTable || isLoadingRows
4977- ? null
4978- : ( ( ) => {
4979- const virtualItems = rowVirtualizer . getVirtualItems ( )
4980- // `item.start`/`item.end` include `scrollMargin` (the sticky-header
4981- // offset) but `getTotalSize()` already nets it out, so both spacer
4982- // heights are computed relative to `scrollMargin`.
4983- const scrollMargin = rowVirtualizer . options . scrollMargin
4984- const paddingTop =
4985- virtualItems . length > 0 ? virtualItems [ 0 ] . start - scrollMargin : 0
4986- const paddingBottom =
4987- virtualItems . length > 0
4988- ? rowVirtualizer . getTotalSize ( ) -
4989- ( virtualItems [ virtualItems . length - 1 ] . end - scrollMargin )
4990- : 0
4991- return (
4992- < >
4993- { paddingTop > 0 && (
4994- < tr aria-hidden >
4995- < td
4996- colSpan = { displayColumns . length + 1 }
4997- style = { { height : paddingTop } }
4998- />
4999- </ tr >
5000- ) }
5001- { virtualItems . map ( ( virtualRow ) => {
5002- const index = virtualRow . index
5003- const row = rows [ index ]
5004- if ( ! row ) return null
5005- return (
5006- < DataRow
5007- key = { row . id }
5008- row = { row }
5009- columns = { displayColumns }
5010- workspaceId = { workspaceId }
5011- timezoneStatus = { timezoneState . status }
5012- rowIndex = { index }
5013- isFirstRow = { index === 0 }
5014- editingColumnName = {
5015- editingCell ?. rowId === row . id ? editingCell . columnName : null
5016- }
5017- initialCharacter = {
5018- editingCell ?. rowId === row . id ? initialCharacter : null
5019- }
5020- editorsReadOnly = { Boolean ( locks ?. updateLocked ) }
5021- pendingCellValue = {
5022- pendingUpdate && pendingUpdate . rowId === row . id
5023- ? pendingUpdate . data
5024- : null
5025- }
5026- normalizedSelection = { normalizedSelection }
5027- onClick = { handleCellClick }
5028- onDoubleClick = { handleCellDoubleClick }
5029- onSave = { handleInlineSave }
5030- onCancel = { handleInlineCancel }
5031- onContextMenu = { handleRowContextMenu }
5032- onCellMouseDown = { handleCellMouseDown }
5033- onCellMouseEnter = { handleCellMouseEnter }
5034- isRowChecked = { rowSelectionIncludes ( rowSelection , row . id ) }
5035- onRowToggle = { handleRowToggle }
5036- onRowMouseDown = { handleRowMouseDown }
5037- onRowMouseEnter = { handleRowMouseEnter }
5038- runningCount = { runningByRowId [ row . id ] ?? 0 }
5039- hasWorkflowColumns = { hasWorkflowColumns }
5040- numRegionWidth = { numRegionWidth }
5041- onStopRow = { onStopRow }
5042- onRunRow = { onRunRow }
5043- workflowGroups = { tableWorkflowGroups }
5044- activeDispatches = { activeDispatches }
5045- pinnedOffsets = { pinnedOffsets . size > 0 ? pinnedOffsets : undefined }
5046- lastPinnedColKey = { lastPinnedColKey }
5047- findMatchColumns = { findMatchColumnsByRowId . get ( row . id ) }
5048- />
5049- )
5050- } ) }
5051- { paddingBottom > 0 && (
5052- < tr aria-hidden >
5053- < td
5054- colSpan = { displayColumns . length + 1 }
5055- style = { { height : paddingBottom } }
5056- />
5057- </ tr >
5058- ) }
5059- { isFetchingNextPage && (
5060- < tr >
5061- < td colSpan = { displayColumns . length + 1 } className = 'h-[35px] p-0' >
5062- < div className = 'flex items-center justify-center' >
5063- < Loader
5064- animate
5065- className = 'size-[14px] shrink-0 text-[var(--text-tertiary)]'
5066- />
5067- </ div >
5068- </ td >
5069- </ tr >
5070- ) }
5071- </ >
5072- )
5073- } ) ( ) }
4977+ { isLoadingTable || isLoadingRows ? null : rowsError ? (
4978+ < tr >
4979+ < td
4980+ colSpan = { displayColumns . length + 1 }
4981+ role = 'alert'
4982+ className = 'px-4 py-3 text-[var(--text-error)] text-small'
4983+ >
4984+ { rowsError . message }
4985+ </ td >
4986+ </ tr >
4987+ ) : (
4988+ ( ( ) => {
4989+ const virtualItems = rowVirtualizer . getVirtualItems ( )
4990+ // `item.start`/`item.end` include `scrollMargin` (the sticky-header
4991+ // offset) but `getTotalSize()` already nets it out, so both spacer
4992+ // heights are computed relative to `scrollMargin`.
4993+ const scrollMargin = rowVirtualizer . options . scrollMargin
4994+ const paddingTop =
4995+ virtualItems . length > 0 ? virtualItems [ 0 ] . start - scrollMargin : 0
4996+ const paddingBottom =
4997+ virtualItems . length > 0
4998+ ? rowVirtualizer . getTotalSize ( ) -
4999+ ( virtualItems [ virtualItems . length - 1 ] . end - scrollMargin )
5000+ : 0
5001+ return (
5002+ < >
5003+ { paddingTop > 0 && (
5004+ < tr aria-hidden >
5005+ < td
5006+ colSpan = { displayColumns . length + 1 }
5007+ style = { { height : paddingTop } }
5008+ />
5009+ </ tr >
5010+ ) }
5011+ { virtualItems . map ( ( virtualRow ) => {
5012+ const index = virtualRow . index
5013+ const row = rows [ index ]
5014+ if ( ! row ) return null
5015+ return (
5016+ < DataRow
5017+ key = { row . id }
5018+ row = { row }
5019+ columns = { displayColumns }
5020+ workspaceId = { workspaceId }
5021+ timezoneStatus = { timezoneState . status }
5022+ rowIndex = { index }
5023+ isFirstRow = { index === 0 }
5024+ editingColumnName = {
5025+ editingCell ?. rowId === row . id ? editingCell . columnName : null
5026+ }
5027+ initialCharacter = {
5028+ editingCell ?. rowId === row . id ? initialCharacter : null
5029+ }
5030+ editorsReadOnly = { Boolean ( locks ?. updateLocked ) }
5031+ pendingCellValue = {
5032+ pendingUpdate && pendingUpdate . rowId === row . id
5033+ ? pendingUpdate . data
5034+ : null
5035+ }
5036+ normalizedSelection = { normalizedSelection }
5037+ onClick = { handleCellClick }
5038+ onDoubleClick = { handleCellDoubleClick }
5039+ onSave = { handleInlineSave }
5040+ onCancel = { handleInlineCancel }
5041+ onContextMenu = { handleRowContextMenu }
5042+ onCellMouseDown = { handleCellMouseDown }
5043+ onCellMouseEnter = { handleCellMouseEnter }
5044+ isRowChecked = { rowSelectionIncludes ( rowSelection , row . id ) }
5045+ onRowToggle = { handleRowToggle }
5046+ onRowMouseDown = { handleRowMouseDown }
5047+ onRowMouseEnter = { handleRowMouseEnter }
5048+ runningCount = { runningByRowId [ row . id ] ?? 0 }
5049+ hasWorkflowColumns = { hasWorkflowColumns }
5050+ numRegionWidth = { numRegionWidth }
5051+ onStopRow = { onStopRow }
5052+ onRunRow = { onRunRow }
5053+ workflowGroups = { tableWorkflowGroups }
5054+ activeDispatches = { activeDispatches }
5055+ pinnedOffsets = { pinnedOffsets . size > 0 ? pinnedOffsets : undefined }
5056+ lastPinnedColKey = { lastPinnedColKey }
5057+ findMatchColumns = { findMatchColumnsByRowId . get ( row . id ) }
5058+ />
5059+ )
5060+ } ) }
5061+ { paddingBottom > 0 && (
5062+ < tr aria-hidden >
5063+ < td
5064+ colSpan = { displayColumns . length + 1 }
5065+ style = { { height : paddingBottom } }
5066+ />
5067+ </ tr >
5068+ ) }
5069+ { isFetchingNextPage && (
5070+ < tr >
5071+ < td colSpan = { displayColumns . length + 1 } className = 'h-[35px] p-0' >
5072+ < div className = 'flex items-center justify-center' >
5073+ < Loader
5074+ animate
5075+ className = 'size-[14px] shrink-0 text-[var(--text-tertiary)]'
5076+ />
5077+ </ div >
5078+ </ td >
5079+ </ tr >
5080+ ) }
5081+ </ >
5082+ )
5083+ } ) ( )
5084+ ) }
50745085 </ tbody >
50755086 </ table >
50765087 { remoteSelections . length > 0 && (
0 commit comments