diff --git a/src/components/Dashboard/common/LoadingPlaceholder.jsx b/src/components/Dashboard/common/LoadingPlaceholder.jsx index dfb67508..edf3d24f 100644 --- a/src/components/Dashboard/common/LoadingPlaceholder.jsx +++ b/src/components/Dashboard/common/LoadingPlaceholder.jsx @@ -4,13 +4,29 @@ import PropTypes from 'prop-types' const { Text } = Typography -const LoadingPlaceholder = ({ message, hasBackground = true }) => { +const LoadingPlaceholder = ({ + message, + hasBackground = true, + hasBorder = true, + height = undefined +}) => { return ( { LoadingPlaceholder.propTypes = { message: PropTypes.string.isRequired, - hasBackground: PropTypes.bool + hasBackground: PropTypes.bool, + hasBorder: PropTypes.bool, + height: PropTypes.string } export default LoadingPlaceholder diff --git a/src/components/Dashboard/common/ObjectCard.jsx b/src/components/Dashboard/common/ObjectCard.jsx index 1959aab4..ad9a1c74 100644 --- a/src/components/Dashboard/common/ObjectCard.jsx +++ b/src/components/Dashboard/common/ObjectCard.jsx @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import ObjectProperty from './ObjectProperty' import { createElement } from 'react' import Thumbnail from './Thumbnail' +import { LoadingOutlined } from '@ant-design/icons' const ObjectCard = ({ isSkeleton = false, @@ -13,6 +14,7 @@ const ObjectCard = ({ isEditing = false, rowActions = [], renderActions, + lazyLoading = false, cardStyle = 'borderless' }) => { const descriptionItems = [] @@ -59,7 +61,7 @@ const ObjectCard = ({ var actions = undefined if (rowActions.length > 0) { - actions = renderActions(record) + actions = renderActions(record, lazyLoading) } const primaryDescriptionItems = thumbnailPresent @@ -146,8 +148,20 @@ const ObjectCard = ({ {actions && ( <> - - {actions} + + + + {actions} + + + {lazyLoading && ( + + )} )} @@ -166,7 +180,8 @@ ObjectCard.propTypes = { rowActions: PropTypes.array, renderActions: PropTypes.func.isRequired, cardStyle: PropTypes.string, - isSkeleton: PropTypes.bool + isSkeleton: PropTypes.bool, + lazyLoading: PropTypes.bool } export default ObjectCard diff --git a/src/components/Dashboard/common/ObjectKanban.jsx b/src/components/Dashboard/common/ObjectKanban.jsx index e4dc9e11..37903dc2 100644 --- a/src/components/Dashboard/common/ObjectKanban.jsx +++ b/src/components/Dashboard/common/ObjectKanban.jsx @@ -101,6 +101,7 @@ const ObjectKanban = forwardRef( baseFilter = {}, masterFilter = {}, sorter = {}, + lazyLoading = false, pageSize = 25, model, modelProperties, @@ -321,6 +322,7 @@ const ObjectKanban = forwardRef( skeletonColumnCount={ showSkeleton ? skeletonLayout.columnCount : 0 } + lazyLoading={showSkeleton || lazyLoading} />
{!showSkeleton && ( @@ -410,6 +412,7 @@ ObjectKanban.propTypes = { baseFilter: PropTypes.object, masterFilter: PropTypes.object, sorter: PropTypes.object, + lazyLoading: PropTypes.bool, pageSize: PropTypes.number, model: PropTypes.object.isRequired, modelProperties: PropTypes.array.isRequired, diff --git a/src/components/Dashboard/common/ObjectKanbanColumn.jsx b/src/components/Dashboard/common/ObjectKanbanColumn.jsx index 3ec8dc8c..8aa7a287 100644 --- a/src/components/Dashboard/common/ObjectKanbanColumn.jsx +++ b/src/components/Dashboard/common/ObjectKanbanColumn.jsx @@ -33,6 +33,7 @@ const ObjectKanbanColumn = forwardRef( visibleColumns = {}, isEditing = false, rowActions = [], + lazyLoading = false, renderActions, scrollElement = null }, @@ -358,60 +359,63 @@ const ObjectKanbanColumn = forwardRef( [loadBoundaryPage] ) - const loadInitialPage = useCallback(async ({ silent = false } = {}) => { - dataLoadGenerationRef.current += 1 - loadingPagesRef.current.clear() - pendingScrollAnchorRef.current = null - const generation = dataLoadGenerationRef.current - const filter = { - ...masterFilterRef.current, - ...baseFilterRef.current, - [categoryProperty]: toCategoryFilterValue(categoryValue) - } - const sorter = sorterRef.current - - if (!silent) { - pagesRef.current = [] - setPages([]) - setLoading(true) - - const skeletonPage = createSkeletonPage(1) - setTablePages([skeletonPage]) - } else { - setLoading(false) - } - - try { - const firstResult = await fetchPage(1, { filter, sorter }) - if (isStaleDataLoad(generation)) return - const loadedPages = [ - { - pageNum: 1, - items: firstResult.data || [], - hasMore: firstResult.hasMore - } - ] - if (!isStaleDataLoad(generation)) { - setTablePages(createPageWindow(loadedPages, 'next')) + const loadInitialPage = useCallback( + async ({ silent = false } = {}) => { + dataLoadGenerationRef.current += 1 + loadingPagesRef.current.clear() + pendingScrollAnchorRef.current = null + const generation = dataLoadGenerationRef.current + const filter = { + ...masterFilterRef.current, + ...baseFilterRef.current, + [categoryProperty]: toCategoryFilterValue(categoryValue) } - } catch { - if (!silent && !isStaleDataLoad(generation)) { - setTablePages([]) - } - } finally { - if (!silent && !isStaleDataLoad(generation)) { + const sorter = sorterRef.current + + if (!silent) { + pagesRef.current = [] + setPages([]) + setLoading(true) + + const skeletonPage = createSkeletonPage(1) + setTablePages([skeletonPage]) + } else { setLoading(false) } - } - }, [ - categoryProperty, - categoryValue, - createPageWindow, - createSkeletonPage, - fetchPage, - isStaleDataLoad, - setTablePages - ]) + + try { + const firstResult = await fetchPage(1, { filter, sorter }) + if (isStaleDataLoad(generation)) return + const loadedPages = [ + { + pageNum: 1, + items: firstResult.data || [], + hasMore: firstResult.hasMore + } + ] + if (!isStaleDataLoad(generation)) { + setTablePages(createPageWindow(loadedPages, 'next')) + } + } catch { + if (!silent && !isStaleDataLoad(generation)) { + setTablePages([]) + } + } finally { + if (!silent && !isStaleDataLoad(generation)) { + setLoading(false) + } + } + }, + [ + categoryProperty, + categoryValue, + createPageWindow, + createSkeletonPage, + fetchPage, + isStaleDataLoad, + setTablePages + ] + ) const reloadLoadedPages = useCallback(async () => { const loadedPages = pagesRef.current.filter( @@ -533,6 +537,7 @@ const ObjectKanbanColumn = forwardRef( rowActions={rowActions} renderActions={renderActions} cardStyle='bordered' + lazyLoading={lazyLoading} />
) @@ -560,6 +565,7 @@ ObjectKanbanColumn.propTypes = { visibleColumns: PropTypes.object, isEditing: PropTypes.bool, rowActions: PropTypes.array, + lazyLoading: PropTypes.bool, renderActions: PropTypes.func, scrollElement: PropTypes.object } diff --git a/src/components/Dashboard/common/ObjectKanbanHeader.jsx b/src/components/Dashboard/common/ObjectKanbanHeader.jsx index e9c735fe..6e3d37d1 100644 --- a/src/components/Dashboard/common/ObjectKanbanHeader.jsx +++ b/src/components/Dashboard/common/ObjectKanbanHeader.jsx @@ -2,20 +2,22 @@ import { Flex, Skeleton } from 'antd' import PropTypes from 'prop-types' import ObjectProperty from './ObjectProperty' import { getCategoryValueKey } from './viewModeUtils' +import { LoadingOutlined } from '@ant-design/icons' const ObjectKanbanHeader = ({ categoryValues, categoryProperty, categoryPropertyDef, trackRef, - skeletonColumnCount = 0 + skeletonColumnCount = 0, + lazyLoading = false }) => { const showSkeleton = skeletonColumnCount > 0 return (
- + {showSkeleton ? Array.from({ length: skeletonColumnCount }).map((_, index) => (
{ const columnKey = getCategoryValueKey(categoryValue) return ( -
+ {categoryPropertyDef ? ( ) : null} -
+ {lazyLoading && ( + + )} + ) })} @@ -57,7 +71,8 @@ ObjectKanbanHeader.propTypes = { categoryProperty: PropTypes.string.isRequired, categoryPropertyDef: PropTypes.object, trackRef: PropTypes.object, - skeletonColumnCount: PropTypes.number + skeletonColumnCount: PropTypes.number, + lazyLoading: PropTypes.bool } export default ObjectKanbanHeader diff --git a/src/components/Dashboard/common/ObjectTable.jsx b/src/components/Dashboard/common/ObjectTable.jsx index 83208128..36d84c29 100644 --- a/src/components/Dashboard/common/ObjectTable.jsx +++ b/src/components/Dashboard/common/ObjectTable.jsx @@ -60,6 +60,7 @@ import Tooltip from './Tooltip' import { ObjectTableFilterContext } from './ObjectTableFilterContext' import ObjectListViewContext from '../context/ObjectListViewContext' import { isCardsView, isKanbanView, normalizeViewMode } from './viewModeUtils' +import LoadingPlaceholder from './LoadingPlaceholder' const logger = loglevel.getLogger('DasboardTable') logger.setLevel(config.logLevel) @@ -563,7 +564,7 @@ const ObjectTable = forwardRef( ) }, []) - const renderActions = (objectData) => { + const renderActions = (objectData, actionsDisabled = false) => { return ( {rowActions.map((action, index) => { @@ -576,9 +577,10 @@ const ObjectTable = forwardRef( action.disabled({ ...objectData, _user: userProfile - }) + }) || + actionsDisabled } else { - disabled = denied || action.disabled + disabled = denied || action.disabled || actionsDisabled } } return ( @@ -1175,8 +1177,10 @@ const ObjectTable = forwardRef( if (!silent) { setLoading(true) + setLazyLoading(false) } else { setLoading(false) + setLazyLoading(true) } try { let loadKanban = kanbanRef.current?.load @@ -1191,8 +1195,12 @@ const ObjectTable = forwardRef( } catch (error) { logger.error('Error loading kanban view:', error) } finally { - if (!silent && generation === dataLoadGenerationRef.current) { - setLoading(false) + if (generation === dataLoadGenerationRef.current) { + if (!silent) { + setLoading(false) + } else { + setLazyLoading(false) + } } } return @@ -1204,6 +1212,7 @@ const ObjectTable = forwardRef( loadingPagesRef.current.clear() pendingScrollAnchorRef.current = null setLoading(false) + setLazyLoading(true) try { const firstResult = await fetchPage(pageNum, filter, sorter) @@ -1224,6 +1233,10 @@ const ObjectTable = forwardRef( if (!isStaleDataLoad(generation)) { logger.error(`Error loading page ${pageNum}:`, error) } + } finally { + if (!isStaleDataLoad(generation)) { + setLazyLoading(false) + } } return } @@ -1235,6 +1248,7 @@ const ObjectTable = forwardRef( const skeletonPage = createSkeletonPage(pageNum) setTablePages([skeletonPage]) setLoading(true) + setLazyLoading(false) if (isStaleDataLoad(generation)) return try { @@ -1970,6 +1984,7 @@ const ObjectTable = forwardRef( modelProperties={modelProperties} visibleColumns={visibleColumns} record={record} + lazyLoading={lazyLoading} isEditing={isEditing} rowActions={rowActions} renderActions={renderActions} @@ -1981,6 +1996,14 @@ const ObjectTable = forwardRef( ) })} + {lazyLoading && tableData.length <= 0 && ( + + )}
) @@ -2030,6 +2053,7 @@ const ObjectTable = forwardRef( baseFilter={effectiveFilter} masterFilter={resolvedMasterFilter} sorter={effectiveSorter} + lazyLoading={lazyLoading} pageSize={pageSize} model={model} modelProperties={modelProperties}