Enhance ObjectKanban and ObjectTable with Silent Loading Options
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- 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.
This commit is contained in:
parent
26d8c80d54
commit
1466fe0f62
@ -211,7 +211,8 @@ const ObjectKanban = forwardRef(
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const load = useCallback(
|
const load = useCallback(
|
||||||
async (filter = null, sorterArg = null) => {
|
async (filter = null, sorterArg = null, options = {}) => {
|
||||||
|
const silent = options.silent === true
|
||||||
const generation = ++loadGenerationRef.current
|
const generation = ++loadGenerationRef.current
|
||||||
|
|
||||||
if (!categoryProperty) {
|
if (!categoryProperty) {
|
||||||
@ -238,8 +239,12 @@ const ObjectKanban = forwardRef(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLoadedRef.current = false
|
// Filter/sort changes keep current columns visible; objectView /
|
||||||
setHasLoaded(false)
|
// initial loads clear to skeleton + Spin.
|
||||||
|
if (!silent || !hasLoadedRef.current) {
|
||||||
|
hasLoadedRef.current = false
|
||||||
|
setHasLoaded(false)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const values = await getModelPropertyValuesRef.current(
|
const values = await getModelPropertyValuesRef.current(
|
||||||
|
|||||||
@ -358,7 +358,7 @@ const ObjectKanbanColumn = forwardRef(
|
|||||||
[loadBoundaryPage]
|
[loadBoundaryPage]
|
||||||
)
|
)
|
||||||
|
|
||||||
const loadInitialPage = useCallback(async () => {
|
const loadInitialPage = useCallback(async ({ silent = false } = {}) => {
|
||||||
dataLoadGenerationRef.current += 1
|
dataLoadGenerationRef.current += 1
|
||||||
loadingPagesRef.current.clear()
|
loadingPagesRef.current.clear()
|
||||||
pendingScrollAnchorRef.current = null
|
pendingScrollAnchorRef.current = null
|
||||||
@ -370,12 +370,16 @@ const ObjectKanbanColumn = forwardRef(
|
|||||||
}
|
}
|
||||||
const sorter = sorterRef.current
|
const sorter = sorterRef.current
|
||||||
|
|
||||||
pagesRef.current = []
|
if (!silent) {
|
||||||
setPages([])
|
pagesRef.current = []
|
||||||
setLoading(true)
|
setPages([])
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
const skeletonPage = createSkeletonPage(1)
|
const skeletonPage = createSkeletonPage(1)
|
||||||
setTablePages([skeletonPage])
|
setTablePages([skeletonPage])
|
||||||
|
} else {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const firstResult = await fetchPage(1, { filter, sorter })
|
const firstResult = await fetchPage(1, { filter, sorter })
|
||||||
@ -391,11 +395,11 @@ const ObjectKanbanColumn = forwardRef(
|
|||||||
setTablePages(createPageWindow(loadedPages, 'next'))
|
setTablePages(createPageWindow(loadedPages, 'next'))
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
if (!isStaleDataLoad(generation)) {
|
if (!silent && !isStaleDataLoad(generation)) {
|
||||||
setTablePages([])
|
setTablePages([])
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (!isStaleDataLoad(generation)) {
|
if (!silent && !isStaleDataLoad(generation)) {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,10 +429,12 @@ const ObjectKanbanColumn = forwardRef(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastColumnQueryKeyRef.current === columnQueryKey) return
|
if (lastColumnQueryKeyRef.current === columnQueryKey) return
|
||||||
|
|
||||||
|
// First mount shows skeleton; later filter/sort updates load silently.
|
||||||
|
const silent = lastColumnQueryKeyRef.current != null
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
|
|
||||||
const runLoad = async () => {
|
const runLoad = async () => {
|
||||||
await loadInitialPage()
|
await loadInitialPage({ silent })
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
lastColumnQueryKeyRef.current = columnQueryKey
|
lastColumnQueryKeyRef.current = columnQueryKey
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1160,19 +1160,24 @@ const ObjectTable = forwardRef(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const loadPage = useCallback(
|
const loadPage = useCallback(
|
||||||
async (pageNum, filter = null, sorter = null) => {
|
async (pageNum, filter = null, sorter = null, options = {}) => {
|
||||||
|
const silent = options.silent === true
|
||||||
|
|
||||||
if (isKanban) {
|
if (isKanban) {
|
||||||
const generation = dataLoadGenerationRef.current + 1
|
const generation = dataLoadGenerationRef.current + 1
|
||||||
dataLoadGenerationRef.current = generation
|
dataLoadGenerationRef.current = generation
|
||||||
const activeFilter =
|
const activeFilter = filter != null ? filter : activeFilterRef.current
|
||||||
filter != null ? filter : activeFilterRef.current
|
|
||||||
const resolvedSorter =
|
const resolvedSorter =
|
||||||
sorter != null
|
sorter != null
|
||||||
? resolveSorter(sorter)
|
? resolveSorter(sorter)
|
||||||
: resolveSorter(tableSorterRef.current)
|
: resolveSorter(tableSorterRef.current)
|
||||||
const sorterForLoad = resolvedSorter?.field ? resolvedSorter : {}
|
const sorterForLoad = resolvedSorter?.field ? resolvedSorter : {}
|
||||||
|
|
||||||
setLoading(true)
|
if (!silent) {
|
||||||
|
setLoading(true)
|
||||||
|
} else {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let loadKanban = kanbanRef.current?.load
|
let loadKanban = kanbanRef.current?.load
|
||||||
if (!loadKanban) {
|
if (!loadKanban) {
|
||||||
@ -1182,16 +1187,47 @@ const ObjectTable = forwardRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!loadKanban) return
|
if (!loadKanban) return
|
||||||
await loadKanban(activeFilter, sorterForLoad)
|
await loadKanban(activeFilter, sorterForLoad, { silent })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error loading kanban view:', error)
|
logger.error('Error loading kanban view:', error)
|
||||||
} finally {
|
} finally {
|
||||||
if (generation === dataLoadGenerationRef.current) {
|
if (!silent && generation === dataLoadGenerationRef.current) {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
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()
|
const generation = beginDataReload()
|
||||||
clearTablePages()
|
clearTablePages()
|
||||||
if (isStaleDataLoad(generation)) return
|
if (isStaleDataLoad(generation)) return
|
||||||
@ -1564,7 +1600,9 @@ const ObjectTable = forwardRef(
|
|||||||
}
|
}
|
||||||
const effective = buildEffectiveFilter(next)
|
const effective = buildEffectiveFilter(next)
|
||||||
activeFilterRef.current = effective
|
activeFilterRef.current = effective
|
||||||
loadPage(initialPage, effective, resolveSorter(nextSorter))
|
loadPage(initialPage, effective, resolveSorter(nextSorter), {
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSidebarFilterChange = useCallback(
|
const handleSidebarFilterChange = useCallback(
|
||||||
@ -1582,7 +1620,9 @@ const ObjectTable = forwardRef(
|
|||||||
}
|
}
|
||||||
const effective = buildEffectiveFilter(newSidebarFilter)
|
const effective = buildEffectiveFilter(newSidebarFilter)
|
||||||
activeFilterRef.current = effective
|
activeFilterRef.current = effective
|
||||||
loadPage(initialPage, effective, resolveSorter(tableSorter))
|
loadPage(initialPage, effective, resolveSorter(tableSorter), {
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
assignSidebarToView,
|
assignSidebarToView,
|
||||||
@ -1609,7 +1649,9 @@ const ObjectTable = forwardRef(
|
|||||||
persistSort(nextSorter)
|
persistSort(nextSorter)
|
||||||
}
|
}
|
||||||
const effective = buildEffectiveFilter(sidebarFilter)
|
const effective = buildEffectiveFilter(sidebarFilter)
|
||||||
loadPage(initialPage, effective, resolveSorter(nextSorter))
|
loadPage(initialPage, effective, resolveSorter(nextSorter), {
|
||||||
|
silent: true
|
||||||
|
})
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
buildEffectiveFilter,
|
buildEffectiveFilter,
|
||||||
@ -1962,6 +2004,10 @@ const ObjectTable = forwardRef(
|
|||||||
[isEditing, registerForm]
|
[isEditing, registerForm]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('loading', loading)
|
||||||
|
}, [loading])
|
||||||
|
|
||||||
const tableContent = (
|
const tableContent = (
|
||||||
<Flex
|
<Flex
|
||||||
gap={'middle'}
|
gap={'middle'}
|
||||||
@ -2006,7 +2052,12 @@ const ObjectTable = forwardRef(
|
|||||||
<Spin
|
<Spin
|
||||||
indicator={<LoadingOutlined />}
|
indicator={<LoadingOutlined />}
|
||||||
spinning={loading}
|
spinning={loading}
|
||||||
style={{ height: '100%', flex: 1, minHeight: 0 }}
|
style={{
|
||||||
|
height: '300px',
|
||||||
|
flex: 1,
|
||||||
|
minHeight: 0,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{renderCards()}
|
{renderCards()}
|
||||||
</Spin>
|
</Spin>
|
||||||
@ -2054,7 +2105,9 @@ const ObjectTable = forwardRef(
|
|||||||
<Flex style={{ flex: 1, minHeight: 0 }}>
|
<Flex style={{ flex: 1, minHeight: 0 }}>
|
||||||
<FilterSidebar
|
<FilterSidebar
|
||||||
type={type}
|
type={type}
|
||||||
filter={activeObjectView ? sidebarFilter : effectiveFilter}
|
filter={
|
||||||
|
activeObjectView ? sidebarFilter : effectiveFilter
|
||||||
|
}
|
||||||
onFilterChange={handleSidebarFilterChange}
|
onFilterChange={handleSidebarFilterChange}
|
||||||
masterFilter={resolvedMasterFilter}
|
masterFilter={resolvedMasterFilter}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user