diff --git a/src/components/Item/ItemHeader/ItemHeader.js b/src/components/Item/ItemHeader/ItemHeader.js index 76e27201d..4b6511909 100644 --- a/src/components/Item/ItemHeader/ItemHeader.js +++ b/src/components/Item/ItemHeader/ItemHeader.js @@ -17,10 +17,10 @@ const getItemActionsMap = (isShortened) => { } const ItemHeader = React.forwardRef( - ({ dashboardMode, title, isShortened, tags, ...rest }, ref) => { + ({ dashboardMode, title, isShortened, style, tags, ...rest }, ref) => { const Actions = getItemActionsMap(isShortened)[dashboardMode] return ( -
+

{title}

{tags ? : null} @@ -36,6 +36,7 @@ ItemHeader.displayName = 'ItemHeader' ItemHeader.propTypes = { dashboardMode: PropTypes.string, isShortened: PropTypes.bool, + style: PropTypes.object, tags: PropTypes.node, title: PropTypes.string, } diff --git a/src/components/ProgressiveLoadingContainer.js b/src/components/ProgressiveLoadingContainer.js index 35d41895e..ce2bdb7f1 100644 --- a/src/components/ProgressiveLoadingContainer.js +++ b/src/components/ProgressiveLoadingContainer.js @@ -1,21 +1,69 @@ +import i18n from '@dhis2/d2-i18n' +import { Divider, spacers, CenteredContent } from '@dhis2/ui' import debounce from 'lodash/debounce.js' import pick from 'lodash/pick.js' import PropTypes from 'prop-types' import React, { Component } from 'react' +import { getVisualizationName } from '../modules/item.js' +import { + APP, + MESSAGES, + RESOURCES, + REPORTS, + isVisualizationType, +} from '../modules/itemTypes.js' +import ItemHeader from './Item/ItemHeader/ItemHeader.js' const defaultDebounceMs = 100 const defaultBufferFactor = 0.25 const observerConfig = { attributes: true, childList: false, subtree: false } +const getItemHeader = ({ item, apps }) => { + if (isVisualizationType(item)) { + const title = getVisualizationName(item) + return + } + + let title + if ([MESSAGES, RESOURCES, REPORTS].includes(item.type)) { + const titleMap = { + [MESSAGES]: i18n.t('Messages'), + [RESOURCES]: i18n.t('Resources'), + [REPORTS]: i18n.t('Reports'), + } + title = titleMap[item.type] + } else if (item.type === APP) { + let appDetails + const appKey = item.appKey + + if (appKey) { + appDetails = apps.find((app) => app.key === appKey) + } + + const hideTitle = appDetails?.settings?.dashboardWidget?.hideTitle + title = hideTitle ? null : appDetails.name + } + + return !title ? null : ( + <> + + + + ) +} + class ProgressiveLoadingContainer extends Component { static propTypes = { children: PropTypes.node.isRequired, + item: PropTypes.object.isRequired, + apps: PropTypes.array, bufferFactor: PropTypes.number, className: PropTypes.string, + dashboardIsCached: PropTypes.bool, debounceMs: PropTypes.number, forceLoad: PropTypes.bool, fullsreenView: PropTypes.bool, - itemId: PropTypes.string, + isOffline: PropTypes.bool, style: PropTypes.object, } static defaultProps = { @@ -32,6 +80,7 @@ class ProgressiveLoadingContainer extends Component { debouncedCheckShouldLoad = null handlerOptions = { passive: true } observer = null + isObserving = null checkShouldLoad() { if (!this.containerRef) { @@ -41,7 +90,9 @@ class ProgressiveLoadingContainer extends Component { // force load item regardless of its position if (this.forceLoad && !this.state.shouldLoad) { this.setState({ shouldLoad: true }) - this.removeHandler() + if (!this.props.isOffline || this.props.dashboardIsCached) { + this.removeHandler() + } return } @@ -60,7 +111,9 @@ class ProgressiveLoadingContainer extends Component { rect.top < window.innerHeight + bufferPx ) { this.setState({ shouldLoad: true }) - this.removeHandler() + if (!this.props.isOffline || this.props.dashboardIsCached) { + this.removeHandler() + } } } @@ -92,6 +145,7 @@ class ProgressiveLoadingContainer extends Component { this.observer = new MutationObserver(mutationCallback) this.observer.observe(this.containerRef, observerConfig) + this.isObserving = true } removeHandler() { @@ -106,6 +160,7 @@ class ProgressiveLoadingContainer extends Component { }) this.observer.disconnect() + this.isObserving = false } componentDidMount() { @@ -124,9 +179,16 @@ class ProgressiveLoadingContainer extends Component { } render() { - const { children, className, style, ...props } = this.props - - const shouldLoad = this.state.shouldLoad || props.forceLoad + const { + children, + className, + style, + apps, + item, + dashboardIsCached, + isOffline, + ...props + } = this.props const eventProps = pick(props, [ 'onMouseDown', @@ -135,15 +197,38 @@ class ProgressiveLoadingContainer extends Component { 'onTouchEnd', ]) + const renderContent = this.state.shouldLoad || props.forceLoad + + const getContent = () => { + if (isOffline && !dashboardIsCached && this.isObserving !== false) { + return !renderContent ? null : ( +
+ {getItemHeader({ item, apps })} + +
{i18n.t('Not available offline')}
+
+
+ ) + } else { + return renderContent && children + } + } + return (
(this.containerRef = ref)} style={style} className={className} - data-test={`dashboarditem-${props.itemId}`} + data-test={`dashboarditem-${item.id}`} {...eventProps} > - {shouldLoad && children} + {getContent()}
) } diff --git a/src/pages/edit/ItemGrid.js b/src/pages/edit/ItemGrid.js index 2e503d04a..fa2464fe7 100644 --- a/src/pages/edit/ItemGrid.js +++ b/src/pages/edit/ItemGrid.js @@ -60,7 +60,7 @@ const EditItemGrid = ({ 'edit', getGridItemDomElementClassName(item.id) )} - itemId={item.id} + item={item} > { +const ResponsiveItemGrid = ({ dashboardIsCached }) => { const dashboardId = useSelector(sGetSelectedId) const dashboardItems = useSelector(sGetSelectedDashboardItems) const { width } = useWindowDimensions() + const { apps } = useCachedDataQuery() const [expandedItems, setExpandedItems] = useState({}) const [displayItems, setDisplayItems] = useState(dashboardItems) const [layoutSm, setLayoutSm] = useState([]) const [gridWidth, setGridWidth] = useState(0) const [forceLoad, setForceLoad] = useState(false) const { recordingState } = useCacheableSection(dashboardId) + const { isDisconnected: isOffline } = useDhis2ConnectionStatus() const firstOfTypes = getFirstOfTypes(dashboardItems) const slideshowElementRef = useRef(null) @@ -142,11 +147,14 @@ const ResponsiveItemGrid = () => { [classes.enteringFullscreen]: isEnteringSlideshow, } )} - itemId={item.id} + item={item} forceLoad={ forceLoad || itemIsFullscreen || itemIsNextPrevFullscreen } fullscreenView={isSlideshowView} + isOffline={isOffline} + dashboardIsCached={dashboardIsCached} + apps={apps} > { ) } +ResponsiveItemGrid.propTypes = { + dashboardIsCached: PropTypes.bool, +} + export default ResponsiveItemGrid diff --git a/src/pages/view/ViewDashboard.js b/src/pages/view/ViewDashboard.js index 62baa8438..03739c1a6 100644 --- a/src/pages/view/ViewDashboard.js +++ b/src/pages/view/ViewDashboard.js @@ -157,7 +157,7 @@ const ViewDashboard = (props) => { <> - + ) }