From 1466fe0f62961f0d36b5808f4dc8145f0912a4ba Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Thu, 3 Sep 2026 03:17:38 +0100 Subject: [PATCH] Enhance ObjectKanban and ObjectTable with Silent Loading Options - Updated ObjectKanban and ObjectTable components to support silent loading, allowing for smoother user experience during data fetching without disrupting the UI. - Refactored load functions to accept an options parameter, enabling conditional loading states based on the silent flag. - Improved loading state management in ObjectKanbanColumn to maintain visual consistency during filter and sort updates. - Adjusted loading behavior in ObjectTable to prevent unnecessary loading indicators when silent loading is enabled. --- .../Dashboard/common/ObjectKanban.jsx | 11 ++- .../Dashboard/common/ObjectKanbanColumn.jsx | 24 +++--- .../Dashboard/common/ObjectTable.jsx | 75 ++++++++++++++++--- 3 files changed, 87 insertions(+), 23 deletions(-) diff --git a/src/components/Dashboard/common/ObjectKanban.jsx b/src/components/Dashboard/common/ObjectKanban.jsx index 16648892..a93bc726 100644 --- a/src/components/Dashboard/common/ObjectKanban.jsx +++ b/src/components/Dashboard/common/ObjectKanban.jsx @@ -211,7 +211,8 @@ const ObjectKanban = forwardRef( }, []) const load = useCallback( - async (filter = null, sorterArg = null) => { + async (filter = null, sorterArg = null, options = {}) => { + const silent = options.silent === true const generation = ++loadGenerationRef.current if (!categoryProperty) { @@ -238,8 +239,12 @@ const ObjectKanban = forwardRef( return } - hasLoadedRef.current = false - setHasLoaded(false) + // Filter/sort changes keep current columns visible; objectView / + // initial loads clear to skeleton + Spin. + if (!silent || !hasLoadedRef.current) { + hasLoadedRef.current = false + setHasLoaded(false) + } try { const values = await getModelPropertyValuesRef.current( diff --git a/src/components/Dashboard/common/ObjectKanbanColumn.jsx b/src/components/Dashboard/common/ObjectKanbanColumn.jsx index ae544e1f..162852f9 100644 --- a/src/components/Dashboard/common/ObjectKanbanColumn.jsx +++ b/src/components/Dashboard/common/ObjectKanbanColumn.jsx @@ -358,7 +358,7 @@ const ObjectKanbanColumn = forwardRef( [loadBoundaryPage] ) - const loadInitialPage = useCallback(async () => { + const loadInitialPage = useCallback(async ({ silent = false } = {}) => { dataLoadGenerationRef.current += 1 loadingPagesRef.current.clear() pendingScrollAnchorRef.current = null @@ -370,12 +370,16 @@ const ObjectKanbanColumn = forwardRef( } const sorter = sorterRef.current - pagesRef.current = [] - setPages([]) - setLoading(true) + if (!silent) { + pagesRef.current = [] + setPages([]) + setLoading(true) - const skeletonPage = createSkeletonPage(1) - setTablePages([skeletonPage]) + const skeletonPage = createSkeletonPage(1) + setTablePages([skeletonPage]) + } else { + setLoading(false) + } try { const firstResult = await fetchPage(1, { filter, sorter }) @@ -391,11 +395,11 @@ const ObjectKanbanColumn = forwardRef( setTablePages(createPageWindow(loadedPages, 'next')) } } catch { - if (!isStaleDataLoad(generation)) { + if (!silent && !isStaleDataLoad(generation)) { setTablePages([]) } } finally { - if (!isStaleDataLoad(generation)) { + if (!silent && !isStaleDataLoad(generation)) { setLoading(false) } } @@ -425,10 +429,12 @@ const ObjectKanbanColumn = forwardRef( useEffect(() => { if (lastColumnQueryKeyRef.current === columnQueryKey) return + // First mount shows skeleton; later filter/sort updates load silently. + const silent = lastColumnQueryKeyRef.current != null let cancelled = false const runLoad = async () => { - await loadInitialPage() + await loadInitialPage({ silent }) if (!cancelled) { lastColumnQueryKeyRef.current = columnQueryKey } diff --git a/src/components/Dashboard/common/ObjectTable.jsx b/src/components/Dashboard/common/ObjectTable.jsx index 77fabb26..b246b48b 100644 --- a/src/components/Dashboard/common/ObjectTable.jsx +++ b/src/components/Dashboard/common/ObjectTable.jsx @@ -1160,19 +1160,24 @@ const ObjectTable = forwardRef( ) const loadPage = useCallback( - async (pageNum, filter = null, sorter = null) => { + async (pageNum, filter = null, sorter = null, options = {}) => { + const silent = options.silent === true + if (isKanban) { const generation = dataLoadGenerationRef.current + 1 dataLoadGenerationRef.current = generation - const activeFilter = - filter != null ? filter : activeFilterRef.current + const activeFilter = filter != null ? filter : activeFilterRef.current const resolvedSorter = sorter != null ? resolveSorter(sorter) : resolveSorter(tableSorterRef.current) const sorterForLoad = resolvedSorter?.field ? resolvedSorter : {} - setLoading(true) + if (!silent) { + setLoading(true) + } else { + setLoading(false) + } try { let loadKanban = kanbanRef.current?.load if (!loadKanban) { @@ -1182,16 +1187,47 @@ const ObjectTable = forwardRef( } if (!loadKanban) return - await loadKanban(activeFilter, sorterForLoad) + await loadKanban(activeFilter, sorterForLoad, { silent }) } catch (error) { logger.error('Error loading kanban view:', error) } finally { - if (generation === dataLoadGenerationRef.current) { + if (!silent && generation === dataLoadGenerationRef.current) { setLoading(false) } } return } + + if (silent) { + const generation = dataLoadGenerationRef.current + 1 + dataLoadGenerationRef.current = generation + loadingPagesRef.current.clear() + pendingScrollAnchorRef.current = null + setLoading(false) + + try { + const firstResult = await fetchPage(pageNum, filter, sorter) + if (isStaleDataLoad(generation)) return + const loadedPages = [ + { + pageNum, + items: firstResult.data || [], + hasMore: firstResult.hasMore + } + ] + + if (!isStaleDataLoad(generation)) { + setTablePages(createPageWindow(loadedPages, 'next')) + suppressTableChange() + } + } catch (error) { + if (!isStaleDataLoad(generation)) { + logger.error(`Error loading page ${pageNum}:`, error) + } + } + return + } + const generation = beginDataReload() clearTablePages() if (isStaleDataLoad(generation)) return @@ -1564,7 +1600,9 @@ const ObjectTable = forwardRef( } const effective = buildEffectiveFilter(next) activeFilterRef.current = effective - loadPage(initialPage, effective, resolveSorter(nextSorter)) + loadPage(initialPage, effective, resolveSorter(nextSorter), { + silent: true + }) } const handleSidebarFilterChange = useCallback( @@ -1582,7 +1620,9 @@ const ObjectTable = forwardRef( } const effective = buildEffectiveFilter(newSidebarFilter) activeFilterRef.current = effective - loadPage(initialPage, effective, resolveSorter(tableSorter)) + loadPage(initialPage, effective, resolveSorter(tableSorter), { + silent: true + }) }, [ assignSidebarToView, @@ -1609,7 +1649,9 @@ const ObjectTable = forwardRef( persistSort(nextSorter) } const effective = buildEffectiveFilter(sidebarFilter) - loadPage(initialPage, effective, resolveSorter(nextSorter)) + loadPage(initialPage, effective, resolveSorter(nextSorter), { + silent: true + }) }, [ buildEffectiveFilter, @@ -1962,6 +2004,10 @@ const ObjectTable = forwardRef( [isEditing, registerForm] ) + useEffect(() => { + console.log('loading', loading) + }, [loading]) + const tableContent = ( } spinning={loading} - style={{ height: '100%', flex: 1, minHeight: 0 }} + style={{ + height: '300px', + flex: 1, + minHeight: 0, + width: '100%' + }} > {renderCards()} @@ -2054,7 +2105,9 @@ const ObjectTable = forwardRef(