Skip to content

Commit

Permalink
feat: upgrade toolbar (DHIS2-15667) (#2936)
Browse files Browse the repository at this point in the history
Changes in the following files are functional changes needed for the new Analytics toolbar:

src/components/app/AppMenu.js - add the HoverMenuBar component and onFileMenuAction callback, which updates the interpretations panel with changes (e.g. sharing, renaming, translating) if it is open
AppLayout - onFileMenuAction and the interpretationRenderId.
FileMenu - added onFileMenuAction
Interpretations, InterpretationsPanel: - added renderId which triggers refetching the map info if it was changed by a file menu action
InterpretationsToggle: use the new InterpretationsAndDetailsToggler from Analytics
DownloadButton: needed different style to look nice with the new toolbar
AddLayerButton: styled to fit into the new toolbar
The new toolbar is a different height than the old one, which caused a bunch of layout issues due to the absolute positioning. Switched to flex where it made sense, and css changes accordingly.

Only change to DownloadSettings is the addition of a wrapping div <div className={styles.downloadSettingsPanel}>
MapPosition: resize due to open/close of the Layers or Details panel has a timeout added, since there is now a 100ms transition when open/close those Drawers
  • Loading branch information
jenniferarnesen authored Sep 13, 2023
1 parent b757770 commit e3a448d
Show file tree
Hide file tree
Showing 37 changed files with 632 additions and 493 deletions.
3 changes: 0 additions & 3 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,6 @@ msgstr "Style by group set"
msgid "Indicator group"
msgstr "Indicator group"

msgid "Interpretations"
msgstr "Interpretations"

msgid "Collapse"
msgstr "Collapse"

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"start-server-and-test": "^1.15.4"
},
"dependencies": {
"@dhis2/analytics": "^24.10.1",
"@dhis2/analytics": "^26.0.17",
"@dhis2/app-runtime": "^3.9.4",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/app-service-alerts": "^3.9.4",
Expand Down
7 changes: 7 additions & 0 deletions src/components/app/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
:root {
--left-panel-width: 300px;
--right-panel-width: 380px;

--header-height: 48px;
--toolbar-height: 32px;
}
7 changes: 4 additions & 3 deletions src/components/app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { CURRENT_AO_KEY } from '../../util/analyticalObject.js'
import { getUrlParameter } from '../../util/requests.js'
import { useSystemSettings } from '../SystemSettingsProvider.js'
import AppLayout from './AppLayout.js'
import styles from './styles/App.module.css'
import './App.css'
import './styles/App.module.css'

const App = () => {
const systemSettings = useSystemSettings()
Expand Down Expand Up @@ -50,10 +51,10 @@ const App = () => {
}, [systemSettings, dispatch])

return !isEmpty(systemSettings) ? (
<div className={styles.app}>
<>
<CssVariables colors spacers theme />
<AppLayout />
</div>
</>
) : null
}

Expand Down
66 changes: 41 additions & 25 deletions src/components/app/AppLayout.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,65 @@
import cx from 'classnames'
import React from 'react'
import React, { useState } from 'react'
import { useSelector } from 'react-redux'
import AlertStack from '../alerts/AlertStack.js'
import BottomPanel from '../datatable/BottomPanel.js'
import DownloadMode from '../download/DownloadMode.js'
import DownloadModeMenu from '../download/DownloadMenubar.js'
import DownloadSettings from '../download/DownloadSettings.js'
import LayerEdit from '../edit/LayerEdit.js'
import Interpretations from '../interpretations/Interpretations.js'
import LayersPanel from '../layers/LayersPanel.js'
import LayersToggle from '../layers/LayersToggle.js'
import LayersLoader from '../loaders/LayersLoader.js'
import ContextMenu from '../map/ContextMenu.js'
import MapPosition from '../map/MapPosition.js'
import OpenAsMapDialog from '../openAs/OpenAsMapDialog.js'
import OrgUnitProfile from '../orgunits/OrgUnitProfile.js'
import AppMenu from './AppMenu.js'
import DetailsPanel from './DetailsPanel.js'
import styles from './styles/AppLayout.module.css'

