From fa9f0d56198088e7eedd335e71355d7bcb576f16 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 3 Sep 2024 11:43:24 +0200 Subject: [PATCH 001/102] chore: update ItemGrid to current standard and fix missing dep in useEffect --- i18n/en.pot | 7 +++-- src/pages/view/ItemGrid.js | 52 +++++++++++++++----------------------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index c5f2aef0b..b030c572f 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-03-19T12:31:03.302Z\n" -"PO-Revision-Date: 2024-03-19T12:31:03.302Z\n" +"POT-Creation-Date: 2024-09-03T09:43:28.012Z\n" +"PO-Revision-Date: 2024-09-03T09:43:28.014Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -410,6 +410,9 @@ msgstr "Start of dashboard" msgid "Print" msgstr "Print" +msgid "Present" +msgstr "Present" + msgid "dashboard layout" msgstr "dashboard layout" diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 0a112be77..7ce648fb8 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -1,9 +1,8 @@ import i18n from '@dhis2/d2-i18n' import cx from 'classnames' -import PropTypes from 'prop-types' import React, { useState, useEffect } from 'react' import { Responsive as ResponsiveReactGridLayout } from 'react-grid-layout' -import { connect } from 'react-redux' +import { useSelector } from 'react-redux' import { Item } from '../../components/Item/Item.js' import NoContentMessage from '../../components/NoContentMessage.js' import ProgressiveLoadingContainer from '../../components/ProgressiveLoadingContainer.js' @@ -34,7 +33,9 @@ import classes from './styles/ItemGrid.module.css' const EXPANDED_HEIGHT = 19 const EXPANDED_HEIGHT_SM = 15 -const ResponsiveItemGrid = ({ dashboardId, dashboardItems }) => { +const ResponsiveItemGrid = () => { + const dashboardId = useSelector(sGetSelectedId) + const dashboardItems = useSelector(sGetSelectedDashboardItems) const { width } = useWindowDimensions() const [expandedItems, setExpandedItems] = useState({}) const [displayItems, setDisplayItems] = useState(dashboardItems) @@ -45,6 +46,22 @@ const ResponsiveItemGrid = ({ dashboardId, dashboardItems }) => { const firstOfTypes = getFirstOfTypes(dashboardItems) useEffect(() => { + const getItemsWithAdjustedHeight = (items) => + items.map((item) => { + const expandedItem = expandedItems[item.id] + + if (expandedItem && expandedItem === true) { + const expandedHeight = isSmallScreen(width) + ? EXPANDED_HEIGHT_SM + : EXPANDED_HEIGHT + return Object.assign({}, item, { + h: item.h + expandedHeight, + smallOriginalH: getProportionalHeight(item, width), + }) + } + + return item + }) setLayoutSm( getItemsWithAdjustedHeight(getSmallLayout(dashboardItems, width)) ) @@ -68,23 +85,6 @@ const ResponsiveItemGrid = ({ dashboardId, dashboardItems }) => { setExpandedItems(newExpandedItems) } - const getItemsWithAdjustedHeight = (items) => - items.map((item) => { - const expandedItem = expandedItems[item.id] - - if (expandedItem && expandedItem === true) { - const expandedHeight = isSmallScreen(width) - ? EXPANDED_HEIGHT_SM - : EXPANDED_HEIGHT - return Object.assign({}, item, { - h: item.h + expandedHeight, - smallOriginalH: getProportionalHeight(item, width), - }) - } - - return item - }) - const getItemComponent = (item) => { if (!layoutSm.length) { return
@@ -157,14 +157,4 @@ const ResponsiveItemGrid = ({ dashboardId, dashboardItems }) => { ) } -ResponsiveItemGrid.propTypes = { - dashboardId: PropTypes.string, - dashboardItems: PropTypes.array, -} - -const mapStateToProps = (state) => ({ - dashboardItems: sGetSelectedDashboardItems(state), - dashboardId: sGetSelectedId(state), -}) - -export default connect(mapStateToProps)(ResponsiveItemGrid) +export default ResponsiveItemGrid From 3d3990e4aa463e6157ce223c9eed0a8c8ccaf010 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 3 Sep 2024 13:17:46 +0200 Subject: [PATCH 002/102] feat: fullscreen for visualization items --- i18n/en.pot | 10 +-- src/actions/presentDashboard.js | 6 ++ src/components/Item/VisualizationItem/Item.js | 4 +- .../Visualization/IframePlugin.js | 9 ++- .../Visualization/Visualization.js | 4 + src/pages/view/ItemGrid.js | 80 ++++++++++++++++++- src/pages/view/TitleBar/ActionsBar.js | 13 +++ .../TitleBar/styles/ActionsBar.module.css | 1 + src/reducers/index.js | 2 + src/reducers/presentDashboard.js | 13 +++ 10 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 src/actions/presentDashboard.js create mode 100644 src/reducers/presentDashboard.js diff --git a/i18n/en.pot b/i18n/en.pot index b030c572f..581e847fc 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-09-03T09:43:28.012Z\n" -"PO-Revision-Date: 2024-09-03T09:43:28.014Z\n" +"POT-Creation-Date: 2024-09-03T11:14:05.234Z\n" +"PO-Revision-Date: 2024-09-03T11:14:05.235Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -410,9 +410,6 @@ msgstr "Start of dashboard" msgid "Print" msgstr "Print" -msgid "Present" -msgstr "Present" - msgid "dashboard layout" msgstr "dashboard layout" @@ -532,6 +529,9 @@ msgstr "Edit" msgid "Share" msgstr "Share" +msgid "Present" +msgstr "Present" + msgid "Clear dashboard filters?" msgstr "Clear dashboard filters?" diff --git a/src/actions/presentDashboard.js b/src/actions/presentDashboard.js new file mode 100644 index 000000000..ed4195c36 --- /dev/null +++ b/src/actions/presentDashboard.js @@ -0,0 +1,6 @@ +import { SET_PRESENT_DASHBOARD } from '../reducers/presentDashboard.js' + +export const acSetPresentDashboard = (isPresent) => ({ + type: SET_PRESENT_DASHBOARD, + value: isPresent, +}) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 93b09b14b..9e340c8cb 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -203,7 +203,7 @@ class Item extends Component { } render() { - const { item, dashboardMode, itemFilters } = this.props + const { item, dashboardMode, itemFilters, isFS } = this.props const { showFooter, showNoFiltersOverlay } = this.state const originalType = getItemTypeForVis(item) const activeType = this.getActiveType() @@ -295,6 +295,7 @@ class Item extends Component { {(dimensions) => ( { const dispatch = useDispatch() const iframePluginStatus = useSelector(sGetIframePluginStatus) @@ -232,6 +233,9 @@ const IframePlugin = ({ ) } + const width = isFS ? '100%' : style.width || '100%' + const height = isFS ? '90vh' : style.height || '100%' // TODO - get the height right for FS + return (
{iframeSrc ? ( @@ -240,8 +244,8 @@ const IframePlugin = ({ src={iframeSrc} // preserve dimensions if provided style={{ - width: style.width || '100%', - height: style.height || '100%', + width, + height, border: 'none', }} > @@ -255,6 +259,7 @@ IframePlugin.propTypes = { dashboardId: PropTypes.string, dashboardMode: PropTypes.string, filterVersion: PropTypes.string, + isFS: PropTypes.bool, isFirstOfType: PropTypes.bool, itemId: PropTypes.string, itemType: PropTypes.string, diff --git a/src/components/Item/VisualizationItem/Visualization/Visualization.js b/src/components/Item/VisualizationItem/Visualization/Visualization.js index 33e5a6fb7..50761bad0 100644 --- a/src/components/Item/VisualizationItem/Visualization/Visualization.js +++ b/src/components/Item/VisualizationItem/Visualization/Visualization.js @@ -40,6 +40,7 @@ const Visualization = ({ originalType, showNoFiltersOverlay, onClickNoFiltersOverlay, + isFS, ...rest }) => { const dashboardId = useSelector(sGetSelectedId) @@ -141,6 +142,7 @@ const Visualization = ({ ) } @@ -191,6 +193,7 @@ const Visualization = ({ ) } @@ -229,6 +232,7 @@ Visualization.propTypes = { availableWidth: PropTypes.number, dashboardMode: PropTypes.string, gridWidth: PropTypes.number, + isFS: PropTypes.bool, item: PropTypes.object, itemFilters: PropTypes.object, originalType: PropTypes.string, diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 7ce648fb8..3baecd2e8 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -1,9 +1,12 @@ import i18n from '@dhis2/d2-i18n' import cx from 'classnames' -import React, { useState, useEffect } from 'react' +import sortBy from 'lodash/sortBy.js' +import React, { useState, useEffect, useRef } from 'react' import { Responsive as ResponsiveReactGridLayout } from 'react-grid-layout' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' +import { acSetPresentDashboard } from '../../actions/presentDashboard.js' import { Item } from '../../components/Item/Item.js' +import { getGridItemElement } from '../../components/Item/VisualizationItem/getGridItemElement.js' import NoContentMessage from '../../components/NoContentMessage.js' import ProgressiveLoadingContainer from '../../components/ProgressiveLoadingContainer.js' import { useWindowDimensions } from '../../components/WindowDimensionsProvider.js' @@ -24,6 +27,7 @@ import { } from '../../modules/gridUtil.js' import { getBreakpoint, isSmallScreen } from '../../modules/smallScreen.js' import { useCacheableSection } from '../../modules/useCacheableSection.js' +import { sGetPresentDashboard } from '../../reducers/presentDashboard.js' import { sGetSelectedId, sGetSelectedDashboardItems, @@ -34,8 +38,11 @@ const EXPANDED_HEIGHT = 19 const EXPANDED_HEIGHT_SM = 15 const ResponsiveItemGrid = () => { + const dispatch = useDispatch() const dashboardId = useSelector(sGetSelectedId) const dashboardItems = useSelector(sGetSelectedDashboardItems) + const isPresentMode = useSelector(sGetPresentDashboard) + const { width } = useWindowDimensions() const [expandedItems, setExpandedItems] = useState({}) const [displayItems, setDisplayItems] = useState(dashboardItems) @@ -45,6 +52,10 @@ const ResponsiveItemGrid = () => { const { recordingState } = useCacheableSection(dashboardId) const firstOfTypes = getFirstOfTypes(dashboardItems) + // for slideshow + const [fsItemIndex, setFsItemIndex] = useState(null) + const sItems = useRef([]) + useEffect(() => { const getItemsWithAdjustedHeight = (items) => items.map((item) => { @@ -74,6 +85,65 @@ const ResponsiveItemGrid = () => { } }, [recordingState]) + useEffect(() => { + const sortedItems = sortBy(displayItems, ['y', 'x']) + sItems.current = sortedItems + }, [displayItems]) + + useEffect(() => { + if (isPresentMode && document.fullscreenElement === null) { + setFsItemIndex(0) + const el = getGridItemElement(sItems.current[0].id) + el.requestFullscreen() + } + }, [isPresentMode]) + + useEffect(() => { + const handleKeyDown = (event) => { + if (document.fullscreenElement) { + let nextElementIndex + + if (event.key === 'ArrowRight' || event.key === 'ArrowDown') { + nextElementIndex = fsItemIndex + 1 + } else if ( + event.key === 'ArrowLeft' || + event.key === 'ArrowUp' + ) { + if (fsItemIndex === null || fsItemIndex === 0) { + nextElementIndex = sItems.current.length - 1 + } else { + nextElementIndex = fsItemIndex - 1 + } + } + const el = getGridItemElement( + sItems.current[nextElementIndex].id + ) + setFsItemIndex(nextElementIndex) + el.requestFullscreen() + } + } + + const handleFullscreenChange = () => { + if (!document.fullscreenElement) { + dispatch(acSetPresentDashboard(false)) + setFsItemIndex(null) + } + } + + // Attach the event listener to the window object + window.addEventListener('keydown', handleKeyDown) + document.addEventListener('fullscreenchange', handleFullscreenChange) + + // Clean up the event listener when the component is unmounted + return () => { + window.removeEventListener('keydown', handleKeyDown) + document.removeEventListener( + 'fullscreenchange', + handleFullscreenChange + ) + } + }, [fsItemIndex, dispatch]) + const onToggleItemExpanded = (clickedId) => { const isExpanded = typeof expandedItems[clickedId] === 'boolean' @@ -111,6 +181,12 @@ const ResponsiveItemGrid = () => { dashboardMode={VIEW} isRecording={forceLoad} onToggleItemExpanded={onToggleItemExpanded} + isFS={ + !!( + Number.isInteger(fsItemIndex) && + sItems.current[fsItemIndex].id === item.id + ) + } /> ) diff --git a/src/pages/view/TitleBar/ActionsBar.js b/src/pages/view/TitleBar/ActionsBar.js index 24da7ec8b..f0b6da581 100644 --- a/src/pages/view/TitleBar/ActionsBar.js +++ b/src/pages/view/TitleBar/ActionsBar.js @@ -18,6 +18,7 @@ import { connect } from 'react-redux' import { Link, Redirect } from 'react-router-dom' import { acSetDashboardStarred } from '../../../actions/dashboards.js' import { acClearItemFilters } from '../../../actions/itemFilters.js' +import { acSetPresentDashboard } from '../../../actions/presentDashboard.js' import { acSetShowDescription } from '../../../actions/showDescription.js' import { apiPostShowDescription } from '../../../api/description.js' import ConfirmActionDialog from '../../../components/ConfirmActionDialog.js' @@ -41,6 +42,7 @@ const ViewActions = ({ showDescription, starred, setDashboardStarred, + setPresentDashboard, updateShowDescription, removeAllFilters, restrictFilters, @@ -260,6 +262,15 @@ const ViewActions = ({ allowedFilters={allowedFilters} restrictFilters={restrictFilters} /> + + + {getMoreButton(classes.moreButton, false)} {getMoreButton(classes.moreButtonSmall, true)}
@@ -294,6 +305,7 @@ ViewActions.propTypes = { removeAllFilters: PropTypes.func, restrictFilters: PropTypes.bool, setDashboardStarred: PropTypes.func, + setPresentDashboard: PropTypes.func, showDescription: PropTypes.bool, starred: PropTypes.bool, updateShowDescription: PropTypes.func, @@ -314,6 +326,7 @@ const mapStateToProps = (state) => { export default connect(mapStateToProps, { setDashboardStarred: acSetDashboardStarred, + setPresentDashboard: acSetPresentDashboard, removeAllFilters: acClearItemFilters, updateShowDescription: acSetShowDescription, })(ViewActions) diff --git a/src/pages/view/TitleBar/styles/ActionsBar.module.css b/src/pages/view/TitleBar/styles/ActionsBar.module.css index a7005736e..652954217 100644 --- a/src/pages/view/TitleBar/styles/ActionsBar.module.css +++ b/src/pages/view/TitleBar/styles/ActionsBar.module.css @@ -19,6 +19,7 @@ @media only screen and (max-width: 480px) { .strip .editButton, + .strip .presentButton, .strip .shareButton { display: none; } diff --git a/src/reducers/index.js b/src/reducers/index.js index 9f839cbb2..f62cb9570 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -10,6 +10,7 @@ import itemActiveTypes from './itemActiveTypes.js' import itemFilters from './itemFilters.js' import messages from './messages.js' import passiveViewRegistered from './passiveViewRegistered.js' +import presentDashboard from './presentDashboard.js' import printDashboard from './printDashboard.js' import selected from './selected.js' import showDescription from './showDescription.js' @@ -29,6 +30,7 @@ export default combineReducers({ activeModalDimension, passiveViewRegistered, showDescription, + presentDashboard, itemActiveTypes, iframePluginStatus, }) diff --git a/src/reducers/presentDashboard.js b/src/reducers/presentDashboard.js new file mode 100644 index 000000000..0cdf4b5c7 --- /dev/null +++ b/src/reducers/presentDashboard.js @@ -0,0 +1,13 @@ +export const SET_PRESENT_DASHBOARD = 'SET_PRESENT_DASHBOARD' + +export default (state = false, action) => { + switch (action.type) { + case SET_PRESENT_DASHBOARD: { + return action.value + } + default: + return state + } +} + +export const sGetPresentDashboard = (state) => state.presentDashboard From 6f604b08260201e1c24f61db5a819b7c2a6a0eb2 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Wed, 4 Sep 2024 11:47:46 +0200 Subject: [PATCH 003/102] feat: add the navigation buttons and keep track of current index in ItemGrid --- i18n/en.pot | 14 ++- src/components/Item/VisualizationItem/Item.js | 55 ++++++++---- .../ItemContextMenu/ItemContextMenu.js | 15 ++-- src/pages/view/ItemGrid.js | 86 ++++++++++++------- src/pages/view/TitleBar/ActionsBar.js | 12 +-- src/reducers/presentDashboard.js | 2 +- 6 files changed, 118 insertions(+), 66 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 581e847fc..b40b48647 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-09-03T11:14:05.234Z\n" -"PO-Revision-Date: 2024-09-03T11:14:05.235Z\n" +"POT-Creation-Date: 2024-09-04T09:41:55.706Z\n" +"PO-Revision-Date: 2024-09-04T09:41:55.707Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -80,6 +80,12 @@ msgstr "Some filters not applied" msgid "There was a problem loading this dashboard item" msgstr "There was a problem loading this dashboard item" +msgid "Previous" +msgstr "Previous" + +msgid "Next" +msgstr "Next" + msgid "Hide details and interpretations" msgstr "Hide details and interpretations" @@ -529,8 +535,8 @@ msgstr "Edit" msgid "Share" msgstr "Share" -msgid "Present" -msgstr "Present" +msgid "Slideshow" +msgstr "Slideshow" msgid "Clear dashboard filters?" msgstr "Clear dashboard filters?" diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 9e340c8cb..9be861555 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -4,11 +4,12 @@ import { DIMENSION_ID_ORGUNIT, } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' -import { Tag, Tooltip } from '@dhis2/ui' +import { Button, Tag, Tooltip } from '@dhis2/ui' import PropTypes from 'prop-types' import React, { Component } from 'react' import { connect } from 'react-redux' import { acSetItemActiveType } from '../../../actions/itemActiveTypes.js' +import { acSetPresentDashboard } from '../../../actions/presentDashboard.js' import { acAddVisualization } from '../../../actions/visualizations.js' import { apiPostDataStatistics } from '../../../api/dataStatistics.js' import { apiFetchVisualization } from '../../../api/fetchVisualization.js' @@ -35,6 +36,7 @@ import { sGetItemFiltersRoot, DEFAULT_STATE_ITEM_FILTERS, } from '../../../reducers/itemFilters.js' +import { sGetPresentDashboard } from '../../../reducers/presentDashboard.js' import { sGetVisualization } from '../../../reducers/visualizations.js' import { SystemSettingsCtx } from '../../SystemSettingsProvider.js' import { WindowDimensionsCtx } from '../../WindowDimensionsProvider.js' @@ -131,22 +133,7 @@ class Item extends Component { onClickNoFiltersOverlay = () => this.setState({ showNoFiltersOverlay: false }) - - onToggleFullscreen = () => { - if (!isElementFullscreen(this.props.item.id)) { - const el = getGridItemElement(this.props.item.id) - if (el?.requestFullscreen) { - el.requestFullscreen() - } else if (el?.webkitRequestFullscreen) { - el.webkitRequestFullscreen() - } - } else { - document.exitFullscreen - ? document.exitFullscreen() - : document.webkitExitFullscreen() - } - } - + ß onToggleFooter = () => { this.setState( { showFooter: !this.state.showFooter }, @@ -203,7 +190,16 @@ class Item extends Component { } render() { - const { item, dashboardMode, itemFilters, isFS } = this.props + const { + item, + dashboardMode, + itemFilters, + isFS, + setPresent, + sortPosition, + numSortItems, + exitFullscreen, + } = this.props const { showFooter, showNoFiltersOverlay } = this.state const originalType = getItemTypeForVis(item) const activeType = this.getActiveType() @@ -216,11 +212,13 @@ class Item extends Component { visualization={this.props.visualization} onSelectActiveType={this.setActiveType} onToggleFooter={this.onToggleFooter} - onToggleFullscreen={this.onToggleFullscreen} + enterFullscreen={() => setPresent(sortPosition - 1)} + exitFullscreen={exitFullscreen} activeType={activeType} activeFooter={showFooter} fullscreenSupported={this.isFullscreenSupported()} loadItemFailed={this.state.loadItemFailed} + isFS={isFS} /> ) : null @@ -319,6 +317,17 @@ class Item extends Component { )}
+ {isFS && ( + <> + + {`${sortPosition}/${numSortItems}`} + + + )} {isViewMode(dashboardMode) && showFooter ? ( ) : null} @@ -332,15 +341,21 @@ Item.propTypes = { apps: PropTypes.array, dashboardMode: PropTypes.string, engine: PropTypes.object, + exitFullscreen: PropTypes.func, gridWidth: PropTypes.number, isEditing: PropTypes.bool, isFS: PropTypes.bool, isRecording: PropTypes.bool, item: PropTypes.object, itemFilters: PropTypes.object, + nextItem: PropTypes.func, + numSortItems: PropTypes.number, + prevItem: PropTypes.func, setActiveType: PropTypes.func, + setPresent: PropTypes.func, setVisualization: PropTypes.func, settings: PropTypes.object, + sortPosition: PropTypes.number, visualization: PropTypes.object, onToggleItemExpanded: PropTypes.func, } @@ -364,12 +379,14 @@ const mapStateToProps = (state, ownProps) => { state, getVisualizationId(ownProps.item) ), + presentDashboard: sGetPresentDashboard(state), } } const mapDispatchToProps = { setActiveType: acSetItemActiveType, setVisualization: acAddVisualization, + setPresent: acSetPresentDashboard, } const ItemWithSettings = (props) => ( diff --git a/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js b/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js index 44372943f..35c011124 100644 --- a/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js +++ b/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js @@ -31,7 +31,6 @@ import { isSmallScreen } from '../../../../modules/smallScreen.js' import MenuItem from '../../../MenuItemWithTooltip.js' import { useSystemSettings } from '../../../SystemSettingsProvider.js' import { useWindowDimensions } from '../../../WindowDimensionsProvider.js' -import { isElementFullscreen } from '../isElementFullscreen.js' import ViewAsMenuItems from './ViewAsMenuItems.js' const ItemContextMenu = (props) => { @@ -65,8 +64,8 @@ const ItemContextMenu = (props) => { } } - const toggleFullscreen = () => { - props.onToggleFullscreen() + const enterFullscreen = () => { + props.enterFullscreen() closeMenu() } @@ -100,8 +99,8 @@ const ItemContextMenu = (props) => { getVisualizationId(item) )}` - return isElementFullscreen(item.id) ? ( - ) : null} - + {getMoreButton(classes.moreButton, false)} {getMoreButton(classes.moreButtonSmall, true)} diff --git a/src/reducers/presentDashboard.js b/src/reducers/presentDashboard.js index 0cdf4b5c7..6b5af95d4 100644 --- a/src/reducers/presentDashboard.js +++ b/src/reducers/presentDashboard.js @@ -1,6 +1,6 @@ export const SET_PRESENT_DASHBOARD = 'SET_PRESENT_DASHBOARD' -export default (state = false, action) => { +export default (state = null, action) => { switch (action.type) { case SET_PRESENT_DASHBOARD: { return action.value From f25c305c9e0e72d2a4839f1f2e8607a99af672b0 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Wed, 4 Sep 2024 11:50:04 +0200 Subject: [PATCH 004/102] fix: remove stray char --- src/components/Item/VisualizationItem/Item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 9be861555..4e9c360a5 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -133,7 +133,7 @@ class Item extends Component { onClickNoFiltersOverlay = () => this.setState({ showNoFiltersOverlay: false }) - ß + onToggleFooter = () => { this.setState( { showFooter: !this.state.showFooter }, From 6033db147f2d9b7b26d8f63b8143edb95d04656f Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Thu, 5 Sep 2024 16:14:43 +0200 Subject: [PATCH 005/102] chore: full of debug comments --- src/components/Item/VisualizationItem/Item.js | 10 +-- .../ItemContextMenu/ItemContextMenu.js | 5 +- .../Visualization/IframePlugin.js | 9 ++- .../Visualization/Visualization.js | 8 +-- .../VisualizationItem/isElementFullscreen.js | 11 +++ src/pages/view/ItemGrid.js | 71 ++++++++++++------- 6 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 4e9c360a5..a7c276d79 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -194,7 +194,7 @@ class Item extends Component { item, dashboardMode, itemFilters, - isFS, + // isFS, setPresent, sortPosition, numSortItems, @@ -218,7 +218,7 @@ class Item extends Component { activeFooter={showFooter} fullscreenSupported={this.isFullscreenSupported()} loadItemFailed={this.state.loadItemFailed} - isFS={isFS} + // isFS={isFS} /> ) : null @@ -293,7 +293,7 @@ class Item extends Component { {(dimensions) => ( - {isFS && ( + {isElementFullscreen(item.id) && ( <> - {`${sortPosition}/${numSortItems}`} - - - )} {isViewMode(dashboardMode) && showFooter ? ( ) : null} diff --git a/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js b/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js index 340269184..a92ac94c9 100644 --- a/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js +++ b/src/components/Item/VisualizationItem/ItemContextMenu/ItemContextMenu.js @@ -100,13 +100,14 @@ const ItemContextMenu = (props) => { getVisualizationId(item) )}` - return isElementFullscreen(item.id) ? ( - - ) : ( + // return isElementFullscreen(item.id) ? ( + // + // ) : ( + return ( <>
+ + +
+ + ) : ( + + {getItemComponents(displayItems)} + + )} + ) } From aa5bf3318229c1a284bb1fc7d40e211d4ffeb319 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Fri, 6 Sep 2024 11:49:47 +0200 Subject: [PATCH 007/102] feat: sizing of the iframe as well as positioning of the nav buttons [skip ci] --- src/components/Item/VisualizationItem/Item.js | 27 +--- .../ItemContextMenu/ItemContextMenu.js | 11 -- .../Visualization/IframePlugin.js | 21 +-- .../Visualization/Visualization.js | 8 +- .../VisualizationItem/isElementFullscreen.js | 21 --- src/pages/view/ItemGrid.js | 127 ++++++++---------- src/pages/view/styles/ItemGrid.module.css | 65 +++++++++ 7 files changed, 144 insertions(+), 136 deletions(-) delete mode 100644 src/components/Item/VisualizationItem/isElementFullscreen.js diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 27a78996f..ba256f954 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -4,7 +4,7 @@ import { DIMENSION_ID_ORGUNIT, } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' -import { Button, Tag, Tooltip } from '@dhis2/ui' +import { Tag, Tooltip } from '@dhis2/ui' import PropTypes from 'prop-types' import React, { Component } from 'react' import { connect } from 'react-redux' @@ -43,7 +43,6 @@ import { WindowDimensionsCtx } from '../../WindowDimensionsProvider.js' import ItemHeader from '../ItemHeader/ItemHeader.js' import FatalErrorBoundary from './FatalErrorBoundary.js' import { getGridItemElement } from './getGridItemElement.js' -import { isElementFullscreen } from './isElementFullscreen.js' import ItemContextMenu from './ItemContextMenu/ItemContextMenu.js' import ItemFooter from './ItemFooter.js' import memoizeOne from './memoizeOne.js' @@ -153,16 +152,7 @@ class Item extends Component { return this.props.activeType || getItemTypeForVis(this.props.item) } - getAvailableHeight = ({ width, height }) => { - if (isElementFullscreen(this.props.item.id)) { - return ( - height - - this.headerRef.current.clientHeight - - this.itemHeaderTotalMargin - - this.itemContentPadding - ) - } - + getAvailableHeight = ({ width }) => { const calculatedHeight = getItemHeightPx(this.props.item, width) - this.headerRef.current.clientHeight - @@ -194,10 +184,9 @@ class Item extends Component { item, dashboardMode, itemFilters, - // isFS, + isFS, setPresent, sortPosition, - numSortItems, exitFullscreen, } = this.props const { showFooter, showNoFiltersOverlay } = this.state @@ -206,7 +195,8 @@ class Item extends Component { const actionButtons = pluginIsAvailable(activeType || item.type, this.props.apps) && - isViewMode(dashboardMode) ? ( + isViewMode(dashboardMode) && + isFS !== true ? ( ( { @@ -100,13 +98,6 @@ const ItemContextMenu = (props) => { getVisualizationId(item) )}` - // return isElementFullscreen(item.id) ? ( - // - // ) : ( return ( <>
@@ -181,9 +172,7 @@ ItemContextMenu.propTypes = { activeFooter: PropTypes.bool, activeType: PropTypes.string, enterFullscreen: PropTypes.func, - exitFullscreen: PropTypes.func, fullscreenSupported: PropTypes.bool, - // isFS: PropTypes.bool, item: PropTypes.object, loadItemFailed: PropTypes.bool, visualization: PropTypes.object, diff --git a/src/components/Item/VisualizationItem/Visualization/IframePlugin.js b/src/components/Item/VisualizationItem/Visualization/IframePlugin.js index 662462d1d..4addf540e 100644 --- a/src/components/Item/VisualizationItem/Visualization/IframePlugin.js +++ b/src/components/Item/VisualizationItem/Visualization/IframePlugin.js @@ -21,7 +21,6 @@ import { sGetIframePluginStatus, } from '../../../../reducers/iframePluginStatus.js' import { useUserSettings } from '../../../UserSettingsProvider.js' -import { isElementFullscreen } from '../isElementFullscreen.js' import MissingPluginMessage from './MissingPluginMessage.js' import { getPluginLaunchUrl } from './plugin.js' import classes from './styles/IframePlugin.module.css' @@ -37,7 +36,7 @@ const IframePlugin = ({ itemId, itemType, isFirstOfType, - // isFS, + isFS, }) => { const dispatch = useDispatch() const iframePluginStatus = useSelector(sGetIframePluginStatus) @@ -234,10 +233,18 @@ const IframePlugin = ({ ) } - const isFS = isElementFullscreen(itemId) - const width = isFS ? '100%' : style.width || '100%' - const height = isFS ? '90vh' : style.height || '100%' // TODO - get the height right for FS + const height = isFS ? '100vh' : style.height || '100%' + // TODO - get the height right for FS that includes space for header + // here's the implementation from Item.js + // if (isFS) { + // return ( + // height - + // this.headerRef.current.clientHeight - + // this.itemHeaderTotalMargin - + // this.itemContentPadding + // ) + // } return (
@@ -247,8 +254,6 @@ const IframePlugin = ({ src={iframeSrc} // preserve dimensions if provided style={{ - // width: style.width || '100%', - // height: style.height || '100%', width, height, border: 'none', @@ -264,7 +269,7 @@ IframePlugin.propTypes = { dashboardId: PropTypes.string, dashboardMode: PropTypes.string, filterVersion: PropTypes.string, - // isFS: PropTypes.bool, + isFS: PropTypes.bool, isFirstOfType: PropTypes.bool, itemId: PropTypes.string, itemType: PropTypes.string, diff --git a/src/components/Item/VisualizationItem/Visualization/Visualization.js b/src/components/Item/VisualizationItem/Visualization/Visualization.js index 3b69da97b..50761bad0 100644 --- a/src/components/Item/VisualizationItem/Visualization/Visualization.js +++ b/src/components/Item/VisualizationItem/Visualization/Visualization.js @@ -40,7 +40,7 @@ const Visualization = ({ originalType, showNoFiltersOverlay, onClickNoFiltersOverlay, - // isFS, + isFS, ...rest }) => { const dashboardId = useSelector(sGetSelectedId) @@ -142,7 +142,7 @@ const Visualization = ({ ) } @@ -193,7 +193,7 @@ const Visualization = ({ ) } @@ -232,7 +232,7 @@ Visualization.propTypes = { availableWidth: PropTypes.number, dashboardMode: PropTypes.string, gridWidth: PropTypes.number, - // isFS: PropTypes.bool, + isFS: PropTypes.bool, item: PropTypes.object, itemFilters: PropTypes.object, originalType: PropTypes.string, diff --git a/src/components/Item/VisualizationItem/isElementFullscreen.js b/src/components/Item/VisualizationItem/isElementFullscreen.js deleted file mode 100644 index 1c34dc83a..000000000 --- a/src/components/Item/VisualizationItem/isElementFullscreen.js +++ /dev/null @@ -1,21 +0,0 @@ -import { getGridItemDomElementClassName } from '../../../modules/getGridItemDomElementClassName.js' - -export const isElementFullscreen = (itemId) => { - const fullscreenElement = - document.fullscreenElement || document.webkitFullscreenElement - - // if (!fullscreenElement) { - // console.log('jj no fs element') - // } - - const isFullscreen = fullscreenElement?.classList.contains( - getGridItemDomElementClassName(itemId) - ) - if (isFullscreen) { - console.log('jj fs element', fullscreenElement.id) - } - - return fullscreenElement?.classList.contains( - getGridItemDomElementClassName(itemId) - ) -} diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 877b47557..645095bbf 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -1,4 +1,5 @@ import i18n from '@dhis2/d2-i18n' +import { IconChevronRight16, IconChevronLeft16, colors } from '@dhis2/ui' import cx from 'classnames' import sortBy from 'lodash/sortBy.js' import React, { useState, useEffect, useRef, useCallback } from 'react' @@ -6,7 +7,6 @@ import { Responsive as ResponsiveReactGridLayout } from 'react-grid-layout' import { useDispatch, useSelector } from 'react-redux' import { acSetPresentDashboard } from '../../actions/presentDashboard.js' import { Item } from '../../components/Item/Item.js' -import { getGridItemElement } from '../../components/Item/VisualizationItem/getGridItemElement.js' import NoContentMessage from '../../components/NoContentMessage.js' import ProgressiveLoadingContainer from '../../components/ProgressiveLoadingContainer.js' import { useWindowDimensions } from '../../components/WindowDimensionsProvider.js' @@ -95,15 +95,10 @@ const ResponsiveItemGrid = () => { // Handle Present button or Item Fullscreen button clicked useEffect(() => { if (Number.isInteger(fsItemStartingIndex)) { - // const el = getGridItemElement( - // sItems.current[fsItemStartingIndex].id - // ) const el = fsElement?.current - console.log('jj set starting fs element', el) el?.requestFullscreen() setFsItemIndex(fsItemStartingIndex) } else { - console.log('jj document.exitFS here') document.exitFullscreen().then(() => { setFsItemIndex(null) }) @@ -112,7 +107,6 @@ const ResponsiveItemGrid = () => { const exitFullscreen = () => { if (document.fullscreenElement) { - console.log('jj document.exitFullscreen') document.exitFullscreen().then(() => { dispatch(acSetPresentDashboard(null)) }) @@ -120,34 +114,18 @@ const ResponsiveItemGrid = () => { } const nextItem = useCallback(() => { - // const el = fsElement.current if (fsItemIndex === sItems.current.length - 1) { - // const el = getGridItemElement(sItems.current[0].id) - // el?.requestFullscreen().then(() => { setFsItemIndex(0) - // }) } else { - // const el = getGridItemElement(sItems.current[fsItemIndex + 1].id) - // el?.requestFullscreen().then(() => { setFsItemIndex(fsItemIndex + 1) - // }) } }, [fsItemIndex]) const prevItem = useCallback(() => { - // const el = fsElement.current if (fsItemIndex === 0) { - // const el = getGridItemElement( - // sItems.current[sItems.current.length - 1].id - // ) - // el?.requestFullscreen().then(() => { setFsItemIndex(sItems.current.length - 1) - // }) } else { - // const el = getGridItemElement(sItems.current[fsItemIndex - 1].id) - // el.requestFullscreen().then(() => { setFsItemIndex(fsItemIndex - 1) - // }) } }, [fsItemIndex]) @@ -164,7 +142,6 @@ const ResponsiveItemGrid = () => { } const handleFullscreenChange = () => { - console.log('jj handleFullscreenChange', document.fullscreenElement) if (!document.fullscreenElement) { setFsItemIndex(null) dispatch(acSetPresentDashboard(null)) @@ -205,13 +182,21 @@ const ResponsiveItemGrid = () => { item.firstOfType = true } + const isFS = Number.isInteger(fsItemIndex) + ? sItems.current[fsItemIndex].id === item.id + : null + return ( { dashboardMode={VIEW} isRecording={forceLoad} onToggleItemExpanded={onToggleItemExpanded} - // isFS={ - // !!( - // Number.isInteger(fsItemIndex) && - // sItems.current[fsItemIndex]?.id === item.id - // ) - // } + isFS={isFS} sortPosition={ sItems.current.findIndex((i) => i.id === item.id) + 1 } - numSortItems={sItems.current.length} nextItem={nextItem} prevItem={prevItem} exitFullscreen={exitFullscreen} @@ -254,51 +233,55 @@ const ResponsiveItemGrid = () => { ) } - console.log('jj render ItemGrid with fsItemIndex:', fsItemIndex) - return (
- {Number.isInteger(fsItemIndex) ? ( - <> - Fullscreen container -
- {getItemComponent(sItems.current[fsItemIndex])} -
-
- - - -
- - ) : ( - - {getItemComponents(displayItems)} - - )} + + {getItemComponents(displayItems)} + + +
+ + {` ${fsItemIndex + 1} / ${ + sItems.current.length + } `} + + +
+
) } diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index b0a2e1368..ca9718a04 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -1,3 +1,68 @@ .grid { margin-top: var(--spacers-dp16); } + +.fscreen>.grid { + margin-top: 0 +} + +#fullscreen-container { + position: relative +} + +.fscreen { + cursor: pointer; +} + +#fullscreen-container.fscreen { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.fullscreenNav { + display: none; +} + +.hideItem { + display: none; +} + +.fscreenItem { + width: 100% !important; + height: 100vh !important; + transform: none !important; +} + +.fullscreenNav.fscreen { + display: flex; + justify-content: center; + position: absolute; + bottom: 50px; + z-index: 1000; + width: 100%; +} + +.buttons { + padding: var(--spacers-dp4); + background-color: var(--colors-grey800); + color: var(--colors-white); +} + +.buttons button { + cursor: pointer; + color: var(--colors-white); +} + +.fullscreenNav button { + border: none; + background-color: transparent; + +} \ No newline at end of file From 7116a28565f94609cb4005f42b3f003ff3c75559 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Fri, 6 Sep 2024 11:56:25 +0200 Subject: [PATCH 008/102] chore: remove props no longer used --- src/components/Item/VisualizationItem/Item.js | 3 --- src/pages/view/ItemGrid.js | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index ba256f954..0d70850aa 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -187,7 +187,6 @@ class Item extends Component { isFS, setPresent, sortPosition, - exitFullscreen, } = this.props const { showFooter, showNoFiltersOverlay } = this.state const originalType = getItemTypeForVis(item) @@ -203,7 +202,6 @@ class Item extends Component { onSelectActiveType={this.setActiveType} onToggleFooter={this.onToggleFooter} enterFullscreen={() => setPresent(sortPosition - 1)} - exitFullscreen={exitFullscreen} activeType={activeType} activeFooter={showFooter} fullscreenSupported={this.isFullscreenSupported()} @@ -319,7 +317,6 @@ Item.propTypes = { apps: PropTypes.array, dashboardMode: PropTypes.string, engine: PropTypes.object, - exitFullscreen: PropTypes.func, gridWidth: PropTypes.number, isEditing: PropTypes.bool, isFS: PropTypes.bool, diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 645095bbf..7c7de2965 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -211,9 +211,6 @@ const ResponsiveItemGrid = () => { sortPosition={ sItems.current.findIndex((i) => i.id === item.id) + 1 } - nextItem={nextItem} - prevItem={prevItem} - exitFullscreen={exitFullscreen} />
) From 2c79ce390b2150cb0444d35008a6b017d6d616d5 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 9 Sep 2024 13:25:29 +0200 Subject: [PATCH 009/102] chore: override display for LL --- src/pages/view/styles/ItemGrid.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index ca9718a04..72c1f3c33 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -32,7 +32,7 @@ } .hideItem { - display: none; + display: none !important; } .fscreenItem { From 41ffd1268b57b7d221cf89fb8903bfec4d49159d Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 9 Sep 2024 15:01:02 +0200 Subject: [PATCH 010/102] chore: fs for LL items --- src/components/Item/VisualizationItem/Item.js | 12 ++++++++++++ .../Visualization/IframePlugin.js | 19 ++----------------- .../Visualization/Visualization.js | 1 + 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index 0d70850aa..c5a6c7ed8 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -49,6 +49,8 @@ import memoizeOne from './memoizeOne.js' import { pluginIsAvailable } from './Visualization/plugin.js' import Visualization from './Visualization/Visualization.js' +const MIN_CLIENT_HEIGHT = 16 + class Item extends Component { state = { showFooter: false, @@ -153,6 +155,13 @@ class Item extends Component { } getAvailableHeight = ({ width }) => { + if (this.props.isFS) { + const totalHeaderHeight = + (this.headerRef.current.clientHeight || MIN_CLIENT_HEIGHT) + + this.itemHeaderTotalMargin + + this.itemContentPadding + return `calc(100vh - ${totalHeaderHeight}px)` + } const calculatedHeight = getItemHeightPx(this.props.item, width) - this.headerRef.current.clientHeight - @@ -168,6 +177,9 @@ class Item extends Component { } getAvailableWidth = () => { + if (this.props.isFS) { + return '100%' + } const rect = getGridItemElement( this.props.item.id )?.getBoundingClientRect() diff --git a/src/components/Item/VisualizationItem/Visualization/IframePlugin.js b/src/components/Item/VisualizationItem/Visualization/IframePlugin.js index 4addf540e..f0a0b5209 100644 --- a/src/components/Item/VisualizationItem/Visualization/IframePlugin.js +++ b/src/components/Item/VisualizationItem/Visualization/IframePlugin.js @@ -36,7 +36,6 @@ const IframePlugin = ({ itemId, itemType, isFirstOfType, - isFS, }) => { const dispatch = useDispatch() const iframePluginStatus = useSelector(sGetIframePluginStatus) @@ -233,19 +232,6 @@ const IframePlugin = ({ ) } - const width = isFS ? '100%' : style.width || '100%' - const height = isFS ? '100vh' : style.height || '100%' - // TODO - get the height right for FS that includes space for header - // here's the implementation from Item.js - // if (isFS) { - // return ( - // height - - // this.headerRef.current.clientHeight - - // this.itemHeaderTotalMargin - - // this.itemContentPadding - // ) - // } - return (
{iframeSrc ? ( @@ -254,8 +240,8 @@ const IframePlugin = ({ src={iframeSrc} // preserve dimensions if provided style={{ - width, - height, + width: style.width || '100%', + height: style.height || '100%', border: 'none', }} > @@ -269,7 +255,6 @@ IframePlugin.propTypes = { dashboardId: PropTypes.string, dashboardMode: PropTypes.string, filterVersion: PropTypes.string, - isFS: PropTypes.bool, isFirstOfType: PropTypes.bool, itemId: PropTypes.string, itemType: PropTypes.string, diff --git a/src/components/Item/VisualizationItem/Visualization/Visualization.js b/src/components/Item/VisualizationItem/Visualization/Visualization.js index 50761bad0..720a5a3c3 100644 --- a/src/components/Item/VisualizationItem/Visualization/Visualization.js +++ b/src/components/Item/VisualizationItem/Visualization/Visualization.js @@ -171,6 +171,7 @@ const Visualization = ({ ) From 609b249895517be2edb6d7ec508a86201dc6adbc Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 9 Sep 2024 15:23:12 +0200 Subject: [PATCH 011/102] fix: only show Slideshow if fullscreen allowed in sys settings --- i18n/en.pot | 13 ++++++++----- src/pages/view/TitleBar/ActionsBar.js | 22 +++++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 70486b6c1..a12a1a9df 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-09-05T14:25:29.856Z\n" -"PO-Revision-Date: 2024-09-05T14:25:29.857Z\n" +"POT-Creation-Date: 2024-09-09T13:19:23.392Z\n" +"PO-Revision-Date: 2024-09-09T13:19:23.393Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -62,6 +62,12 @@ msgstr "Text box" msgid "Add text here" msgstr "Add text here" +msgid "Open in {{appName}}" +msgstr "Open in {{appName}}" + +msgid "View fullscreen" +msgstr "View fullscreen" + msgid "Back to all interpretations" msgstr "Back to all interpretations" @@ -89,9 +95,6 @@ msgstr "Show details and interpretations" msgid "Open in {{appName}} app" msgstr "Open in {{appName}} app" -msgid "View fullscreen" -msgstr "View fullscreen" - msgid "This map can't be displayed as a chart" msgstr "This map can't be displayed as a chart" diff --git a/src/pages/view/TitleBar/ActionsBar.js b/src/pages/view/TitleBar/ActionsBar.js index 40d0eb85e..69b889bb2 100644 --- a/src/pages/view/TitleBar/ActionsBar.js +++ b/src/pages/view/TitleBar/ActionsBar.js @@ -24,6 +24,7 @@ import { apiPostShowDescription } from '../../../api/description.js' import ConfirmActionDialog from '../../../components/ConfirmActionDialog.js' import DropdownButton from '../../../components/DropdownButton/DropdownButton.js' import MenuItem from '../../../components/MenuItemWithTooltip.js' +import { useSystemSettings } from '../../../components/SystemSettingsProvider.js' import { useCacheableSection } from '../../../modules/useCacheableSection.js' import { orObject } from '../../../modules/util.js' import { sGetDashboardStarred } from '../../../reducers/dashboards.js' @@ -59,6 +60,7 @@ const ViewActions = ({ const { isDisconnected: offline } = useDhis2ConnectionStatus() const { lastUpdated, isCached, startRecording, remove } = useCacheableSection(id) + const { allowVisFullscreen } = useSystemSettings().systemSettings const { show } = useAlert( ({ msg }) => msg, @@ -258,15 +260,17 @@ const ViewActions = ({ ) : null} - - - + {allowVisFullscreen ? ( + + + + ) : null} Date: Mon, 9 Sep 2024 15:23:57 +0200 Subject: [PATCH 012/102] fix: filter out SPACER and MESSAGES items from sorted items list --- src/pages/view/ItemGrid.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 7c7de2965..2edbbb434 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -25,6 +25,7 @@ import { getGridWidth, getProportionalHeight, } from '../../modules/gridUtil.js' +import { SPACER, MESSAGES } from '../../modules/itemTypes.js' import { getBreakpoint, isSmallScreen } from '../../modules/smallScreen.js' import { useCacheableSection } from '../../modules/useCacheableSection.js' import { sGetPresentDashboard } from '../../reducers/presentDashboard.js' @@ -87,8 +88,9 @@ const ResponsiveItemGrid = () => { }, [recordingState]) useEffect(() => { - const sortedItems = sortBy(displayItems, ['y', 'x']) - // TODO - remove the spacer and message items + const sortedItems = sortBy(displayItems, ['y', 'x']).filter( + (i) => [SPACER, MESSAGES].indexOf(i.type) === -1 + ) sItems.current = sortedItems }, [displayItems]) From 3df05ba82ae802cabf1a593a031bf8386704ee7b Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 9 Sep 2024 17:26:08 +0200 Subject: [PATCH 013/102] feat: styling and show/hide controls --- i18n/en.pot | 13 ++--- src/pages/view/ItemGrid.js | 62 +++++++++++++-------- src/pages/view/styles/ItemGrid.module.css | 66 +++++++++++++++-------- 3 files changed, 90 insertions(+), 51 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index a12a1a9df..3f7c8212c 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-09-09T13:19:23.392Z\n" -"PO-Revision-Date: 2024-09-09T13:19:23.393Z\n" +"POT-Creation-Date: 2024-09-09T15:15:02.457Z\n" +"PO-Revision-Date: 2024-09-09T15:15:02.458Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -62,12 +62,6 @@ msgstr "Text box" msgid "Add text here" msgstr "Add text here" -msgid "Open in {{appName}}" -msgstr "Open in {{appName}}" - -msgid "View fullscreen" -msgstr "View fullscreen" - msgid "Back to all interpretations" msgstr "Back to all interpretations" @@ -95,6 +89,9 @@ msgstr "Show details and interpretations" msgid "Open in {{appName}} app" msgstr "Open in {{appName}} app" +msgid "View fullscreen" +msgstr "View fullscreen" + msgid "This map can't be displayed as a chart" msgstr "This map can't be displayed as a chart" diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 2edbbb434..222c2e396 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -1,5 +1,5 @@ import i18n from '@dhis2/d2-i18n' -import { IconChevronRight16, IconChevronLeft16, colors } from '@dhis2/ui' +import { IconChevronRight24, IconChevronLeft24, colors } from '@dhis2/ui' import cx from 'classnames' import sortBy from 'lodash/sortBy.js' import React, { useState, useEffect, useRef, useCallback } from 'react' @@ -57,6 +57,8 @@ const ResponsiveItemGrid = () => { const fsItemStartingIndex = useSelector(sGetPresentDashboard) const [fsItemIndex, setFsItemIndex] = useState(null) const fsElement = useRef(null) + const hideControlsTimeout = useRef(null) + const controlsRef = useRef(null) useEffect(() => { const getItemsWithAdjustedHeight = (items) => @@ -100,20 +102,23 @@ const ResponsiveItemGrid = () => { const el = fsElement?.current el?.requestFullscreen() setFsItemIndex(fsItemStartingIndex) - } else { + } else if (document.fullscreenElement) { document.exitFullscreen().then(() => { setFsItemIndex(null) }) + } else { + setFsItemIndex(null) } }, [fsItemStartingIndex]) - const exitFullscreen = () => { - if (document.fullscreenElement) { - document.exitFullscreen().then(() => { - dispatch(acSetPresentDashboard(null)) - }) - } - } + // TODO - this is for an eventual Exit button + // const exitFullscreen = () => { + // if (document.fullscreenElement) { + // document.exitFullscreen().then(() => { + // dispatch(acSetPresentDashboard(null)) + // }) + // } + // } const nextItem = useCallback(() => { if (fsItemIndex === sItems.current.length - 1) { @@ -121,6 +126,7 @@ const ResponsiveItemGrid = () => { } else { setFsItemIndex(fsItemIndex + 1) } + showControls() }, [fsItemIndex]) const prevItem = useCallback(() => { @@ -129,8 +135,17 @@ const ResponsiveItemGrid = () => { } else { setFsItemIndex(fsItemIndex - 1) } + showControls() }, [fsItemIndex]) + const showControls = () => { + clearTimeout(hideControlsTimeout.current) + controlsRef.current?.classList.add(classes.visible) + hideControlsTimeout.current = setTimeout(() => { + controlsRef.current?.classList.remove(classes.visible) + }, 1000) + } + // This effect handles the keyboard navigation for the fullscreen mode useEffect(() => { const handleKeyDown = (event) => { @@ -154,6 +169,8 @@ const ResponsiveItemGrid = () => { window.addEventListener('keydown', handleKeyDown) document.addEventListener('fullscreenchange', handleFullscreenChange) + document.addEventListener('mousemove', showControls) + // Clean up the event listener when the component is unmounted return () => { window.removeEventListener('keydown', handleKeyDown) @@ -161,6 +178,7 @@ const ResponsiveItemGrid = () => { 'fullscreenchange', handleFullscreenChange ) + document.removeEventListener('mousemove', showControls) } }, [dispatch, nextItem, prevItem]) @@ -263,24 +281,24 @@ const ResponsiveItemGrid = () => { > {getItemComponents(displayItems)} - -
+ {Number.isInteger(fsItemIndex) && ( +
- {` ${fsItemIndex + 1} / ${ - sItems.current.length - } `} + {`${ + fsItemIndex + 1 + } / ${sItems.current.length}`} -
- + )}
) } diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index 72c1f3c33..7ea99b480 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -10,10 +10,6 @@ position: relative } -.fscreen { - cursor: pointer; -} - #fullscreen-container.fscreen { position: fixed; top: 0; @@ -27,10 +23,6 @@ align-items: center; } -.fullscreenNav { - display: none; -} - .hideItem { display: none !important; } @@ -41,28 +33,60 @@ transform: none !important; } -.fullscreenNav.fscreen { +/* Control buttons */ +.fullscreenNav { + display: none; +} + +.fullscreenNav.visible { display: flex; justify-content: center; - position: absolute; - bottom: 50px; - z-index: 1000; + position: fixed; + bottom: 20px; + z-index: 10; width: 100%; } -.buttons { - padding: var(--spacers-dp4); - background-color: var(--colors-grey800); - color: var(--colors-white); +.controls { + background: #202124; + padding: 8px; + border-radius: 5px; + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + transition: opacity 0.5s; + z-index: 10; } -.buttons button { - cursor: pointer; - color: var(--colors-white); +.controls.visible { + opacity: 1; + visibility: visible; } -.fullscreenNav button { +.controls button { + color: var(--colors-white); + background-color: #000; + background: #000; + border-radius: 3px; border: none; - background-color: transparent; + width: 32px; + height: 32px; + padding: 4px; + cursor: pointer; + } +.pageCounter { + font-family: "Roboto", sans-serif; + font-weight: 400; + font-style: normal; + color: white; + font-size: 14px; + margin: 0 10px; + user-select: none; } \ No newline at end of file From 09345905f1214935e114d5bc55810535df2652a7 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 8 Oct 2024 15:33:10 +0200 Subject: [PATCH 014/102] chore: fix jest tests --- .../__tests__/ItemContextMenu.offline.spec.js | 31 +------------------ .../__tests__/ItemContextMenu.spec.js | 31 +------------------ 2 files changed, 2 insertions(+), 60 deletions(-) diff --git a/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.offline.spec.js b/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.offline.spec.js index e1891d484..cdc63879a 100644 --- a/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.offline.spec.js +++ b/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.offline.spec.js @@ -1,7 +1,6 @@ import { fireEvent } from '@testing-library/dom' -import { render, waitFor, screen } from '@testing-library/react' +import { render, waitFor } from '@testing-library/react' import React from 'react' -import { getGridItemDomElementClassName } from '../../../../../modules/getGridItemDomElementClassName.js' import { useSystemSettings } from '../../../../SystemSettingsProvider.js' import WindowDimensionsProvider from '../../../../WindowDimensionsProvider.js' import ItemContextMenu from '../ItemContextMenu.js' @@ -66,34 +65,6 @@ test('renders just the button when menu closed', () => { expect(queryByText('View fullscreen')).toBeNull() }) -test('renders exit fullscreen button', () => { - useSystemSettings.mockReturnValue(mockSystemSettingsDefault) - const gridItemClassName = getGridItemDomElementClassName( - defaultProps.item.id - ) - - const { rerender } = render( - -
- -
-
- ) - - document.fullscreenElement = document.querySelector(`.${gridItemClassName}`) - - rerender( - -
- -
-
- ) - - document.fullscreenElement = null - expect(screen.getByTestId('exit-fullscreen-button')).toBeTruthy() -}) - test('renders popover menu for BAR chart', async () => { useSystemSettings.mockReturnValue(mockSystemSettingsDefault) const props = Object.assign({}, defaultProps, { diff --git a/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.spec.js b/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.spec.js index 185b54be8..5f9eeacc8 100644 --- a/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.spec.js +++ b/src/components/Item/VisualizationItem/ItemContextMenu/__tests__/ItemContextMenu.spec.js @@ -1,7 +1,6 @@ import { fireEvent } from '@testing-library/dom' -import { render, waitFor, screen } from '@testing-library/react' +import { render, waitFor } from '@testing-library/react' import React from 'react' -import { getGridItemDomElementClassName } from '../../../../../modules/getGridItemDomElementClassName.js' import { useSystemSettings } from '../../../../SystemSettingsProvider.js' import WindowDimensionsProvider from '../../../../WindowDimensionsProvider.js' import ItemContextMenu from '../ItemContextMenu.js' @@ -66,34 +65,6 @@ test('renders just the button when menu closed', () => { expect(queryByText('View fullscreen')).toBeNull() }) -test('renders exit fullscreen button', () => { - useSystemSettings.mockReturnValue(mockSystemSettingsDefault) - const gridItemClassName = getGridItemDomElementClassName( - defaultProps.item.id - ) - - const { rerender } = render( - -
- -
-
- ) - - document.fullscreenElement = document.querySelector(`.${gridItemClassName}`) - - rerender( - -
- -
-
- ) - - document.fullscreenElement = null - expect(screen.getByTestId('exit-fullscreen-button')).toBeTruthy() -}) - test('renders popover menu for BAR chart', async () => { useSystemSettings.mockReturnValue(mockSystemSettingsDefault) const props = Object.assign({}, defaultProps, { From ed77aaca14a4ad19d54db8fe4fd5e8de1b82cdb7 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 8 Oct 2024 15:53:43 +0200 Subject: [PATCH 015/102] feat: add exit button and always show controls on hover --- src/pages/view/ItemGrid.js | 60 +++++++++++++---------- src/pages/view/styles/ItemGrid.module.css | 20 ++------ 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 222c2e396..833e0b6bd 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -1,5 +1,10 @@ import i18n from '@dhis2/d2-i18n' -import { IconChevronRight24, IconChevronLeft24, colors } from '@dhis2/ui' +import { + IconChevronRight24, + IconChevronLeft24, + IconCross24, + colors, +} from '@dhis2/ui' import cx from 'classnames' import sortBy from 'lodash/sortBy.js' import React, { useState, useEffect, useRef, useCallback } from 'react' @@ -111,14 +116,13 @@ const ResponsiveItemGrid = () => { } }, [fsItemStartingIndex]) - // TODO - this is for an eventual Exit button - // const exitFullscreen = () => { - // if (document.fullscreenElement) { - // document.exitFullscreen().then(() => { - // dispatch(acSetPresentDashboard(null)) - // }) - // } - // } + const exitFullscreen = () => { + if (document.fullscreenElement) { + document.exitFullscreen().then(() => { + dispatch(acSetPresentDashboard(null)) + }) + } + } const nextItem = useCallback(() => { if (fsItemIndex === sItems.current.length - 1) { @@ -140,6 +144,7 @@ const ResponsiveItemGrid = () => { const showControls = () => { clearTimeout(hideControlsTimeout.current) + controlsRef.current?.classList.add(classes.visible) hideControlsTimeout.current = setTimeout(() => { controlsRef.current?.classList.remove(classes.visible) @@ -282,22 +287,27 @@ const ResponsiveItemGrid = () => { {getItemComponents(displayItems)} {Number.isInteger(fsItemIndex) && ( -
- - {`${ - fsItemIndex + 1 - } / ${sItems.current.length}`} - -
+ <> +
+ + {`${ + fsItemIndex + 1 + } / ${sItems.current.length}`} + + +
+ )}
) diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index adb09c53e..68d4a1877 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -33,28 +33,13 @@ transform: none !important; } -/* Control buttons */ -.fullscreenNav { - display: none; -} - -.fullscreenNav.visible { - display: flex; - justify-content: center; - position: fixed; - inset-block-end: 20px; - z-index: 10; - inline-size: 100%; -} - .controls { background: #202124; padding: 8px; border-radius: 5px; position: fixed; - inset-block-end: 20px; - inset-inline-start: 50%; - transform: translateX(-50%); + inset-block-start: 20px; + inset-inline-end: 20px; display: flex; align-items: center; justify-content: center; @@ -64,6 +49,7 @@ z-index: 10; } +.controls:hover, .controls.visible { opacity: 1; visibility: visible; From 6c4e86bc5710ec73fb3afbf21f53393893a8a34a Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 8 Oct 2024 16:00:23 +0200 Subject: [PATCH 016/102] chore: consistent class names --- src/pages/view/ItemGrid.js | 8 ++++---- src/pages/view/styles/ItemGrid.module.css | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 833e0b6bd..c5a36d204 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -219,8 +219,8 @@ const ResponsiveItemGrid = () => { 'view', getGridItemDomElementClassName(item.id), { - [classes.hideItem]: isFS === false, - [classes.fscreenItem]: isFS, + [classes.hiddenItem]: isFS === false, + [classes.fullscreenItem]: isFS, } )} itemId={item.id} @@ -259,7 +259,7 @@ const ResponsiveItemGrid = () => {
@@ -289,7 +289,7 @@ const ResponsiveItemGrid = () => { {Number.isInteger(fsItemIndex) && ( <>
Date: Thu, 10 Oct 2024 11:47:02 +0200 Subject: [PATCH 017/102] fix: always show fs controls at bottm --- src/components/Item/VisualizationItem/Item.js | 8 +++-- src/pages/view/ItemGrid.js | 32 ++++--------------- src/pages/view/styles/ItemGrid.module.css | 22 +++++-------- 3 files changed, 20 insertions(+), 42 deletions(-) diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index c5a6c7ed8..fa552c56f 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -50,6 +50,7 @@ import { pluginIsAvailable } from './Visualization/plugin.js' import Visualization from './Visualization/Visualization.js' const MIN_CLIENT_HEIGHT = 16 +const FS_CONTROLS_BUFFER = 48 // space for the fullscreen controls at bottom class Item extends Component { state = { @@ -156,11 +157,12 @@ class Item extends Component { getAvailableHeight = ({ width }) => { if (this.props.isFS) { - const totalHeaderHeight = + const totalNonVisHeight = (this.headerRef.current.clientHeight || MIN_CLIENT_HEIGHT) + this.itemHeaderTotalMargin + - this.itemContentPadding - return `calc(100vh - ${totalHeaderHeight}px)` + this.itemContentPadding + + FS_CONTROLS_BUFFER + return `calc(100vh - ${totalNonVisHeight}px)` } const calculatedHeight = getItemHeightPx(this.props.item, width) - diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index c5a36d204..4d3b75a4a 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -62,8 +62,6 @@ const ResponsiveItemGrid = () => { const fsItemStartingIndex = useSelector(sGetPresentDashboard) const [fsItemIndex, setFsItemIndex] = useState(null) const fsElement = useRef(null) - const hideControlsTimeout = useRef(null) - const controlsRef = useRef(null) useEffect(() => { const getItemsWithAdjustedHeight = (items) => @@ -130,7 +128,6 @@ const ResponsiveItemGrid = () => { } else { setFsItemIndex(fsItemIndex + 1) } - showControls() }, [fsItemIndex]) const prevItem = useCallback(() => { @@ -139,18 +136,8 @@ const ResponsiveItemGrid = () => { } else { setFsItemIndex(fsItemIndex - 1) } - showControls() }, [fsItemIndex]) - const showControls = () => { - clearTimeout(hideControlsTimeout.current) - - controlsRef.current?.classList.add(classes.visible) - hideControlsTimeout.current = setTimeout(() => { - controlsRef.current?.classList.remove(classes.visible) - }, 1000) - } - // This effect handles the keyboard navigation for the fullscreen mode useEffect(() => { const handleKeyDown = (event) => { @@ -174,8 +161,6 @@ const ResponsiveItemGrid = () => { window.addEventListener('keydown', handleKeyDown) document.addEventListener('fullscreenchange', handleFullscreenChange) - document.addEventListener('mousemove', showControls) - // Clean up the event listener when the component is unmounted return () => { window.removeEventListener('keydown', handleKeyDown) @@ -183,7 +168,6 @@ const ResponsiveItemGrid = () => { 'fullscreenchange', handleFullscreenChange ) - document.removeEventListener('mousemove', showControls) } }, [dispatch, nextItem, prevItem]) @@ -264,7 +248,9 @@ const ResponsiveItemGrid = () => { ref={fsElement} > { > {getItemComponents(displayItems)} + {Number.isInteger(fsItemIndex) && ( - <> -
+
+
@@ -307,7 +289,7 @@ const ResponsiveItemGrid = () => {
- +
)}
) diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index 9af44d03f..0179be1e9 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -2,7 +2,7 @@ margin-block-start: var(--spacers-dp16); } -.fscreen > .grid { +.fullscreenGrid { margin-block-start: 0; } @@ -33,26 +33,20 @@ transform: none !important; } +.fsControlsContainer { + position: fixed; + inset-block-end: 0; + inline-size: 100vw; + display: flex; + justify-content: center; +} .fullscreenControls { background: #202124; padding: 8px; border-radius: 5px; - position: fixed; - inset-block-start: 20px; - inset-inline-end: 20px; display: flex; align-items: center; justify-content: center; - opacity: 0; - visibility: hidden; - transition: opacity 0.5s; - z-index: 10; -} - -.fullscreenControls:hover, -.fullscreenControls.visible { - opacity: 1; - visibility: visible; } .fullscreenControls button { From 63a33a10c3727d7e695d9bd55fcf0d837365b79d Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Thu, 31 Oct 2024 15:43:49 +0100 Subject: [PATCH 018/102] fix: persistent nav bar --- src/components/Item/TextItem/Item.js | 51 ++++++++++--------- .../Item/TextItem/styles/TextItem.module.css | 9 ++++ src/pages/view/ItemGrid.js | 9 ++-- src/pages/view/styles/ItemGrid.module.css | 12 +++-- 4 files changed, 51 insertions(+), 30 deletions(-) create mode 100644 src/components/Item/TextItem/styles/TextItem.module.css diff --git a/src/components/Item/TextItem/Item.js b/src/components/Item/TextItem/Item.js index 1668c274f..732a11e0e 100644 --- a/src/components/Item/TextItem/Item.js +++ b/src/components/Item/TextItem/Item.js @@ -1,6 +1,7 @@ import { RichTextParser, RichTextEditor } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { Divider, spacers } from '@dhis2/ui' +import cx from 'classnames' import PropTypes from 'prop-types' import React from 'react' import { connect } from 'react-redux' @@ -14,27 +15,19 @@ import { import { sGetSelectedDashboardItems } from '../../../reducers/selected.js' import ItemHeader from '../ItemHeader/ItemHeader.js' import PrintItemInfo from '../ItemHeader/PrintItemInfo.js' +import classes from './styles/TextItem.module.css' -const style = { - textDiv: { - padding: '10px', - lineHeight: '16px', - }, - textField: { - fontSize: '14px', - fontStretch: 'normal', - margin: '0 auto', - display: 'block', - lineHeight: '24px', - }, - container: { - marginBottom: '20px', - marginTop: '20px', - }, +const parserTextStyle = { + padding: '10px', + fontSize: '14px', + fontStretch: 'normal', + margin: '0 auto', + display: 'block', + lineHeight: '16px', } const TextItem = (props) => { - const { item, dashboardMode, text, acUpdateDashboardItem } = props + const { item, dashboardMode, text, isFS, acUpdateDashboardItem } = props const onChangeText = (text) => { const updatedItem = { @@ -46,11 +39,17 @@ const TextItem = (props) => { } const viewItem = () => { - const textDivStyle = Object.assign({}, style.textField, style.textDiv) return ( -
- {text} -
+ <> +
+ + {text} + +
+ {isFS &&
} + ) } @@ -77,12 +76,15 @@ const TextItem = (props) => { } const printItem = () => { - const textDivStyle = Object.assign({}, style.textField, style.textDiv) return ( <> {props.item.shortened ? : null} -
- {text} +
+ + {text} +
) @@ -121,6 +123,7 @@ const mapStateToProps = (state, ownProps) => { TextItem.propTypes = { acUpdateDashboardItem: PropTypes.func, dashboardMode: PropTypes.string, + isFS: PropTypes.bool, item: PropTypes.object, text: PropTypes.string, } diff --git a/src/components/Item/TextItem/styles/TextItem.module.css b/src/components/Item/TextItem/styles/TextItem.module.css new file mode 100644 index 000000000..feee17a47 --- /dev/null +++ b/src/components/Item/TextItem/styles/TextItem.module.css @@ -0,0 +1,9 @@ +.container { + margin-block: 20px; + margin-block-start: 20px; +} + +.fsControlsBuffer { + block-size: 48px; + inline-size: 100%; +} diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 4d3b75a4a..e58204bc1 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -276,6 +276,12 @@ const ResponsiveItemGrid = () => { {Number.isInteger(fsItemIndex) && (
+ @@ -285,9 +291,6 @@ const ResponsiveItemGrid = () => { -
)} diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index 0179be1e9..47986a8df 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -39,6 +39,7 @@ inline-size: 100vw; display: flex; justify-content: center; + background-color: black; } .fullscreenControls { background: #202124; @@ -50,9 +51,8 @@ } .fullscreenControls button { - color: var(--colors-white); - background-color: #000; - background: #000; + color: white; + background-color: #1f2023; border-radius: 3px; border: none; inline-size: 32px; @@ -70,3 +70,9 @@ margin: 0 10px; user-select: none; } + +.exitButton { + position: absolute; + inset-block-end: 6px; + inset-inline-start: 6px; +} From a25b0d6c726ef76130eb04ffffb58ef31190b666 Mon Sep 17 00:00:00 2001 From: Joseph John Aas Cooper <33054985+cooper-joe@users.noreply.github.com> Date: Tue, 5 Nov 2024 09:43:58 +0100 Subject: [PATCH 019/102] fix: slideshow control bar styles --- src/pages/view/styles/ItemGrid.module.css | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index 47986a8df..bcdbf04aa 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -42,8 +42,7 @@ background-color: black; } .fullscreenControls { - background: #202124; - padding: 8px; + padding: 4px; border-radius: 5px; display: flex; align-items: center; @@ -52,7 +51,7 @@ .fullscreenControls button { color: white; - background-color: #1f2023; + background-color: #171819; border-radius: 3px; border: none; inline-size: 32px; @@ -60,6 +59,9 @@ padding: 4px; cursor: pointer; } +.fullscreenControls button:hover { + background-color: #202124; +} .pageCounter { font-family: 'Roboto', sans-serif; @@ -67,12 +69,14 @@ font-style: normal; color: white; font-size: 14px; - margin: 0 10px; + margin: 0 8px; + min-width: 60px; /* avoid moving buttons for most counts below 999 items */ + text-align: center; user-select: none; } .exitButton { position: absolute; - inset-block-end: 6px; - inset-inline-start: 6px; + inset-block-end: 4px; + inset-inline-start: 4px; } From 4d8f8df071bb0dbfa74b738214e850479eec0eea Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Tue, 5 Nov 2024 16:31:21 +0100 Subject: [PATCH 020/102] fix: text item style --- src/components/Item/TextItem/Item.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Item/TextItem/Item.js b/src/components/Item/TextItem/Item.js index 732a11e0e..8e8d2c111 100644 --- a/src/components/Item/TextItem/Item.js +++ b/src/components/Item/TextItem/Item.js @@ -18,12 +18,12 @@ import PrintItemInfo from '../ItemHeader/PrintItemInfo.js' import classes from './styles/TextItem.module.css' const parserTextStyle = { - padding: '10px', - fontSize: '14px', + padding: '24px', + fontSize: '18px', fontStretch: 'normal', margin: '0 auto', display: 'block', - lineHeight: '16px', + lineHeight: '23px', } const TextItem = (props) => { From 021a6de8b08dc27be986f30c0e8a0057283f7a6e Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Wed, 6 Nov 2024 14:29:20 +0100 Subject: [PATCH 021/102] chore: move fullscreen handling to a hook --- .../Item/TextItem/styles/TextItem.module.css | 2 +- src/components/Item/VisualizationItem/Item.js | 2 +- src/modules/useFullscreen.js | 104 +++++++++++++++++ src/pages/view/ItemGrid.js | 109 +++--------------- src/pages/view/styles/ItemGrid.module.css | 3 +- 5 files changed, 122 insertions(+), 98 deletions(-) create mode 100644 src/modules/useFullscreen.js diff --git a/src/components/Item/TextItem/styles/TextItem.module.css b/src/components/Item/TextItem/styles/TextItem.module.css index feee17a47..1a04da29c 100644 --- a/src/components/Item/TextItem/styles/TextItem.module.css +++ b/src/components/Item/TextItem/styles/TextItem.module.css @@ -4,6 +4,6 @@ } .fsControlsBuffer { - block-size: 48px; + block-size: 40px; inline-size: 100%; } diff --git a/src/components/Item/VisualizationItem/Item.js b/src/components/Item/VisualizationItem/Item.js index fa552c56f..b435917ca 100644 --- a/src/components/Item/VisualizationItem/Item.js +++ b/src/components/Item/VisualizationItem/Item.js @@ -50,7 +50,7 @@ import { pluginIsAvailable } from './Visualization/plugin.js' import Visualization from './Visualization/Visualization.js' const MIN_CLIENT_HEIGHT = 16 -const FS_CONTROLS_BUFFER = 48 // space for the fullscreen controls at bottom +const FS_CONTROLS_BUFFER = 40 // space for the fullscreen controls at bottom class Item extends Component { state = { diff --git a/src/modules/useFullscreen.js b/src/modules/useFullscreen.js new file mode 100644 index 000000000..bc42139a1 --- /dev/null +++ b/src/modules/useFullscreen.js @@ -0,0 +1,104 @@ +import sortBy from 'lodash/sortBy.js' +import { useState, useEffect, useRef, useCallback } from 'react' +import { useSelector, useDispatch } from 'react-redux' +import { acSetPresentDashboard } from '../actions/presentDashboard.js' +import { sGetPresentDashboard } from '../reducers/presentDashboard.js' +import { SPACER, MESSAGES } from './itemTypes.js' + +const useFullscreen = (displayItems) => { + const dispatch = useDispatch() + const sItems = useRef([]) + const fsItemStartingIndex = useSelector(sGetPresentDashboard) + const [fsItemIndex, setFsItemIndex] = useState(null) + const fsElement = useRef(null) + + useEffect(() => { + const sortedItems = sortBy(displayItems, ['y', 'x']).filter( + (i) => [SPACER, MESSAGES].indexOf(i.type) === -1 + ) + sItems.current = sortedItems + }, [displayItems]) + + // Handle Present button or Item Fullscreen button clicked + useEffect(() => { + if (Number.isInteger(fsItemStartingIndex)) { + const el = fsElement?.current + el?.requestFullscreen() + setFsItemIndex(fsItemStartingIndex) + } else if (document.fullscreenElement) { + document.exitFullscreen().then(() => { + setFsItemIndex(null) + }) + } else { + setFsItemIndex(null) + } + }, [fsItemStartingIndex]) + + const exitFullscreen = () => { + if (document.fullscreenElement) { + document.exitFullscreen().then(() => { + dispatch(acSetPresentDashboard(null)) + }) + } + } + + const nextItem = useCallback(() => { + if (fsItemIndex === sItems.current.length - 1) { + setFsItemIndex(0) + } else { + setFsItemIndex(fsItemIndex + 1) + } + }, [fsItemIndex]) + + const prevItem = useCallback(() => { + if (fsItemIndex === 0) { + setFsItemIndex(sItems.current.length - 1) + } else { + setFsItemIndex(fsItemIndex - 1) + } + }, [fsItemIndex]) + + // This effect handles the keyboard navigation for the fullscreen mode + useEffect(() => { + const handleKeyDown = (event) => { + if (document.fullscreenElement) { + if (event.key === 'ArrowRight') { + nextItem() + } else if (event.key === 'ArrowLeft') { + prevItem() + } + } + } + + const handleFullscreenChange = () => { + if (!document.fullscreenElement) { + setFsItemIndex(null) + dispatch(acSetPresentDashboard(null)) + } + } + + // Attach the event listener to the window object + window.addEventListener('keydown', handleKeyDown) + document.addEventListener('fullscreenchange', handleFullscreenChange) + + // Clean up the event listener when the component is unmounted + return () => { + window.removeEventListener('keydown', handleKeyDown) + document.removeEventListener( + 'fullscreenchange', + handleFullscreenChange + ) + } + }, [dispatch, nextItem, prevItem]) + + return { + fsItemIndex, + fsElement, + exitFullscreen, + nextItem, + prevItem, + sortedItems: sItems.current, + } +} + +export default useFullscreen diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index e58204bc1..17d9cb00b 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -6,11 +6,9 @@ import { colors, } from '@dhis2/ui' import cx from 'classnames' -import sortBy from 'lodash/sortBy.js' -import React, { useState, useEffect, useRef, useCallback } from 'react' +import React, { useState, useEffect } from 'react' import { Responsive as ResponsiveReactGridLayout } from 'react-grid-layout' -import { useDispatch, useSelector } from 'react-redux' -import { acSetPresentDashboard } from '../../actions/presentDashboard.js' +import { useSelector } from 'react-redux' import { Item } from '../../components/Item/Item.js' import NoContentMessage from '../../components/NoContentMessage.js' import ProgressiveLoadingContainer from '../../components/ProgressiveLoadingContainer.js' @@ -30,10 +28,9 @@ import { getGridWidth, getProportionalHeight, } from '../../modules/gridUtil.js' -import { SPACER, MESSAGES } from '../../modules/itemTypes.js' import { getBreakpoint, isSmallScreen } from '../../modules/smallScreen.js' import { useCacheableSection } from '../../modules/useCacheableSection.js' -import { sGetPresentDashboard } from '../../reducers/presentDashboard.js' +import useFullscreen from '../../modules/useFullscreen.js' import { sGetSelectedId, sGetSelectedDashboardItems, @@ -44,10 +41,8 @@ const EXPANDED_HEIGHT = 19 const EXPANDED_HEIGHT_SM = 15 const ResponsiveItemGrid = () => { - const dispatch = useDispatch() const dashboardId = useSelector(sGetSelectedId) const dashboardItems = useSelector(sGetSelectedDashboardItems) - const { width } = useWindowDimensions() const [expandedItems, setExpandedItems] = useState({}) const [displayItems, setDisplayItems] = useState(dashboardItems) @@ -57,11 +52,14 @@ const ResponsiveItemGrid = () => { const { recordingState } = useCacheableSection(dashboardId) const firstOfTypes = getFirstOfTypes(dashboardItems) - // for slideshow - const sItems = useRef([]) - const fsItemStartingIndex = useSelector(sGetPresentDashboard) - const [fsItemIndex, setFsItemIndex] = useState(null) - const fsElement = useRef(null) + const { + fsItemIndex, + fsElement, + exitFullscreen, + nextItem, + prevItem, + sortedItems, + } = useFullscreen(displayItems) useEffect(() => { const getItemsWithAdjustedHeight = (items) => @@ -92,85 +90,6 @@ const ResponsiveItemGrid = () => { } }, [recordingState]) - useEffect(() => { - const sortedItems = sortBy(displayItems, ['y', 'x']).filter( - (i) => [SPACER, MESSAGES].indexOf(i.type) === -1 - ) - sItems.current = sortedItems - }, [displayItems]) - - // Handle Present button or Item Fullscreen button clicked - useEffect(() => { - if (Number.isInteger(fsItemStartingIndex)) { - const el = fsElement?.current - el?.requestFullscreen() - setFsItemIndex(fsItemStartingIndex) - } else if (document.fullscreenElement) { - document.exitFullscreen().then(() => { - setFsItemIndex(null) - }) - } else { - setFsItemIndex(null) - } - }, [fsItemStartingIndex]) - - const exitFullscreen = () => { - if (document.fullscreenElement) { - document.exitFullscreen().then(() => { - dispatch(acSetPresentDashboard(null)) - }) - } - } - - const nextItem = useCallback(() => { - if (fsItemIndex === sItems.current.length - 1) { - setFsItemIndex(0) - } else { - setFsItemIndex(fsItemIndex + 1) - } - }, [fsItemIndex]) - - const prevItem = useCallback(() => { - if (fsItemIndex === 0) { - setFsItemIndex(sItems.current.length - 1) - } else { - setFsItemIndex(fsItemIndex - 1) - } - }, [fsItemIndex]) - - // This effect handles the keyboard navigation for the fullscreen mode - useEffect(() => { - const handleKeyDown = (event) => { - if (document.fullscreenElement) { - if (event.key === 'ArrowRight') { - nextItem() - } else if (event.key === 'ArrowLeft') { - prevItem() - } - } - } - - const handleFullscreenChange = () => { - if (!document.fullscreenElement) { - setFsItemIndex(null) - dispatch(acSetPresentDashboard(null)) - } - } - - // Attach the event listener to the window object - window.addEventListener('keydown', handleKeyDown) - document.addEventListener('fullscreenchange', handleFullscreenChange) - - // Clean up the event listener when the component is unmounted - return () => { - window.removeEventListener('keydown', handleKeyDown) - document.removeEventListener( - 'fullscreenchange', - handleFullscreenChange - ) - } - }, [dispatch, nextItem, prevItem]) - const onToggleItemExpanded = (clickedId) => { const isExpanded = typeof expandedItems[clickedId] === 'boolean' @@ -192,7 +111,7 @@ const ResponsiveItemGrid = () => { } const isFS = Number.isInteger(fsItemIndex) - ? sItems.current[fsItemIndex].id === item.id + ? sortedItems[fsItemIndex].id === item.id : null return ( @@ -218,7 +137,7 @@ const ResponsiveItemGrid = () => { onToggleItemExpanded={onToggleItemExpanded} isFS={isFS} sortPosition={ - sItems.current.findIndex((i) => i.id === item.id) + 1 + sortedItems.findIndex((i) => i.id === item.id) + 1 } /> @@ -287,7 +206,7 @@ const ResponsiveItemGrid = () => { {`${ fsItemIndex + 1 - } / ${sItems.current.length}`} + } / ${sortedItems.length}`} diff --git a/src/pages/view/styles/ItemGrid.module.css b/src/pages/view/styles/ItemGrid.module.css index bcdbf04aa..e0f00af51 100644 --- a/src/pages/view/styles/ItemGrid.module.css +++ b/src/pages/view/styles/ItemGrid.module.css @@ -70,7 +70,8 @@ color: white; font-size: 14px; margin: 0 8px; - min-width: 60px; /* avoid moving buttons for most counts below 999 items */ + min-inline-size: 60px; + /* avoid moving buttons for most counts below 999 items */ text-align: center; user-select: none; } From 34a643a731da3825f4bb8d119a0ce12dd952f558 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Fri, 8 Nov 2024 14:09:28 +0100 Subject: [PATCH 022/102] chore: renaming vars --- src/modules/useFullscreen.js | 18 +++++++++--------- src/pages/view/ItemGrid.js | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/modules/useFullscreen.js b/src/modules/useFullscreen.js index bc42139a1..dbb13676a 100644 --- a/src/modules/useFullscreen.js +++ b/src/modules/useFullscreen.js @@ -7,22 +7,22 @@ import { SPACER, MESSAGES } from './itemTypes.js' const useFullscreen = (displayItems) => { const dispatch = useDispatch() - const sItems = useRef([]) + const sortedItems = useRef([]) const fsItemStartingIndex = useSelector(sGetPresentDashboard) const [fsItemIndex, setFsItemIndex] = useState(null) - const fsElement = useRef(null) + const fsElementRef = useRef(null) useEffect(() => { - const sortedItems = sortBy(displayItems, ['y', 'x']).filter( + const sItems = sortBy(displayItems, ['y', 'x']).filter( (i) => [SPACER, MESSAGES].indexOf(i.type) === -1 ) - sItems.current = sortedItems + sortedItems.current = sItems }, [displayItems]) // Handle Present button or Item Fullscreen button clicked useEffect(() => { if (Number.isInteger(fsItemStartingIndex)) { - const el = fsElement?.current + const el = fsElementRef?.current el?.requestFullscreen() setFsItemIndex(fsItemStartingIndex) } else if (document.fullscreenElement) { @@ -43,7 +43,7 @@ const useFullscreen = (displayItems) => { } const nextItem = useCallback(() => { - if (fsItemIndex === sItems.current.length - 1) { + if (fsItemIndex === sortedItems.current.length - 1) { setFsItemIndex(0) } else { setFsItemIndex(fsItemIndex + 1) @@ -52,7 +52,7 @@ const useFullscreen = (displayItems) => { const prevItem = useCallback(() => { if (fsItemIndex === 0) { - setFsItemIndex(sItems.current.length - 1) + setFsItemIndex(sortedItems.current.length - 1) } else { setFsItemIndex(fsItemIndex - 1) } @@ -93,11 +93,11 @@ const useFullscreen = (displayItems) => { return { fsItemIndex, - fsElement, + fsElementRef, exitFullscreen, nextItem, prevItem, - sortedItems: sItems.current, + sortedItems: sortedItems.current, } } diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index 17d9cb00b..cb6a2dbef 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -54,7 +54,7 @@ const ResponsiveItemGrid = () => { const { fsItemIndex, - fsElement, + fsElementRef, exitFullscreen, nextItem, prevItem, @@ -164,7 +164,7 @@ const ResponsiveItemGrid = () => { className={cx(classes.fullscreenWrapper, { [classes.isFullscreenMode]: Number.isInteger(fsItemIndex), })} - ref={fsElement} + ref={fsElementRef} > Date: Fri, 8 Nov 2024 14:31:06 +0100 Subject: [PATCH 023/102] fix: force load when in fullscreen --- src/pages/view/ItemGrid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/view/ItemGrid.js b/src/pages/view/ItemGrid.js index cb6a2dbef..c5f2d18b1 100644 --- a/src/pages/view/ItemGrid.js +++ b/src/pages/view/ItemGrid.js @@ -127,7 +127,7 @@ const ResponsiveItemGrid = () => { } )} itemId={item.id} - forceLoad={forceLoad} + forceLoad={forceLoad || Number.isInteger(fsItemIndex)} > Date: Fri, 8 Nov 2024 14:55:38 +0100 Subject: [PATCH 024/102] fix: add controls buffer to App items --- src/components/Item/AppItem/Item.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Item/AppItem/Item.js b/src/components/Item/AppItem/Item.js index 442b38368..30a114028 100644 --- a/src/components/Item/AppItem/Item.js +++ b/src/components/Item/AppItem/Item.js @@ -10,7 +10,9 @@ import { import ItemHeader from '../ItemHeader/ItemHeader.js' import { getIframeSrc } from './getIframeSrc.js' -const AppItem = ({ dashboardMode, item, itemFilters, apps }) => { +const FS_CONTROLS_BUFFER = '40px' // space for the fullscreen controls at bottom + +const AppItem = ({ dashboardMode, item, itemFilters, apps, isFS }) => { let appDetails const appKey = item.appKey @@ -46,6 +48,7 @@ const AppItem = ({ dashboardMode, item, itemFilters, apps }) => { } style={{ border: 'none' }} /> + {isFS &&
} ) : ( <> @@ -69,6 +72,7 @@ const AppItem = ({ dashboardMode, item, itemFilters, apps }) => { AppItem.propTypes = { apps: PropTypes.array, dashboardMode: PropTypes.string, + isFS: PropTypes.bool, item: PropTypes.object, itemFilters: PropTypes.object, } From 78d928014385548be7dff4065f69df6f2a0d9365 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Sun, 10 Nov 2024 16:29:30 +0100 Subject: [PATCH 025/102] chore: slideshow button tooltip and refactor fs enabled on types --- i18n/en.pot | 7 +++++-- src/modules/itemTypes.js | 19 +++++++++++++++++++ src/modules/useFullscreen.js | 6 +++--- src/pages/view/TitleBar/ActionsBar.js | 19 +++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 646e0c62f..2bdc76b57 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-09-09T15:15:02.457Z\n" -"PO-Revision-Date: 2024-09-09T15:15:02.458Z\n" +"POT-Creation-Date: 2024-11-08T18:16:23.173Z\n" +"PO-Revision-Date: 2024-11-08T18:16:23.174Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -526,6 +526,9 @@ msgstr "Close dashboard" msgid "More" msgstr "More" +msgid "No dashboard items with fullscreen support" +msgstr "No dashboard items with fullscreen support" + msgid "Edit" msgstr "Edit" diff --git a/src/modules/itemTypes.js b/src/modules/itemTypes.js index 985aa3cfd..e6b5cd6b1 100644 --- a/src/modules/itemTypes.js +++ b/src/modules/itemTypes.js @@ -71,6 +71,7 @@ export const itemTypeMap = { appName: 'Data Visualizer', appKey: 'data-visualizer', defaultItemCount: 10, + supportsFullscreen: true, }, [REPORT_TABLE]: { id: REPORT_TABLE, @@ -82,6 +83,7 @@ export const itemTypeMap = { isVisualizationType: true, appUrl: (id) => `dhis-web-data-visualizer/#/${id}`, appName: 'Data Visualizer', + supportsFullscreen: true, }, [CHART]: { id: CHART, @@ -93,6 +95,7 @@ export const itemTypeMap = { isVisualizationType: true, appUrl: (id) => `dhis-web-data-visualizer/#/${id}`, appName: 'Data Visualizer', + supportsFullscreen: true, }, [MAP]: { id: MAP, @@ -104,6 +107,7 @@ export const itemTypeMap = { isVisualizationType: true, appUrl: (id) => `dhis-web-maps/?id=${id}`, appName: 'Maps', + supportsFullscreen: true, }, [EVENT_REPORT]: { id: EVENT_REPORT, @@ -114,6 +118,7 @@ export const itemTypeMap = { isVisualizationType: true, appUrl: (id) => `dhis-web-event-reports/?id=${id}`, appName: 'Event Reports', + supportsFullscreen: true, }, [EVENT_CHART]: { id: EVENT_CHART, @@ -124,6 +129,7 @@ export const itemTypeMap = { isVisualizationType: true, appUrl: (id) => `dhis-web-event-visualizer/?id=${id}`, appName: 'Event Visualizer', + supportsFullscreen: true, }, [EVENT_VISUALIZATION]: { id: EVENT_VISUALIZATION, @@ -136,11 +142,13 @@ export const itemTypeMap = { appUrl: (id) => `api/apps/line-listing/index.html#/${id}`, appName: 'Line Listing', appKey: 'line-listing', + supportsFullscreen: true, }, [APP]: { endPointName: 'apps', propName: 'appKey', pluralTitle: i18n.t('Apps'), + supportsFullscreen: true, }, [REPORTS]: { id: REPORTS, @@ -158,6 +166,7 @@ export const itemTypeMap = { return `api/reports/${id}/data.pdf?t=${new Date().getTime()}` } }, + supportsFullscreen: true, }, [RESOURCES]: { id: RESOURCES, @@ -165,6 +174,7 @@ export const itemTypeMap = { propName: 'resources', pluralTitle: i18n.t('Resources'), appUrl: (id) => `api/documents/${id}/data`, + supportsFullscreen: true, }, [USERS]: { id: USERS, @@ -173,22 +183,28 @@ export const itemTypeMap = { pluralTitle: i18n.t('Users'), appUrl: (id) => `dhis-web-dashboard-integration/profile.action?id=${id}`, + supportsFullscreen: true, }, [TEXT]: { id: TEXT, propName: 'text', + supportsFullscreen: true, }, [MESSAGES]: { propName: 'messages', + supportsFullscreen: false, }, [SPACER]: { propName: 'text', + supportsFullscreen: false, }, [PAGEBREAK]: { propName: 'text', + supportsFullscreen: false, }, [PRINT_TITLE_PAGE]: { propName: 'text', + supportsFullscreen: false, }, } @@ -211,6 +227,9 @@ export const getItemUrl = (type, item, baseUrl) => { return url } +export const itemTypeSupportsFullscreen = (type) => + itemTypeMap[type].supportsFullscreen + export const getItemIcon = (type) => { switch (type) { case REPORT_TABLE: diff --git a/src/modules/useFullscreen.js b/src/modules/useFullscreen.js index dbb13676a..40fcf2a91 100644 --- a/src/modules/useFullscreen.js +++ b/src/modules/useFullscreen.js @@ -3,7 +3,7 @@ import { useState, useEffect, useRef, useCallback } from 'react' import { useSelector, useDispatch } from 'react-redux' import { acSetPresentDashboard } from '../actions/presentDashboard.js' import { sGetPresentDashboard } from '../reducers/presentDashboard.js' -import { SPACER, MESSAGES } from './itemTypes.js' +import { itemTypeSupportsFullscreen } from './itemTypes.js' const useFullscreen = (displayItems) => { const dispatch = useDispatch() @@ -13,8 +13,8 @@ const useFullscreen = (displayItems) => { const fsElementRef = useRef(null) useEffect(() => { - const sItems = sortBy(displayItems, ['y', 'x']).filter( - (i) => [SPACER, MESSAGES].indexOf(i.type) === -1 + const sItems = sortBy(displayItems, ['y', 'x']).filter((i) => + itemTypeSupportsFullscreen(i.type) ) sortedItems.current = sItems }, [displayItems]) diff --git a/src/pages/view/TitleBar/ActionsBar.js b/src/pages/view/TitleBar/ActionsBar.js index 69b889bb2..e46382110 100644 --- a/src/pages/view/TitleBar/ActionsBar.js +++ b/src/pages/view/TitleBar/ActionsBar.js @@ -25,6 +25,7 @@ import ConfirmActionDialog from '../../../components/ConfirmActionDialog.js' import DropdownButton from '../../../components/DropdownButton/DropdownButton.js' import MenuItem from '../../../components/MenuItemWithTooltip.js' import { useSystemSettings } from '../../../components/SystemSettingsProvider.js' +import { itemTypeSupportsFullscreen } from '../../../modules/itemTypes.js' import { useCacheableSection } from '../../../modules/useCacheableSection.js' import { orObject } from '../../../modules/util.js' import { sGetDashboardStarred } from '../../../reducers/dashboards.js' @@ -49,6 +50,7 @@ const ViewActions = ({ restrictFilters, allowedFilters, filtersLength, + dashboardItems, }) => { const [moreOptionsSmallIsOpen, setMoreOptionsSmallIsOpen] = useState(false) const [moreOptionsIsOpen, setMoreOptionsIsOpen] = useState(false) @@ -137,6 +139,10 @@ const ViewActions = ({ const userAccess = orObject(access) + const hasSlideshowItems = dashboardItems?.some( + (i) => itemTypeSupportsFullscreen(i.type) || false + ) + const getMoreMenu = () => ( {lastUpdated ? ( @@ -230,6 +236,11 @@ const ViewActions = ({ ) + const content = + !offline && !hasSlideshowItems + ? i18n.t('No dashboard items with fullscreen support') + : null + return ( <>
@@ -261,9 +272,12 @@ const ViewActions = ({ ) : null} {allowVisFullscreen ? ( - + @@ -324,7 +324,7 @@ ViewActions.propTypes = { removeAllFilters: PropTypes.func, restrictFilters: PropTypes.bool, setDashboardStarred: PropTypes.func, - setPresentDashboard: PropTypes.func, + setSlideshow: PropTypes.func, showDescription: PropTypes.bool, starred: PropTypes.bool, updateShowDescription: PropTypes.func, @@ -345,7 +345,7 @@ const mapStateToProps = (state) => { export default connect(mapStateToProps, { setDashboardStarred: acSetDashboardStarred, - setPresentDashboard: acSetPresentDashboard, + setSlideshow: acSetSlideshow, removeAllFilters: acClearItemFilters, updateShowDescription: acSetShowDescription, })(ViewActions) diff --git a/src/pages/view/TitleBar/styles/ActionsBar.module.css b/src/pages/view/TitleBar/styles/ActionsBar.module.css index 5b7273784..6f7602507 100644 --- a/src/pages/view/TitleBar/styles/ActionsBar.module.css +++ b/src/pages/view/TitleBar/styles/ActionsBar.module.css @@ -19,7 +19,7 @@ @media only screen and (max-width: 480px) { .strip .editButton, - .strip .presentButton, + .strip .slideshowButton, .strip .shareButton { display: none; } diff --git a/src/reducers/index.js b/src/reducers/index.js index f62cb9570..19756dc46 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -10,10 +10,10 @@ import itemActiveTypes from './itemActiveTypes.js' import itemFilters from './itemFilters.js' import messages from './messages.js' import passiveViewRegistered from './passiveViewRegistered.js' -import presentDashboard from './presentDashboard.js' import printDashboard from './printDashboard.js' import selected from './selected.js' import showDescription from './showDescription.js' +import slideshow from './slideshow.js' import visualizations from './visualizations.js' export default combineReducers({ @@ -30,7 +30,7 @@ export default combineReducers({ activeModalDimension, passiveViewRegistered, showDescription, - presentDashboard, + slideshow, itemActiveTypes, iframePluginStatus, }) diff --git a/src/reducers/presentDashboard.js b/src/reducers/presentDashboard.js deleted file mode 100644 index 6b5af95d4..000000000 --- a/src/reducers/presentDashboard.js +++ /dev/null @@ -1,13 +0,0 @@ -export const SET_PRESENT_DASHBOARD = 'SET_PRESENT_DASHBOARD' - -export default (state = null, action) => { - switch (action.type) { - case SET_PRESENT_DASHBOARD: { - return action.value - } - default: - return state - } -} - -export const sGetPresentDashboard = (state) => state.presentDashboard diff --git a/src/reducers/slideshow.js b/src/reducers/slideshow.js new file mode 100644 index 000000000..714b6666b --- /dev/null +++ b/src/reducers/slideshow.js @@ -0,0 +1,13 @@ +export const SET_SLIDESHOW = 'SET_SLIDESHOW' + +export default (state = null, action) => { + switch (action.type) { + case SET_SLIDESHOW: { + return action.value + } + default: + return state + } +} + +export const sGetSlideshow = (state) => state.slideshow From b5793b671ca3cd0cfa328f7773866a240a59fc16 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Thu, 21 Nov 2024 15:53:30 +0100 Subject: [PATCH 031/102] fix: margins and styling on app item in fullscreen --- i18n/en.pot | 7 ++-- src/components/Item/AppItem/Item.js | 30 ++++++++--------- .../Item/AppItem/styles/AppItem.module.css | 33 +++++++++++++++++++ src/components/styles/ItemGrid.css | 11 +------ 4 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 src/components/Item/AppItem/styles/AppItem.module.css diff --git a/i18n/en.pot b/i18n/en.pot index f4c2af120..f12e1fdc4 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-11-12T15:09:25.555Z\n" -"PO-Revision-Date: 2024-11-12T15:09:25.556Z\n" +"POT-Creation-Date: 2024-11-21T14:44:35.575Z\n" +"PO-Revision-Date: 2024-11-21T14:44:35.577Z\n" msgid "Untitled dashboard" msgstr "Untitled dashboard" @@ -26,6 +26,9 @@ msgstr "Show fewer dashboards" msgid "Show more dashboards" msgstr "Show more dashboards" +msgid "{{appKey}} app not found" +msgstr "{{appKey}} app not found" + msgid "Remove this item" msgstr "Remove this item" diff --git a/src/components/Item/AppItem/Item.js b/src/components/Item/AppItem/Item.js index 30a114028..61209aecc 100644 --- a/src/components/Item/AppItem/Item.js +++ b/src/components/Item/AppItem/Item.js @@ -1,4 +1,6 @@ +import i18n from '@dhis2/d2-i18n' import { Divider, colors, spacers, IconQuestion24 } from '@dhis2/ui' +import cx from 'classnames' import PropTypes from 'prop-types' import React from 'react' import { connect } from 'react-redux' @@ -9,8 +11,7 @@ import { } from '../../../reducers/itemFilters.js' import ItemHeader from '../ItemHeader/ItemHeader.js' import { getIframeSrc } from './getIframeSrc.js' - -const FS_CONTROLS_BUFFER = '40px' // space for the fullscreen controls at bottom +import styles from './styles/AppItem.module.css' const AppItem = ({ dashboardMode, item, itemFilters, apps, isFS }) => { let appDetails @@ -41,27 +42,24 @@ const AppItem = ({ dashboardMode, item, itemFilters, apps, isFS }) => {