From e1bda3702edc5c254bce6bacb573da5dd9f54305 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Wed, 13 Sep 2023 15:49:43 +0200 Subject: [PATCH 01/11] feat: upgrade toolbar (DHIS2-15667) (#2936) 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
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 --- i18n/en.pot | 3 - package.json | 2 +- src/components/app/App.css | 7 + src/components/app/App.js | 7 +- src/components/app/AppLayout.js | 66 +++-- src/components/app/AppMenu.js | 19 +- src/components/app/DetailsPanel.js | 40 +++ src/components/app/FileMenu.js | 36 +-- src/components/app/styles/App.module.css | 5 - .../app/styles/AppLayout.module.css | 20 +- src/components/app/styles/AppMenu.module.css | 9 - .../app/styles/DetailsPanel.module.css | 7 + src/components/core/styles/Drawer.module.css | 14 +- src/components/datatable/BottomPanel.js | 100 +++----- .../datatable/styles/BottomPanel.module.css | 2 +- src/components/download/DownloadButton.js | 13 +- .../{DownloadMode.js => DownloadMenubar.js} | 22 +- src/components/download/DownloadSettings.js | 232 +++++++++--------- .../download/__tests__/DownloadButton.spec.js | 38 --- .../__snapshots__/DownloadButton.spec.js.snap | 12 - .../download/styles/DownloadButton.module.css | 34 +++ .../styles/DownloadMapInfo.module.css | 6 +- ....module.css => DownloadMenubar.module.css} | 9 +- .../styles/DownloadSettings.module.css | 5 + .../interpretations/Interpretations.js | 14 +- .../interpretations/InterpretationsPanel.js | 10 +- .../interpretations/InterpretationsToggle.js | 71 ++---- src/components/layers/LayersPanel.js | 59 +++-- src/components/layers/LayersToggle.js | 5 +- .../layers/overlays/AddLayerButton.js | 21 +- .../overlays/styles/AddLayerButton.module.css | 55 ++++- .../layers/styles/LayersPanel.module.css | 21 ++ .../layers/styles/LayersToggle.module.css | 6 +- src/components/map/MapPosition.js | 31 ++- .../map/styles/MapPosition.module.css | 44 ++-- src/constants/layout.js | 5 +- yarn.lock | 75 +++++- 37 files changed, 632 insertions(+), 493 deletions(-) create mode 100644 src/components/app/App.css create mode 100644 src/components/app/DetailsPanel.js delete mode 100644 src/components/app/styles/AppMenu.module.css create mode 100644 src/components/app/styles/DetailsPanel.module.css rename src/components/download/{DownloadMode.js => DownloadMenubar.js} (50%) delete mode 100644 src/components/download/__tests__/DownloadButton.spec.js delete mode 100644 src/components/download/__tests__/__snapshots__/DownloadButton.spec.js.snap create mode 100644 src/components/download/styles/DownloadButton.module.css rename src/components/download/styles/{DownloadMode.module.css => DownloadMenubar.module.css} (76%) create mode 100644 src/components/layers/styles/LayersPanel.module.css diff --git a/i18n/en.pot b/i18n/en.pot index 2ff7557e9..fbce2a3d2 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -499,9 +499,6 @@ msgstr "Style by group set" msgid "Indicator group" msgstr "Indicator group" -msgid "Interpretations" -msgstr "Interpretations" - msgid "Collapse" msgstr "Collapse" diff --git a/package.json b/package.json index 90d10a274..66e6d4cd0 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/app/App.css b/src/components/app/App.css new file mode 100644 index 000000000..c938f8e6f --- /dev/null +++ b/src/components/app/App.css @@ -0,0 +1,7 @@ +:root { + --left-panel-width: 300px; + --right-panel-width: 380px; + + --header-height: 48px; + --toolbar-height: 32px; +} diff --git a/src/components/app/App.js b/src/components/app/App.js index 1e8dce8a2..762d13b8a 100644 --- a/src/components/app/App.js +++ b/src/components/app/App.js @@ -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() @@ -50,10 +51,10 @@ const App = () => { }, [systemSettings, dispatch]) return !isEmpty(systemSettings) ? ( -
+ <> -
+ ) : null } diff --git a/src/components/app/AppLayout.js b/src/components/app/AppLayout.js index f7db05188..21b42a987 100644 --- a/src/components/app/AppLayout.js +++ b/src/components/app/AppLayout.js @@ -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 ( -
- {downloadMode ? ( - + <> + {downloadModeOpen ? ( + ) : ( - <> - - - - - + )} - - - - +
+ {downloadModeOpen ? : } +
+ + {dataTableOpen && } +
+ {!downloadModeOpen && ( + + )} +
+ + - -
+ ) } diff --git a/src/components/app/AppMenu.js b/src/components/app/AppMenu.js index 8b4ba49f9..51eac1306 100644 --- a/src/components/app/AppMenu.js +++ b/src/components/app/AppMenu.js @@ -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 = () => ( -
+const AppMenu = ({ onFileMenuAction }) => ( + - - + + + + -
+ ) +AppMenu.propTypes = { + onFileMenuAction: PropTypes.func.isRequired, +} + export default AppMenu diff --git a/src/components/app/DetailsPanel.js b/src/components/app/DetailsPanel.js new file mode 100644 index 000000000..ddb88d10e --- /dev/null +++ b/src/components/app/DetailsPanel.js @@ -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 ? ( + + ) : ( + + ) + } + + return ( +
+ {getContent()} +
+ ) +} + +DetailsPanel.propTypes = { + interpretationsRenderCount: PropTypes.number.isRequired, +} + +export default DetailsPanel diff --git a/src/components/app/FileMenu.js b/src/components/app/FileMenu.js index 81e52efa6..382d8c5de 100644 --- a/src/components/app/FileMenu.js +++ b/src/components/app/FileMenu.js @@ -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, @@ -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( @@ -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}`, { @@ -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 { @@ -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 ( ) } 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 diff --git a/src/components/app/styles/App.module.css b/src/components/app/styles/App.module.css index 9555647be..c8ccb4856 100644 --- a/src/components/app/styles/App.module.css +++ b/src/components/app/styles/App.module.css @@ -19,11 +19,6 @@ max-height: calc(100vh - 64px) } -.app { - font-family: 'Roboto', sans-serif; - height: 100vh; -} - /* Scrollbar width */ ::-webkit-scrollbar { width: 6px; diff --git a/src/components/app/styles/AppLayout.module.css b/src/components/app/styles/AppLayout.module.css index 43edee537..be2ac384e 100644 --- a/src/components/app/styles/AppLayout.module.css +++ b/src/components/app/styles/AppLayout.module.css @@ -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; } diff --git a/src/components/app/styles/AppMenu.module.css b/src/components/app/styles/AppMenu.module.css deleted file mode 100644 index 493141a01..000000000 --- a/src/components/app/styles/AppMenu.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.appMenu { - display: flex; - position: absolute; - width: 100%; - height: 38px; - z-index: 1200; - box-shadow: 0 1px 1px 0 #9e9e9e; - padding-top: 1px; -} diff --git a/src/components/app/styles/DetailsPanel.module.css b/src/components/app/styles/DetailsPanel.module.css new file mode 100644 index 000000000..42e2cc665 --- /dev/null +++ b/src/components/app/styles/DetailsPanel.module.css @@ -0,0 +1,7 @@ +.detailsPanel { + width: var(--right-panel-width); +} + +.detailsPanel.collapsed { + width: 0px; +} diff --git a/src/components/core/styles/Drawer.module.css b/src/components/core/styles/Drawer.module.css index 2c108b63e..ade930198 100644 --- a/src/components/core/styles/Drawer.module.css +++ b/src/components/core/styles/Drawer.module.css @@ -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; } diff --git a/src/components/datatable/BottomPanel.js b/src/components/datatable/BottomPanel.js index d1fb19eba..24f005bf0 100644 --- a/src/components/datatable/BottomPanel.js +++ b/src/components/datatable/BottomPanel.js @@ -1,10 +1,10 @@ import { IconCross16 } from '@dhis2/ui' -import PropTypes from 'prop-types' import React, { useRef, useCallback } from 'react' -import { connect } from 'react-redux' +import { useSelector, useDispatch } from 'react-redux' import { closeDataTable, resizeDataTable } from '../../actions/dataTable.js' import { HEADER_HEIGHT, + APP_MENU_HEIGHT, LAYERS_PANEL_WIDTH, RIGHT_PANEL_WIDTH, } from '../../constants/layout.js' @@ -14,69 +14,47 @@ import ResizeHandle from './ResizeHandle.js' import styles from './styles/BottomPanel.module.css' // Container for DataTable -const BottomPanel = ({ - layersPanelOpen, - rightPanelOpen, - dataTableOpen, - dataTableHeight, - resizeDataTable, - closeDataTable, -}) => { +const BottomPanel = () => { + const dataTableHeight = useSelector((state) => state.ui.dataTableHeight) + const layersPanelOpen = useSelector((state) => state.ui.layersPanelOpen) + const rightPanelOpen = useSelector((state) => state.ui.rightPanelOpen) + + const dispatch = useDispatch() const { width, height } = useWindowDimensions() - const node = useRef(null) + const panelRef = useRef(null) const onResize = useCallback( - (h) => (node.current.style.height = `${h}px`), - [node] + (h) => (panelRef.current.style.height = `${h}px`), + [panelRef] ) - if (dataTableOpen) { - const maxHeight = height - HEADER_HEIGHT - 20 - const tableHeight = - dataTableHeight < maxHeight ? dataTableHeight : maxHeight - const layersWidth = layersPanelOpen ? LAYERS_PANEL_WIDTH : 0 - const rightPanelWidth = rightPanelOpen ? RIGHT_PANEL_WIDTH : 0 - const tableWidth = width - layersWidth - rightPanelWidth - - const style = { - height: tableHeight, - left: layersWidth, - right: rightPanelWidth, - } - - return ( -
- - - - - -
- ) - } - - return null -} - -BottomPanel.propTypes = { - closeDataTable: PropTypes.func.isRequired, - dataTableHeight: PropTypes.number.isRequired, - dataTableOpen: PropTypes.bool.isRequired, - layersPanelOpen: PropTypes.bool.isRequired, - resizeDataTable: PropTypes.func.isRequired, - rightPanelOpen: PropTypes.bool.isRequired, + const maxHeight = height - HEADER_HEIGHT - APP_MENU_HEIGHT + const tableHeight = + dataTableHeight < maxHeight ? dataTableHeight : maxHeight + const layersWidth = layersPanelOpen ? LAYERS_PANEL_WIDTH : 0 + const rightPanelWidth = rightPanelOpen ? RIGHT_PANEL_WIDTH : 0 + const tableWidth = width - layersWidth - rightPanelWidth + + return ( +
+ dispatch(closeDataTable())} + > + + + dispatch(resizeDataTable(height))} + /> + +
+ ) } -export default connect( - ({ dataTable, ui }) => ({ - dataTableOpen: !!dataTable, - dataTableHeight: ui.dataTableHeight, - layersPanelOpen: ui.layersPanelOpen, - rightPanelOpen: ui.rightPanelOpen, - }), - { closeDataTable, resizeDataTable } -)(BottomPanel) +export default BottomPanel diff --git a/src/components/datatable/styles/BottomPanel.module.css b/src/components/datatable/styles/BottomPanel.module.css index 345eedba3..cd3dff206 100644 --- a/src/components/datatable/styles/BottomPanel.module.css +++ b/src/components/datatable/styles/BottomPanel.module.css @@ -1,6 +1,6 @@ .bottomPanel { position: absolute; - right: 0; + left: 0; bottom: 0; z-index: 1040; background: #fff; diff --git a/src/components/download/DownloadButton.js b/src/components/download/DownloadButton.js index 24649834d..b9e738dc6 100644 --- a/src/components/download/DownloadButton.js +++ b/src/components/download/DownloadButton.js @@ -2,17 +2,18 @@ import i18n from '@dhis2/d2-i18n' import React from 'react' import { useDispatch } from 'react-redux' import { setDownloadMode } from '../../actions/download.js' -import { MenuButton } from '../core/index.js' +import styles from './styles/DownloadButton.module.css' const DownloadButton = () => { const dispatch = useDispatch() return ( - <> - dispatch(setDownloadMode(true))}> - {i18n.t('Download')} - - + ) } diff --git a/src/components/download/DownloadMode.js b/src/components/download/DownloadMenubar.js similarity index 50% rename from src/components/download/DownloadMode.js rename to src/components/download/DownloadMenubar.js index 17a0b9567..a6b7c476a 100644 --- a/src/components/download/DownloadMode.js +++ b/src/components/download/DownloadMenubar.js @@ -3,10 +3,9 @@ import { Button, IconChevronLeft24, colors } from '@dhis2/ui' import React, { useEffect } from 'react' import { useDispatch } from 'react-redux' import { setDownloadMode } from '../../actions/download.js' -import DownloadSettings from './DownloadSettings.js' -import styles from './styles/DownloadMode.module.css' +import styles from './styles/DownloadMenubar.module.css' -const DownloadMode = () => { +const DownloadMenubar = () => { const dispatch = useDispatch() useEffect(() => { @@ -18,16 +17,13 @@ const DownloadMode = () => { }, []) return ( - <> -
- -
- - +
+ +
) } -export default DownloadMode +export default DownloadMenubar diff --git a/src/components/download/DownloadSettings.js b/src/components/download/DownloadSettings.js index e2e54f1ad..533752a47 100644 --- a/src/components/download/DownloadSettings.js +++ b/src/components/download/DownloadSettings.js @@ -76,138 +76,144 @@ const DownloadSettings = () => { const showMarginsCheckbox = false // Not in use return ( - -
-

{i18n.t('Download map')}

-
- {isSupported ? ( - <> - - dispatch( - setDownloadConfig({ showName: value }) - ) - } - /> - - dispatch( - setDownloadConfig({ - showDescription: value, - }) - ) - } - tooltip={ - description - ? i18n.t( - 'Description can be changed from File > Rename menu' - ) - : i18n.t( - 'Set the map description when you save the map or from File > Rename menu' - ) - } - /> - - dispatch( - setDownloadConfig({ - showLegend: value, - }) - ) - } - /> - {showLegend && legendLayers.length > 1 && ( - + +
+

{i18n.t('Download map')}

+
+ {isSupported ? ( + <> + + dispatch( + setDownloadConfig({ + showName: value, + }) + ) + } /> - )} - - dispatch( - setDownloadConfig({ - showOverviewMap: value, - }) - ) - } - /> - - dispatch( - setDownloadConfig({ - showNorthArrow: value, - }) - ) - } - /> - {showNorthArrow && !isSplitView && ( - dispatch( setDownloadConfig({ - northArrowPosition: value, + showDescription: value, }) ) } + tooltip={ + description + ? i18n.t( + 'Description can be changed from File > Rename menu' + ) + : i18n.t( + 'Set the map description when you save the map or from File > Rename menu' + ) + } /> - )} - {showMarginsCheckbox && ( dispatch( setDownloadConfig({ - includeMargins: value, + showLegend: value, }) ) } /> - )} - - {i18n.t( - 'Resize your browser window to change the map dimensions.' + {showLegend && legendLayers.length > 1 && ( + )} - - - ) : ( - i18n.t( - 'Map download is not supported by your browser. Try Google Chrome or Firefox.' - ) - )} -
-
- - - {isSupported && ( - + + dispatch( + setDownloadConfig({ + showOverviewMap: value, + }) + ) + } + /> + + dispatch( + setDownloadConfig({ + showNorthArrow: value, + }) + ) + } + /> + {showNorthArrow && !isSplitView && ( + + dispatch( + setDownloadConfig({ + northArrowPosition: value, + }) + ) + } + /> + )} + {showMarginsCheckbox && ( + + dispatch( + setDownloadConfig({ + includeMargins: value, + }) + ) + } + /> + )} + + {i18n.t( + 'Resize your browser window to change the map dimensions.' + )} + + + ) : ( + i18n.t( + 'Map download is not supported by your browser. Try Google Chrome or Firefox.' + ) )} - +
+
+ + + {isSupported && ( + + )} + +
-
- + +
) } diff --git a/src/components/download/__tests__/DownloadButton.spec.js b/src/components/download/__tests__/DownloadButton.spec.js deleted file mode 100644 index 17027f162..000000000 --- a/src/components/download/__tests__/DownloadButton.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import { render } from '@testing-library/react' -import React from 'react' -import { Provider } from 'react-redux' -import configureMockStore from 'redux-mock-store' -import DownloadButton from '../DownloadButton.js' - -jest.mock('../../../actions/download', () => { - return { - setDownloadMode: jest - .fn() - .mockReturnValue({ type: 'DOWNLOAD_MODE_SET' }), - } -}) - -/* eslint-disable react/prop-types */ -jest.mock('../../core/index.js', () => { - return { - MenuButton: function Mock(props) { - return - }, - } -}) -/* eslint-enable react/prop-types */ - -const mockStore = configureMockStore() - -describe('DownloadButton', () => { - it('renders a download button', () => { - const store = {} - - const { container } = render( - - - - ) - expect(container).toMatchSnapshot() - }) -}) diff --git a/src/components/download/__tests__/__snapshots__/DownloadButton.spec.js.snap b/src/components/download/__tests__/__snapshots__/DownloadButton.spec.js.snap deleted file mode 100644 index c82530ec6..000000000 --- a/src/components/download/__tests__/__snapshots__/DownloadButton.spec.js.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`DownloadButton renders a download button 1`] = ` -
- -
-`; - diff --git a/src/components/download/styles/DownloadButton.module.css b/src/components/download/styles/DownloadButton.module.css new file mode 100644 index 000000000..13c63b6e8 --- /dev/null +++ b/src/components/download/styles/DownloadButton.module.css @@ -0,0 +1,34 @@ +/* Based on https: //github.com/dhis2/analytics/blob/master/src/components/Toolbar/MenuButton.styles.js */ + +.button { + all: unset; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 14px; + line-height: 14px; + padding: 0 var(--spacers-dp12); + color: var(--colors-grey900); + transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + cursor: pointer; +} + +.button:hover:enabled, +.button:active { + background-color: var(--colors-grey200); +} + +.button:focus { + outline: 3px solid var(--theme-focus); + outline-offset: -3px; +} + +/* Prevent focus styles when mouse clicking */ +.button:focus:not(:focus-visible) { + outline: none; +} + +.button:disabled { + color: var(--colors-grey500); + cursor: not-allowed; +} diff --git a/src/components/download/styles/DownloadMapInfo.module.css b/src/components/download/styles/DownloadMapInfo.module.css index 60bdc42a9..f45f313df 100644 --- a/src/components/download/styles/DownloadMapInfo.module.css +++ b/src/components/download/styles/DownloadMapInfo.module.css @@ -1,11 +1,7 @@ .downloadMapInfo { - padding-left: var(--spacers-dp24); background-color: #fff; height: 100%; - width: 380px; - position: absolute; - top: 0; - right: 0; + width: calc(var(--right-panel-width) - var(--spacers-dp24)); box-sizing: border-box; display: flex; flex-direction: column; diff --git a/src/components/download/styles/DownloadMode.module.css b/src/components/download/styles/DownloadMenubar.module.css similarity index 76% rename from src/components/download/styles/DownloadMode.module.css rename to src/components/download/styles/DownloadMenubar.module.css index d154aacaf..fccd907d2 100644 --- a/src/components/download/styles/DownloadMode.module.css +++ b/src/components/download/styles/DownloadMenubar.module.css @@ -1,18 +1,19 @@ .downloadModeMenu { display: flex; position: absolute; + align-items: center; width: 100%; - height: 44px; + height: var(--header-height); z-index: 1200; - padding-top: 1px; background-color: var(--colors-grey600); + left: 0; + top: 0 } .downloadModeMenu button { - margin: 3px 0 0 var(--spacers-dp16); + margin-left: var(--spacers-dp16); } -:global(.downloadModeMenu) header, :global(.dhis2-map-download .dhis2-map-ctrl-measure-actions), :global(.dhis2-map-download .dhis2-map-popup-orgunit button), :global(.dhis2-map-downloading .maplibregl-popup-close-button) { diff --git a/src/components/download/styles/DownloadSettings.module.css b/src/components/download/styles/DownloadSettings.module.css index 705cfd0f4..c78eae801 100644 --- a/src/components/download/styles/DownloadSettings.module.css +++ b/src/components/download/styles/DownloadSettings.module.css @@ -1,3 +1,8 @@ +.downloadSettingsPanel { + width: var(--left-panel-width); + overflow-y: auto; +} + .downloadSettings { padding: var(--spacers-dp8) var(--spacers-dp16); background-color: #f4f6f8; diff --git a/src/components/interpretations/Interpretations.js b/src/components/interpretations/Interpretations.js index 6c8b7022d..ef7cb361c 100644 --- a/src/components/interpretations/Interpretations.js +++ b/src/components/interpretations/Interpretations.js @@ -1,3 +1,4 @@ +import PropTypes from 'prop-types' import React, { useEffect } from 'react' import { useSelector, useDispatch } from 'react-redux' import { setInterpretation } from '../../actions/interpretations.js' @@ -5,14 +6,11 @@ import { openInterpretationsPanel } from '../../actions/ui.js' import { getUrlParameter } from '../../util/requests.js' import InterpretationsPanel from './InterpretationsPanel.js' -const Interpretations = () => { +const Interpretations = ({ renderCount }) => { const isMapLoaded = useSelector( (state) => state.map.id && !state.map.mapViews.find((layer) => !layer.isLoaded) ) - const isPanelOpen = useSelector( - (state) => state.ui.rightPanelOpen && !state.orgUnitProfile - ) const dispatch = useDispatch() useEffect(() => { @@ -26,7 +24,13 @@ const Interpretations = () => { } }, [isMapLoaded, dispatch]) - return isPanelOpen && isMapLoaded ? : null + return isMapLoaded ? ( + + ) : null +} + +Interpretations.propTypes = { + renderCount: PropTypes.number.isRequired, } export default Interpretations diff --git a/src/components/interpretations/InterpretationsPanel.js b/src/components/interpretations/InterpretationsPanel.js index 1fdcedb14..e1e92ddda 100644 --- a/src/components/interpretations/InterpretationsPanel.js +++ b/src/components/interpretations/InterpretationsPanel.js @@ -11,7 +11,12 @@ import { setInterpretation } from '../../actions/interpretations.js' import Drawer from '../core/Drawer.js' import InterpretationMap from './InterpretationMap.js' -const InterpretationsPanel = ({ interpretationId, map, setInterpretation }) => { +const InterpretationsPanel = ({ + interpretationId, + map, + setInterpretation, + renderCount, +}) => { const [initialFocus, setInitialFocus] = useState(false) const interpretationsUnitRef = useRef() const { d2 } = useD2() @@ -39,7 +44,7 @@ const InterpretationsPanel = ({ interpretationId, map, setInterpretation }) => { return ( <> - + { InterpretationsPanel.propTypes = { map: PropTypes.object.isRequired, + renderCount: PropTypes.number.isRequired, setInterpretation: PropTypes.func.isRequired, interpretationId: PropTypes.string, } diff --git a/src/components/interpretations/InterpretationsToggle.js b/src/components/interpretations/InterpretationsToggle.js index d1d16f959..a47cce286 100644 --- a/src/components/interpretations/InterpretationsToggle.js +++ b/src/components/interpretations/InterpretationsToggle.js @@ -1,54 +1,33 @@ -import i18n from '@dhis2/d2-i18n' -import { IconChevronLeft24, IconChevronRight24 } from '@dhis2/ui' -import PropTypes from 'prop-types' -import React from 'react' -import { connect } from 'react-redux' +import { InterpretationsAndDetailsToggler as AnalyticsInterpretationsAndDetailsToggler } from '@dhis2/analytics' +import React, { useCallback } from 'react' +import { useSelector, useDispatch } from 'react-redux' import { openInterpretationsPanel, closeInterpretationsPanel, } from '../../actions/ui.js' -import { MenuButton } from '../core/index.js' -import styles from './styles/InterpretationsToggle.module.css' -const InterpretationsToggle = ({ - interpretationsOpen, - interpretationsEnabled, - openInterpretationsPanel, - closeInterpretationsPanel, -}) => ( -
- - {interpretationsOpen ? ( - - ) : ( - - )} - {i18n.t('Interpretations')} - -
-) +const InterpretationsToggle = () => { + const interpretationsEnabled = useSelector((state) => Boolean(state.map.id)) + const interpretationsOpen = useSelector( + (state) => state.ui.rightPanelOpen && !state.orgUnitProfile + ) + const dispatch = useDispatch() -InterpretationsToggle.propTypes = { - closeInterpretationsPanel: PropTypes.func.isRequired, - interpretationsEnabled: PropTypes.bool.isRequired, - interpretationsOpen: PropTypes.bool.isRequired, - openInterpretationsPanel: PropTypes.func.isRequired, + const onClick = useCallback(() => { + if (interpretationsOpen) { + dispatch(closeInterpretationsPanel()) + } else { + dispatch(openInterpretationsPanel()) + } + }, [dispatch, interpretationsOpen]) + + return ( + + ) } -export default connect( - (state) => ({ - interpretationsOpen: state.ui.rightPanelOpen && !state.orgUnitProfile, - interpretationsEnabled: Boolean(state.map.id), - }), - { - openInterpretationsPanel, - closeInterpretationsPanel, - } -)(InterpretationsToggle) +export default InterpretationsToggle diff --git a/src/components/layers/LayersPanel.js b/src/components/layers/LayersPanel.js index e358bc79c..dba967aa1 100644 --- a/src/components/layers/LayersPanel.js +++ b/src/components/layers/LayersPanel.js @@ -1,11 +1,12 @@ -import PropTypes from 'prop-types' +import cx from 'classnames' import React from 'react' -import { connect } from 'react-redux' +import { useSelector, useDispatch } from 'react-redux' import { SortableContainer, SortableElement } from 'react-sortable-hoc' import { sortLayers } from '../../actions/layers.js' -import Drawer from '../core/Drawer.js' import BasemapCard from '../layers/basemaps/BasemapCard.js' +import LayersToggle from '../layers/LayersToggle.js' import OverlayCard from './overlays/OverlayCard.js' +import styles from './styles/LayersPanel.module.css' const SortableLayer = SortableElement(OverlayCard) @@ -18,29 +19,37 @@ const SortableLayersList = SortableContainer(({ layers }) => (
)) -const LayersPanel = ({ layersPanelOpen, layers, sortLayers }) => - layersPanelOpen && ( - - -
- +const LayersPanel = () => { + const layersPanelOpen = useSelector((state) => state.ui.layersPanelOpen) + const layers = useSelector((state) => [...state.map.mapViews].reverse()) + + const dispatch = useDispatch() + + const onSort = () => dispatch(sortLayers()) + + return ( +
+
+ {layersPanelOpen ? ( + <> + +
+ +
+ + ) : null}
- + +
) - -LayersPanel.propTypes = { - layers: PropTypes.array.isRequired, - layersPanelOpen: PropTypes.bool.isRequired, - sortLayers: PropTypes.func.isRequired, } -const mapStateToProps = (state) => ({ - layers: [...state.map.mapViews].reverse(), - layersPanelOpen: state.ui.layersPanelOpen, -}) - -export default connect(mapStateToProps, { sortLayers })(LayersPanel) +export default LayersPanel diff --git a/src/components/layers/LayersToggle.js b/src/components/layers/LayersToggle.js index 6b3683146..f9f31a69c 100644 --- a/src/components/layers/LayersToggle.js +++ b/src/components/layers/LayersToggle.js @@ -1,11 +1,11 @@ import { IconChevronLeft24, IconChevronRight24 } from '@dhis2/ui' +import cx from 'classnames' import PropTypes from 'prop-types' import React from 'react' import { connect } from 'react-redux' import { openLayersPanel, closeLayersPanel } from '../../actions/ui.js' import styles from './styles/LayersToggle.module.css' -// This expand/collapse toggle is separate from LayersPanel to avoid overflow issue const LayersToggle = ({ isOpen, isDownload, @@ -15,8 +15,7 @@ const LayersToggle = ({ !isDownload && (
{isOpen ? : }
diff --git a/src/components/layers/overlays/AddLayerButton.js b/src/components/layers/overlays/AddLayerButton.js index 60459ba65..7adf7871d 100644 --- a/src/components/layers/overlays/AddLayerButton.js +++ b/src/components/layers/overlays/AddLayerButton.js @@ -1,7 +1,6 @@ import i18n from '@dhis2/d2-i18n' import { IconAddCircle24 } from '@dhis2/ui' -import React, { Fragment, useState, useRef } from 'react' -import { MenuButton } from '../../core/index.js' +import React, { useState, useRef } from 'react' import AddLayerPopover from './AddLayerPopover.js' import styles from './styles/AddLayerButton.module.css' @@ -11,19 +10,23 @@ const AddLayerButton = () => { const toggleDialog = () => setIsOpen(!isOpen) return ( - -
- - + <> +
+
{isOpen && ( )} - + ) } diff --git a/src/components/layers/overlays/styles/AddLayerButton.module.css b/src/components/layers/overlays/styles/AddLayerButton.module.css index 2542ee503..529d04c8d 100644 --- a/src/components/layers/overlays/styles/AddLayerButton.module.css +++ b/src/components/layers/overlays/styles/AddLayerButton.module.css @@ -1,16 +1,49 @@ -.addLayerBtn { - margin-right: var(--spacers-dp8); - border-right: 1px solid #e0e0e0; -} +/* Adapted from https: //github.com/dhis2/analytics/blob/master/src/components/Toolbar/MenuButton.styles.js */ -.btnContent { - width: 276px; - padding-left: var(--spacers-dp8); - text-align: left; +.container { + width: var(--left-panel-width); display: flex; + align-items: stretch; + border-right: 1px solid var(--colors-grey400); +} + +.button { + all: unset; + display: inline-flex; + align-items: center; + justify-content: flex-start; + font-size: 14px; + line-height: 14px; + color: var(--colors-grey900); + cursor: pointer; + user-select: none; + padding: 0px 12px; + width: 100% +} + +.content { + display: inline-flex; + align-items: center; + padding: var(--spacers-dp4) var(--spacers-dp8); + gap: var(--spacers-dp8); +} + +.button:hover:enabled, +.button:active { + background-color: var(--colors-grey200); +} + +.button:focus { + outline: 3px solid var(--theme-focus); + outline-offset: -3px; +} + +/* Prevent focus styles when mouse clicking */ +.button:focus:not(:focus-visible) { + outline: none; } -.btnContent svg { - margin-right: var(--spacers-dp8); - color: var(--colors-grey700); +.button:disabled { + color: var(--colors-grey500); + cursor: not-allowed; } diff --git a/src/components/layers/styles/LayersPanel.module.css b/src/components/layers/styles/LayersPanel.module.css new file mode 100644 index 000000000..7edd3910a --- /dev/null +++ b/src/components/layers/styles/LayersPanel.module.css @@ -0,0 +1,21 @@ +.layersPanel { + width: var(--left-panel-width); +} + +.layersPanel.collapsed { + width: 0px; +} + +.layersPanelInner { + background-color: #f4f6f8; + border-right: 1px solid #e0e0e0; + box-shadow: 1px 0 1px 0 rgba(0, 0, 0, 0.2); + height: 100%; + overflow-y: auto; + z-index: 1190; + transform: translateX(0); +} + +.layersPanel.collapsed .layersPanelInner { + transform: translateX(calc(var(--left-panel-width) * -1)); +} diff --git a/src/components/layers/styles/LayersToggle.module.css b/src/components/layers/styles/LayersToggle.module.css index 5ec6ae5df..e4dcfa7a4 100644 --- a/src/components/layers/styles/LayersToggle.module.css +++ b/src/components/layers/styles/LayersToggle.module.css @@ -1,7 +1,7 @@ .layersToggle { position: absolute; top: 104px; - left: 300px; + left: var(--left-panel-width); width: 24px; height: 40px; padding: var(--spacers-dp8) 0; @@ -12,6 +12,10 @@ cursor: pointer; } +.layersToggle.collapsed { + left: 0; +} + .layersToggle:hover { background-color: var(--colors-grey100); } diff --git a/src/components/map/MapPosition.js b/src/components/map/MapPosition.js index 7d0098d34..67a821e5e 100644 --- a/src/components/map/MapPosition.js +++ b/src/components/map/MapPosition.js @@ -1,12 +1,7 @@ import cx from 'classnames' import React, { useState, useEffect } from 'react' import { useSelector } from 'react-redux' -import { - APP_MENU_HEIGHT, - DOWNLOAD_MENU_HEIGHT, - LAYERS_PANEL_WIDTH, - RIGHT_PANEL_WIDTH, -} from '../../constants/layout.js' +import { APP_MENU_HEIGHT, HEADER_HEIGHT } from '../../constants/layout.js' import { getSplitViewLayer } from '../../util/helpers.js' import DownloadMapInfo from '../download/DownloadMapInfo.js' import NorthArrow from '../download/NorthArrow.js' @@ -31,6 +26,15 @@ const MapPosition = () => { ) const dataTableOpen = useSelector((state) => !!state.dataTable) + let mapHeight = `calc(100vh - ${HEADER_HEIGHT}px)` + if (!downloadMode) { + if (dataTableOpen) { + mapHeight = `calc(100vh - ${HEADER_HEIGHT}px - ${APP_MENU_HEIGHT}px - ${dataTableHeight}px)` + } else { + mapHeight = `calc(100vh - ${HEADER_HEIGHT}px - ${APP_MENU_HEIGHT}px)` + } + } + const downloadMapInfoOpen = downloadMode && (showName || @@ -40,22 +44,15 @@ const MapPosition = () => { const isSplitView = !!getSplitViewLayer(layers) - const mapPosition = { - top: downloadMode ? DOWNLOAD_MENU_HEIGHT : APP_MENU_HEIGHT, - left: layersPanelOpen || downloadMode ? LAYERS_PANEL_WIDTH : 0, - right: rightPanelOpen ? RIGHT_PANEL_WIDTH : 0, - bottom: dataTableOpen ? dataTableHeight : 0, - } - // Trigger map resize when panels are expanded, collapsed or dragged useEffect(() => { setResizeCount((count) => count + 1) }, [ - layersPanelOpen, - rightPanelOpen, dataTableOpen, dataTableHeight, downloadMapInfoOpen, + layersPanelOpen, + rightPanelOpen, ]) // Reset bearing and pitch when new map (mapId changed) @@ -91,7 +88,7 @@ const MapPosition = () => { }, [map, downloadMode]) return ( -
+
{ >
diff --git a/src/components/map/styles/MapPosition.module.css b/src/components/map/styles/MapPosition.module.css index 4c241c171..98f2f90d8 100644 --- a/src/components/map/styles/MapPosition.module.css +++ b/src/components/map/styles/MapPosition.module.css @@ -1,13 +1,36 @@ -.mapPosition { - position: absolute; +.mapPosition > div { + height: 100%; } -.mapPosition > div { +.mapContainer { height: 100%; + width: 100%; + position: relative; + overflow: hidden; + flex: auto +} + +.mapContainer.download { + display: flex; + flex-direction: row; + gap: var(--spacers-dp24); +} + +.mapContainerDownload { + flex: auto; +} + +:not(.downloadMapInfoOpen) > div.download > div:first-child { + width: 100%; +} + +.downloadMapInfoOpen > div.download > div:first-child { + flex: auto; } .mapDownload { - border: var(--spacers-dp24) solid #fff + border: var(--spacers-dp24) solid #fff; + background-color: var(--colors-white); } .mapDownload :global(.dhis2-map-timeline) { @@ -16,7 +39,7 @@ .mapDownload :global(.dhis2-map-period) { bottom: 10px !important; -} +} .mapDownload :global(.maplibregl-ctrl-group:not(:empty)) { box-shadow: none; @@ -32,14 +55,3 @@ border-right: none; border-bottom: none; } - -.downloadMapInfoOpen > div > div:first-child { - width: calc(100% - 380px); -} - -.mapContainer { - height: 100%; - width: 100%; - position: relative; - overflow: hidden; -} diff --git a/src/constants/layout.js b/src/constants/layout.js index 99e56e748..a9128dbe4 100644 --- a/src/constants/layout.js +++ b/src/constants/layout.js @@ -1,5 +1,4 @@ -export const HEADER_HEIGHT = 86 -export const APP_MENU_HEIGHT = 38 -export const DOWNLOAD_MENU_HEIGHT = 44 +export const HEADER_HEIGHT = 48 +export const APP_MENU_HEIGHT = 32 export const LAYERS_PANEL_WIDTH = 300 export const RIGHT_PANEL_WIDTH = 380 diff --git a/yarn.lock b/yarn.lock index b886043cb..11fbd9bda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2015,17 +2015,22 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2/analytics@^24.10.1": - version "24.10.1" - resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-24.10.1.tgz#ad595451b724044448c22a413875f0d36df20e8d" - integrity sha512-HhKDYzTnk8Uh11523JIjx0lhgIRgcWihCkTlT3qHoaDOhAQdQcadd5i/byjhXpeXrrtqfL0x2gn0Scy3siA2Cg== +"@dhis2/analytics@^26.0.17": + version "26.0.17" + resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-26.0.17.tgz#f6f550c266478c38872429ee422f6a890b189a82" + integrity sha512-681OmaLrAetgHL59iU9ldeaXZ7NLp5T3nWLxGQGAklUwCpmny32wJKj2aXsCQN6WYuGDvz9PgpqN+YrkAMChFQ== dependencies: - "@dhis2/d2-ui-rich-text" "^7.4.0" + "@dhis2/d2-ui-rich-text" "^7.4.1" "@dhis2/multi-calendar-dates" "1.0.0" + "@dnd-kit/core" "^6.0.7" + "@dnd-kit/sortable" "^7.0.2" + "@dnd-kit/utilities" "^3.2.1" + "@react-hook/debounce" "^4.0.0" classnames "^2.3.1" + crypto-js "^4.1.1" d2-utilizr "^0.2.16" d3-color "^1.2.3" - highcharts "^10.2.0" + highcharts "^10.3.3" lodash "^4.17.21" mathjs "^9.4.2" react-beautiful-dnd "^10.1.1" @@ -2227,10 +2232,10 @@ i18next "^10.3" moment "^2.24.0" -"@dhis2/d2-ui-rich-text@^7.4.0": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@dhis2/d2-ui-rich-text/-/d2-ui-rich-text-7.4.1.tgz#8764208c59c6758bf34765b1dbe01762ce435d11" - integrity sha512-/n5nE0b4EDI/kX0/aN+vFDOswoWT5JQ3lwtHsUxailvnEHMu4/3l27Q38Z+5qhKwl+jYNB9GOFxWoSiymUgBbw== +"@dhis2/d2-ui-rich-text@^7.4.1": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@dhis2/d2-ui-rich-text/-/d2-ui-rich-text-7.4.3.tgz#a42c8e231bcc05186dd432dac86b33aed4ddc10d" + integrity sha512-60k/6CO2I8f4t3jU1nAic7uWONME1rckM8RcLnelhwUG20EZWq45OnDDdSfHgOWTwVDtxFnG3wspInkG/530KA== dependencies: babel-runtime "^6.26.0" markdown-it "^8.4.2" @@ -2375,6 +2380,37 @@ "@dhis2/ui-icons" "8.13.15" prop-types "^15.7.2" +"@dnd-kit/accessibility@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz#3ccbefdfca595b0a23a5dc57d3de96bc6935641c" + integrity sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@^6.0.7": + version "6.0.8" + resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.0.8.tgz#040ae13fea9787ee078e5f0361f3b49b07f3f005" + integrity sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA== + dependencies: + "@dnd-kit/accessibility" "^3.0.0" + "@dnd-kit/utilities" "^3.2.1" + tslib "^2.0.0" + +"@dnd-kit/sortable@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-7.0.2.tgz#791d550872457f3f3c843e00d159b640f982011c" + integrity sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA== + dependencies: + "@dnd-kit/utilities" "^3.2.0" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.0", "@dnd-kit/utilities@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.1.tgz#53f9e2016fd2506ec49e404c289392cfff30332a" + integrity sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA== + dependencies: + tslib "^2.0.0" + "@eslint/eslintrc@^0.4.3": version "0.4.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" @@ -2887,6 +2923,13 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@react-hook/debounce@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@react-hook/debounce/-/debounce-4.0.0.tgz#5da87e7bfa158cfe2830ffc997dc1b755e261379" + integrity sha512-706Xcg+KKWHk9BuZQUQ0ZQKp9zhv3/MbqFenWVfHcynYpSGRVwQTzJRGvPxvsdtXxJv+HfgKTY/O/hEejakwmA== + dependencies: + "@react-hook/latest" "^1.0.2" + "@react-hook/latest@^1.0.2": version "1.0.3" resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" @@ -6001,6 +6044,11 @@ crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" + integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -8683,7 +8731,7 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -highcharts@^10.2.0: +highcharts@^10.3.3: version "10.3.3" resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-10.3.3.tgz#b8acca24f2d4b1f2f726540734166e59e07b35c4" integrity sha512-r7wgUPQI9tr3jFDn3XT36qsNwEIZYcfgz4mkKEA6E4nn5p86y+u1EZjazIG4TRkl5/gmGRtkBUiZW81g029RIw== @@ -15124,6 +15172,11 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.0.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" From 2a77caafdd6d8ee42db14d35a9ab3034e5e8897a Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Thu, 14 Sep 2023 03:36:33 +0200 Subject: [PATCH 02/11] fix(translations): sync translations from transifex (dev) Automatically merged. --- .tx/config | 2 +- i18n/ar.po | 25 +- i18n/ar_IQ.po | 23 +- i18n/cs.po | 27 +- i18n/da.po | 27 +- i18n/es.po | 45 +- i18n/fr.po | 25 +- i18n/id.po | 25 +- i18n/km.po | 25 +- i18n/lo.po | 25 +- i18n/my.po | 27 +- i18n/nb.po | 23 +- i18n/nl.po | 23 +- i18n/prs.po | 27 +- i18n/ps.po | 25 +- i18n/pt.po | 30 +- i18n/pt_BR.po | 25 +- i18n/ru.po | 25 +- i18n/sv.po | 25 +- i18n/tet.po | 276 +++---- i18n/tg.po | 25 +- i18n/uk.po | 25 +- i18n/ur.po | 25 +- i18n/{uz.po => uz_UZ_Cyrl.po} | 23 +- i18n/uz_UZ_Latn.po | 1393 +++++++++++++++++++++++++++++++++ i18n/vi.po | 25 +- i18n/zh.po | 25 +- i18n/zh_CN.po | 23 +- 28 files changed, 2047 insertions(+), 272 deletions(-) rename i18n/{uz.po => uz_UZ_Cyrl.po} (98%) create mode 100644 i18n/uz_UZ_Latn.po diff --git a/.tx/config b/.tx/config index ede697fd9..8ceb89a93 100644 --- a/.tx/config +++ b/.tx/config @@ -1,6 +1,6 @@ [main] host = https://www.transifex.com -lang_map = fa_AF: prs, uz@Cyrl: uz, uz@Latn: uz_Latn +lang_map = fa_AF: prs, uz@Cyrl: uz_UZ_Cyrl, uz@Latn: uz_UZ_Latn [o:hisp-uio:p:app-maps:r:en-pot] diff --git a/i18n/ar.po b/i18n/ar.po index be6b7746e..ab5913c49 100644 --- a/i18n/ar.po +++ b/i18n/ar.po @@ -1,13 +1,13 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Hamza Assada <7amza.it@gmail.com>, 2022 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Arabic (https://app.transifex.com/hisp-uio/teams/100509/ar/)\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "تصنيف" @@ -429,6 +438,9 @@ msgstr "عنصر بيانات الحدث مطلوب" msgid "Program indicator is required" msgstr "مؤشر البرنامج مطلوب" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "الفترة مطلوبة" @@ -444,6 +456,9 @@ msgstr "عناصر بيانات الحدث" msgid "Program indicators" msgstr "مؤشرات البرنامج" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "نوع العنصر" @@ -509,9 +524,6 @@ msgstr "" msgid "Indicator group" msgstr "مجموعة المؤشرات" -msgid "Interpretations" -msgstr "التفسيرات" - msgid "Collapse" msgstr "انهيار" @@ -1273,6 +1285,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "ليس لديك حق الوصول إلى بيانات الطبقة هذه" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "حدث خطأ غير معروف أثناء قراءة بيانات الطبقة" diff --git a/i18n/ar_IQ.po b/i18n/ar_IQ.po index 176164ef8..72a135269 100644 --- a/i18n/ar_IQ.po +++ b/i18n/ar_IQ.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: KRG HIS , 2021\n" "Language-Team: Arabic (Iraq) (https://app.transifex.com/hisp-uio/teams/100509/ar_IQ/)\n" @@ -24,6 +24,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -426,6 +435,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -441,6 +453,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -506,9 +521,6 @@ msgstr "" msgid "Indicator group" msgstr "" -msgid "Interpretations" -msgstr "التفسيرات" - msgid "Collapse" msgstr "" @@ -1260,6 +1272,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/cs.po b/i18n/cs.po index 410ac85fe..367119c09 100644 --- a/i18n/cs.po +++ b/i18n/cs.po @@ -1,11 +1,11 @@ -# +# # Translators: # Jiří Podhorecký, 2023 -# +# msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Jiří Podhorecký, 2023\n" "Language-Team: Czech (https://app.transifex.com/hisp-uio/teams/100509/cs/)\n" @@ -24,6 +24,15 @@ msgstr "Mapa \"{{- name}}\" je uložena." msgid "Failed to save map: {{message}}" msgstr "Nepodařilo se uložit mapu: {{message}}" +msgid "Calculation" +msgstr "Výpočet" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Klasifikace" @@ -435,6 +444,9 @@ msgstr "Položka dat události je povinná" msgid "Program indicator is required" msgstr "Je vyžadován indikátor programu" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Období je vyžadováno" @@ -450,6 +462,9 @@ msgstr "Položky dat události" msgid "Program indicators" msgstr "Ukazatele programu" +msgid "Calculations" +msgstr "Výpočty" + msgid "Item type" msgstr "Typ položky" @@ -516,9 +531,6 @@ msgstr "Styl podle sady skupiny" msgid "Indicator group" msgstr "Skupina indikátorů" -msgid "Interpretations" -msgstr "Interpretace" - msgid "Collapse" msgstr "Sbalit" @@ -1292,6 +1304,9 @@ msgstr "Chyba {{message}}" msgid "You don't have access to this layer data" msgstr "K datům této vrstvy nemáte přístup" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "Při čtení dat vrstvy došlo k neznámé chybě" diff --git a/i18n/da.po b/i18n/da.po index d6c85985c..41a346627 100644 --- a/i18n/da.po +++ b/i18n/da.po @@ -1,13 +1,13 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: phil_dhis2, 2021\n" +"Last-Translator: Philip Larsen Donnelly, 2021\n" "Language-Team: Danish (https://app.transifex.com/hisp-uio/teams/100509/da/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,6 +24,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -426,6 +435,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -441,6 +453,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -506,9 +521,6 @@ msgstr "" msgid "Indicator group" msgstr "Indicator group" -msgid "Interpretations" -msgstr "Interpretations" - msgid "Collapse" msgstr "" @@ -1260,6 +1272,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index f3d78704f..da70c867b 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -4,21 +4,22 @@ # ericbp , 2020 # Sergio Valenzuela , 2020 # Alison Andrade , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Juan M Alcantara Acosta , 2021 # Prabhjot Singh, 2021 # Carlos Tejo Alonso, 2022 # Marta Vila , 2023 # Viktor Varland , 2023 -# Janeth Cruz, 2023 # Enzo Nicolas Rossi , 2023 +# Alejandra Avila , 2023 +# Janeth Cruz, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: Enzo Nicolas Rossi , 2023\n" +"Last-Translator: Janeth Cruz, 2023\n" "Language-Team: Spanish (https://app.transifex.com/hisp-uio/teams/100509/es/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,6 +36,15 @@ msgstr "El mapa \"{{- name}}\" está guardado." msgid "Failed to save map: {{message}}" msgstr "Error al guardar el mapa: {{message}}" +msgid "Calculation" +msgstr "Cálculo" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Clasificación" @@ -157,7 +167,7 @@ msgid "Org unit" msgstr "Unidad Organizativa" msgid "Id" -msgstr "" +msgstr "Id" msgid "Event time" msgstr "Event time" @@ -444,6 +454,9 @@ msgstr "Se requiere el dato de evento" msgid "Program indicator is required" msgstr "Se requiere indicador de programa" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Período requerido" @@ -459,6 +472,9 @@ msgstr "Datos de eventos" msgid "Program indicators" msgstr "Indicadores de programa" +msgid "Calculations" +msgstr "Cálculos" + msgid "Item type" msgstr "Item type" @@ -524,9 +540,6 @@ msgstr "" msgid "Indicator group" msgstr "Grupo de indicadores" -msgid "Interpretations" -msgstr "Interpretaciones" - msgid "Collapse" msgstr "Contraer" @@ -756,7 +769,7 @@ msgid "" msgstr "" msgid "Use associated geometry" -msgstr "" +msgstr "Utilizar geometría asociada" msgid "None (default)" msgstr "Ninguno (predeterminado)" @@ -903,7 +916,7 @@ msgid "Acres" msgstr "" msgid "Mean" -msgstr "" +msgstr "Media" msgid "Median" msgstr "Mediana" @@ -915,7 +928,7 @@ msgid "OSM Light" msgstr "OSM Sencillo" msgid "OSM Detailed" -msgstr "" +msgstr "OSM Detallado" msgid "Google Streets" msgstr "Google Streets" @@ -924,16 +937,16 @@ msgid "Google Hybrid" msgstr "Google Híbrido" msgid "Bing Road" -msgstr "" +msgstr "Bing Carretera" msgid "Bing Dark" msgstr "Bing Dark" msgid "Bing Aerial" -msgstr "" +msgstr "Bing Aéreo" msgid "Bing Aerial Labels" -msgstr "" +msgstr "Etiquetas aéreas Bing" msgid "Population" msgstr "Población" @@ -1281,6 +1294,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "No tiene acceso a los datos de esta capa" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "Se produjo un error desconocido al leer los datos de la capa" @@ -1349,6 +1365,7 @@ msgstr "No" msgid "Cannot get authorization token for Google Earth Engine." msgstr "" +"No se puede obtener el token de autorización para Google Earth Engine." msgid "" "This layer requires a Google Earth Engine account. Check the DHIS2 " diff --git a/i18n/fr.po b/i18n/fr.po index 8c14e0440..e017cfcc8 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -6,7 +6,7 @@ # Gabriela Rodriguez , 2020 # Edem Kossi , 2020 # Bram Piot , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # tx_e2f_fr r25 , 2021 # Yayra Gomado , 2021 # Yury Rogachev , 2022 @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: French (https://app.transifex.com/hisp-uio/teams/100509/fr/)\n" @@ -35,6 +35,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Classification" @@ -450,6 +459,9 @@ msgstr "L'élément de données évènement est requis" msgid "Program indicator is required" msgstr "L'indicateur de programme est requis" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "La période est requise" @@ -465,6 +477,9 @@ msgstr "Eléments de données évènement" msgid "Program indicators" msgstr "Program indicators" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Type d'élément" @@ -538,9 +553,6 @@ msgstr "Style par ensemble de groupes" msgid "Indicator group" msgstr "Groupe d'indicateurs" -msgid "Interpretations" -msgstr "interprétations" - msgid "Collapse" msgstr "Plier" @@ -1320,6 +1332,9 @@ msgstr "Erreur : {{message}}" msgid "You don't have access to this layer data" msgstr "Vous n'avez pas accès aux données de cette couche." +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" "Une erreur inconnue est survenue lors de la lecture des données de la couche" diff --git a/i18n/id.po b/i18n/id.po index d95d37b9a..a6d04282a 100644 --- a/i18n/id.po +++ b/i18n/id.po @@ -2,7 +2,7 @@ # Translators: # Farida Sibuea , 2020 # Guardian Sanjaya , 2020 -# phil_dhis2, 2020 +# Philip Larsen Donnelly, 2020 # Yusuf Setiawan , 2021 # Carwoto Sa'an , 2021 # Untoro Dwi Raharjo , 2021 @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Aprisa Chrysantina , 2022\n" "Language-Team: Indonesian (https://app.transifex.com/hisp-uio/teams/100509/id/)\n" @@ -31,6 +31,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Klasifikasi" @@ -439,6 +448,9 @@ msgstr "Item data event diperlukan" msgid "Program indicator is required" msgstr "Indikator program diperlukan" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Periode diperlukan" @@ -454,6 +466,9 @@ msgstr "Item data event" msgid "Program indicators" msgstr "Indikator program" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Tipe item" @@ -523,9 +538,6 @@ msgstr "" msgid "Indicator group" msgstr "group indikator" -msgid "Interpretations" -msgstr "Interpretasi" - msgid "Collapse" msgstr "Tutup" @@ -1293,6 +1305,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "Anda tidak memiliki akses ke data layer ini" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "Terjadi kesalahan yang tidak diketahui saat membaca data layer" diff --git a/i18n/km.po b/i18n/km.po index 03c1b02e8..5d1c5189f 100644 --- a/i18n/km.po +++ b/i18n/km.po @@ -1,13 +1,13 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2022 # channara rin, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: channara rin, 2023\n" "Language-Team: Khmer (https://app.transifex.com/hisp-uio/teams/100509/km/)\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -428,6 +437,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -443,6 +455,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -508,9 +523,6 @@ msgstr "" msgid "Indicator group" msgstr "Indicator group" -msgid "Interpretations" -msgstr "កន្លែងសន្ទនារ" - msgid "Collapse" msgstr "" @@ -1262,6 +1274,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/lo.po b/i18n/lo.po index 234470e0d..8555b5555 100644 --- a/i18n/lo.po +++ b/i18n/lo.po @@ -1,6 +1,6 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Thuy Nguyen , 2022 # Viktor Varland , 2023 # Phouthasinh PHEUAYSITHIPHONE, 2023 @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Phouthasinh PHEUAYSITHIPHONE, 2023\n" "Language-Team: Lao (https://app.transifex.com/hisp-uio/teams/100509/lo/)\n" @@ -27,6 +27,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -429,6 +438,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -444,6 +456,9 @@ msgstr "ຂໍ້ມູນລາຍບຸກຄົນ" msgid "Program indicators" msgstr "ຕົວຊີ້ວັດສະເພາະວຽກຂອງຂະແໜງ" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -509,9 +524,6 @@ msgstr "" msgid "Indicator group" msgstr "ກຸ່ມຂອງຕົວຊີ້ວັດ" -msgid "Interpretations" -msgstr "ການແປຂໍ້ມູນ" - msgid "Collapse" msgstr "ຫຍໍ້" @@ -1263,6 +1275,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/my.po b/i18n/my.po index f7939a26b..5ccaf8c7f 100644 --- a/i18n/my.po +++ b/i18n/my.po @@ -2,14 +2,14 @@ # Translators: # Aung Kyi Min , 2020 # Viktor Varland , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: phil_dhis2, 2021\n" +"Last-Translator: Philip Larsen Donnelly, 2021\n" "Language-Team: Burmese (https://app.transifex.com/hisp-uio/teams/100509/my/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -428,6 +437,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -443,6 +455,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -508,9 +523,6 @@ msgstr "" msgid "Indicator group" msgstr "Indicator group" -msgid "Interpretations" -msgstr "Interpretations" - msgid "Collapse" msgstr "" @@ -1262,6 +1274,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/nb.po b/i18n/nb.po index f3886da8c..b8327d4b5 100644 --- a/i18n/nb.po +++ b/i18n/nb.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Karoline Tufte Lien , 2023\n" "Language-Team: Norwegian Bokmål (https://app.transifex.com/hisp-uio/teams/100509/nb/)\n" @@ -25,6 +25,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Klassifisering" @@ -429,6 +438,9 @@ msgstr "Hendelsesdatapunkt er påkrevd" msgid "Program indicator is required" msgstr "Programindikator er påkrevd" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Periode er påkrevd" @@ -444,6 +456,9 @@ msgstr "Hendelsesdatapunkter" msgid "Program indicators" msgstr "Programindikatorer" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Elementtype" @@ -511,9 +526,6 @@ msgstr "" msgid "Indicator group" msgstr "Indikatorgruppe" -msgid "Interpretations" -msgstr "Tolkninger" - msgid "Collapse" msgstr "Kollaps" @@ -1277,6 +1289,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "Du har ikke tilgang til disse lagdataene" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "En ukjent feil oppstod under lesing av lagdata" diff --git a/i18n/nl.po b/i18n/nl.po index b096d2162..1bb2b9344 100644 --- a/i18n/nl.po +++ b/i18n/nl.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Charel van den Elsen, 2023\n" "Language-Team: Dutch (https://app.transifex.com/hisp-uio/teams/100509/nl/)\n" @@ -27,6 +27,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Classificatie" @@ -437,6 +446,9 @@ msgstr "Gegevensitem van gebeurtenis is verplicht" msgid "Program indicator is required" msgstr "Programmaindicator is verplicht" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Periode is verplicht" @@ -452,6 +464,9 @@ msgstr "Gebeurtenisgegevensitems" msgid "Program indicators" msgstr "Programmaindicators" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Itemsoort" @@ -525,9 +540,6 @@ msgstr "Stileer volgens groepsreeks" msgid "Indicator group" msgstr "Indicatorgroep" -msgid "Interpretations" -msgstr "Interpretaties" - msgid "Collapse" msgstr "Inklappen" @@ -1296,6 +1308,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "U heeft geen toegang to deze laaggegevens." +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" "Een onbekende fout is opgetreden tijdens het inlezen van laaggegevens." diff --git a/i18n/prs.po b/i18n/prs.po index 63dfe5ca0..589a5eda7 100644 --- a/i18n/prs.po +++ b/i18n/prs.po @@ -1,13 +1,13 @@ # # Translators: -# phil_dhis2, 2023 +# Philip Larsen Donnelly, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: phil_dhis2, 2023\n" +"Last-Translator: Philip Larsen Donnelly, 2023\n" "Language-Team: Persian (Afghanistan) (https://app.transifex.com/hisp-uio/teams/100509/fa_AF/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -24,6 +24,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -426,6 +435,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -441,6 +453,9 @@ msgstr "د پېښې د مالوماتو (ډاټا) موضوعات" msgid "Program indicators" msgstr "د پروګرام شاخصونه" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "د نېټې ډول" @@ -506,9 +521,6 @@ msgstr "" msgid "Indicator group" msgstr "د شاخص ګروپ" -msgid "Interpretations" -msgstr "تفسیر ها" - msgid "Collapse" msgstr "فرو ریختن" @@ -1260,6 +1272,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/ps.po b/i18n/ps.po index 6b70482c9..2c9f2c2b2 100644 --- a/i18n/ps.po +++ b/i18n/ps.po @@ -1,12 +1,12 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Pashto (https://app.transifex.com/hisp-uio/teams/100509/ps/)\n" @@ -25,6 +25,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -427,6 +436,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -442,6 +454,9 @@ msgstr "د پېښې د ډاټا یا مالوماتو محتویات" msgid "Program indicators" msgstr "د پروګرام شاخص" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "د اطلاعات ډول" @@ -507,9 +522,6 @@ msgstr "" msgid "Indicator group" msgstr "د شاخص ګروپ" -msgid "Interpretations" -msgstr "شفاهي ژباړې" - msgid "Collapse" msgstr "له منځه يې يوسئ" @@ -1261,6 +1273,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/pt.po b/i18n/pt.po index 0e51e29d5..5418b516d 100644 --- a/i18n/pt.po +++ b/i18n/pt.po @@ -2,17 +2,18 @@ # Translators: # Sheila André , 2020 # Ge Joao , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Fernando Jorge Bade, 2021 # Gabriela Rodriguez , 2022 # Viktor Varland , 2023 +# David Júnior , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: Viktor Varland , 2023\n" +"Last-Translator: David Júnior , 2023\n" "Language-Team: Portuguese (https://app.transifex.com/hisp-uio/teams/100509/pt/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -29,6 +30,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Classificação" @@ -437,6 +447,9 @@ msgstr "O item de dados do evento é obrigatório" msgid "Program indicator is required" msgstr "Indicador de programa é necessário" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Período é obrigatório" @@ -452,6 +465,9 @@ msgstr "Itens de dados do evento" msgid "Program indicators" msgstr "Indicador do programa" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Tipo de item" @@ -525,9 +541,6 @@ msgstr "" msgid "Indicator group" msgstr "Grupo de Indicador" -msgid "Interpretations" -msgstr "Interpretações" - msgid "Collapse" msgstr "colapsar" @@ -787,7 +800,7 @@ msgid "URL" msgstr "URL" msgid "Link" -msgstr "" +msgstr "Ligação" msgid "Contact" msgstr "" @@ -1292,6 +1305,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/pt_BR.po b/i18n/pt_BR.po index 3b493a7e8..e113273d7 100644 --- a/i18n/pt_BR.po +++ b/i18n/pt_BR.po @@ -1,13 +1,13 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Oscar Mesones Lapouble , 2022 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Portuguese (Brazil) (https://app.transifex.com/hisp-uio/teams/100509/pt_BR/)\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -428,6 +437,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -443,6 +455,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -508,9 +523,6 @@ msgstr "" msgid "Indicator group" msgstr "Grupo do indicador" -msgid "Interpretations" -msgstr "Interpretações" - msgid "Collapse" msgstr "" @@ -1262,6 +1274,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/ru.po b/i18n/ru.po index 1812a5c89..a87ed5a2d 100644 --- a/i18n/ru.po +++ b/i18n/ru.po @@ -2,13 +2,13 @@ # Translators: # Saurabh Leekha , 2021 # Ulanbek Abakirov , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Russian (https://app.transifex.com/hisp-uio/teams/100509/ru/)\n" @@ -27,6 +27,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -429,6 +438,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -444,6 +456,9 @@ msgstr "Элементы данных событий" msgid "Program indicators" msgstr "Программные показатели" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Тип элемента" @@ -509,9 +524,6 @@ msgstr "" msgid "Indicator group" msgstr "Группа индикаторов" -msgid "Interpretations" -msgstr "Interpretations" - msgid "Collapse" msgstr "Свернуть" @@ -1263,6 +1275,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/sv.po b/i18n/sv.po index 66ebbaf0f..20d53d3cb 100644 --- a/i18n/sv.po +++ b/i18n/sv.po @@ -1,13 +1,13 @@ # # Translators: # Jason Pickering , 2019 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2022 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2022\n" "Language-Team: Swedish (https://app.transifex.com/hisp-uio/teams/100509/sv/)\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Klassificering" @@ -428,6 +437,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -443,6 +455,9 @@ msgstr "Händelsedataposter" msgid "Program indicators" msgstr "programindikatorer" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -508,9 +523,6 @@ msgstr "" msgid "Indicator group" msgstr "Indikatorgrupp" -msgid "Interpretations" -msgstr "tolkningar" - msgid "Collapse" msgstr "" @@ -1262,6 +1274,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/tet.po b/i18n/tet.po index dd1f49d2a..7a638e671 100644 --- a/i18n/tet.po +++ b/i18n/tet.po @@ -1,32 +1,38 @@ # # Translators: # Viktor Varland , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2022-07-27T11:36:02.370Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" -"Last-Translator: phil_dhis2, 2021\n" -"Language-Team: Tetum (Tetun) (https://www.transifex.com/hisp-uio/teams/100509/tet/)\n" +"Last-Translator: Philip Larsen Donnelly, 2021\n" +"Language-Team: Tetum (Tetun) (https://app.transifex.com/hisp-uio/teams/100509/tet/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: tet\n" "Plural-Forms: nplurals=1; plural=0;\n" -msgid "Maps" +msgid "Untitled map, {{date}}" msgstr "" -msgid "Map \"{{name}}\" is saved." +msgid "Map \"{{- name}}\" is saved." msgstr "" -msgid "Failed to save map. {{message}}" +msgid "Failed to save map: {{message}}" msgstr "" -msgid "Error" -msgstr "Erru" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" msgid "Classification" msgstr "" @@ -43,6 +49,18 @@ msgstr "" msgid "Size" msgstr "" +msgid "Name" +msgstr "Naran" + +msgid "Name and value" +msgstr "" + +msgid "Value" +msgstr "Valor" + +msgid "Display" +msgstr "" + msgid "Data element group" msgstr "" @@ -61,24 +79,72 @@ msgstr "Detalles" msgid "Yes" msgstr "Sim" +msgid "None" +msgstr "Nein ida" + +msgid "Cascading" +msgstr "" + msgid "Event location" msgstr "" +msgid "Enrollment location" +msgstr "" + +msgid "Tracked entity location" +msgstr "" + +msgid "Organisation unit location" +msgstr "" + +msgid "Fallback coordinate field" +msgstr "" + msgid "Coordinate field" msgstr "" -msgid "None" -msgstr "Nein ida" +msgid "Enrollment > event > tracked entity > org unit coordinate" +msgstr "" -msgid "Data item" +msgid "Event > org unit coordinate" msgstr "" msgid "Event data item" msgstr "" +msgid "Selected value not available in in list: {{name}}" +msgstr "" + msgid "Style by data element" msgstr "" +msgid "Filtering is available after selecting a program stage." +msgstr "" + +msgid "Add filter" +msgstr "" + +msgid "Data item" +msgstr "" + +msgid "one of" +msgstr "" + +msgid "contains" +msgstr "" + +msgid "is" +msgstr "" + +msgid "is not" +msgstr "" + +msgid "Operator" +msgstr "Operador" + +msgid "Date" +msgstr "Data" + msgid "Data set" msgstr "Pakote dadus" @@ -88,18 +154,12 @@ msgstr "" msgid "Org unit" msgstr "" -msgid "Name" -msgstr "Naran" - msgid "Id" msgstr "" msgid "Event time" msgstr "" -msgid "Value" -msgstr "Valor" - msgid "Legend" msgstr "" @@ -118,9 +178,6 @@ msgstr "Tipu" msgid "Data table is not supported when events are grouped on the server." msgstr "" -msgid "Add filter" -msgstr "" - msgid "Items" msgstr "" @@ -130,15 +187,40 @@ msgstr "" msgid "Download" msgstr "Hatun" +msgid "Exit download mode" +msgstr "" + msgid "Download map" msgstr "" -msgid "Show name" +msgid "Show map name" +msgstr "" + +msgid "Show map description" +msgstr "" + +msgid "Description can be changed from File > Rename menu" +msgstr "" + +msgid "" +"Set the map description when you save the map or from File > Rename menu" msgstr "" msgid "Show legend" msgstr "" +msgid "Show overview map" +msgstr "" + +msgid "Show north arrow" +msgstr "" + +msgid "Include margins in download" +msgstr "" + +msgid "Resize your browser window to change the map dimensions." +msgstr "" + msgid "" "Map download is not supported by your browser. Try Google Chrome or Firefox." msgstr "" @@ -149,7 +231,7 @@ msgstr "Kansela" msgid "Close" msgstr "Taka" -msgid "Legend position" +msgid "No organisation units are selected" msgstr "" msgid "Organisation Units" @@ -164,9 +246,6 @@ msgstr "" msgid "Point radius" msgstr "" -msgid "No organisation units are selected" -msgstr "" - msgid "event" msgstr "" @@ -200,9 +279,6 @@ msgstr "" msgid "Aggregation method" msgstr "" -msgid "Choosing many groups takes a long time to calculate and display." -msgstr "" - msgid "Groups" msgstr "" @@ -276,9 +352,6 @@ msgstr "" msgid "Filter" msgstr "Filtru" -msgid "Events" -msgstr "" - msgid "Group events" msgstr "" @@ -363,6 +436,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -378,6 +454,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -410,25 +489,6 @@ msgstr "" msgid "Display Tracked Entity relationships" msgstr "" -msgid "" -"Include relationships that connect entities outside \"{{program}}\" program" -msgstr "" - -msgid "Selection mode" -msgstr "" - -msgid "Selected only" -msgstr "" - -msgid "Selected and below" -msgstr "" - -msgid "Selected and all below" -msgstr "" - -msgid "Tracked entities" -msgstr "" - msgid "Tracked entity style" msgstr "" @@ -441,54 +501,12 @@ msgstr "" msgid "Line Color" msgstr "" -msgid "Failed to load relationship types." -msgstr "" - msgid "No relationship types were found for tracked entity type {{type}}" msgstr "" msgid "Relationship type" msgstr "" -msgid "An error occurred in the DHIS2 Maps application." -msgstr "" - -msgid "Something went wrong" -msgstr "" - -msgid "Refresh to try again" -msgstr "" - -msgid "Hide technical details" -msgstr "" - -msgid "Show technical details" -msgstr "" - -msgid "The following information may be requested by technical support." -msgstr "" - -msgid "Filtering is available after selecting a program stage." -msgstr "" - -msgid "one of" -msgstr "" - -msgid "contains" -msgstr "" - -msgid "is" -msgstr "" - -msgid "is not" -msgstr "" - -msgid "Operator" -msgstr "Operador" - -msgid "Date" -msgstr "Data" - msgid "Remove filter" msgstr "" @@ -504,9 +522,6 @@ msgstr "" msgid "Indicator group" msgstr "" -msgid "Interpretations" -msgstr "Interpretasoens" - msgid "Collapse" msgstr "" @@ -530,15 +545,15 @@ msgid "" "Desktop." msgstr "" -msgid "Data download failed." -msgstr "" - msgid "ID Format" msgstr "" msgid "Use human-readable keys" msgstr "" +msgid "Data download failed." +msgstr "" + msgid "External layer" msgstr "" @@ -560,6 +575,9 @@ msgstr "" msgid "Set layer opacity" msgstr "" +msgid "Toggle layer menu" +msgstr "" + msgid "More actions" msgstr "" @@ -611,12 +629,15 @@ msgstr "" msgid "Latitude" msgstr "" -msgid "Viewing interpretation from {{interpretationDate}}" +msgid "Basemap could not be added: {{message}}" msgstr "" msgid "Not set" msgstr "Seidauk define" +msgid "Could not retrieve event data" +msgstr "" + msgid "Organisation unit" msgstr "Unidade organizasional" @@ -726,13 +747,13 @@ msgid "" " is {{max}}." msgstr "" -msgid "No data found for this period." +msgid "Use associated geometry" msgstr "" -msgid "Use associated geometry" +msgid "None (default)" msgstr "" -msgid "Select groups" +msgid "No data found for this period." msgstr "" msgid "Image of the organisation unit" @@ -774,48 +795,19 @@ msgstr "Id" msgid "Comment" msgstr "Komentáriu" -msgid "Select levels" -msgstr "" - msgid "Organisation unit profile" msgstr "" -msgid "" -"It’s not possible to combine user organisation units and select individual " -"units." -msgstr "" - -msgid "user organisation unit" -msgstr "" - -msgid "right below user organisation unit" -msgstr "" - -msgid "two levels below user organisation unit" -msgstr "" - -msgid "{{units}} in {{orgunits}}" -msgstr "" - -msgid "{{units}} in and right below {{orgunits}}" -msgstr "" - -msgid "{{units}} in and all below {{orgunits}}" -msgstr "" - -msgid "Selected organisation units" -msgstr "" - -msgid "Main" +msgid "Selected only" msgstr "" -msgid "Below" +msgid "Selected and below" msgstr "" -msgid "2 x below" +msgid "Selected and all below" msgstr "" -msgid "User organisation units" +msgid "Selection mode" msgstr "" msgid "Previous year" @@ -1281,6 +1273,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" @@ -1302,6 +1297,9 @@ msgstr "" msgid "Organisation units" msgstr "Unidade organizasional" +msgid "Error" +msgstr "Erru" + msgid "Thematic layer" msgstr "" @@ -1320,6 +1318,12 @@ msgstr "" msgid "Thematic" msgstr "" +msgid "Events" +msgstr "" + +msgid "Tracked entities" +msgstr "" + msgid "Org units" msgstr "" diff --git a/i18n/tg.po b/i18n/tg.po index 436885820..4fbddf775 100644 --- a/i18n/tg.po +++ b/i18n/tg.po @@ -1,12 +1,12 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Tajik (https://app.transifex.com/hisp-uio/teams/100509/tg/)\n" @@ -25,6 +25,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -427,6 +436,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -442,6 +454,9 @@ msgstr "" msgid "Program indicators" msgstr "" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -507,9 +522,6 @@ msgstr "" msgid "Indicator group" msgstr "Гурӯҳи индикаторҳо" -msgid "Interpretations" -msgstr "Тафсирҳо" - msgid "Collapse" msgstr "" @@ -1261,6 +1273,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/uk.po b/i18n/uk.po index c0cc7d3f1..29dd3eac9 100644 --- a/i18n/uk.po +++ b/i18n/uk.po @@ -2,14 +2,14 @@ # Translators: # Wanda , 2021 # Viktor Varland , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Nadiia , 2022 # Éva Tamási, 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Éva Tamási, 2023\n" "Language-Team: Ukrainian (https://app.transifex.com/hisp-uio/teams/100509/uk/)\n" @@ -28,6 +28,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -430,6 +439,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -445,6 +457,9 @@ msgstr "Складові дані події" msgid "Program indicators" msgstr "Програмні показники" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "" @@ -510,9 +525,6 @@ msgstr "" msgid "Indicator group" msgstr "Група показників" -msgid "Interpretations" -msgstr "Інтерпретації" - msgid "Collapse" msgstr "Згорнути" @@ -1264,6 +1276,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/ur.po b/i18n/ur.po index 35492bf70..dee8250b6 100644 --- a/i18n/ur.po +++ b/i18n/ur.po @@ -1,12 +1,12 @@ # # Translators: -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2022 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2022\n" "Language-Team: Urdu (https://app.transifex.com/hisp-uio/teams/100509/ur/)\n" @@ -25,6 +25,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -427,6 +436,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -442,6 +454,9 @@ msgstr "واقعہ کے اعداد و شمار کی اشیاء" msgid "Program indicators" msgstr "پروگرام اشارے" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "چیز کی قسم" @@ -507,9 +522,6 @@ msgstr "" msgid "Indicator group" msgstr "اشاروں کا گروپ" -msgid "Interpretations" -msgstr "تشریحات" - msgid "Collapse" msgstr "گرنے" @@ -1261,6 +1273,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/uz.po b/i18n/uz_UZ_Cyrl.po similarity index 98% rename from i18n/uz.po rename to i18n/uz_UZ_Cyrl.po index db90fb224..bff13e30d 100644 --- a/i18n/uz.po +++ b/i18n/uz_UZ_Cyrl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Ibatov , 2023\n" "Language-Team: Uzbek (Cyrillic) (https://app.transifex.com/hisp-uio/teams/100509/uz@Cyrl/)\n" @@ -24,6 +24,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "Таснифи" @@ -431,6 +440,9 @@ msgstr "Ҳодиса/Тадбир маълумоти элементи талаб msgid "Program indicator is required" msgstr "Дастур индикатори талаб қилинади" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "Давр талаб қилинади" @@ -446,6 +458,9 @@ msgstr "Ҳодиса/Тадбирлар ҳақида маълумот элеме msgid "Program indicators" msgstr "Дастур кўрсатгичлари" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Элемент тури" @@ -514,9 +529,6 @@ msgstr "" msgid "Indicator group" msgstr "Кўрсатгич гуруҳи" -msgid "Interpretations" -msgstr "Талқинлар" - msgid "Collapse" msgstr "Йиқилиш" @@ -1281,6 +1293,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "Ушбу қатлам маълумотларига кириш ҳуқуқига эга эмассиз" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "Қатлам маълумотларини ўқиш пайтида номаълум хатолик юз берди" diff --git a/i18n/uz_UZ_Latn.po b/i18n/uz_UZ_Latn.po new file mode 100644 index 000000000..9106249b6 --- /dev/null +++ b/i18n/uz_UZ_Latn.po @@ -0,0 +1,1393 @@ +# +# Translators: +# Yury Rogachev , 2023 +# +msgid "" +msgstr "" +"Project-Id-Version: i18next-conv\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" +"PO-Revision-Date: 2019-06-25 18:35+0000\n" +"Last-Translator: Yury Rogachev , 2023\n" +"Language-Team: Uzbek (Latin) (https://app.transifex.com/hisp-uio/teams/100509/uz@Latn/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: uz@Latn\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +msgid "Untitled map, {{date}}" +msgstr "" + +msgid "Map \"{{- name}}\" is saved." +msgstr "" + +msgid "Failed to save map: {{message}}" +msgstr "" + +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + +msgid "Classification" +msgstr "Tasnifi" + +msgid "Classes" +msgstr "Sinflar" + +msgid "Legend set" +msgstr "Таърифлар тўплами" + +msgid "Color" +msgstr "Rang" + +msgid "Size" +msgstr "Oʼlcham" + +msgid "Name" +msgstr "Исми" + +msgid "Name and value" +msgstr "" + +msgid "Value" +msgstr "Қиймат" + +msgid "Display" +msgstr "Ekranda koʼrsatish" + +msgid "Data element group" +msgstr "Maʼlumotlar elementi guruhi" + +msgid "Data element operand" +msgstr "Maʼlumotlar guruhi operandi" + +msgid "Data element" +msgstr "Maʼlumotlar elementi" + +msgid "Totals" +msgstr "Жами" + +msgid "Details" +msgstr "Тафсилотлари" + +msgid "Yes" +msgstr "Ҳа" + +msgid "None" +msgstr "Йўқ" + +msgid "Cascading" +msgstr "" + +msgid "Event location" +msgstr "Hodisa/Tadbir oʼtkaziladigan joy" + +msgid "Enrollment location" +msgstr "" + +msgid "Tracked entity location" +msgstr "" + +msgid "Organisation unit location" +msgstr "" + +msgid "Fallback coordinate field" +msgstr "" + +msgid "Coordinate field" +msgstr "Koordinatalar maydoni" + +msgid "Enrollment > event > tracked entity > org unit coordinate" +msgstr "" + +msgid "Event > org unit coordinate" +msgstr "" + +msgid "Event data item" +msgstr "Hodisa/Tadbir maʼlumoti elementi" + +msgid "Selected value not available in in list: {{name}}" +msgstr "" + +msgid "Style by data element" +msgstr "Maʼlumot elementi boʼyicha uslub" + +msgid "Filtering is available after selecting a program stage." +msgstr "Dastur bosqichi tanlangandan soʼng Filtrdan foydalanish mumkin" + +msgid "Add filter" +msgstr "Filtr kiritish" + +msgid "Data item" +msgstr "Maʼlumot elementi" + +msgid "one of" +msgstr "bittasi" + +msgid "contains" +msgstr "oʼz ichiga oladi" + +msgid "is" +msgstr "bor" + +msgid "is not" +msgstr "emas" + +msgid "Operator" +msgstr "Operator" + +msgid "Date" +msgstr "Sana" + +msgid "Data set" +msgstr "Maʼlumotlar toʼplami" + +msgid "Index" +msgstr "Indenks" + +msgid "Org unit" +msgstr "Tashkiliy birlik" + +msgid "Id" +msgstr "" + +msgid "Event time" +msgstr "Hodisa/Tadbir vaqti" + +msgid "Legend" +msgstr "Taʼrif" + +msgid "Range" +msgstr "Oraliq" + +msgid "Level" +msgstr "Daraja" + +msgid "Parent" +msgstr "Аjdod" + +msgid "Type" +msgstr "Turi" + +msgid "Data table is not supported when events are grouped on the server." +msgstr "" +"Hodisa/Tadbirlar serverda guruhlanayotganda, maʼlumotlar jadvali qoʼllab-" +"quvvatlanmaydi" + +msgid "Items" +msgstr "" +"Hodisa/Tadbirlar serverda guruhlanayotganda, maʼlumotlar jadvali qoʼllab-" +"quvvatlanmaydi" + +msgid "Dimension" +msgstr "Hajm" + +msgid "Download" +msgstr "Юклаш" + +msgid "Exit download mode" +msgstr "" + +msgid "Download map" +msgstr "Xaritani yuklash" + +msgid "Show map name" +msgstr "" + +msgid "Show map description" +msgstr "" + +msgid "Description can be changed from File > Rename menu" +msgstr "" + +msgid "" +"Set the map description when you save the map or from File > Rename menu" +msgstr "" + +msgid "Show legend" +msgstr "Taʼrifni koʼrsatish" + +msgid "Show overview map" +msgstr "" + +msgid "Show north arrow" +msgstr "" + +msgid "Include margins in download" +msgstr "" + +msgid "Resize your browser window to change the map dimensions." +msgstr "" + +msgid "" +"Map download is not supported by your browser. Try Google Chrome or Firefox." +msgstr "" +"Sizning brauzeringiz xarita yuklanishini taʼminlay olmaydi. Google Chrome " +"yoki Firefox orqali urinib koʼring." + +msgid "Cancel" +msgstr "Бекор қилиш" + +msgid "Close" +msgstr "Yopmoq" + +msgid "No organisation units are selected" +msgstr "Tashkiliy boʼlimlar tanlanmagan" + +msgid "Organisation Units" +msgstr "Tashkiliy Boʼlimlar" + +msgid "Style" +msgstr "Услуб" + +msgid "Point color" +msgstr "Нуқта ранги" + +msgid "Point radius" +msgstr "Nuqta radiusi" + +msgid "event" +msgstr "" + +msgid "tracked entity" +msgstr "Kuzatuvdagi obʼekt" + +msgid "facility" +msgstr "imkoniyat" + +msgid "thematic" +msgstr "tematik" + +msgid "org unit" +msgstr "" + +msgid "Earth Engine" +msgstr "Uydagi mexanizm" + +msgid "Edit {{name}} layer" +msgstr "{{Ism}} qatlamini tahrirlash" + +msgid "Add new {{name}} layer" +msgstr "Yangi qatlamni {{ism}} qoʼshish" + +msgid "Update layer" +msgstr "Qatlamni yangilash" + +msgid "Add layer" +msgstr "Qatlam qoʼshish" + +msgid "Aggregation method" +msgstr "" + +msgid "Groups" +msgstr "Гуруҳлар" + +msgid "This field is required" +msgstr "Ushbu qator toʼldirilishi shart" + +msgid "Data" +msgstr "Маълумот" + +msgid "Period" +msgstr "davr" + +msgid "" +"Data will be calculated on Google Earth Engine for the chosen organisation " +"units." +msgstr "" + +msgid "Multiple aggregation methods are available." +msgstr "" + +msgid "" +"See the aggregation results by clicking map regions or viewing the data " +"table. The results can also be downloaded." +msgstr "" + +msgid "Unit" +msgstr "" + +msgid "Source" +msgstr "Manba/Izlash" + +msgid "Legend preview" +msgstr "Oldingi taʼrif" + +msgid "Year" +msgstr "Yil" + +msgid "Available periods are set by the source data" +msgstr "" + +msgid "Loading periods" +msgstr "" + +msgid "Min value is required" +msgstr "" + +msgid "Max value is required" +msgstr "" + +msgid "Max should be greater than min" +msgstr "" + +msgid "Valid steps are {{minSteps}} to {{maxSteps}}" +msgstr "" + +msgid "Unit: {{ unit }}" +msgstr "" + +msgid "Min" +msgstr "Минимум" + +msgid "Max" +msgstr "Максимум" + +msgid "Steps" +msgstr "Qadamlar" + +msgid "Org Units" +msgstr "Tashkiliy Boʼlimlar" + +msgid "Filter" +msgstr "Filtr" + +msgid "Group events" +msgstr "Hodisa/Tadbirlar guruhlari" + +msgid "View all events" +msgstr "Barcha hodisa/tadbirlarni koʼrish" + +msgid "Radius" +msgstr "Radius" + +msgid "You can style events by data element after selecting a program." +msgstr "" +"Hodisa/Tadbirlarda maʼlumotlar elementini uslublash uchun dasturni tanlang" + +msgid "Program is required" +msgstr "Dastur talab qilinadi" + +msgid "Program stage is required" +msgstr "Dastur bosqichi talab qilinadi" + +msgid "No organisation units are selected." +msgstr "Tashkiliy boʼlimlar tanlanmagan" + +msgid "No legend set is selected" +msgstr "Taʼrif toʼplami tanlanmagan" + +msgid "Event status" +msgstr "Hodisa/Tadbir holati" + +msgid "Boundary color" +msgstr "" + +msgid "Buffer" +msgstr "Bufer" + +msgid "Radius in meters" +msgstr "Radius metrlarda" + +msgid "Buffer can't be combined with associated geometry." +msgstr "" + +msgid "Labels" +msgstr "Yorliqlar" + +msgid "Aggregation type" +msgstr "Бирлаштириш тури" + +msgid "Only show completed events" +msgstr "" + +msgid "Show no data" +msgstr "Maʼlumot yoʼq" + +msgid "Low radius" +msgstr "Kichik radius" + +msgid "High radius" +msgstr "Katta radius" + +msgid "High radius should be greater than low radius" +msgstr "" + +msgid "Radius should be between {{min}} and {{max}}" +msgstr "Radius {{minimum}} va {{maksimum}} oraligʼida boʼlishi lozim" + +msgid "Indicator group is required" +msgstr "Koʼrsatgichlar guruhi talab qilinadi" + +msgid "Indicator is required" +msgstr "Indikator talab qilinadi" + +msgid "Data element group is required" +msgstr "Maʼlumot elementi talab qilinadi" + +msgid "Data element is required" +msgstr "Maʼlumot elementi talab qilingan" + +msgid "Data set is required" +msgstr "Maʼlumot toʼplami talab qilingan" + +msgid "Event data item is required" +msgstr "Hodisa/Tadbir maʼlumoti elementi talab qilinadi" + +msgid "Program indicator is required" +msgstr "Dastur indikatori talab qilinadi" + +msgid "Calculation is required" +msgstr "" + +msgid "Period is required" +msgstr "Davr talab qilinadi" + +msgid "Indicator" +msgstr "Indikator" + +msgid "Reporting rates" +msgstr "Ҳисобот таърифлари" + +msgid "Event data items" +msgstr "Hodisalar haqida maʼlumot elementlari" + +msgid "Program indicators" +msgstr "Dastur koʼrsatgichlari" + +msgid "Calculations" +msgstr "" + +msgid "Item type" +msgstr "Element turi" + +msgid "Select period when tracked entities were last updated" +msgstr "" +"Kuzatuvdagi obʼektlar maʼlumoti yangilanganligi oxirgi davrini tanlang" + +msgid "Program/Enrollment date" +msgstr "Dastur/qayd qilish sanasi" + +msgid "the date a tracked entity was registered or enrolled in a program" +msgstr "" +"sana, kuzatuvdagi shaxs roʼyxatga olingan yoki dasturda roʼyxatga olingan" + +msgid "Program status" +msgstr "dastur holati" + +msgid "Relationships" +msgstr "Oʼzaro aloqalar" + +msgid "Follow up" +msgstr "Kuzatib borish" + +msgid "" +"Please select a Tracked Entity Type before selecting a Relationship Type" +msgstr "" +"Iltimos, oʼzaro aloqalar turini tanlashdan oldin kuzatuvdagi obʼektni " +"tanlang" + +msgid "" +"Displaying tracked entity relationships in Maps is an experimental feature" +msgstr "" +"Xaritalarda obʼektlarning oʼzaro aloqalar tizimining koʼrsatilishi - " +"eksperimental funktsiya" + +msgid "Display Tracked Entity relationships" +msgstr "Xaritalarda obʼektlarning oʼzaro aloqalar tizimining koʼrsatilishi" + +msgid "Tracked entity style" +msgstr "Kuzatuvdagi obʼektlar xususiyatlari" + +msgid "Point size" +msgstr "Nuqta oʼlchami" + +msgid "Related entity style" +msgstr "Oʼzaro bogʼlangan xususiyatlar" + +msgid "Line Color" +msgstr "Qator rangi" + +msgid "No relationship types were found for tracked entity type {{type}}" +msgstr "Kuzatuvdagi obʼektlar oʼzaro aloqalar turlari {{turi}} topilmadi" + +msgid "Relationship type" +msgstr "Oʼzaro aloqalar turi" + +msgid "Remove filter" +msgstr "Filtrni olib tashlash" + +msgid "Group set" +msgstr "" + +msgid "Failed to load organisation unit groups." +msgstr "" + +msgid "Style by group set" +msgstr "" + +msgid "Indicator group" +msgstr "Koʼrsatgich guruhi" + +msgid "Collapse" +msgstr "Yiqilish" + +msgid "Expand" +msgstr "Kengaytiring" + +msgid "External basemap" +msgstr "Tashqi asosiy xarita" + +msgid "Basemap" +msgstr "Аsosiy xarita" + +msgid "Download Layer Data" +msgstr "Qavat maʼlumotlarini yuklash" + +msgid "Downloading GeoJSON data for \"{{layerName}}\"" +msgstr "{{QavatIsmi}} uchun GeoJSON maʼlumotlari yuklanmoqda" + +msgid "" +"GeoJSON is supported by most GIS software, including QGIS and ArcGIS " +"Desktop." +msgstr "" +"GeoJSON aksariyat GIS dasturlari tomonidan qoʼllab quvvatlanadi, shu " +"jumladan QGIS va ArcGIS ham." + +msgid "ID Format" +msgstr "ID format" + +msgid "Use human-readable keys" +msgstr "oʼqilishi qulay kalitlardan foydalaning" + +msgid "Data download failed." +msgstr "Maʼlumot yuklanishi amalga oshmadi" + +msgid "External layer" +msgstr "Tashqi qavat" + +msgid "Split view can not be combined with other layer types." +msgstr "" +"Аjratilgan koʼrinishlarni boshqa qatlam turlari bilan birlashtirib " +"boʼlmaydi." + +msgid "Loading layer" +msgstr "Yuklanadigan qavat" + +msgid "{{name}} deleted." +msgstr "{{ismi}} oʼchirilgan" + +msgid "Edit" +msgstr "Tahrirlash" + +msgid "Toggle visibility" +msgstr "Koʼrinishni yoqing" + +msgid "Set layer opacity" +msgstr "Qatlam xiraligini tahrirlang" + +msgid "Toggle layer menu" +msgstr "" + +msgid "More actions" +msgstr "Boshqa harakatlar" + +msgid "Hide data table" +msgstr "Maʼlumotlar jadvali berkitilsin" + +msgid "Show data table" +msgstr "Maʼlumotlar jadvalini koʼrsatish" + +msgid "Open as chart" +msgstr "Diagramma sifatida oching" + +msgid "Download data" +msgstr "Maʼlumotni yuklab oling" + +msgid "Edit layer" +msgstr "Qatlamni tahrirlash" + +msgid "Remove layer" +msgstr "Qatlamni oʼchirish" + +msgid "Mid" +msgstr "Oʼrta" + +msgid "Group" +msgstr "Гуруҳ" + +msgid "Filters" +msgstr "Filrlar" + +msgid "Drill up one level" +msgstr "Bir pogʼonaga koʼtariling" + +msgid "Drill down one level" +msgstr "Bir darajaga tushing" + +msgid "View profile" +msgstr "Profilni koʼrish" + +msgid "Show longitude/latitude" +msgstr "Kenglik/Uzunlikni koʼrsating" + +msgid "Show {{name}}" +msgstr "Koʼrsatish {{nomi}}" + +msgid "Longitude" +msgstr "Kenglik" + +msgid "Latitude" +msgstr "Kenglik" + +msgid "Basemap could not be added: {{message}}" +msgstr "" + +msgid "Not set" +msgstr "Oʼrnatilmagan" + +msgid "Could not retrieve event data" +msgstr "" + +msgid "Organisation unit" +msgstr "Ташкилий бирлик" + +msgid "Parent unit" +msgstr "Аjdod boʼlimi" + +msgid "Last updated" +msgstr "Oxirgi yangilangan" + +msgid "" +"Google Earth Engine failed. Is the service configured for this DHIS2 " +"instance?" +msgstr "" + +msgid "no value" +msgstr "" + +msgid "All groups" +msgstr "" + +msgid "Loading data" +msgstr "" + +msgid "acres" +msgstr "akr" + +msgid "Area" +msgstr "Maydon" + +msgid "Center map on area" +msgstr "Maydon boʼyicha xaritani markashtirish" + +msgid "Center map on line" +msgstr "Chiziq boʼyicha xaritani markazlashtirish" + +msgid "Click the next position" +msgstr "Keyingi pozitsiyani bosing" + +msgid "Click where you want to start the measurement" +msgstr "Oʼlchovni boshlanish joyini bosing" + +msgid "Delete" +msgstr "Oʼchirib tashlash" + +msgid "Distance" +msgstr "Masofa" + +msgid "Enter fullscreen" +msgstr "Toʼliq ekranga kiring" + +msgid "Exit fullscreen" +msgstr "Toʼliq ekrandan chiking" + +msgid "Finish measurement" +msgstr "Oʼlchovni tugatish" + +msgid "ha" +msgstr "xa" + +msgid "km" +msgstr "km" + +msgid "Measure distances and areas" +msgstr "Oʼlchov masofasi va maydoni" + +msgid "mi" +msgstr "Mil" + +msgid "Perimeter" +msgstr "Perimetr" + +msgid "Reset bearing to north" +msgstr "Pelengni shimolga tashlash" + +msgid "Search for place or address" +msgstr "Joyi yoki mandilini izlash" + +msgid "Zoom in" +msgstr "Kattalashtirish" + +msgid "Zoom out" +msgstr "Uzoqlashtirish" + +msgid "Zoom to content" +msgstr "Tarkib boʼyicha yaqinlashtirish" + +msgid "Open as map" +msgstr "Xarita sifatida ochish" + +msgid "" +"This chart/table contains {{numItems}} data items. Choose which items you " +"want to import from the list below. Each data item will be created as a map " +"layer." +msgstr "" +"Ushbu diagramma / jadval {{numitems}} maʼlumotlar elementlaridan tashkil " +"topgan. Quyidagi roʼyxatdan import qilmoqchi boʼlgan elementlarni tanlang. " +"Har bir element xarita qavati sifatida yaratiladi." + +msgid "Data items" +msgstr "Maʼlumot elementlari" + +msgid "Proceed" +msgstr "Davom eting" + +msgid "Options" +msgstr "Вариант" + +msgid "" +"This data element has too many options ({{length}}). Max options for styling" +" is {{max}}." +msgstr "" + +msgid "Use associated geometry" +msgstr "" + +msgid "None (default)" +msgstr "" + +msgid "No data found for this period." +msgstr "Ushbu davr uchun maʼlumot topilmadi" + +msgid "Image of the organisation unit" +msgstr "" + +msgid "Code" +msgstr "Kod" + +msgid "Short name" +msgstr "Qisqacha nomi" + +msgid "Opening date" +msgstr "Ochilish sanasi" + +msgid "Closed date" +msgstr "Yopilgan sana" + +msgid "URL" +msgstr "URL" + +msgid "Link" +msgstr "Havola" + +msgid "Contact" +msgstr "" + +msgid "Email" +msgstr "ye-Pochta" + +msgid "Address" +msgstr "Manzil" + +msgid "Phone" +msgstr "" + +msgid "ID" +msgstr "ID" + +msgid "Comment" +msgstr "Izoh" + +msgid "Organisation unit profile" +msgstr "" + +msgid "Selected only" +msgstr "Faqatgina tanlangan" + +msgid "Selected and below" +msgstr "Tanlangan va quyida" + +msgid "Selected and all below" +msgstr "Tanlangan va barchasi quyida" + +msgid "Selection mode" +msgstr "Rejimni tanlash" + +msgid "Previous year" +msgstr "Oldingi yil" + +msgid "Next year" +msgstr "Keyngi yil" + +msgid "Relative" +msgstr "Oʼzaro bogʼliqlik" + +msgid "Period type" +msgstr "Davr turi" + +msgid "Start/end dates" +msgstr "Boshlanish/Tugash vaqtlari" + +msgid "Only one timeline is allowed." +msgstr "Faqatgina bitta vaqt oraligʼi boʼlishi mumkin" + +msgid "Remove other layers to enable split map views." +msgstr "" +"Xaritani koʼzdan kechirish rejimini yoqish uchun, boshqa qavatlarni " +"oʼchiring" + +msgid "Display periods" +msgstr "Koʼrinish davrlari" + +msgid "Single (aggregate)" +msgstr "Yakka (Birlashtirilgan)" + +msgid "Timeline" +msgstr "Xronologiya" + +msgid "Split map views" +msgstr "Xarita koʼrinishlarini ajratish" + +msgid "Start date" +msgstr "Boshlanish sanasi" + +msgid "End date" +msgstr "Yakunlanish sanasi" + +msgid "Not available offline" +msgstr "" + +msgid "Program indicator" +msgstr "Dastur indikatori" + +msgid "No program" +msgstr "Dastur mavjud emas" + +msgid "Program" +msgstr "Dastur" + +msgid "Stage" +msgstr "Босқич" + +msgid "Tracked Entity Type" +msgstr "" + +msgid "By data element" +msgstr "Маълумотлар элементи бўйича" + +msgid "Count" +msgstr "Ҳисоблаш" + +msgid "Average" +msgstr "Ўртача" + +msgid "Sum" +msgstr "Жамлаш" + +msgid "Standard deviation" +msgstr "Standart ogʼish" + +msgid "Variance" +msgstr "Номувофиқлик" + +msgid "Percentage" +msgstr "Foiz" + +msgid "Hectares" +msgstr "" + +msgid "Acres" +msgstr "" + +msgid "Mean" +msgstr "" + +msgid "Median" +msgstr "" + +msgid "Std dev" +msgstr "" + +msgid "OSM Light" +msgstr "OSM manba" + +msgid "OSM Detailed" +msgstr "OSM Batafsil" + +msgid "Google Streets" +msgstr "Google Streets" + +msgid "Google Hybrid" +msgstr "Google Hybrid" + +msgid "Bing Road" +msgstr "Yoʼl" + +msgid "Bing Dark" +msgstr "Toʼq rangli moʼyqalam" + +msgid "Bing Aerial" +msgstr "Gibrid koʼrinish" + +msgid "Bing Aerial Labels" +msgstr "Belgilar" + +msgid "Population" +msgstr "" + +msgid "people per hectare" +msgstr "" + +msgid "Estimated number of people living in an area." +msgstr "" + +msgid "Population age groups" +msgstr "" + +msgid "" +"Estimated number of people living in an area, grouped by age and gender." +msgstr "" + +msgid "Male 0 - 1 years" +msgstr "" + +msgid "Male 1 - 4 years" +msgstr "" + +msgid "Male 5 - 9 years" +msgstr "" + +msgid "Male 10 - 14 years" +msgstr "" + +msgid "Male 15 - 19 years" +msgstr "" + +msgid "Male 20 - 24 years" +msgstr "" + +msgid "Male 25 - 29 years" +msgstr "" + +msgid "Male 30 - 34 years" +msgstr "" + +msgid "Male 35 - 39 years" +msgstr "" + +msgid "Male 40 - 44 years" +msgstr "" + +msgid "Male 45 - 49 years" +msgstr "" + +msgid "Male 50 - 54 years" +msgstr "" + +msgid "Male 55 - 59 years" +msgstr "" + +msgid "Male 60 - 64 years" +msgstr "" + +msgid "Male 65 - 69 years" +msgstr "" + +msgid "Male 70 - 74 years" +msgstr "" + +msgid "Male 75 - 79 years" +msgstr "" + +msgid "Male 80 years and above" +msgstr "" + +msgid "Female 0 - 1 years" +msgstr "" + +msgid "Female 1 - 4 years" +msgstr "" + +msgid "Female 5 - 9 years" +msgstr "" + +msgid "Female 10 - 14 years" +msgstr "" + +msgid "Female 15 - 19 years" +msgstr "" + +msgid "Female 20 - 24 years" +msgstr "" + +msgid "Female 25 - 29 years" +msgstr "" + +msgid "Female 30 - 34 years" +msgstr "" + +msgid "Female 35 - 39 years" +msgstr "" + +msgid "Female 40 - 44 years" +msgstr "" + +msgid "Female 45 - 49 years" +msgstr "" + +msgid "Female 50 - 54 years" +msgstr "" + +msgid "Female 55 - 59 years" +msgstr "" + +msgid "Female 60 - 64 years" +msgstr "" + +msgid "Female 65 - 69 years" +msgstr "" + +msgid "Female 70 - 74 years" +msgstr "" + +msgid "Female 75 - 79 years" +msgstr "" + +msgid "Female 80 years and above" +msgstr "" + +msgid "Building footprints" +msgstr "" + +msgid "Number of buildings" +msgstr "" + +msgid "" +"The outlines of buildings derived from high-resolution satellite imagery. " +"Only for the continent of Africa." +msgstr "" + +msgid "" +"Building counts are only available for smaller organisation unit areas." +msgstr "" + +msgid "" +"Select a smaller area or single organization unit to see the count of " +"buildings." +msgstr "" + +msgid "Elevation" +msgstr "Balandlik" + +msgid "meters" +msgstr "" + +msgid "Elevation above sea-level." +msgstr "Dengiz sathidan balandlik" + +msgid "Precipitation" +msgstr "Yogʼingarchilik" + +msgid "millimeter" +msgstr "millimetr" + +msgid "" +"Precipitation collected from satellite and weather stations on the ground. " +"The values are in millimeters within 5 days periods. Updated monthly, during" +" the 3rd week of the following month." +msgstr "" +"Sunʼiy yoʼldosh va yerdagi stantsiyalardan yigʼilgan yogʼingarchilik " +"maʼlumotlari. Qiymatlar 5 kunlik yigʼilgan maʼlumotlar asosida mm larda aks " +"ettiriladi. Doimo oyning 3chi haftasida yangilanadi." + +msgid "Temperature" +msgstr "Temperatura" + +msgid "°C during daytime" +msgstr "Kunduzgi °C" + +msgid "" +"Land surface temperatures collected from satellite. Blank spots will appear " +"in areas with a persistent cloud cover." +msgstr "" +"Yer usti harorati sunʼiy yoʼldosh orqali aniqlashtirilgan. Doimiy bulutlar " +"bilan qoplangan maydonlarda boʼsh dogʼlar paydo boʼladi" + +msgid "Landcover" +msgstr "Oʼsimliklar qavati" + +msgid "Distinct landcover types collected from satellites." +msgstr "Sputnik yordamida yer qatlamining turi aniqlangan" + +msgid "Evergreen Needleleaf forest" +msgstr "Yashil igna bargli doimiy oʼrmonlar" + +msgid "Evergreen Broadleaf forest" +msgstr "Doimiy yashil yapaloq bargli oʼrmonlar" + +msgid "Deciduous Needleleaf forest" +msgstr "Nina bargli oʼrmonlar" + +msgid "Deciduous Broadleaf forest" +msgstr "Yapaloq bargli oʼrmonlar" + +msgid "Mixed forest" +msgstr "Аralash oʼrmonlar" + +msgid "Closed shrublands" +msgstr "Zich butazorlar" + +msgid "Open shrublands" +msgstr "Siyrak butazorlar" + +msgid "Woody savannas" +msgstr "Savannalar (yogʼochli)" + +msgid "Savannas" +msgstr "Savanna" + +msgid "Grasslands" +msgstr "Oʼtloqlar" + +msgid "Permanent wetlands" +msgstr "Doimiy botqoq yerlar" + +msgid "Croplands" +msgstr "Oʼsimliklar" + +msgid "Urban and built-up" +msgstr "Urbanizatsiya va shaharsozlik" + +msgid "Cropland/Natural vegetation mosaic" +msgstr "Oʼsimliklar/Tabiiy oʼsimliklar dunyosi" + +msgid "Snow and ice" +msgstr "Qor va muz" + +msgid "Barren or sparsely vegetated" +msgstr "Hosilsiz yoki kam oʼsimliklardan" + +msgid "Water" +msgstr "Suv" + +msgid "people per km²" +msgstr "1 km² da odamlar" + +msgid "Nighttime lights" +msgstr "Tungi chiroqlar" + +msgid "light intensity" +msgstr "Yorugʼlik intensivligi" + +msgid "" +"Light intensity from cities, towns, and other sites with persistent " +"lighting, including gas flares." +msgstr "" +"Yorugʼlik intensivligi maʼlumotlari shaharlar, qishloqlar va shu jumladan " +"yoqilgan gaz fakellaridan." + +msgid "All" +msgstr "Barchasi" + +msgid "Active" +msgstr "Faol" + +msgid "Completed" +msgstr "bajarildi" + +msgid "Choropleth" +msgstr "Xoroplet" + +msgid "Bubble map" +msgstr "Qiymatlar koʼrsatilgan xarita" + +msgid "Automatic color legend" +msgstr "Аvtomatik rangli taʼrif" + +msgid "Predefined color legend" +msgstr "Oldindan belgilangan rangli taʼrif" + +msgid "Single color legend" +msgstr "Bir rangli taʼrif" + +msgid "Equal intervals" +msgstr "teng intervallar" + +msgid "Equal counts" +msgstr "Teng miqdorda" + +msgid "Symbol" +msgstr "" + +msgid "Daily" +msgstr "Кунлик" + +msgid "Weekly" +msgstr "Ҳафталик" + +msgid "Weekly (Start Wednesday)" +msgstr "Ҳафталик (Бошланиши Чоршанба)" + +msgid "Weekly (Start Thursday)" +msgstr "Ҳафталик (Бошланиши Пайшанба)" + +msgid "Weekly (Start Saturday)" +msgstr "Ҳафталик (Бошланиши Шанба)" + +msgid "Weekly (Start Sunday)" +msgstr "Ҳафталик (Бошланиши Якшанба)" + +msgid "Bi-weekly" +msgstr "Juft hafta" + +msgid "Monthly" +msgstr "Ойлик" + +msgid "Bi-monthly" +msgstr "Жуфт ойлик" + +msgid "Quarterly" +msgstr "Ҳар квартал" + +msgid "Six-monthly" +msgstr "Yarim yillik" + +msgid "Six-monthly April" +msgstr "Yarim yillik Аprel" + +msgid "Yearly" +msgstr "Йиллик" + +msgid "Financial year (Start November)" +msgstr "Moliyaviy yil (Boshlanishi Noyabr)" + +msgid "Financial year (Start October)" +msgstr "Молиявий йил (бошланиши Октябр)" + +msgid "Financial year (Start July)" +msgstr "Молиявий йил (бошланиши Июл)" + +msgid "Financial year (Start April)" +msgstr "Молиявий йил (бошланиши Апрел)" + +msgid "Cancelled" +msgstr "Bekor qilindi" + +msgid "{{name}}: No coordinates found" +msgstr "" + +msgid "Selected org units: No coordinates found" +msgstr "" + +msgid "Error: {{message}}" +msgstr "" + +msgid "You don't have access to this layer data" +msgstr "Ushbu qatlam maʼlumotlariga kirish huquqiga ega emassiz" + +msgid "The event filter is not supported" +msgstr "" + +msgid "An unknown error occurred while reading layer data" +msgstr "Qatlam maʼlumotlarini oʼqish paytida nomaʼlum xatolik yuz berdi" + +msgid "Displaying first {{pageSize}} events out of {{total}}" +msgstr "" + +msgid "No data found" +msgstr "Maʼlumotlar topilmadi" + +msgid "Event" +msgstr "Hodisa/Tadbir" + +msgid "Facilities" +msgstr "Muassasalar" + +msgid "Facilities: No coordinates found" +msgstr "" + +msgid "Organisation units" +msgstr "Tashkiliy birliklar" + +msgid "Error" +msgstr "Xatolik" + +msgid "Thematic layer" +msgstr "Tematik qavat" + +msgid "No data" +msgstr "Maʼlumot yoʼq" + +msgid "Tracked entity" +msgstr "Kuzatuv obʼekti" + +msgid "No tracked entities found" +msgstr "Hech qanday kuzatuvdagi obʼekt topilmadi" + +msgid "related" +msgstr "bogʼliqlik" + +msgid "Thematic" +msgstr "" + +msgid "Events" +msgstr "Hodisa/tadbirlar" + +msgid "Tracked entities" +msgstr "Kuzatuvdagi obʼektlar" + +msgid "Org units" +msgstr "" + +msgid "not one of" +msgstr "bittasi ham emas" + +msgid "doesn't contains" +msgstr "oʼz ichiga olmaydi" + +msgid "true" +msgstr "toʼgʼri" + +msgid "false" +msgstr "yolgʼon" + +msgid "No" +msgstr "Йўқ" + +msgid "Cannot get authorization token for Google Earth Engine." +msgstr "" + +msgid "" +"This layer requires a Google Earth Engine account. Check the DHIS2 " +"documentation for more information." +msgstr "" +"Ushbu qatlam uchun Google Earth Engine akkaunti zarur. Qoʼshimcha maʼlumot " +"olish uchunDHIS2 hujjatlarini tekshiring." + +msgid "Facility" +msgstr "" + +msgid "Start date is invalid" +msgstr "Boshlanish sanasi notoʼgʼri" + +msgid "End date is invalid" +msgstr "Yakunlanish sanasi notoʼgʼri" + +msgid "End date cannot be earlier than start date" +msgstr "Yakunlanish sanasi boshlanish sanasidan oldin boʼlishi mumkin emas" diff --git a/i18n/vi.po b/i18n/vi.po index b22ca6749..ba5265cf0 100644 --- a/i18n/vi.po +++ b/i18n/vi.po @@ -1,13 +1,13 @@ # # Translators: # Mai Nguyen , 2021 -# phil_dhis2, 2021 +# Philip Larsen Donnelly, 2021 # Viktor Varland , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: Viktor Varland , 2023\n" "Language-Team: Vietnamese (https://app.transifex.com/hisp-uio/teams/100509/vi/)\n" @@ -26,6 +26,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -428,6 +437,9 @@ msgstr "" msgid "Program indicator is required" msgstr "" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "" @@ -443,6 +455,9 @@ msgstr "Mục dữ liệu sự kiện" msgid "Program indicators" msgstr "Chỉ Số Chương Trình" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "Kiểu mục" @@ -508,9 +523,6 @@ msgstr "" msgid "Indicator group" msgstr "Nhóm chỉ số" -msgid "Interpretations" -msgstr "Diễn giải báo cáo" - msgid "Collapse" msgstr "Thu gọn" @@ -1262,6 +1274,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" diff --git a/i18n/zh.po b/i18n/zh.po index 12dfbdbe8..8195b7435 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -1,14 +1,14 @@ # # Translators: # 晓东 林 <13981924470@126.com>, 2022 -# phil_dhis2, 2022 +# Philip Larsen Donnelly, 2022 # Viktor Varland , 2023 # easylin , 2023 # msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: easylin , 2023\n" "Language-Team: Chinese (https://app.transifex.com/hisp-uio/teams/100509/zh/)\n" @@ -27,6 +27,15 @@ msgstr "地图“{{- name}}”已保存。" msgid "Failed to save map: {{message}}" msgstr "无法保存地图:{{message}}" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "分类" @@ -429,6 +438,9 @@ msgstr "需要事件数据项" msgid "Program indicator is required" msgstr "需要项目指标" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "需要期间" @@ -444,6 +456,9 @@ msgstr "事件数据项" msgid "Program indicators" msgstr "项目指标" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "条目类型" @@ -509,9 +524,6 @@ msgstr "按组集设置样式" msgid "Indicator group" msgstr "指标组" -msgid "Interpretations" -msgstr "注释" - msgid "Collapse" msgstr "折叠" @@ -1263,6 +1275,9 @@ msgstr "错误: {{message}}" msgid "You don't have access to this layer data" msgstr "您无权访问此图层数据" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "读取图层数据时发生未知错误" diff --git a/i18n/zh_CN.po b/i18n/zh_CN.po index fd52046af..ff38db2a2 100644 --- a/i18n/zh_CN.po +++ b/i18n/zh_CN.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2023-04-12T09:23:26.646Z\n" +"POT-Creation-Date: 2023-09-06T13:08:55.205Z\n" "PO-Revision-Date: 2019-06-25 18:35+0000\n" "Last-Translator: 晓东 林 <13981924470@126.com>, 2023\n" "Language-Team: Chinese (China) (https://app.transifex.com/hisp-uio/teams/100509/zh_CN/)\n" @@ -25,6 +25,15 @@ msgstr "" msgid "Failed to save map: {{message}}" msgstr "" +msgid "Calculation" +msgstr "" + +msgid "No calculations found" +msgstr "" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "" + msgid "Classification" msgstr "" @@ -427,6 +436,9 @@ msgstr "必须提供事件数据项" msgid "Program indicator is required" msgstr "必须提供项目指标" +msgid "Calculation is required" +msgstr "" + msgid "Period is required" msgstr "需要时段" @@ -442,6 +454,9 @@ msgstr "事件数据项" msgid "Program indicators" msgstr "项目指标" +msgid "Calculations" +msgstr "" + msgid "Item type" msgstr "条目类型" @@ -507,9 +522,6 @@ msgstr "" msgid "Indicator group" msgstr "指标组" -msgid "Interpretations" -msgstr "注释" - msgid "Collapse" msgstr "折叠" @@ -1261,6 +1273,9 @@ msgstr "" msgid "You don't have access to this layer data" msgstr "" +msgid "The event filter is not supported" +msgstr "" + msgid "An unknown error occurred while reading layer data" msgstr "" From 8fdd67eb0b57e3c185cda9da3486d727dc2a64c7 Mon Sep 17 00:00:00 2001 From: Bjorn Sandvik Date: Fri, 15 Sep 2023 11:26:32 +0200 Subject: [PATCH 03/11] chore: fixed period select refactor (#2958) --- .../integration/layers/thematiclayer.cy.js | 81 ++++++- i18n/en.pot | 15 ++ .../calculations/CalculationSelect.js | 62 +++++ .../styles/CalculationSelect.module.css | 3 + src/components/core/SelectField.js | 6 + .../edit/thematic/ThematicDialog.js | 18 ++ .../edit/thematic/ValueTypeSelect.js | 40 ++-- src/components/layers/overlays/OverlayCard.js | 5 +- src/components/orgunits/OrgUnitData.js | 2 +- src/components/periods/PeriodSelect.js | 217 +++++++++--------- src/constants/dimension.js | 6 + src/util/periods.js | 38 ++- 12 files changed, 351 insertions(+), 142 deletions(-) create mode 100644 src/components/calculations/CalculationSelect.js create mode 100644 src/components/calculations/styles/CalculationSelect.module.css diff --git a/cypress/integration/layers/thematiclayer.cy.js b/cypress/integration/layers/thematiclayer.cy.js index d9966fc7d..4dacacc0b 100644 --- a/cypress/integration/layers/thematiclayer.cy.js +++ b/cypress/integration/layers/thematiclayer.cy.js @@ -6,7 +6,7 @@ import { expectContextMenuOptions, } from '../../elements/map_context_menu.js' import { ThematicLayer } from '../../elements/thematic_layer.js' -import { CURRENT_YEAR } from '../../support/util.js' +import { CURRENT_YEAR, getApiBaseUrl } from '../../support/util.js' const INDICATOR_NAME = 'VCCT post-test counselling rate' @@ -136,4 +136,83 @@ context('Thematic Layers', () => { { name: VIEW_PROFILE }, ]) }) + + // TODO - update demo database with calculations instead of creating on the fly + it('adds a thematic layer with a calculation', () => { + const timestamp = new Date().toUTCString().slice(-24, -4) + const calculationName = `map calc ${timestamp}` + + // add a calculation + cy.request('POST', `${getApiBaseUrl()}/api/expressionDimensionItems`, { + name: calculationName, + shortName: calculationName, + expression: '#{fbfJHSPpUQD}/2', + }).then((response) => { + expect(response.status).to.eq(201) + + const calculationUid = response.body.response.uid + + // open thematic dialog + cy.getByDataTest('add-layer-button').click() + cy.getByDataTest('addlayeritem-thematic').click() + + // choose "Calculation" in item type + cy.getByDataTest('thematic-layer-value-type-select').click() + cy.contains('Calculations').click() + + // assert that the label on the Calculation select is "Calculation" + cy.getByDataTest('calculationselect-label').contains('Calculation') + + // click to open the calculation select + cy.getByDataTest('calculationselect').click() + + // check search box exists "Type to filter options" + cy.getByDataTest('dhis2-uicore-popper') + .find('input[type="text"]') + .should('have.attr', 'placeholder', 'Type to filter options') + + // search for something that doesn't exist + cy.getByDataTest('dhis2-uicore-popper') + .find('input[type="text"]') + .type('foo') + + cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper') + .contains('No options found') + .should('be.visible') + + // try search for something that exists + cy.getByDataTest('dhis2-uicore-popper') + .find('input[type="text"]') + .clear() + + cy.getByDataTest('dhis2-uicore-popper') + .find('input[type="text"]') + .type(calculationName) + + cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper') + .contains(calculationName) + .should('be.visible') + + // select the calculation and close dialog + cy.contains(calculationName).click() + + cy.getByDataTest('dhis2-uicore-modalactions') + .contains('Add layer') + .click() + + // check the layer card title + cy.getByDataTest('layercard') + .contains(calculationName, { timeout: 50000 }) + .should('be.visible') + + // check the map canvas is displayed + cy.get('canvas.maplibregl-canvas').should('be.visible') + + // delete the calculation + cy.request( + 'DELETE', + `${getApiBaseUrl()}/api/expressionDimensionItems/${calculationUid}` + ) + }) + }) }) diff --git a/i18n/en.pot b/i18n/en.pot index fbce2a3d2..86649bf58 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -17,6 +17,15 @@ msgstr "Map \"{{- name}}\" is saved." msgid "Failed to save map: {{message}}" msgstr "Failed to save map: {{message}}" +msgid "Calculation" +msgstr "Calculation" + +msgid "No calculations found" +msgstr "No calculations found" + +msgid "Calculations can be created in the Data Visualizer app." +msgstr "Calculations can be created in the Data Visualizer app." + msgid "Classification" msgstr "Classification" @@ -421,6 +430,9 @@ msgstr "Event data item is required" msgid "Program indicator is required" msgstr "Program indicator is required" +msgid "Calculation is required" +msgstr "Calculation is required" + msgid "Period is required" msgstr "Period is required" @@ -436,6 +448,9 @@ msgstr "Event data items" msgid "Program indicators" msgstr "Program indicators" +msgid "Calculations" +msgstr "Calculations" + msgid "Item type" msgstr "Item type" diff --git a/src/components/calculations/CalculationSelect.js b/src/components/calculations/CalculationSelect.js new file mode 100644 index 000000000..8bdc94ad6 --- /dev/null +++ b/src/components/calculations/CalculationSelect.js @@ -0,0 +1,62 @@ +import { useDataQuery } from '@dhis2/app-runtime' +import i18n from '@dhis2/d2-i18n' +import PropTypes from 'prop-types' +import React from 'react' +import { SelectField, Help } from '../core/index.js' +import { useUserSettings } from '../UserSettingsProvider.js' +import styles from './styles/CalculationSelect.module.css' + +// Load all calculations +const CALCULATIONS_QUERY = { + calculations: { + resource: 'expressionDimensionItems', + params: ({ nameProperty }) => ({ + fields: ['id', `${nameProperty}~rename(name)`], + paging: false, + }), + }, +} + +const CalculationSelect = ({ calculation, className, errorText, onChange }) => { + const { nameProperty } = useUserSettings() + const { loading, error, data } = useDataQuery(CALCULATIONS_QUERY, { + variables: { nameProperty }, + }) + + const items = data?.calculations.expressionDimensionItems + const value = calculation?.id + + return ( +
+ onChange(dataItem, 'calculation')} + className={className} + emptyText={i18n.t('No calculations found')} + errorText={ + error?.message || + (!calculation && errorText ? errorText : null) + } + filterable={true} + dataTest="calculationselect" + /> + + {i18n.t( + 'Calculations can be created in the Data Visualizer app.' + )} + +
+ ) +} + +CalculationSelect.propTypes = { + onChange: PropTypes.func.isRequired, + calculation: PropTypes.object, + className: PropTypes.string, + errorText: PropTypes.string, +} + +export default CalculationSelect diff --git a/src/components/calculations/styles/CalculationSelect.module.css b/src/components/calculations/styles/CalculationSelect.module.css new file mode 100644 index 000000000..d8cf160d2 --- /dev/null +++ b/src/components/calculations/styles/CalculationSelect.module.css @@ -0,0 +1,3 @@ +.calculationSelect { + margin-bottom: var(--spacers-dp16); +} diff --git a/src/components/core/SelectField.js b/src/components/core/SelectField.js index ecfed175d..fa21e24c9 100644 --- a/src/components/core/SelectField.js +++ b/src/components/core/SelectField.js @@ -17,6 +17,7 @@ import styles from './styles/InputField.module.css' const SelectField = (props) => { const { dense = true, + emptyText, errorText, helpText, warning, @@ -25,6 +26,7 @@ const SelectField = (props) => { prefix, loading, multiple, + filterable, disabled, onChange, className, @@ -65,12 +67,14 @@ const SelectField = (props) => { label={label} prefix={prefix} selected={!isLoading ? selected : undefined} + filterable={filterable} disabled={disabled} loading={isLoading} error={!!errorText} warning={!!warning} validationText={warning ? warning : errorText} helpText={helpText} + empty={emptyText} onChange={onSelectChange} dataTest={dataTest} > @@ -88,7 +92,9 @@ SelectField.propTypes = { dataTest: PropTypes.string, dense: PropTypes.bool, disabled: PropTypes.bool, + emptyText: PropTypes.string, // If set, shows empty text when no options errorText: PropTypes.string, // If set, shows the error message below the SelectField + filterable: PropTypes.bool, helpText: PropTypes.string, // If set, shows the help text below the SelectField items: PropTypes.arrayOf( PropTypes.shape({ diff --git a/src/components/edit/thematic/ThematicDialog.js b/src/components/edit/thematic/ThematicDialog.js index 263c4120f..7470902a9 100644 --- a/src/components/edit/thematic/ThematicDialog.js +++ b/src/components/edit/thematic/ThematicDialog.js @@ -36,6 +36,7 @@ import { } from '../../../util/analytics.js' import { isPeriodAvailable } from '../../../util/periods.js' import { getStartEndDateError } from '../../../util/time.js' +import CalculationSelect from '../../calculations/CalculationSelect.js' import NumericLegendStyle from '../../classification/NumericLegendStyle.js' import { Tab, Tabs } from '../../core/index.js' import DataElementGroupSelect from '../../dataElement/DataElementGroupSelect.js' @@ -255,6 +256,7 @@ class ThematicDialog extends Component { dataElementError, dataSetError, programError, + calculationError, eventDataItemError, programIndicatorError, periodTypeError, @@ -408,6 +410,14 @@ class ThematicDialog extends Component { /> ), ]} + {valueType === dimConf.calculation.objectName && ( + + )}
@@ -609,6 +619,14 @@ class ThematicDialog extends Component { } } + if (valueType === dimConf.calculation.objectName && !dataItem) { + return this.setErrorState( + 'calculationError', + i18n.t('Calculation is required'), + 'data' + ) + } + if (!period && periodType !== START_END_DATES) { return this.setErrorState( 'periodError', diff --git a/src/components/edit/thematic/ValueTypeSelect.js b/src/components/edit/thematic/ValueTypeSelect.js index 018b87ab8..0726f9b86 100644 --- a/src/components/edit/thematic/ValueTypeSelect.js +++ b/src/components/edit/thematic/ValueTypeSelect.js @@ -1,11 +1,29 @@ import i18n from '@dhis2/d2-i18n' import PropTypes from 'prop-types' -import React from 'react' +import React, { useMemo } from 'react' import { dimConf } from '../../../constants/dimension.js' import { SelectField } from '../../core/index.js' -const ValueTypeSelect = (props) => { - const { value, onChange, className } = props +const getValueTypes = () => [ + { id: dimConf.indicator.objectName, name: i18n.t('Indicator') }, + { id: dimConf.dataElement.objectName, name: i18n.t('Data element') }, + { id: dimConf.dataSet.objectName, name: i18n.t('Reporting rates') }, + { + id: dimConf.eventDataItem.objectName, + name: i18n.t('Event data items'), + }, + { + id: dimConf.programIndicator.objectName, + name: i18n.t('Program indicators'), + }, + { + id: dimConf.calculation.objectName, + name: i18n.t('Calculations'), + }, +] + +const ValueTypeSelect = ({ value, onChange, className }) => { + const items = useMemo(() => getValueTypes(), []) // If value type is data element operand, make it data element const type = @@ -13,21 +31,6 @@ const ValueTypeSelect = (props) => { ? dimConf.dataElement.objectName : value - // TODO: Avoid creating on each render (needs to be created after i18next contains translations - const items = [ - { id: dimConf.indicator.objectName, name: i18n.t('Indicator') }, - { id: dimConf.dataElement.objectName, name: i18n.t('Data element') }, - { id: dimConf.dataSet.objectName, name: i18n.t('Reporting rates') }, - { - id: dimConf.eventDataItem.objectName, - name: i18n.t('Event data items'), - }, - { - id: dimConf.programIndicator.objectName, - name: i18n.t('Program indicators'), - }, - ] - return ( { value={type} onChange={(valueType) => onChange(valueType.id)} className={className} + dataTest="thematic-layer-value-type-select" /> ) } diff --git a/src/components/layers/overlays/OverlayCard.js b/src/components/layers/overlays/OverlayCard.js index 7c1405dff..cfd1e86e3 100644 --- a/src/components/layers/overlays/OverlayCard.js +++ b/src/components/layers/overlays/OverlayCard.js @@ -105,7 +105,10 @@ const OverlayCard = ({ await set(currentAO) // Open it in another app - window.location.href = `${baseUrl}/${APP_URLS[type]}/#/currentAnalyticalObject` + window.open( + `${baseUrl}/${APP_URLS[type]}/#/currentAnalyticalObject`, + '_blank' + ) } : undefined } diff --git a/src/components/orgunits/OrgUnitData.js b/src/components/orgunits/OrgUnitData.js index bce650e02..4108d34d1 100644 --- a/src/components/orgunits/OrgUnitData.js +++ b/src/components/orgunits/OrgUnitData.js @@ -23,7 +23,7 @@ const ORGUNIT_PROFILE_QUERY = { // Only YEARLY period type is supported in first version const periodType = 'YEARLY' const currentYear = String(new Date().getFullYear()) -const periods = getFixedPeriodsByType(periodType, currentYear) +const periods = getFixedPeriodsByType({ periodType, currentYear }) const defaultPeriod = filterFuturePeriods(periods)[0] || periods[0] /* diff --git a/src/components/periods/PeriodSelect.js b/src/components/periods/PeriodSelect.js index f020e3ce4..f8261ac88 100644 --- a/src/components/periods/PeriodSelect.js +++ b/src/components/periods/PeriodSelect.js @@ -7,7 +7,8 @@ import { } from '@dhis2/ui' import cx from 'classnames' import PropTypes from 'prop-types' -import React, { Component } from 'react' +import React, { useState, useMemo, useCallback, useEffect } from 'react' +import usePrevious from '../../hooks/usePrevious.js' import { getFixedPeriodsByType, filterFuturePeriods, @@ -16,124 +17,118 @@ import { getYear } from '../../util/time.js' import { SelectField } from '../core/index.js' import styles from './styles/PeriodSelect.module.css' -class PeriodSelect extends Component { - static propTypes = { - onChange: PropTypes.func.isRequired, - className: PropTypes.string, - errorText: PropTypes.string, - period: PropTypes.shape({ - id: PropTypes.string.isRequired, - startDate: PropTypes.string, - }), - periodType: PropTypes.string, - } - - state = { - year: null, - periods: null, - } - - componentDidMount() { - this.setPeriods() - } - - componentDidUpdate(prevProps, prevState) { - const { periodType, period, onChange } = this.props - const { year, periods } = this.state - - if (periodType !== prevProps.periodType) { - this.setPeriods() - } else if (periods && !period) { - onChange(filterFuturePeriods(periods)[0] || periods[0]) // Autoselect most recent period - } - - // Change period if year is changed (but keep period index) - if (period && prevState.periods && year !== prevState.year) { - const periodIndex = prevState.periods.findIndex( - (item) => item.id === period.id - ) - onChange(periods[periodIndex]) - } - } - - render() { - const { periodType, period, onChange, className, errorText } = - this.props - const { periods } = this.state - - if (!periods) { - return null +const PeriodSelect = ({ + onChange, + className, + errorText, + firstDate, + lastDate, + period, + periodType, +}) => { + const [year, setYear] = useState(getYear(period?.startDate || lastDate)) + const prevYear = usePrevious(year) + + // Set periods when periodType or year changes + /* eslint-disable react-hooks/exhaustive-deps */ + const periods = useMemo( + () => + periodType + ? getFixedPeriodsByType({ + periodType, + year, + firstDate, + lastDate, + }) + : [period], // saved map period (not included in depency array by design) + [periodType, year, firstDate, lastDate] + ) + /* eslint-enable react-hooks/exhaustive-deps */ + + // Increment/decrement year + const changeYear = useCallback( + (change) => { + const newYear = year + change + + if ( + (!firstDate || newYear >= getYear(firstDate)) && + (!lastDate || newYear <= getYear(lastDate)) + ) { + setYear(newYear) + } + }, + [year, firstDate, lastDate] + ) + + // Autoselect most recent period + useEffect(() => { + if (!period) { + onChange(filterFuturePeriods(periods)[0] || periods[0]) } + }, [period, periods, year, onChange]) - const value = - period && periods.some((p) => p.id === period.id) ? period.id : null - - return ( -
- - {periodType && ( -
- -
- )} -
- ) - } - - setPeriods() { - const { periodType, period } = this.props - const year = this.state.year || getYear(period && period.startDate) - let periods + // Keep the same period position when year changes + useEffect(() => { + if (period && !periods.some((p) => p.id === period.id)) { + const periodId = period.id.replace(prevYear, year) - if (periodType) { - periods = getFixedPeriodsByType(periodType, year) - } else if (period) { - periods = [period] // If period is loaded in favorite + onChange(periods.find((p) => p.id === periodId)) } + }, [period, periods, year, prevYear, onChange]) - this.setState({ periods, year }) + if (!periods) { + return null } - nextYear = () => { - this.changeYear(1) - } - - previousYear = () => { - this.changeYear(-1) - } - - changeYear = (change) => { - const { periodType } = this.props - const year = this.state.year + change + const value = + period && periods.some((p) => p.id === period.id) ? period.id : null + + return ( +
+ + {periodType && ( +
+ +
+ )} +
+ ) +} - this.setState({ - year, - periods: getFixedPeriodsByType(periodType, year), - }) - } +PeriodSelect.propTypes = { + onChange: PropTypes.func.isRequired, + className: PropTypes.string, + errorText: PropTypes.string, + firstDate: PropTypes.string, + lastDate: PropTypes.string, + period: PropTypes.shape({ + id: PropTypes.string.isRequired, + startDate: PropTypes.string, + }), + periodType: PropTypes.string, } export default PeriodSelect diff --git a/src/constants/dimension.js b/src/constants/dimension.js index 16b6d48ae..3834de2b0 100644 --- a/src/constants/dimension.js +++ b/src/constants/dimension.js @@ -64,6 +64,12 @@ export const dimConf = { objectName: 'pi', itemType: 'PROGRAM_INDICATOR', }, + calculation: { + value: 'expressionDimensionItems', + dimensionName: 'dx', + objectName: 'ed', // Created by Bjorn, don't seem to be in use when the map is saved + itemType: 'EXPRESSION_DIMENSION_ITEM', + }, period: { id: 'period', value: 'period', diff --git a/src/util/periods.js b/src/util/periods.js index 366633e8a..777ab1bd6 100644 --- a/src/util/periods.js +++ b/src/util/periods.js @@ -6,23 +6,41 @@ import { periodTypes, periodGroups } from '../constants/periods.js' const getYearOffsetFromNow = (year) => year - new Date(Date.now()).getFullYear() +const filterPeriods = (periods, firstDate, lastDate) => + periods.filter( + (p) => + (!firstDate || p.startDate >= firstDate) && + (!lastDate || p.endDate <= lastDate) + ) + export const getPeriodTypes = (hiddenPeriods = []) => periodTypes().filter(({ group }) => !hiddenPeriods.includes(group)) -export const getFixedPeriodsByType = (periodType, year) => { +export const getFixedPeriodsByType = ({ + periodType, + year, + firstDate, + lastDate, +}) => { const period = getFixedPeriodsOptionsById(periodType) const forceDescendingForYearTypes = !!periodType.match(/^FY|YEARLY/) const offset = getYearOffsetFromNow(year) - const periods = period?.getPeriods({ offset, reversePeriods: true }) || null - if (periods && forceDescendingForYearTypes) { - // TODO: the reverse() is a workaround for a bug in the analytics - // getPeriods function that no longer correctly reverses the order - // for YEARLY and FY period types - return periods.reverse() + let periods = period?.getPeriods({ offset, reversePeriods: true }) + + if (!periods) { + return null } - return periods + + if (firstDate || lastDate) { + periods = filterPeriods(periods, firstDate, lastDate) + } + + // TODO: the reverse() is a workaround for a bug in the analytics + // getPeriods function that no longer correctly reverses the order + // for YEARLY and FY period types + return forceDescendingForYearTypes ? periods.reverse() : periods } export const getRelativePeriods = (hiddenPeriods = []) => @@ -46,7 +64,7 @@ export const getPeriodNames = () => ({ }, {}), }) -export const filterFuturePeriods = (periods) => { - const now = new Date(Date.now()) +export const filterFuturePeriods = (periods, date) => { + const now = new Date(date || Date.now()) return periods.filter(({ startDate }) => new Date(startDate) < now) } From 6cd3a0357a2ac9d59ab80fa3da74b09450d68d0c Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Fri, 15 Sep 2023 14:06:47 +0200 Subject: [PATCH 04/11] chore: send success message to slack when release succeeds (#2954) Be alerted to release success as well as failure in the analytics-internal-bot slack channel. --- .github/workflows/dhis2-verify-app.yml | 57 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dhis2-verify-app.yml b/.github/workflows/dhis2-verify-app.yml index 2de2d79b7..72c88d2d3 100644 --- a/.github/workflows/dhis2-verify-app.yml +++ b/.github/workflows/dhis2-verify-app.yml @@ -126,11 +126,66 @@ jobs: !cancelled() && github.ref == 'refs/heads/master' steps: + - name: Checkout code + uses: actions/checkout@master + + - name: Extract version + id: extract_version + uses: Saionaro/extract-package-version@v1.2.1 + - name: Send failure message to analytics-internal-bot slack channel id: slack uses: slackapi/slack-github-action@v1.23.0 with: channel-id: ${{ secrets.SLACK_CHANNEL_ID }} - slack-message: ':small_red_triangle_down: Maps-app release ' + payload: | + { + "text": ":small_red_triangle_down: :maps-app: Maps version ${{ steps.extract_version.outputs.version }} release ", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":small_red_triangle_down: :maps-app: Maps version ${{ steps.extract_version.outputs.version }} release " + } + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + + report-release-success: + runs-on: ubuntu-latest + needs: release + if: | + success() && + !cancelled() && + github.ref == 'refs/heads/master' + steps: + - name: Checkout code + uses: actions/checkout@master + + - name: Extract version + id: extract_version + uses: Saionaro/extract-package-version@v1.2.1 + + - name: Send success message to analytics-internal-bot slack channel + id: slack + uses: slackapi/slack-github-action@v1.23.0 + with: + channel-id: ${{ secrets.SLACK_CHANNEL_ID }} + payload: | + { + "text": ":large_green_circle: :maps-app: :tada: Maps app release succeeded for version: ${{ steps.extract_version.outputs.version }}", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ":large_green_circle: :maps-app: :tada: Maps version ${{ steps.extract_version.outputs.version }} released " + } + } + ] + } env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} From bfff4ab2a4036c3afce74bda58e24bc77504edbd Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Sat, 16 Sep 2023 03:33:47 +0200 Subject: [PATCH 05/11] fix(translations): sync translations from transifex (dev) Automatically merged. --- i18n/cs.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/cs.po b/i18n/cs.po index 367119c09..4e7ea0aad 100644 --- a/i18n/cs.po +++ b/i18n/cs.po @@ -28,10 +28,10 @@ msgid "Calculation" msgstr "Výpočet" msgid "No calculations found" -msgstr "" +msgstr "Nenalezeny žádné výpočty" msgid "Calculations can be created in the Data Visualizer app." -msgstr "" +msgstr "Výpočty lze vytvářet v aplikaci Data Visualizer." msgid "Classification" msgstr "Klasifikace" @@ -445,7 +445,7 @@ msgid "Program indicator is required" msgstr "Je vyžadován indikátor programu" msgid "Calculation is required" -msgstr "" +msgstr "Je vyžadován výpočet" msgid "Period is required" msgstr "Období je vyžadováno" @@ -1305,7 +1305,7 @@ msgid "You don't have access to this layer data" msgstr "K datům této vrstvy nemáte přístup" msgid "The event filter is not supported" -msgstr "" +msgstr "Filtr událostí není podporován" msgid "An unknown error occurred while reading layer data" msgstr "Při čtení dat vrstvy došlo k neznámé chybě" From 1ec1b5cac53d2f36a80201a258fe99757523ab15 Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Tue, 19 Sep 2023 03:37:03 +0200 Subject: [PATCH 06/11] fix(translations): sync translations from transifex (dev) Automatically merged. --- i18n/zh.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/i18n/zh.po b/i18n/zh.po index 8195b7435..f05ab5b05 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -19,7 +19,7 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" msgid "Untitled map, {{date}}" -msgstr "无标题地图,{{日期}}" +msgstr "无标题地图,{{date}}" msgid "Map \"{{- name}}\" is saved." msgstr "地图“{{- name}}”已保存。" @@ -28,13 +28,13 @@ msgid "Failed to save map: {{message}}" msgstr "无法保存地图:{{message}}" msgid "Calculation" -msgstr "" +msgstr "计算" msgid "No calculations found" -msgstr "" +msgstr "没有找到计算结果" msgid "Calculations can be created in the Data Visualizer app." -msgstr "" +msgstr "可以在数据可视化工具应用程序中创建计算。" msgid "Classification" msgstr "分类" @@ -439,7 +439,7 @@ msgid "Program indicator is required" msgstr "需要项目指标" msgid "Calculation is required" -msgstr "" +msgstr "需要计算" msgid "Period is required" msgstr "需要期间" @@ -457,7 +457,7 @@ msgid "Program indicators" msgstr "项目指标" msgid "Calculations" -msgstr "" +msgstr "计算" msgid "Item type" msgstr "条目类型" @@ -1276,7 +1276,7 @@ msgid "You don't have access to this layer data" msgstr "您无权访问此图层数据" msgid "The event filter is not supported" -msgstr "" +msgstr "不支持事件过滤器" msgid "An unknown error occurred while reading layer data" msgstr "读取图层数据时发生未知错误" From c171b3d26189206e546361911e31f887082ee136 Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 25 Sep 2023 09:28:46 +0200 Subject: [PATCH 07/11] fix: accept both lowercase and camelCase interpretationId in url(#2937) Needed for: https://dhis2.atlassian.net/browse/DHIS2-15441 The analytics interpretation component sends a camelcase interpretationId url parameter. This same format is used in DV and LL. Including both lowercase and camelcase ensures that this version of maps isn't dependent on also having the updated dashboard app --- src/components/interpretations/Interpretations.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/interpretations/Interpretations.js b/src/components/interpretations/Interpretations.js index ef7cb361c..c937e5ef9 100644 --- a/src/components/interpretations/Interpretations.js +++ b/src/components/interpretations/Interpretations.js @@ -15,7 +15,10 @@ const Interpretations = ({ renderCount }) => { useEffect(() => { if (isMapLoaded) { - const urlInterpretationId = getUrlParameter('interpretationid') + // analytics interpretation component uses camelcase + const urlInterpretationId = + getUrlParameter('interpretationid') || + getUrlParameter('interpretationId') if (urlInterpretationId) { dispatch(setInterpretation(urlInterpretationId)) From 202fae08f7082dccc18b5589e24ece01e0ae27ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 13:49:48 +0200 Subject: [PATCH 08/11] chore(deps-dev): bump start-server-and-test from 1.15.5 to 2.0.1 (#2980) Bumps [start-server-and-test](https://github.com/bahmutov/start-server-and-test) from 1.15.5 to 2.0.1. - [Release notes](https://github.com/bahmutov/start-server-and-test/releases) - [Commits](https://github.com/bahmutov/start-server-and-test/compare/v1.15.5...v2.0.1) --- updated-dependencies: - dependency-name: start-server-and-test dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 66e6d4cd0..92113ed13 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "patch-package": "^6.5.1", "redux-devtools": "^3.7.0", "redux-mock-store": "^1.5.4", - "start-server-and-test": "^1.15.4" + "start-server-and-test": "^2.0.1" }, "dependencies": { "@dhis2/analytics": "^26.0.17", diff --git a/yarn.lock b/yarn.lock index 11fbd9bda..eb6b06666 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14376,10 +14376,10 @@ stackframe@^1.3.4: resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== -start-server-and-test@^1.15.4: - version "1.15.5" - resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.15.5.tgz#5c9103bd87c06678fc62658fbe97d09501714011" - integrity sha512-o3EmkX0++GV+qsvIJ/OKWm3w91fD8uS/bPQVPrh/7loaxkpXSuAIHdnmN/P/regQK9eNAK76aBJcHt+OSTk+nA== +start-server-and-test@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-2.0.1.tgz#e110e0b5a54c80963f65b9689c2c320ab8ac9025" + integrity sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ== dependencies: arg "^5.0.2" bluebird "3.7.2" From f532a81463e1842a3e3aa938497505d290be028a Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Mon, 25 Sep 2023 16:25:09 +0200 Subject: [PATCH 09/11] revert: "chore: fixed period select refactor (#2958)" (#2984) This reverts commit 8fdd67eb0b57e3c185cda9da3486d727dc2a64c7. --- .../integration/layers/thematiclayer.cy.js | 81 +------ i18n/en.pot | 15 -- .../calculations/CalculationSelect.js | 62 ----- .../styles/CalculationSelect.module.css | 3 - src/components/core/SelectField.js | 6 - .../edit/thematic/ThematicDialog.js | 18 -- .../edit/thematic/ValueTypeSelect.js | 40 ++-- src/components/layers/overlays/OverlayCard.js | 5 +- src/components/orgunits/OrgUnitData.js | 2 +- src/components/periods/PeriodSelect.js | 217 +++++++++--------- src/constants/dimension.js | 6 - src/util/periods.js | 38 +-- 12 files changed, 142 insertions(+), 351 deletions(-) delete mode 100644 src/components/calculations/CalculationSelect.js delete mode 100644 src/components/calculations/styles/CalculationSelect.module.css diff --git a/cypress/integration/layers/thematiclayer.cy.js b/cypress/integration/layers/thematiclayer.cy.js index 4dacacc0b..d9966fc7d 100644 --- a/cypress/integration/layers/thematiclayer.cy.js +++ b/cypress/integration/layers/thematiclayer.cy.js @@ -6,7 +6,7 @@ import { expectContextMenuOptions, } from '../../elements/map_context_menu.js' import { ThematicLayer } from '../../elements/thematic_layer.js' -import { CURRENT_YEAR, getApiBaseUrl } from '../../support/util.js' +import { CURRENT_YEAR } from '../../support/util.js' const INDICATOR_NAME = 'VCCT post-test counselling rate' @@ -136,83 +136,4 @@ context('Thematic Layers', () => { { name: VIEW_PROFILE }, ]) }) - - // TODO - update demo database with calculations instead of creating on the fly - it('adds a thematic layer with a calculation', () => { - const timestamp = new Date().toUTCString().slice(-24, -4) - const calculationName = `map calc ${timestamp}` - - // add a calculation - cy.request('POST', `${getApiBaseUrl()}/api/expressionDimensionItems`, { - name: calculationName, - shortName: calculationName, - expression: '#{fbfJHSPpUQD}/2', - }).then((response) => { - expect(response.status).to.eq(201) - - const calculationUid = response.body.response.uid - - // open thematic dialog - cy.getByDataTest('add-layer-button').click() - cy.getByDataTest('addlayeritem-thematic').click() - - // choose "Calculation" in item type - cy.getByDataTest('thematic-layer-value-type-select').click() - cy.contains('Calculations').click() - - // assert that the label on the Calculation select is "Calculation" - cy.getByDataTest('calculationselect-label').contains('Calculation') - - // click to open the calculation select - cy.getByDataTest('calculationselect').click() - - // check search box exists "Type to filter options" - cy.getByDataTest('dhis2-uicore-popper') - .find('input[type="text"]') - .should('have.attr', 'placeholder', 'Type to filter options') - - // search for something that doesn't exist - cy.getByDataTest('dhis2-uicore-popper') - .find('input[type="text"]') - .type('foo') - - cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper') - .contains('No options found') - .should('be.visible') - - // try search for something that exists - cy.getByDataTest('dhis2-uicore-popper') - .find('input[type="text"]') - .clear() - - cy.getByDataTest('dhis2-uicore-popper') - .find('input[type="text"]') - .type(calculationName) - - cy.getByDataTest('dhis2-uicore-select-menu-menuwrapper') - .contains(calculationName) - .should('be.visible') - - // select the calculation and close dialog - cy.contains(calculationName).click() - - cy.getByDataTest('dhis2-uicore-modalactions') - .contains('Add layer') - .click() - - // check the layer card title - cy.getByDataTest('layercard') - .contains(calculationName, { timeout: 50000 }) - .should('be.visible') - - // check the map canvas is displayed - cy.get('canvas.maplibregl-canvas').should('be.visible') - - // delete the calculation - cy.request( - 'DELETE', - `${getApiBaseUrl()}/api/expressionDimensionItems/${calculationUid}` - ) - }) - }) }) diff --git a/i18n/en.pot b/i18n/en.pot index 86649bf58..fbce2a3d2 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -17,15 +17,6 @@ msgstr "Map \"{{- name}}\" is saved." msgid "Failed to save map: {{message}}" msgstr "Failed to save map: {{message}}" -msgid "Calculation" -msgstr "Calculation" - -msgid "No calculations found" -msgstr "No calculations found" - -msgid "Calculations can be created in the Data Visualizer app." -msgstr "Calculations can be created in the Data Visualizer app." - msgid "Classification" msgstr "Classification" @@ -430,9 +421,6 @@ msgstr "Event data item is required" msgid "Program indicator is required" msgstr "Program indicator is required" -msgid "Calculation is required" -msgstr "Calculation is required" - msgid "Period is required" msgstr "Period is required" @@ -448,9 +436,6 @@ msgstr "Event data items" msgid "Program indicators" msgstr "Program indicators" -msgid "Calculations" -msgstr "Calculations" - msgid "Item type" msgstr "Item type" diff --git a/src/components/calculations/CalculationSelect.js b/src/components/calculations/CalculationSelect.js deleted file mode 100644 index 8bdc94ad6..000000000 --- a/src/components/calculations/CalculationSelect.js +++ /dev/null @@ -1,62 +0,0 @@ -import { useDataQuery } from '@dhis2/app-runtime' -import i18n from '@dhis2/d2-i18n' -import PropTypes from 'prop-types' -import React from 'react' -import { SelectField, Help } from '../core/index.js' -import { useUserSettings } from '../UserSettingsProvider.js' -import styles from './styles/CalculationSelect.module.css' - -// Load all calculations -const CALCULATIONS_QUERY = { - calculations: { - resource: 'expressionDimensionItems', - params: ({ nameProperty }) => ({ - fields: ['id', `${nameProperty}~rename(name)`], - paging: false, - }), - }, -} - -const CalculationSelect = ({ calculation, className, errorText, onChange }) => { - const { nameProperty } = useUserSettings() - const { loading, error, data } = useDataQuery(CALCULATIONS_QUERY, { - variables: { nameProperty }, - }) - - const items = data?.calculations.expressionDimensionItems - const value = calculation?.id - - return ( -
- onChange(dataItem, 'calculation')} - className={className} - emptyText={i18n.t('No calculations found')} - errorText={ - error?.message || - (!calculation && errorText ? errorText : null) - } - filterable={true} - dataTest="calculationselect" - /> - - {i18n.t( - 'Calculations can be created in the Data Visualizer app.' - )} - -
- ) -} - -CalculationSelect.propTypes = { - onChange: PropTypes.func.isRequired, - calculation: PropTypes.object, - className: PropTypes.string, - errorText: PropTypes.string, -} - -export default CalculationSelect diff --git a/src/components/calculations/styles/CalculationSelect.module.css b/src/components/calculations/styles/CalculationSelect.module.css deleted file mode 100644 index d8cf160d2..000000000 --- a/src/components/calculations/styles/CalculationSelect.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.calculationSelect { - margin-bottom: var(--spacers-dp16); -} diff --git a/src/components/core/SelectField.js b/src/components/core/SelectField.js index fa21e24c9..ecfed175d 100644 --- a/src/components/core/SelectField.js +++ b/src/components/core/SelectField.js @@ -17,7 +17,6 @@ import styles from './styles/InputField.module.css' const SelectField = (props) => { const { dense = true, - emptyText, errorText, helpText, warning, @@ -26,7 +25,6 @@ const SelectField = (props) => { prefix, loading, multiple, - filterable, disabled, onChange, className, @@ -67,14 +65,12 @@ const SelectField = (props) => { label={label} prefix={prefix} selected={!isLoading ? selected : undefined} - filterable={filterable} disabled={disabled} loading={isLoading} error={!!errorText} warning={!!warning} validationText={warning ? warning : errorText} helpText={helpText} - empty={emptyText} onChange={onSelectChange} dataTest={dataTest} > @@ -92,9 +88,7 @@ SelectField.propTypes = { dataTest: PropTypes.string, dense: PropTypes.bool, disabled: PropTypes.bool, - emptyText: PropTypes.string, // If set, shows empty text when no options errorText: PropTypes.string, // If set, shows the error message below the SelectField - filterable: PropTypes.bool, helpText: PropTypes.string, // If set, shows the help text below the SelectField items: PropTypes.arrayOf( PropTypes.shape({ diff --git a/src/components/edit/thematic/ThematicDialog.js b/src/components/edit/thematic/ThematicDialog.js index 7470902a9..263c4120f 100644 --- a/src/components/edit/thematic/ThematicDialog.js +++ b/src/components/edit/thematic/ThematicDialog.js @@ -36,7 +36,6 @@ import { } from '../../../util/analytics.js' import { isPeriodAvailable } from '../../../util/periods.js' import { getStartEndDateError } from '../../../util/time.js' -import CalculationSelect from '../../calculations/CalculationSelect.js' import NumericLegendStyle from '../../classification/NumericLegendStyle.js' import { Tab, Tabs } from '../../core/index.js' import DataElementGroupSelect from '../../dataElement/DataElementGroupSelect.js' @@ -256,7 +255,6 @@ class ThematicDialog extends Component { dataElementError, dataSetError, programError, - calculationError, eventDataItemError, programIndicatorError, periodTypeError, @@ -410,14 +408,6 @@ class ThematicDialog extends Component { /> ), ]} - {valueType === dimConf.calculation.objectName && ( - - )}
@@ -619,14 +609,6 @@ class ThematicDialog extends Component { } } - if (valueType === dimConf.calculation.objectName && !dataItem) { - return this.setErrorState( - 'calculationError', - i18n.t('Calculation is required'), - 'data' - ) - } - if (!period && periodType !== START_END_DATES) { return this.setErrorState( 'periodError', diff --git a/src/components/edit/thematic/ValueTypeSelect.js b/src/components/edit/thematic/ValueTypeSelect.js index 0726f9b86..018b87ab8 100644 --- a/src/components/edit/thematic/ValueTypeSelect.js +++ b/src/components/edit/thematic/ValueTypeSelect.js @@ -1,29 +1,11 @@ import i18n from '@dhis2/d2-i18n' import PropTypes from 'prop-types' -import React, { useMemo } from 'react' +import React from 'react' import { dimConf } from '../../../constants/dimension.js' import { SelectField } from '../../core/index.js' -const getValueTypes = () => [ - { id: dimConf.indicator.objectName, name: i18n.t('Indicator') }, - { id: dimConf.dataElement.objectName, name: i18n.t('Data element') }, - { id: dimConf.dataSet.objectName, name: i18n.t('Reporting rates') }, - { - id: dimConf.eventDataItem.objectName, - name: i18n.t('Event data items'), - }, - { - id: dimConf.programIndicator.objectName, - name: i18n.t('Program indicators'), - }, - { - id: dimConf.calculation.objectName, - name: i18n.t('Calculations'), - }, -] - -const ValueTypeSelect = ({ value, onChange, className }) => { - const items = useMemo(() => getValueTypes(), []) +const ValueTypeSelect = (props) => { + const { value, onChange, className } = props // If value type is data element operand, make it data element const type = @@ -31,6 +13,21 @@ const ValueTypeSelect = ({ value, onChange, className }) => { ? dimConf.dataElement.objectName : value + // TODO: Avoid creating on each render (needs to be created after i18next contains translations + const items = [ + { id: dimConf.indicator.objectName, name: i18n.t('Indicator') }, + { id: dimConf.dataElement.objectName, name: i18n.t('Data element') }, + { id: dimConf.dataSet.objectName, name: i18n.t('Reporting rates') }, + { + id: dimConf.eventDataItem.objectName, + name: i18n.t('Event data items'), + }, + { + id: dimConf.programIndicator.objectName, + name: i18n.t('Program indicators'), + }, + ] + return ( { value={type} onChange={(valueType) => onChange(valueType.id)} className={className} - dataTest="thematic-layer-value-type-select" /> ) } diff --git a/src/components/layers/overlays/OverlayCard.js b/src/components/layers/overlays/OverlayCard.js index cfd1e86e3..7c1405dff 100644 --- a/src/components/layers/overlays/OverlayCard.js +++ b/src/components/layers/overlays/OverlayCard.js @@ -105,10 +105,7 @@ const OverlayCard = ({ await set(currentAO) // Open it in another app - window.open( - `${baseUrl}/${APP_URLS[type]}/#/currentAnalyticalObject`, - '_blank' - ) + window.location.href = `${baseUrl}/${APP_URLS[type]}/#/currentAnalyticalObject` } : undefined } diff --git a/src/components/orgunits/OrgUnitData.js b/src/components/orgunits/OrgUnitData.js index 4108d34d1..bce650e02 100644 --- a/src/components/orgunits/OrgUnitData.js +++ b/src/components/orgunits/OrgUnitData.js @@ -23,7 +23,7 @@ const ORGUNIT_PROFILE_QUERY = { // Only YEARLY period type is supported in first version const periodType = 'YEARLY' const currentYear = String(new Date().getFullYear()) -const periods = getFixedPeriodsByType({ periodType, currentYear }) +const periods = getFixedPeriodsByType(periodType, currentYear) const defaultPeriod = filterFuturePeriods(periods)[0] || periods[0] /* diff --git a/src/components/periods/PeriodSelect.js b/src/components/periods/PeriodSelect.js index f8261ac88..f020e3ce4 100644 --- a/src/components/periods/PeriodSelect.js +++ b/src/components/periods/PeriodSelect.js @@ -7,8 +7,7 @@ import { } from '@dhis2/ui' import cx from 'classnames' import PropTypes from 'prop-types' -import React, { useState, useMemo, useCallback, useEffect } from 'react' -import usePrevious from '../../hooks/usePrevious.js' +import React, { Component } from 'react' import { getFixedPeriodsByType, filterFuturePeriods, @@ -17,118 +16,124 @@ import { getYear } from '../../util/time.js' import { SelectField } from '../core/index.js' import styles from './styles/PeriodSelect.module.css' -const PeriodSelect = ({ - onChange, - className, - errorText, - firstDate, - lastDate, - period, - periodType, -}) => { - const [year, setYear] = useState(getYear(period?.startDate || lastDate)) - const prevYear = usePrevious(year) - - // Set periods when periodType or year changes - /* eslint-disable react-hooks/exhaustive-deps */ - const periods = useMemo( - () => - periodType - ? getFixedPeriodsByType({ - periodType, - year, - firstDate, - lastDate, - }) - : [period], // saved map period (not included in depency array by design) - [periodType, year, firstDate, lastDate] - ) - /* eslint-enable react-hooks/exhaustive-deps */ - - // Increment/decrement year - const changeYear = useCallback( - (change) => { - const newYear = year + change - - if ( - (!firstDate || newYear >= getYear(firstDate)) && - (!lastDate || newYear <= getYear(lastDate)) - ) { - setYear(newYear) - } - }, - [year, firstDate, lastDate] - ) - - // Autoselect most recent period - useEffect(() => { - if (!period) { - onChange(filterFuturePeriods(periods)[0] || periods[0]) +class PeriodSelect extends Component { + static propTypes = { + onChange: PropTypes.func.isRequired, + className: PropTypes.string, + errorText: PropTypes.string, + period: PropTypes.shape({ + id: PropTypes.string.isRequired, + startDate: PropTypes.string, + }), + periodType: PropTypes.string, + } + + state = { + year: null, + periods: null, + } + + componentDidMount() { + this.setPeriods() + } + + componentDidUpdate(prevProps, prevState) { + const { periodType, period, onChange } = this.props + const { year, periods } = this.state + + if (periodType !== prevProps.periodType) { + this.setPeriods() + } else if (periods && !period) { + onChange(filterFuturePeriods(periods)[0] || periods[0]) // Autoselect most recent period + } + + // Change period if year is changed (but keep period index) + if (period && prevState.periods && year !== prevState.year) { + const periodIndex = prevState.periods.findIndex( + (item) => item.id === period.id + ) + onChange(periods[periodIndex]) + } + } + + render() { + const { periodType, period, onChange, className, errorText } = + this.props + const { periods } = this.state + + if (!periods) { + return null } - }, [period, periods, year, onChange]) - // Keep the same period position when year changes - useEffect(() => { - if (period && !periods.some((p) => p.id === period.id)) { - const periodId = period.id.replace(prevYear, year) + const value = + period && periods.some((p) => p.id === period.id) ? period.id : null + + return ( +
+ + {periodType && ( +
+ +
+ )} +
+ ) + } + + setPeriods() { + const { periodType, period } = this.props + const year = this.state.year || getYear(period && period.startDate) + let periods - onChange(periods.find((p) => p.id === periodId)) + if (periodType) { + periods = getFixedPeriodsByType(periodType, year) + } else if (period) { + periods = [period] // If period is loaded in favorite } - }, [period, periods, year, prevYear, onChange]) - if (!periods) { - return null + this.setState({ periods, year }) } - const value = - period && periods.some((p) => p.id === period.id) ? period.id : null - - return ( -
- - {periodType && ( -
- -
- )} -
- ) -} + nextYear = () => { + this.changeYear(1) + } + + previousYear = () => { + this.changeYear(-1) + } -PeriodSelect.propTypes = { - onChange: PropTypes.func.isRequired, - className: PropTypes.string, - errorText: PropTypes.string, - firstDate: PropTypes.string, - lastDate: PropTypes.string, - period: PropTypes.shape({ - id: PropTypes.string.isRequired, - startDate: PropTypes.string, - }), - periodType: PropTypes.string, + changeYear = (change) => { + const { periodType } = this.props + const year = this.state.year + change + + this.setState({ + year, + periods: getFixedPeriodsByType(periodType, year), + }) + } } export default PeriodSelect diff --git a/src/constants/dimension.js b/src/constants/dimension.js index 3834de2b0..16b6d48ae 100644 --- a/src/constants/dimension.js +++ b/src/constants/dimension.js @@ -64,12 +64,6 @@ export const dimConf = { objectName: 'pi', itemType: 'PROGRAM_INDICATOR', }, - calculation: { - value: 'expressionDimensionItems', - dimensionName: 'dx', - objectName: 'ed', // Created by Bjorn, don't seem to be in use when the map is saved - itemType: 'EXPRESSION_DIMENSION_ITEM', - }, period: { id: 'period', value: 'period', diff --git a/src/util/periods.js b/src/util/periods.js index 777ab1bd6..366633e8a 100644 --- a/src/util/periods.js +++ b/src/util/periods.js @@ -6,41 +6,23 @@ import { periodTypes, periodGroups } from '../constants/periods.js' const getYearOffsetFromNow = (year) => year - new Date(Date.now()).getFullYear() -const filterPeriods = (periods, firstDate, lastDate) => - periods.filter( - (p) => - (!firstDate || p.startDate >= firstDate) && - (!lastDate || p.endDate <= lastDate) - ) - export const getPeriodTypes = (hiddenPeriods = []) => periodTypes().filter(({ group }) => !hiddenPeriods.includes(group)) -export const getFixedPeriodsByType = ({ - periodType, - year, - firstDate, - lastDate, -}) => { +export const getFixedPeriodsByType = (periodType, year) => { const period = getFixedPeriodsOptionsById(periodType) const forceDescendingForYearTypes = !!periodType.match(/^FY|YEARLY/) const offset = getYearOffsetFromNow(year) - let periods = period?.getPeriods({ offset, reversePeriods: true }) - - if (!periods) { - return null + const periods = period?.getPeriods({ offset, reversePeriods: true }) || null + if (periods && forceDescendingForYearTypes) { + // TODO: the reverse() is a workaround for a bug in the analytics + // getPeriods function that no longer correctly reverses the order + // for YEARLY and FY period types + return periods.reverse() } - - if (firstDate || lastDate) { - periods = filterPeriods(periods, firstDate, lastDate) - } - - // TODO: the reverse() is a workaround for a bug in the analytics - // getPeriods function that no longer correctly reverses the order - // for YEARLY and FY period types - return forceDescendingForYearTypes ? periods.reverse() : periods + return periods } export const getRelativePeriods = (hiddenPeriods = []) => @@ -64,7 +46,7 @@ export const getPeriodNames = () => ({ }, {}), }) -export const filterFuturePeriods = (periods, date) => { - const now = new Date(date || Date.now()) +export const filterFuturePeriods = (periods) => { + const now = new Date(Date.now()) return periods.filter(({ startDate }) => new Date(startDate) < now) } From af3183cb28928d5a2f862b13a57c45377d136b8b Mon Sep 17 00:00:00 2001 From: "@dhis2-bot" Date: Tue, 26 Sep 2023 03:37:31 +0200 Subject: [PATCH 10/11] fix(translations): sync translations from transifex (dev) Automatically merged. --- i18n/cs.po | 15 --------------- i18n/es.po | 15 --------------- i18n/zh.po | 15 --------------- 3 files changed, 45 deletions(-) diff --git a/i18n/cs.po b/i18n/cs.po index 4e7ea0aad..74f0ce52e 100644 --- a/i18n/cs.po +++ b/i18n/cs.po @@ -24,15 +24,6 @@ msgstr "Mapa \"{{- name}}\" je uložena." msgid "Failed to save map: {{message}}" msgstr "Nepodařilo se uložit mapu: {{message}}" -msgid "Calculation" -msgstr "Výpočet" - -msgid "No calculations found" -msgstr "Nenalezeny žádné výpočty" - -msgid "Calculations can be created in the Data Visualizer app." -msgstr "Výpočty lze vytvářet v aplikaci Data Visualizer." - msgid "Classification" msgstr "Klasifikace" @@ -444,9 +435,6 @@ msgstr "Položka dat události je povinná" msgid "Program indicator is required" msgstr "Je vyžadován indikátor programu" -msgid "Calculation is required" -msgstr "Je vyžadován výpočet" - msgid "Period is required" msgstr "Období je vyžadováno" @@ -462,9 +450,6 @@ msgstr "Položky dat události" msgid "Program indicators" msgstr "Ukazatele programu" -msgid "Calculations" -msgstr "Výpočty" - msgid "Item type" msgstr "Typ položky" diff --git a/i18n/es.po b/i18n/es.po index da70c867b..68929d7f4 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -36,15 +36,6 @@ msgstr "El mapa \"{{- name}}\" está guardado." msgid "Failed to save map: {{message}}" msgstr "Error al guardar el mapa: {{message}}" -msgid "Calculation" -msgstr "Cálculo" - -msgid "No calculations found" -msgstr "" - -msgid "Calculations can be created in the Data Visualizer app." -msgstr "" - msgid "Classification" msgstr "Clasificación" @@ -454,9 +445,6 @@ msgstr "Se requiere el dato de evento" msgid "Program indicator is required" msgstr "Se requiere indicador de programa" -msgid "Calculation is required" -msgstr "" - msgid "Period is required" msgstr "Período requerido" @@ -472,9 +460,6 @@ msgstr "Datos de eventos" msgid "Program indicators" msgstr "Indicadores de programa" -msgid "Calculations" -msgstr "Cálculos" - msgid "Item type" msgstr "Item type" diff --git a/i18n/zh.po b/i18n/zh.po index f05ab5b05..8d9826663 100644 --- a/i18n/zh.po +++ b/i18n/zh.po @@ -27,15 +27,6 @@ msgstr "地图“{{- name}}”已保存。" msgid "Failed to save map: {{message}}" msgstr "无法保存地图:{{message}}" -msgid "Calculation" -msgstr "计算" - -msgid "No calculations found" -msgstr "没有找到计算结果" - -msgid "Calculations can be created in the Data Visualizer app." -msgstr "可以在数据可视化工具应用程序中创建计算。" - msgid "Classification" msgstr "分类" @@ -438,9 +429,6 @@ msgstr "需要事件数据项" msgid "Program indicator is required" msgstr "需要项目指标" -msgid "Calculation is required" -msgstr "需要计算" - msgid "Period is required" msgstr "需要期间" @@ -456,9 +444,6 @@ msgstr "事件数据项" msgid "Program indicators" msgstr "项目指标" -msgid "Calculations" -msgstr "计算" - msgid "Item type" msgstr "条目类型" From 73503ab9dfa20ad261c27ccdd430dd46c71c927d Mon Sep 17 00:00:00 2001 From: Jen Jones Arnesen Date: Wed, 27 Sep 2023 09:56:38 +0200 Subject: [PATCH 11/11] chore: update the toolbar feature commit with a fix for interpretationId url parameter (#2987) With the changes from the toolbar update, the Interpretations panel might not be loaded by default. So when the url included the interpretationId, no component was listening for it, resulting in the interpretation modal not being opened. The url param listener is thus moved to App. Jest and cypress tests added --- cypress/integration/interpretations.cy.js | 29 ++++ cypress/integration/smoke.cy.js | 42 ++++++ src/components/app/App.js | 10 ++ src/components/app/DetailsPanel.js | 11 +- .../app/__tests__/Detailspanel.spec.js | 142 ++++++++++++++++++ .../__snapshots__/Detailspanel.spec.js.snap | 89 +++++++++++ .../interpretations/Interpretations.js | 12 +- 7 files changed, 317 insertions(+), 18 deletions(-) create mode 100644 src/components/app/__tests__/Detailspanel.spec.js create mode 100644 src/components/app/__tests__/__snapshots__/Detailspanel.spec.js.snap diff --git a/cypress/integration/interpretations.cy.js b/cypress/integration/interpretations.cy.js index 7662150da..4a1e54abe 100644 --- a/cypress/integration/interpretations.cy.js +++ b/cypress/integration/interpretations.cy.js @@ -67,4 +67,33 @@ context('Interpretations', () => { deleteMap() }) + + it('opens and closes the interpretation panel', () => { + cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( + 'postDataStatistics' + ) + cy.visit( + '/?id=ZBjCfSaLSqD&interpretationId=yKqhXZdeJ6a', + EXTENDED_TIMEOUT + ) //ANC: LLITN coverage district and facility + + cy.wait('@postDataStatistics') + .its('response.statusCode') + .should('eq', 201) + + cy.getByDataTest('interpretation-modal') + .find('h1') + .contains( + 'Viewing interpretation: ANC: LLITN coverage district and facility' + ) + .should('be.visible') + + cy.getByDataTest('interpretation-modal') + .findByDataTest('dhis2-modal-close-button') + .click() + + cy.getByDataTest('interpretation-modal').should('not.exist') + + cy.getByDataTest('interpretations-list').should('be.visible') + }) }) diff --git a/cypress/integration/smoke.cy.js b/cypress/integration/smoke.cy.js index 5a7ad16e3..be0d0f82d 100644 --- a/cypress/integration/smoke.cy.js +++ b/cypress/integration/smoke.cy.js @@ -38,4 +38,46 @@ context('Smoke Test', () => { Layer.validateCardTitle('ANC 1 Coverage') cy.get('canvas.maplibregl-canvas').should('be.visible') }) + + it('loads with map id and interpretationid lowercase', () => { + cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( + 'postDataStatistics' + ) + cy.visit( + '/?id=ZBjCfSaLSqD&interpretationid=yKqhXZdeJ6a', + EXTENDED_TIMEOUT + ) //ANC: LLITN coverage district and facility + + cy.wait('@postDataStatistics') + .its('response.statusCode') + .should('eq', 201) + + cy.getByDataTest('interpretation-modal') + .find('h1') + .contains( + 'Viewing interpretation: ANC: LLITN coverage district and facility' + ) + .should('be.visible') + }) + + it('loads with map id and interpretationId uppercase', () => { + cy.intercept({ method: 'POST', url: /dataStatistics/ }).as( + 'postDataStatistics' + ) + cy.visit( + '/?id=ZBjCfSaLSqD&interpretationId=yKqhXZdeJ6a', + EXTENDED_TIMEOUT + ) //ANC: LLITN coverage district and facility + + cy.wait('@postDataStatistics') + .its('response.statusCode') + .should('eq', 201) + + cy.getByDataTest('interpretation-modal') + .find('h1') + .contains( + 'Viewing interpretation: ANC: LLITN coverage district and facility' + ) + .should('be.visible') + }) }) diff --git a/src/components/app/App.js b/src/components/app/App.js index 762d13b8a..7e8f8ca55 100644 --- a/src/components/app/App.js +++ b/src/components/app/App.js @@ -7,6 +7,7 @@ import { useDispatch } from 'react-redux' import { tSetAnalyticalObject } from '../../actions/analyticalObject.js' import { removeBingBasemaps, setBingMapsApiKey } from '../../actions/basemap.js' import { tSetExternalLayers } from '../../actions/externalLayers.js' +import { setInterpretation } from '../../actions/interpretations.js' import { tOpenMap } from '../../actions/map.js' import { CURRENT_AO_KEY } from '../../util/analyticalObject.js' import { getUrlParameter } from '../../util/requests.js' @@ -33,6 +34,15 @@ const App = () => { } else if (getUrlParameter('currentAnalyticalObject') === 'true') { await dispatch(tSetAnalyticalObject(currentAO)) } + + // analytics interpretation component uses camelcase + const interpretationId = + getUrlParameter('interpretationid') || + getUrlParameter('interpretationId') + + if (interpretationId) { + dispatch(setInterpretation(interpretationId)) + } } if (!isEmpty(systemSettings)) { diff --git a/src/components/app/DetailsPanel.js b/src/components/app/DetailsPanel.js index ddb88d10e..a5dee646a 100644 --- a/src/components/app/DetailsPanel.js +++ b/src/components/app/DetailsPanel.js @@ -9,17 +9,14 @@ import styles from './styles/DetailsPanel.module.css' const DetailsPanel = ({ interpretationsRenderCount }) => { const detailsPanelOpen = useSelector((state) => state.ui.rightPanelOpen) const viewOrgUnitProfile = useSelector((state) => state.orgUnitProfile) + const interpretationId = useSelector((state) => state.interpretation?.id) const getContent = () => { - if (!detailsPanelOpen) { - return null + if (interpretationId || (detailsPanelOpen && !viewOrgUnitProfile)) { + return } - return viewOrgUnitProfile ? ( - - ) : ( - - ) + return detailsPanelOpen ? : null } return ( diff --git a/src/components/app/__tests__/Detailspanel.spec.js b/src/components/app/__tests__/Detailspanel.spec.js new file mode 100644 index 000000000..6d6110eef --- /dev/null +++ b/src/components/app/__tests__/Detailspanel.spec.js @@ -0,0 +1,142 @@ +import { render } from '@testing-library/react' +import React from 'react' +import { Provider } from 'react-redux' +import configureMockStore from 'redux-mock-store' +import DetailsPanel from '../DetailsPanel.js' + +const mockStore = configureMockStore() + +jest.mock( + '../../interpretations/Interpretations.js', + () => + function MockInterpretations() { + return
Interpretations
+ } +) + +jest.mock( + '../../orgunits/OrgUnitProfile.js', + () => + function MockOrgUnitProfile() { + return
Org Unit Profile
+ } +) + +describe('DetailsPanel', () => { + test('renders InterpretationsPanel when has interpretationId, has orgUnitProfile and panel is open', () => { + const store = { + interpretation: { id: 'abc123' }, + orgUnitProfile: 'xyzpdq', + ui: { rightPanelOpen: true }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + test('renders InterpretationsPanel when has interpretationId, has orgUnitProfile and panel is closed', () => { + const store = { + interpretation: { id: 'abc123' }, + orgUnitProfile: 'xyzpdq', + ui: { rightPanelOpen: false }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + test('renders InterpretationsPanel when has interpretationId, no orgUnitProfile and panel is open', () => { + const store = { + interpretation: { id: 'abc123' }, + orgUnitProfile: null, + ui: { rightPanelOpen: true }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + + test('renders InterpretationsPanel when has interpretationId, no orgUnitProfile and panel is closed', () => { + const store = { + interpretation: { id: 'abc123' }, + orgUnitProfile: null, + ui: { rightPanelOpen: false }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + + test('renders OrgUnitProfile when no interpretationId, has orgUnitProfile and panel is open', () => { + const store = { + interpretation: {}, + orgUnitProfile: 'xyzpdq', + ui: { rightPanelOpen: true }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + + test('renders null when no interpretationId, has orgUnitProfile, and panel closed', () => { + const store = { + interpretation: {}, + orgUnitProfile: 'xyzpdq', + ui: { rightPanelOpen: false }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + test('renders InterpretationsPanel when no interpretationId, no orgUnitProfile and panel open', () => { + const store = { + interpretation: {}, + orgUnitProfile: null, + ui: { rightPanelOpen: true }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) + + test('renders null when no interpretationId, no orgUnitProfile, and panel closed', () => { + const store = { + interpretation: {}, + orgUnitProfile: null, + ui: { rightPanelOpen: false }, + } + + const { container } = render( + + + + ) + expect(container).toMatchSnapshot() + }) +}) diff --git a/src/components/app/__tests__/__snapshots__/Detailspanel.spec.js.snap b/src/components/app/__tests__/__snapshots__/Detailspanel.spec.js.snap new file mode 100644 index 000000000..b45d254ce --- /dev/null +++ b/src/components/app/__tests__/__snapshots__/Detailspanel.spec.js.snap @@ -0,0 +1,89 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DetailsPanel renders InterpretationsPanel when has interpretationId, has orgUnitProfile and panel is closed 1`] = ` +
+ +
+`; + +exports[`DetailsPanel renders InterpretationsPanel when has interpretationId, has orgUnitProfile and panel is open 1`] = ` +
+
+
+ Interpretations +
+
+
+`; + +exports[`DetailsPanel renders InterpretationsPanel when has interpretationId, no orgUnitProfile and panel is closed 1`] = ` +
+ +
+`; + +exports[`DetailsPanel renders InterpretationsPanel when has interpretationId, no orgUnitProfile and panel is open 1`] = ` +
+
+
+ Interpretations +
+
+
+`; + +exports[`DetailsPanel renders InterpretationsPanel when no interpretationId, no orgUnitProfile and panel open 1`] = ` +
+
+
+ Interpretations +
+
+
+`; + +exports[`DetailsPanel renders OrgUnitProfile when no interpretationId, has orgUnitProfile and panel is open 1`] = ` +
+
+
+ Org Unit Profile +
+
+
+`; + +exports[`DetailsPanel renders null when no interpretationId, has orgUnitProfile, and panel closed 1`] = ` +
+ +`; + +exports[`DetailsPanel renders null when no interpretationId, no orgUnitProfile, and panel closed 1`] = ` +
+ +`; diff --git a/src/components/interpretations/Interpretations.js b/src/components/interpretations/Interpretations.js index c937e5ef9..f3cf14087 100644 --- a/src/components/interpretations/Interpretations.js +++ b/src/components/interpretations/Interpretations.js @@ -1,9 +1,7 @@ import PropTypes from 'prop-types' import React, { useEffect } from 'react' import { useSelector, useDispatch } from 'react-redux' -import { setInterpretation } from '../../actions/interpretations.js' import { openInterpretationsPanel } from '../../actions/ui.js' -import { getUrlParameter } from '../../util/requests.js' import InterpretationsPanel from './InterpretationsPanel.js' const Interpretations = ({ renderCount }) => { @@ -15,15 +13,7 @@ const Interpretations = ({ renderCount }) => { useEffect(() => { if (isMapLoaded) { - // analytics interpretation component uses camelcase - const urlInterpretationId = - getUrlParameter('interpretationid') || - getUrlParameter('interpretationId') - - if (urlInterpretationId) { - dispatch(setInterpretation(urlInterpretationId)) - dispatch(openInterpretationsPanel()) - } + dispatch(openInterpretationsPanel()) } }, [isMapLoaded, dispatch])