const AppLayout = () => {
const downloadMode = useSelector((state) => state.download.downloadMode)
const [interpretationsRenderCount, setInterpretationsRenderCount] =
useState(1)

const dataTableOpen = useSelector((state) => !!state.dataTable)
const downloadModeOpen = useSelector(
(state) => !!state.download.downloadMode
)
const detailsPanelOpen = useSelector(
(state) => state.ui.rightPanelOpen && !state.orgUnitProfile
)

const onFileMenuAction = () =>
detailsPanelOpen &&
setInterpretationsRenderCount(interpretationsRenderCount + 1)

return (
<div
className={cx(styles.appLayout, {
[styles.downloadMode]: downloadMode,
})}
>
{downloadMode ? (
<DownloadMode />
<>
{downloadModeOpen ? (
<DownloadModeMenu />
) : (
<>
<AppMenu />
<LayersToggle />
<LayersPanel />
<LayersLoader />
</>
<AppMenu onFileMenuAction={onFileMenuAction} />
)}
<MapPosition />
<Interpretations />
<BottomPanel />
<LayerEdit />
<div
className={cx(styles.content, {
[styles.downloadContent]: downloadModeOpen,
})}
>
{downloadModeOpen ? <DownloadSettings /> : <LayersPanel />}
<div className={styles.appMapAndTable}>
<MapPosition />
{dataTableOpen && <BottomPanel />}
</div>
{!downloadModeOpen && (
<DetailsPanel
interpretationsRenderCount={interpretationsRenderCount}
/>
)}
</div>
<LayersLoader />
<ContextMenu />
<LayerEdit />
<AlertStack />
<OpenAsMapDialog />
<OrgUnitProfile />
</div>
</>
)
}

Expand Down
19 changes: 13 additions & 6 deletions src/components/app/AppMenu.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { Toolbar, HoverMenuBar } from '@dhis2/analytics'
import PropTypes from 'prop-types'
import React from 'react'
import DownloadButton from '../download/DownloadButton.js'
import InterpretationsToggle from '../interpretations/InterpretationsToggle.js'
import AddLayerButton from '../layers/overlays/AddLayerButton.js'
import FileMenu from './FileMenu.js'
import styles from './styles/AppMenu.module.css'

const AppMenu = () => (
<div className={styles.appMenu}>
const AppMenu = ({ onFileMenuAction }) => (
<Toolbar>
<AddLayerButton />
<FileMenu />
<DownloadButton />
<HoverMenuBar>
<FileMenu onFileMenuAction={onFileMenuAction} />
<DownloadButton />
</HoverMenuBar>
<InterpretationsToggle />
</div>
</Toolbar>
)

AppMenu.propTypes = {
onFileMenuAction: PropTypes.func.isRequired,
}

export default AppMenu
40 changes: 40 additions & 0 deletions src/components/app/DetailsPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import cx from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
import { useSelector } from 'react-redux'
import Interpretations from '../interpretations/Interpretations.js'
import OrgUnitProfile from '../orgunits/OrgUnitProfile.js'
import styles from './styles/DetailsPanel.module.css'

const DetailsPanel = ({ interpretationsRenderCount }) => {
const detailsPanelOpen = useSelector((state) => state.ui.rightPanelOpen)
const viewOrgUnitProfile = useSelector((state) => state.orgUnitProfile)

const getContent = () => {
if (!detailsPanelOpen) {
return null
}

return viewOrgUnitProfile ? (
<OrgUnitProfile />
) : (
<Interpretations renderCount={interpretationsRenderCount} />
)
}

return (
<div
className={cx(styles.detailsPanel, {
[styles.collapsed]: !detailsPanelOpen,
})}
>
{getContent()}
</div>
)
}

DetailsPanel.propTypes = {
interpretationsRenderCount: PropTypes.number.isRequired,
}

export default DetailsPanel
36 changes: 18 additions & 18 deletions src/components/app/FileMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useAlert } from '@dhis2/app-service-alerts'
import i18n from '@dhis2/d2-i18n'
import PropTypes from 'prop-types'
import React from 'react'
import { connect } from 'react-redux'
import { useSelector, useDispatch } from 'react-redux'
import { newMap, tOpenMap, setMapProps } from '../../actions/map.js'
import {
ALERT_CRITICAL,
Expand Down Expand Up @@ -53,11 +53,12 @@ const getSaveFailureMessage = (message) =>
nsSeparator: ';',
})

const FileMenu = ({ map, newMap, tOpenMap, setMapProps }) => {
const FileMenu = ({ onFileMenuAction }) => {
const { d2 } = useD2()
const engine = useDataEngine()
const map = useSelector((state) => state.map)
const dispatch = useDispatch()
const { keyDefaultBaseMap } = useSystemSettings()
//alerts
const saveAlert = useAlert(ALERT_MESSAGE_DYNAMIC, ALERT_OPTIONS_DYNAMIC)
const saveAsAlert = useAlert(ALERT_MESSAGE_DYNAMIC, ALERT_OPTIONS_DYNAMIC)
const deleteAlert = useAlert(
Expand Down Expand Up @@ -112,7 +113,7 @@ const FileMenu = ({ map, newMap, tOpenMap, setMapProps }) => {
}

const openMap = async (id) => {
const error = await tOpenMap(id, keyDefaultBaseMap, engine)
const error = await dispatch(tOpenMap(id, keyDefaultBaseMap, engine))
if (error) {
openMapErrorAlert.show({
msg: i18n.t(`Error while opening map: ${error.message}`, {
Expand Down Expand Up @@ -154,7 +155,7 @@ const FileMenu = ({ map, newMap, tOpenMap, setMapProps }) => {
delete newMapConfig.basemap
delete newMapConfig.mapViews

setMapProps(newMapConfig)
dispatch(setMapProps(newMapConfig))

saveAsAlert.show({ msg: getSavedMessage(config.name) })
} else {
Expand All @@ -165,39 +166,38 @@ const FileMenu = ({ map, newMap, tOpenMap, setMapProps }) => {
}
}

const onRename = ({ name, description }) =>
setMapProps({ name: getMapName(name), description })
const onRename = ({ name, description }) => {
dispatch(setMapProps({ name: getMapName(name), description }))
onFileMenuAction()
}

const onDelete = () => {
newMap()
onNew()
deleteAlert.show()
}

const onNew = () => dispatch(newMap())

return (
<UiFileMenu
currentUser={d2.currentUser}
fileType="map"
fileObject={map}
onNew={newMap}
onNew={onNew}
onOpen={openMap}
onSave={saveMap}
onSaveAs={saveAsNewMap}
onRename={onRename}
onDelete={onDelete}
onError={onFileMenuError}
onShare={onFileMenuAction}
onTranslate={onFileMenuAction}
/>
)
}

FileMenu.propTypes = {
map: PropTypes.object.isRequired,
newMap: PropTypes.func.isRequired,
setMapProps: PropTypes.func.isRequired,
tOpenMap: PropTypes.func.isRequired,
onFileMenuAction: PropTypes.func.isRequired,
}

export default connect(({ map }) => ({ map }), {
newMap,
tOpenMap,
setMapProps,
})(FileMenu)
export default FileMenu
5 changes: 0 additions & 5 deletions src/components/app/styles/App.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
max-height: calc(100vh - 64px)
}

.app {
font-family: 'Roboto', sans-serif;
height: 100vh;
}

/* Scrollbar width */
::-webkit-scrollbar {
width: 6px;
Expand Down
20 changes: 12 additions & 8 deletions src/components/app/styles/AppLayout.module.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
.appLayout {
position: absolute;
top: 48px;
bottom: 0;
left: 0;
right: 0
.content {
display: flex;
flex-direction: row;
height: calc(100vh - var(--header-height) - var(--toolbar-height));
}

.downloadMode {
top: 0;
.downloadContent {
margin-top: var(--header-height);
height: calc(100vh - var(--header-height));
}

.appMapAndTable {
flex: auto;
position: relative;
}
9 changes: 0 additions & 9 deletions src/components/app/styles/AppMenu.module.css

This file was deleted.

7 changes: 7 additions & 0 deletions src/components/app/styles/DetailsPanel.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.detailsPanel {
width: var(--right-panel-width);
}

.detailsPanel.collapsed {
width: 0px;
}
14 changes: 1 addition & 13 deletions src/components/core/styles/Drawer.module.css
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
.drawer {
position: absolute;
top: 38px;
bottom: 0;
background-color: #f4f6f8;
height: auto;
max-height: 100%;
overflow-x: hidden;
height: 100%;
overflow-y: auto;
z-index: 1190;
}

.left {
left: 0;
right: auto;
border-right: 1px solid #e0e0e0;
box-shadow: 1px 0 1px 0 rgba(0, 0, 0, 0.2);
width: 300px;
}

.right {
left: auto;
right: 0;
border-left: 1px solid #e0e0e0;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
width: 380px;
}
Loading

0 comments on commit e3a448d

Please sign in to comment.