From 21141fecedacdbfc5ec6e77cd6d1929839610551 Mon Sep 17 00:00:00 2001 From: Hendrik de Graaf Date: Wed, 9 Aug 2023 11:54:56 +0200 Subject: [PATCH] feat: use Toolbar and ToolbarSidebar from analytics (#2358) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: use Toolbar and ToolbarSidebar from analytics * feat: use UpdateButton and HoverMenubar from analytics * feat: update download menu to use hovermenu components from analytics * feat: use hover menu components from analytics for options menu * feat: use interpretations button from analytics * chore: update pot file * chore: upgrade @dhis2/analytics to latest * chore: fix typo in component name * fix: adjust e2e element slectors * chore: fix missing and redundant imports * chore: fix odd linter error which only fires on ci * fix: adjust data test name * chore: fix lines e2e test * fix: adjust closeFileMenuWithClick command * chore: fix failing legens e2e test * chore: fix legend e2e test even better * chore: fix scatter e2e * chore: fix icon e2e * chore: fix start e2e * chore: clean up unused imports * fix: remove divider from plain data source submenu * chore: upgrade @dhis2/analytics to get toolbar UI improvements * fix: tweak viz type selector styles to match toolbar * chore: remove yarn start command which was only used for development * chore: upgrade analytics to get decreased padding * fix: ensure `MenuSectionHeader` is `dense` when in `HoverMenuBar` --------- Co-authored-by: Jan Henrik Øverland --- cypress/elements/fileMenu/index.js | 11 +- cypress/elements/menuBar.js | 12 +- cypress/integration/options/axes.cy.js | 23 ++-- cypress/integration/options/fontStyles.cy.js | 30 ++--- cypress/integration/options/icon.cy.js | 11 +- cypress/integration/options/legend.cy.js | 127 ++++++------------ cypress/integration/options/lines.cy.js | 8 +- cypress/integration/visTypes/scatter.cy.js | 9 +- i18n/en.pot | 7 +- package.json | 2 +- src/components/App.css | 16 --- src/components/App.js | 20 ++- .../DownloadMenu/AdvancedSubMenu.js | 107 ++++++++------- src/components/DownloadMenu/DownloadMenu.js | 91 ++++++++----- src/components/DownloadMenu/GraphicsMenu.js | 48 ++++--- .../DownloadMenu/ModalDownloadDropdown.js | 36 +++-- .../DownloadMenu/PlainDataSourceSubMenu.js | 81 ++++++----- src/components/DownloadMenu/TableMenu.js | 84 ++++++------ .../DownloadMenu/ToolbarDownloadDropdown.js | 45 ++----- .../{useDownloadMenu.js => useDownload.js} | 12 +- .../MenuBar/InterpretationsButton.js | 55 +++----- src/components/MenuBar/MenuBar.js | 46 +++---- .../styles/InterpretationsButton.module.css | 4 - .../MenuBar/styles/MenuBar.module.css | 13 -- src/components/MenuButton/MenuButton.js | 34 ----- .../MenuButton/styles/MenuButton.module.css | 47 ------- .../VisualizationOptionsManager.js | 44 +++--- .../VisualizationTypeSelector.js | 42 +++--- .../VisualizationTypeSelector.module.css | 14 +- yarn.lock | 8 +- 30 files changed, 479 insertions(+), 608 deletions(-) rename src/components/DownloadMenu/{useDownloadMenu.js => useDownload.js} (95%) delete mode 100644 src/components/MenuBar/styles/InterpretationsButton.module.css delete mode 100644 src/components/MenuBar/styles/MenuBar.module.css delete mode 100644 src/components/MenuButton/MenuButton.js delete mode 100644 src/components/MenuButton/styles/MenuButton.module.css diff --git a/cypress/elements/fileMenu/index.js b/cypress/elements/fileMenu/index.js index db31dfaa09..cec32b8baf 100644 --- a/cypress/elements/fileMenu/index.js +++ b/cypress/elements/fileMenu/index.js @@ -1,9 +1,7 @@ -import { clickMenuBarFileButton } from '../menuBar.js' +import { clickMenuBarFileButton, menubarEl } from '../menuBar.js' const deleteModalEl = 'file-menu-delete-modal' const fileMenuContainerEl = 'file-menu-container' -const fileMenuToggleEl = 'file-menu-toggle' -const fileMenuToggleLayerEl = 'file-menu-toggle-layer' export const FILE_MENU_BUTTON_NEW = 'New' export const FILE_MENU_BUTTON_OPEN = 'Open…' @@ -16,12 +14,11 @@ export const FILE_MENU_BUTTON_SHARE = 'Share…' export const FILE_MENU_BUTTON_GETLINK = 'Get link…' export const FILE_MENU_BUTTON_DELETE = 'Delete' -export const closeFileMenuWithClick = () => - cy.getBySel(fileMenuToggleLayerEl).click('topLeft') +export const closeFileMenuWithClick = () => cy.get('body').click() export const closeFileMenuWithEsc = () => - cy.getBySel(fileMenuToggleEl).type('{esc}', { force: true }) -// use force as the element that's being typed into is hidden + // use force as the element that's being typed into is hidden + cy.getBySel(menubarEl).contains('File').type('{esc}', { force: true }) export const clickFileMenuButton = (buttonName) => cy.getBySel(fileMenuContainerEl).contains(buttonName).click() diff --git a/cypress/elements/menuBar.js b/cypress/elements/menuBar.js index 22bf72f3e0..4811c77b56 100644 --- a/cypress/elements/menuBar.js +++ b/cypress/elements/menuBar.js @@ -1,4 +1,4 @@ -const menubarEl = 'app-menubar' +export const menubarEl = 'dhis2-analytics-hovermenubar' const updateButton = 'app-menubar-update-button' const optionsButton = 'app-menubar-options-button' @@ -7,5 +7,11 @@ export const clickMenuBarUpdateButton = () => cy.getBySel(updateButton).click() export const clickMenuBarFileButton = () => cy.getBySel(menubarEl).contains('File').click() -export const clickMenuBarOptionsButton = () => - cy.getBySel(optionsButton).click() +export function clickMenuBarOptionsButton() { + return cy.getBySel(optionsButton).click() +} + +export const openOptionsModal = (section = 'Data') => { + clickMenuBarOptionsButton() + return cy.getBySel('options-menu-list').contains(section).click() +} diff --git a/cypress/integration/options/axes.cy.js b/cypress/integration/options/axes.cy.js index 6ca92a3144..8b42ce1868 100644 --- a/cypress/integration/options/axes.cy.js +++ b/cypress/integration/options/axes.cy.js @@ -8,7 +8,7 @@ import { clickDimensionModalUpdateButton, } from '../../elements/dimensionModal/index.js' import { openDimension } from '../../elements/dimensionsPanel.js' -import { clickMenuBarOptionsButton } from '../../elements/menuBar.js' +import { openOptionsModal } from '../../elements/menuBar.js' import { clickOptionsModalUpdateButton, clickOptionsTab, @@ -57,8 +57,7 @@ describe('Options - Vertical axis', () => { }) describe('title', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it("sets axis title to 'Custom'", () => { setAxisTitleTextModeTo('Custom') @@ -76,8 +75,7 @@ describe('Options - Vertical axis', () => { }) describe('range', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it('sets min value', () => { setAxisRangeMinValue(TEST_AXIS, TEST_MIN_VALUE) @@ -111,8 +109,7 @@ describe('Options - Vertical axis', () => { }) describe('options modal keeps changes when reopening', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it(`title is "${TEST_TITLE}"`, () => { expectAxisTitleToBeValue(TEST_AXIS, TEST_TITLE) @@ -141,8 +138,7 @@ describe('Options - Horizontal axis', () => { }) describe('title', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it(`switches to '${TEST_TAB}' tab`, () => { switchAxesTabTo(TEST_TAB) @@ -163,8 +159,7 @@ describe('Options - Horizontal axis', () => { }) describe('options modal keeps changes when reopening', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it(`switches to '${TEST_TAB}' tab`, () => { switchAxesTabTo(TEST_TAB) @@ -185,8 +180,7 @@ describe('Options - Auto-generated axis title', () => { }) describe('Single item - single axis', () => { it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it("sets axis title to 'Auto generated'", () => { setAxisTitleTextModeTo('Auto generated') @@ -238,8 +232,7 @@ describe('Options - Auto-generated axis title', () => { expectVisualizationToBeVisible(VIS_TYPE_COLUMN) }) it('opens Options -> Series', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_SERIES) + openOptionsModal(OPTIONS_TAB_SERIES) }) it('enables multi axis', () => { setItemToAxis(1, 2) diff --git a/cypress/integration/options/fontStyles.cy.js b/cypress/integration/options/fontStyles.cy.js index 4f445c95d9..15408d334f 100644 --- a/cypress/integration/options/fontStyles.cy.js +++ b/cypress/integration/options/fontStyles.cy.js @@ -9,11 +9,10 @@ import { clickDimensionModalUpdateButton, } from '../../elements/dimensionModal/index.js' import { openDimension } from '../../elements/dimensionsPanel.js' -import { clickMenuBarOptionsButton } from '../../elements/menuBar.js' +import { openOptionsModal } from '../../elements/menuBar.js' import { changeFontSizeOption, clickOptionsModalUpdateButton, - clickOptionsTab, changeTextAlignOption, clickBoldButton, clickItalicButton, @@ -129,8 +128,7 @@ describe('Options - Font styles', () => { expectWindowConfigTitleToBeValue(CONFIG_DEFAULT_TITLE) }) it('opens Options -> Style', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) }) setFontStyleOptions({ fontSize: TEST_FONT_SIZE_OPTION.input, @@ -174,8 +172,7 @@ describe('Options - Font styles', () => { expectWindowConfigSubtitleToBeValue(CONFIG_DEFAULT_SUBTITLE) }) it('opens Options -> Style', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) }) it('sets a custom subtitle', () => { setCustomSubtitle(TEST_SUBTITLE_TEXT) @@ -220,8 +217,7 @@ describe('Options - Font styles', () => { const prefix = TARGET_LINE_PREFIX it('opens Options -> Data', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_DATA) + openOptionsModal(OPTIONS_TAB_DATA) }) it('sets target line', () => { cy.log(`Test value: ${TEST_VALUE}`) @@ -280,8 +276,7 @@ describe('Options - Font styles', () => { const prefix = BASE_LINE_PREFIX it('opens Options -> Data', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_DATA) + openOptionsModal(OPTIONS_TAB_DATA) }) it('sets base line', () => { cy.log(`Test value: ${TEST_VALUE}`) @@ -338,8 +333,7 @@ describe('Options - Font styles', () => { const prefix = SERIES_KEY_PREFIX it('opens Options -> Style', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) }) setFontStyleOptions({ fontSize: TEST_FONT_SIZE_OPTION.input, @@ -375,8 +369,7 @@ describe('Options - Font styles', () => { const prefix = VERTICAL_AXIS_LABELS_PREFIX it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) setFontStyleOptions({ fontSize: TEST_FONT_SIZE_OPTION.input, @@ -410,8 +403,7 @@ describe('Options - Font styles', () => { const prefix = HORIZONTAL_AXIS_LABELS_PREFIX it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) switchAxesTabTo('Horizontal (x) axis') }) setFontStyleOptions({ @@ -451,8 +443,7 @@ describe('Options - Font styles', () => { const prefix = HORIZONTAL_AXIS_TITLE_PREFIX it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it(`sets horizontal axis title to "${TEST_TITLE}"`, () => { switchAxesTabTo('Horizontal (x) axis') @@ -500,8 +491,7 @@ describe('Options - Font styles', () => { const prefix = VERTICAL_AXIS_TITLE_PREFIX it('opens Options -> Axes', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) }) it(`sets vertical axis title to "${TEST_TITLE}"`, () => { setAxisTitleTextModeTo('Custom') diff --git a/cypress/integration/options/icon.cy.js b/cypress/integration/options/icon.cy.js index 66b8942338..541e586eac 100644 --- a/cypress/integration/options/icon.cy.js +++ b/cypress/integration/options/icon.cy.js @@ -27,7 +27,7 @@ import { unselectAllItemsByButton, } from '../../elements/dimensionModal/index.js' import { openDimension } from '../../elements/dimensionsPanel.js' -import { clickMenuBarOptionsButton } from '../../elements/menuBar.js' +import { openOptionsModal } from '../../elements/menuBar.js' import { OPTIONS_TAB_LEGEND, OPTIONS_TAB_STYLE, @@ -97,8 +97,7 @@ describe('Icon', () => { TEST_TYPES.forEach((type) => { it(`icon shows when option is enabled for ${type}`, () => { // enable the icon - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) clickCheckbox('option-show-data-item-icon') clickOptionsModalHideButton() @@ -129,8 +128,7 @@ describe('Icon', () => { // TODO: Skipped because of the same reason as the commented out tests above it.skip('icon gets correct color when a legend is in use', () => { // enable the icon - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) clickCheckbox('option-show-data-item-icon') // enable the legend @@ -176,8 +174,7 @@ describe('Icon', () => { expectSingleValueToHaveIconColor('#ffffff') // switch to apply legend color to text - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) changeDisplayStyleToText() clickOptionsModalUpdateButton() diff --git a/cypress/integration/options/legend.cy.js b/cypress/integration/options/legend.cy.js index 022ea9e717..4b1d67b9cd 100644 --- a/cypress/integration/options/legend.cy.js +++ b/cypress/integration/options/legend.cy.js @@ -31,15 +31,14 @@ import { openDimension, } from '../../elements/layout.js' import { - clickMenuBarOptionsButton, clickMenuBarUpdateButton, + openOptionsModal, } from '../../elements/menuBar.js' import { changeDisplayStrategyToFixed, changeDisplayStyleToText, changeFixedLegendSet, clickOptionsModalUpdateButton, - clickOptionsTab, toggleLegend, expectFixedLegendSetToBe, expectLegendDisplayStrategyToBeByDataItem, @@ -102,8 +101,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_COLUMN) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -119,8 +117,7 @@ describe('Options - Legend', () => { ) }) it(`changes legend display strategy to fixed (${TEST_LEGEND_SET})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() changeDisplayStrategyToFixed() expectLegendDisplayStrategyToBeFixed() @@ -140,8 +137,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectFixedLegendSetToBe(TEST_LEGEND_SET) }) @@ -180,8 +176,7 @@ describe('Options - Legend', () => { expectSingleValueToNotHaveBackgroundColor() }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -197,8 +192,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_STANDARD_SUBTITLE_COLOR) }) it('changes legend display style to text color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() expectLegendDisplayStyleToBeFill() changeDisplayStyleToText() @@ -214,8 +208,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_STANDARD_SUBTITLE_COLOR) }) it(`changes legend display strategy to fixed (${TEST_LEGEND_SET_WITH_CONTRAST})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStyleToBeText() expectLegendDisplayStrategyToBeByDataItem() changeDisplayStrategyToFixed() @@ -232,8 +225,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_STANDARD_SUBTITLE_COLOR) }) it('changes legend display style to background color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectLegendDisplayStyleToBeText() changeDisplayStyleToFill() @@ -249,8 +241,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_CONTRAST_TEXT_COLOR) }) it(`changes title and subtitle colors`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_STYLE) + openOptionsModal(OPTIONS_TAB_STYLE) changeColor('option-chart-title', EXPECTED_CUSTOM_TITLE_COLOR) changeColor('option-chart-subtitle', EXPECTED_CUSTOM_SUBTITLE_COLOR) clickOptionsModalUpdateButton() @@ -263,8 +254,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR) }) it('changes legend display style to text color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectLegendDisplayStyleToBeFill() changeDisplayStyleToText() @@ -280,8 +270,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR) }) it(`changes legend display strategy to by data item`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStyleToBeText() expectLegendDisplayStrategyToBeFixed() changeDisplayStrategyToByDataItem() @@ -297,8 +286,7 @@ describe('Options - Legend', () => { expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR) }) it('changes legend display style to background color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) changeDisplayStrategyToByDataItem() expectLegendDisplayStyleToBeText() changeDisplayStyleToFill() @@ -317,8 +305,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('enables legend key option', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegendKeyOption() expectLegendKeyOptionToBeEnabled() clickOptionsModalUpdateButton() @@ -342,8 +329,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_GAUGE) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -355,8 +341,7 @@ describe('Options - Legend', () => { expectWindowConfigYAxisToHaveColor(EXPECTED_BY_DATA_COLOR) }) it(`changes legend display strategy to fixed (${TEST_LEGEND_SET})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() expectLegendDisplayStyleToBeFill() changeDisplayStrategyToFixed() @@ -369,8 +354,7 @@ describe('Options - Legend', () => { expectWindowConfigYAxisToHaveColor(EXPECTED_FIXED_COLOR) }) it('changes legend display style to text color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectFixedLegendSetToBe(TEST_LEGEND_SET) expectLegendDisplayStyleToBeFill() @@ -389,8 +373,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectFixedLegendSetToBe(TEST_LEGEND_SET) }) @@ -415,8 +398,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_STACKED_COLUMN) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -432,8 +414,7 @@ describe('Options - Legend', () => { ) }) it(`changes legend display strategy to fixed (${TEST_LEGEND_SET})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() changeDisplayStrategyToFixed() expectLegendDisplayStrategyToBeFixed() @@ -453,8 +434,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeFixed() expectFixedLegendSetToBe(TEST_LEGEND_SET) }) @@ -490,8 +470,7 @@ describe('Options - Legend', () => { }) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -508,8 +487,7 @@ describe('Options - Legend', () => { }) }) it('changes legend display style to text color', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() expectLegendDisplayStyleToBeFill() changeDisplayStyleToText() @@ -529,8 +507,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() }) it('enables legend key option', () => { @@ -558,8 +535,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_PIVOT_TABLE) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -592,8 +568,7 @@ describe('Options - Legend', () => { ) }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStyleToBeText() expectLegendDisplayStrategyToBeFixed() }) @@ -613,8 +588,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_PIVOT_TABLE) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -643,8 +617,7 @@ describe('Options - Legend', () => { expectSingleValueToHaveBackgroundColor(EXPECTED_FIXED_COLOR) }) it('verifies that options are persisted', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStyleToBeFill() expectLegendDisplayStrategyToBeFixed() }) @@ -658,8 +631,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible() }) it('enables legend (Column)', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() clickOptionsModalUpdateButton() @@ -669,8 +641,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('enables legend key option (Column)', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegendKeyOption() expectLegendKeyOptionToBeEnabled() clickOptionsModalUpdateButton() @@ -690,8 +661,7 @@ describe('Options - Legend', () => { expectLegedKeyItemAmountToBe(TEST_ITEMS.length) }) it('disables legend key option (Pivot table)', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegendKeyOption() expectLegendKeyOptionToBeDisabled() clickOptionsModalUpdateButton() @@ -709,8 +679,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it('enables legend key option (Gauge)', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegendKeyOption() expectLegendKeyOptionToBeEnabled() clickOptionsModalUpdateButton() @@ -730,8 +699,7 @@ describe('Options - Legend', () => { expectLegedKeyItemAmountToBe(1) }) it('disables legend key option (Single value)', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegendKeyOption() expectLegendKeyOptionToBeDisabled() clickOptionsModalUpdateButton() @@ -750,8 +718,7 @@ describe('Options - Legend', () => { expectVisualizationToBeVisible(VIS_TYPE_COLUMN) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -777,7 +744,7 @@ describe('Options - Legend', () => { ) }) it('legend options are not available', () => { - clickMenuBarOptionsButton() + openOptionsModal() expectOptionsTabToBeHidden(OPTIONS_TAB_LEGEND) clickOptionsModalHideButton() }) @@ -803,7 +770,7 @@ describe('Options - Legend', () => { ) }) it('legend options are not available', () => { - clickMenuBarOptionsButton() + openOptionsModal() expectOptionsTabToBeHidden(OPTIONS_TAB_LEGEND) }) it('legend key is hidden', () => { @@ -825,8 +792,7 @@ describe('Options - Legend', () => { expectSeriesKeyToHaveSeriesKeyItems(2) }) it('enables legend', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -834,8 +800,7 @@ describe('Options - Legend', () => { expectChartTitleToBeVisible() }) it(`changes legend display strategy to fixed (${TEST_ITEMS[1].legendSet})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() changeDisplayStrategyToFixed() expectLegendDisplayStrategyToBeFixed() @@ -852,8 +817,7 @@ describe('Options - Legend', () => { selectIndicators([TEST_ITEM.name]) clickDimensionModalUpdateButton() expectVisualizationToBeVisible(VIS_TYPE_COLUMN) - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -895,8 +859,7 @@ describe('Options - Legend', () => { expectLegendKeyToBeHidden() }) it(`changes legend display strategy to fixed (${TEST_ITEMS[1].legendSet})`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) expectLegendDisplayStrategyToBeByDataItem() changeDisplayStrategyToFixed() expectLegendDisplayStrategyToBeFixed() @@ -924,8 +887,7 @@ describe('Options - Legend', () => { selectIndicators(TEST_ITEMS.map((item) => item.name)) clickDimensionModalUpdateButton() expectVisualizationToBeVisible(VIS_TYPE_COLUMN) - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_LEGEND) + openOptionsModal(OPTIONS_TAB_LEGEND) toggleLegend() expectLegendToBeEnabled() expectLegendDisplayStrategyToBeByDataItem() @@ -943,8 +905,7 @@ describe('Options - Legend', () => { ) }) it(`changes all items to type ${VIS_TYPE_LINE}`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_SERIES) + openOptionsModal(OPTIONS_TAB_SERIES) TEST_ITEMS.forEach((item, index) => setItemToType(index, VIS_TYPE_LINE) ) @@ -964,8 +925,7 @@ describe('Options - Legend', () => { expectSeriesKeyToHaveSeriesKeyItems(2) }) it(`changes first item (${TEST_ITEMS[0].name}) to type ${VIS_TYPE_COLUMN}`, () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_SERIES) + openOptionsModal(OPTIONS_TAB_SERIES) setItemToType(0, VIS_TYPE_COLUMN) clickOptionsModalUpdateButton() expectVisualizationToBeVisible() @@ -995,8 +955,7 @@ describe('Options - Legend', () => { selectIndicators([TEST_ITEM.name]) clickDimensionModalUpdateButton() expectVisualizationToBeVisible(VIS_TYPE_COLUMN) - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_SERIES) + openOptionsModal(OPTIONS_TAB_SERIES) setItemToType(2, VIS_TYPE_LINE) clickOptionsModalUpdateButton() expectVisualizationToBeVisible() diff --git a/cypress/integration/options/lines.cy.js b/cypress/integration/options/lines.cy.js index 839925efe5..ea8fef0357 100644 --- a/cypress/integration/options/lines.cy.js +++ b/cypress/integration/options/lines.cy.js @@ -8,10 +8,9 @@ import { clickDimensionModalUpdateButton, } from '../../elements/dimensionModal/index.js' import { openDimension } from '../../elements/dimensionsPanel.js' -import { clickMenuBarOptionsButton } from '../../elements/menuBar.js' +import { openOptionsModal } from '../../elements/menuBar.js' import { clickOptionsModalUpdateButton, - clickOptionsTab, clickTrendLineCheckbox, OPTIONS_TAB_DATA, selectTrendLineType, @@ -51,8 +50,7 @@ describe('Options - Lines', () => { trendLineTypes.forEach((trendLineType, index) => { describe(trendLineType.name, () => { it('opens Options -> Data', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_DATA) + openOptionsModal(OPTIONS_TAB_DATA) }) if (index === 0) { it('enables trendline', () => { @@ -79,7 +77,7 @@ describe('Options - Lines', () => { }) }) }) - /* TODO: + /* TODO: - Test base line and target line like trend line (above) - Pie, PT, SV shouldn't have the lines section in options - Gauge should only display base and target line (no trend line) diff --git a/cypress/integration/visTypes/scatter.cy.js b/cypress/integration/visTypes/scatter.cy.js index 88dea58ccd..6fba12f094 100644 --- a/cypress/integration/visTypes/scatter.cy.js +++ b/cypress/integration/visTypes/scatter.cy.js @@ -36,12 +36,11 @@ import { openDimensionOnAxis, } from '../../elements/layout.js' import { - clickMenuBarOptionsButton, clickMenuBarUpdateButton, + openOptionsModal, } from '../../elements/menuBar.js' import { clickOptionsModalUpdateButton, - clickOptionsTab, clickOutliersCheckbox, OPTIONS_TAB_AXES, OPTIONS_TAB_OUTLIERS, @@ -166,8 +165,7 @@ describe('using a Scatter chart', () => { max: 200, }, ] - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_AXES) + openOptionsModal(OPTIONS_TAB_AXES) TEST_AXES.forEach((test) => { switchAxesTabTo(test.label) setAxisRangeMinValue(test.axis, test.min) @@ -181,8 +179,7 @@ describe('using a Scatter chart', () => { expectWindowConfigXAxisToHaveRangeMaxValue(TEST_AXES[1].max) }) it('Options -> Outliers -> enables outliers', () => { - clickMenuBarOptionsButton() - clickOptionsTab(OPTIONS_TAB_OUTLIERS) + openOptionsModal(OPTIONS_TAB_OUTLIERS) clickOutliersCheckbox() // TODO: Set more outlier options clickOptionsModalUpdateButton() diff --git a/i18n/en.pot b/i18n/en.pot index e739fac14c..148b9e9dcb 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2023-03-07T12:07:38.393Z\n" -"PO-Revision-Date: 2023-03-07T12:07:38.393Z\n" +"POT-Creation-Date: 2023-05-30T12:32:59.044Z\n" +"PO-Revision-Date: 2023-05-30T12:32:59.044Z\n" msgid "All items" msgstr "All items" @@ -210,9 +210,6 @@ msgstr "Select a period" msgid "Select years" msgstr "Select years" -msgid "Interpretations" -msgstr "Interpretations" - msgid "" "This visualization can't be deleted because it is used on one or more " "dashboards" diff --git a/package.json b/package.json index eababf7151..966d651621 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "start-server-and-test": "^2.0.0" }, "dependencies": { - "@dhis2/analytics": "^25.1.11", + "@dhis2/analytics": "^26.0.7", "@dhis2/app-runtime": "^3.7.0", "@dhis2/app-runtime-adapter-d2": "^1.1.0", "@dhis2/app-service-datastore": "^1.0.0-beta.3", diff --git a/src/components/App.css b/src/components/App.css index 8aea36a21f..9508d24b08 100644 --- a/src/components/App.css +++ b/src/components/App.css @@ -37,22 +37,6 @@ body { height: 48px; } -/* Toolbar */ - -.section-toolbar { - height: 39px; -} - -.toolbar-type { - width: 260px; - border-right: 1px solid var(--colors-grey400); - border-bottom: 1px solid var(--colors-grey400); -} - -.toolbar-menubar { - background-color: var(--colors-grey400); -} - /* Main */ .section-main { overflow: hidden; diff --git a/src/components/App.js b/src/components/App.js index 7e67b30a06..f268ab0f4c 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,4 +1,4 @@ -import { apiFetchOrganisationUnitLevels } from '@dhis2/analytics' +import { apiFetchOrganisationUnitLevels, Toolbar } from '@dhis2/analytics' import { useSetting } from '@dhis2/app-service-datastore' import i18n from '@dhis2/d2-i18n' import { @@ -233,17 +233,13 @@ export class UnconnectedApp extends Component { return ( <>
-
-
- -
-
- -
-
+ + + +
diff --git a/src/components/DownloadMenu/AdvancedSubMenu.js b/src/components/DownloadMenu/AdvancedSubMenu.js index bf447da4f0..0f536d3aaf 100644 --- a/src/components/DownloadMenu/AdvancedSubMenu.js +++ b/src/components/DownloadMenu/AdvancedSubMenu.js @@ -1,3 +1,4 @@ +import { HoverMenuListItem } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { MenuItem, MenuSectionHeader } from '@dhis2/ui' import PropTypes from 'prop-types' @@ -10,53 +11,69 @@ import { FILE_FORMAT_SQL, } from './constants.js' -export const AdvancedSubMenu = ({ onDownload, label, ...menuItemProps }) => ( - - - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format: FILE_FORMAT_JSON, - path: 'dataValueSet', - }) - } - /> - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format: FILE_FORMAT_XML, - path: 'dataValueSet', - }) - } - /> - - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format: FILE_FORMAT_JRXML, - }) - } - /> - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format: FILE_FORMAT_SQL, - path: 'debug/sql', - }) - } - /> - -) +export const AdvancedSubMenu = ({ + hoverable, + onDownload, + label, + ...menuItemProps +}) => { + const MenuItemComponent = hoverable ? HoverMenuListItem : MenuItem + + return ( + + + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format: FILE_FORMAT_JSON, + path: 'dataValueSet', + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format: FILE_FORMAT_XML, + path: 'dataValueSet', + }) + } + /> + + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format: FILE_FORMAT_JRXML, + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format: FILE_FORMAT_SQL, + path: 'debug/sql', + }) + } + /> + + ) +} AdvancedSubMenu.propTypes = { label: PropTypes.string.isRequired, onDownload: PropTypes.func.isRequired, + hoverable: PropTypes.bool, } diff --git a/src/components/DownloadMenu/DownloadMenu.js b/src/components/DownloadMenu/DownloadMenu.js index b1c01fc11f..bc7f5320a1 100644 --- a/src/components/DownloadMenu/DownloadMenu.js +++ b/src/components/DownloadMenu/DownloadMenu.js @@ -1,4 +1,4 @@ -import { VIS_TYPE_PIVOT_TABLE } from '@dhis2/analytics' +import { VIS_TYPE_PIVOT_TABLE, HoverMenuList } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { FlyoutMenu, MenuSectionHeader } from '@dhis2/ui' import PropTypes from 'prop-types' @@ -14,45 +14,66 @@ import { GraphicsMenu } from './GraphicsMenu.js' import { PlainDataSourceSubMenu } from './PlainDataSourceSubMenu.js' import { TableMenu } from './TableMenu.js' -const DownloadMenu = ({ visType, onDownloadData, onDownloadImage }) => ( - - {visType === VIS_TYPE_PIVOT_TABLE ? ( - - ) : ( - - )} - - - - - - - -) +const DownloadMenu = ({ + visType, + onDownloadData, + onDownloadImage, + hoverable, +}) => { + const MenuComponent = hoverable ? HoverMenuList : FlyoutMenu + + return ( + + {visType === VIS_TYPE_PIVOT_TABLE ? ( + + ) : ( + + )} + + + + + + + + ) +} DownloadMenu.propTypes = { visType: PropTypes.string.isRequired, onDownloadData: PropTypes.func.isRequired, onDownloadImage: PropTypes.func.isRequired, + hoverable: PropTypes.bool, } export { DownloadMenu } diff --git a/src/components/DownloadMenu/GraphicsMenu.js b/src/components/DownloadMenu/GraphicsMenu.js index 3fe856aa82..83537ebf52 100644 --- a/src/components/DownloadMenu/GraphicsMenu.js +++ b/src/components/DownloadMenu/GraphicsMenu.js @@ -1,3 +1,4 @@ +import { HoverMenuListItem } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { MenuItem, @@ -10,27 +11,34 @@ import PropTypes from 'prop-types' import React from 'react' import { FILE_FORMAT_PDF, FILE_FORMAT_PNG } from './constants.js' -export const GraphicsMenu = ({ onDownload }) => - React.Children.toArray([ - , - } - label={i18n.t('Image (.png)')} - onClick={() => onDownload({ format: FILE_FORMAT_PNG })} - />, - } - label={i18n.t('PDF (.pdf)')} - onClick={() => onDownload({ format: FILE_FORMAT_PDF })} - />, - ]) +export const GraphicsMenu = ({ hoverable, onDownload }) => { + const MenuItemComponent = hoverable ? HoverMenuListItem : MenuItem + + return ( + <> + + } + label={i18n.t('Image (.png)')} + onClick={() => onDownload({ format: FILE_FORMAT_PNG })} + /> + } + label={i18n.t('PDF (.pdf)')} + onClick={() => onDownload({ format: FILE_FORMAT_PDF })} + /> + + ) +} GraphicsMenu.propTypes = { onDownload: PropTypes.func.isRequired, + hoverable: PropTypes.bool, } diff --git a/src/components/DownloadMenu/ModalDownloadDropdown.js b/src/components/DownloadMenu/ModalDownloadDropdown.js index 421962a1c0..47ba771802 100644 --- a/src/components/DownloadMenu/ModalDownloadDropdown.js +++ b/src/components/DownloadMenu/ModalDownloadDropdown.js @@ -1,28 +1,40 @@ import i18n from '@dhis2/d2-i18n' import { DropdownButton } from '@dhis2/ui' import PropTypes from 'prop-types' -import React from 'react' +import React, { useCallback, useState } from 'react' import { DownloadMenu } from './DownloadMenu.js' import styles from './ModalDownloadDropdown.module.css' -import { useDownloadMenu } from './useDownloadMenu.js' +import { useDownload } from './useDownload.js' const ModalDownloadDropdown = ({ relativePeriodDate }) => { - const { - isOpen, - toggleOpen, - disabled, - doDownloadData, - doDownloadImage, - visType, - } = useDownloadMenu(relativePeriodDate) + const { disabled, doDownloadData, doDownloadImage, visType } = + useDownload(relativePeriodDate) + const [isOpen, setIsOpen] = useState(false) + const toggleOpen = useCallback(() => { + setIsOpen((currentIsOpen) => !currentIsOpen) + }, []) + const onDownloadData = useCallback( + (payload) => { + doDownloadData(payload) + setIsOpen(false) + }, + [doDownloadData] + ) + const onDownloadImage = useCallback( + (payload) => { + doDownloadImage(payload) + setIsOpen(false) + }, + [doDownloadImage] + ) return (
} diff --git a/src/components/DownloadMenu/PlainDataSourceSubMenu.js b/src/components/DownloadMenu/PlainDataSourceSubMenu.js index aaa8f06ac5..3f790e3a59 100644 --- a/src/components/DownloadMenu/PlainDataSourceSubMenu.js +++ b/src/components/DownloadMenu/PlainDataSourceSubMenu.js @@ -1,3 +1,4 @@ +import { HoverMenuListItem } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { MenuItem, MenuSectionHeader } from '@dhis2/ui' import PropTypes from 'prop-types' @@ -12,46 +13,56 @@ import { export const PlainDataSourceSubMenu = ({ onDownload, format, + hoverable, label, ...menuItemProps -}) => ( - - - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format, - idScheme: ID_SCHEME_UID, - }) - } - /> - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format, - idScheme: ID_SCHEME_CODE, - }) - } - /> - - onDownload({ - type: DOWNLOAD_TYPE_PLAIN, - format, - idScheme: ID_SCHEME_NAME, - }) - } - /> - -) +}) => { + const MenuItemComponent = hoverable ? HoverMenuListItem : MenuItem + + return ( + + + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format, + idScheme: ID_SCHEME_UID, + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format, + idScheme: ID_SCHEME_CODE, + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_PLAIN, + format, + idScheme: ID_SCHEME_NAME, + }) + } + /> + + ) +} PlainDataSourceSubMenu.propTypes = { format: PropTypes.string.isRequired, label: PropTypes.string.isRequired, onDownload: PropTypes.func.isRequired, + hoverable: PropTypes.bool, } diff --git a/src/components/DownloadMenu/TableMenu.js b/src/components/DownloadMenu/TableMenu.js index 1d73292836..b2b3227e70 100644 --- a/src/components/DownloadMenu/TableMenu.js +++ b/src/components/DownloadMenu/TableMenu.js @@ -1,3 +1,4 @@ +import { HoverMenuListItem } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import { MenuItem, MenuSectionHeader } from '@dhis2/ui' import PropTypes from 'prop-types' @@ -9,45 +10,52 @@ import { FILE_FORMAT_HTML_CSS, } from './constants.js' -export const TableMenu = ({ onDownload }) => - React.Children.toArray([ - , - - onDownload({ - type: DOWNLOAD_TYPE_TABLE, - format: FILE_FORMAT_XLS, - }) - } - />, - - onDownload({ - type: DOWNLOAD_TYPE_TABLE, - format: FILE_FORMAT_CSV, - }) - } - />, - - onDownload({ - type: DOWNLOAD_TYPE_TABLE, - format: FILE_FORMAT_HTML_CSS, - }) - } - />, - ]) +export const TableMenu = ({ hoverable, onDownload }) => { + const MenuItemComponent = hoverable ? HoverMenuListItem : MenuItem + + return ( + <> + + + onDownload({ + type: DOWNLOAD_TYPE_TABLE, + format: FILE_FORMAT_XLS, + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_TABLE, + format: FILE_FORMAT_CSV, + }) + } + /> + + onDownload({ + type: DOWNLOAD_TYPE_TABLE, + format: FILE_FORMAT_HTML_CSS, + }) + } + /> + + ) +} TableMenu.propTypes = { onDownload: PropTypes.func.isRequired, + hoverable: PropTypes.bool, } diff --git a/src/components/DownloadMenu/ToolbarDownloadDropdown.js b/src/components/DownloadMenu/ToolbarDownloadDropdown.js index bdff72784e..5dcbae0948 100644 --- a/src/components/DownloadMenu/ToolbarDownloadDropdown.js +++ b/src/components/DownloadMenu/ToolbarDownloadDropdown.js @@ -1,42 +1,21 @@ +import { HoverMenuDropdown } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' -import { Layer, Popper } from '@dhis2/ui' -import React, { useRef } from 'react' -import MenuButton from '../MenuButton/MenuButton.js' +import React from 'react' import { DownloadMenu } from './DownloadMenu.js' -import { useDownloadMenu } from './useDownloadMenu.js' +import { useDownload } from './useDownload.js' const ToolbarDownloadDropdown = () => { - const buttonRef = useRef() - const { - isOpen, - toggleOpen, - disabled, - doDownloadData, - doDownloadImage, - visType, - } = useDownloadMenu() + const { disabled, doDownloadData, doDownloadImage, visType } = useDownload() return ( - <> - - {i18n.t('Download')} - - {isOpen && ( - - - - - - )} - + + + ) } diff --git a/src/components/DownloadMenu/useDownloadMenu.js b/src/components/DownloadMenu/useDownload.js similarity index 95% rename from src/components/DownloadMenu/useDownloadMenu.js rename to src/components/DownloadMenu/useDownload.js index 3b6fb60afa..07a32c8357 100644 --- a/src/components/DownloadMenu/useDownloadMenu.js +++ b/src/components/DownloadMenu/useDownload.js @@ -1,6 +1,6 @@ import { Analytics } from '@dhis2/analytics' import { useConfig, useDataEngine, useDataMutation } from '@dhis2/app-runtime' -import { useState, useCallback } from 'react' +import { useCallback } from 'react' import { useSelector } from 'react-redux' import { sGetChart } from '../../reducers/chart.js' import { sGetCurrent } from '../../reducers/current.js' @@ -53,7 +53,7 @@ const addCommonParameters = (req, visualization, options) => { return req } -const useDownloadMenu = (relativePeriodDate) => { +const useDownload = (relativePeriodDate) => { const visualization = useSelector(sGetCurrent) const visType = useSelector(sGetUiType) const chart = useSelector(sGetChart) @@ -62,7 +62,6 @@ const useDownloadMenu = (relativePeriodDate) => { const { baseUrl } = useConfig() const dataEngine = useDataEngine() const analyticsEngine = Analytics.getAnalytics(dataEngine) - const [isOpen, setIsOpen] = useState(false) const openDownloadedFileInBlankTab = useCallback((blob) => { const url = URL.createObjectURL(blob) @@ -94,8 +93,6 @@ const useDownloadMenu = (relativePeriodDate) => { format === FILE_FORMAT_PNG ? getPng({ formData }) : getPdf({ formData }) - - setIsOpen(false) }, [chart, getPdf, getPng, visualization] ) @@ -177,7 +174,6 @@ const useDownloadMenu = (relativePeriodDate) => { ) window.open(url, target) - setIsOpen(false) }, [ analyticsEngine, @@ -190,8 +186,6 @@ const useDownloadMenu = (relativePeriodDate) => { ) return { - isOpen, - toggleOpen: () => setIsOpen(!isOpen), disabled: !visualization, doDownloadData, doDownloadImage, @@ -199,4 +193,4 @@ const useDownloadMenu = (relativePeriodDate) => { } } -export { useDownloadMenu } +export { useDownload } diff --git a/src/components/MenuBar/InterpretationsButton.js b/src/components/MenuBar/InterpretationsButton.js index e39e1fbe55..41fd8b3203 100644 --- a/src/components/MenuBar/InterpretationsButton.js +++ b/src/components/MenuBar/InterpretationsButton.js @@ -1,45 +1,24 @@ -import i18n from '@dhis2/d2-i18n' -import { IconChevronRight24, IconChevronLeft24 } from '@dhis2/ui' -import PropTypes from 'prop-types' +import { InterpretationsAndDetailsToggler } from '@dhis2/analytics' import React from 'react' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { acToggleUiRightSidebarOpen } from '../../actions/ui.js' import { sGetCurrent } from '../../reducers/current.js' import { sGetUiRightSidebarOpen } from '../../reducers/ui.js' -import MenuButton from '../MenuButton/MenuButton.js' -import styles from './styles/InterpretationsButton.module.css' -export const UnconnectedInterpretationsButton = (props) => ( - - {props.rightSidebarOpen ? ( -
- -
- ) : ( -
- -
- )} - {i18n.t('Interpretations')} -
-) +export const InterpretationsButton = () => { + const isShowing = useSelector(sGetUiRightSidebarOpen) + const current = useSelector(sGetCurrent) + const isDisabled = !current?.id + const dispatch = useDispatch() + const onClick = () => { + dispatch(acToggleUiRightSidebarOpen()) + } -UnconnectedInterpretationsButton.propTypes = { - id: PropTypes.string, - rightSidebarOpen: PropTypes.bool, - onClick: PropTypes.func, + return ( + + ) } - -const mapStateToProps = (state) => ({ - rightSidebarOpen: sGetUiRightSidebarOpen(state), - id: (sGetCurrent(state) || {}).id, -}) - -const mapDispatchToProps = (dispatch) => ({ - onClick: () => dispatch(acToggleUiRightSidebarOpen()), -}) - -export const InterpretationsButton = connect( - mapStateToProps, - mapDispatchToProps -)(UnconnectedInterpretationsButton) diff --git a/src/components/MenuBar/MenuBar.js b/src/components/MenuBar/MenuBar.js index 7e1c93b6b6..75a23f20b5 100644 --- a/src/components/MenuBar/MenuBar.js +++ b/src/components/MenuBar/MenuBar.js @@ -1,7 +1,9 @@ import { FileMenu, + HoverMenuBar, VIS_TYPE_GROUP_ALL, VIS_TYPE_GROUP_CHARTS, + UpdateButton, } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' import PropTypes from 'prop-types' @@ -13,11 +15,9 @@ import history from '../../modules/history.js' import { visTypes } from '../../modules/visualization.js' import { sGetCurrent } from '../../reducers/current.js' import { ToolbarDownloadDropdown } from '../DownloadMenu/ToolbarDownloadDropdown.js' -import UpdateButton from '../UpdateButton/UpdateButton.js' import UpdateVisualizationContainer from '../UpdateButton/UpdateVisualizationContainer.js' import VisualizationOptionsManager from '../VisualizationOptions/VisualizationOptionsManager.js' import { InterpretationsButton } from './InterpretationsButton.js' -import styles from './styles/MenuBar.module.css' const onOpen = (id) => { const path = `/${id}` @@ -51,38 +51,36 @@ const filterVisTypes = [ ] const UnconnectedMenuBar = ({ dataTest, ...props }, context) => ( -
+ <> ( )} /> - - - - + + + -
+ + -
+ ) UnconnectedMenuBar.propTypes = { diff --git a/src/components/MenuBar/styles/InterpretationsButton.module.css b/src/components/MenuBar/styles/InterpretationsButton.module.css deleted file mode 100644 index 35a769f317..0000000000 --- a/src/components/MenuBar/styles/InterpretationsButton.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.iconWrapper { - display: flex; - margin-right: var(--spacers-dp4); -} diff --git a/src/components/MenuBar/styles/MenuBar.module.css b/src/components/MenuBar/styles/MenuBar.module.css deleted file mode 100644 index 1ff0da6243..0000000000 --- a/src/components/MenuBar/styles/MenuBar.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.menuBar { - background: var(--colors-white); - display: flex; - align-items: center; - padding: 0 var(--spacers-dp8); - height: 38px; -} -.updateButton { - margin-right: var(--spacers-dp8); -} -.grow { - flex: 1 1 0%; -} diff --git a/src/components/MenuButton/MenuButton.js b/src/components/MenuButton/MenuButton.js deleted file mode 100644 index a8f7291cab..0000000000 --- a/src/components/MenuButton/MenuButton.js +++ /dev/null @@ -1,34 +0,0 @@ -import PropTypes from 'prop-types' -import React, { forwardRef } from 'react' -import styles from './styles/MenuButton.module.css' - -const MenuButton = forwardRef( - ({ children, dataTest, disabled, name, onBlur, onClick, onFocus }, ref) => ( - - ) -) - -MenuButton.displayName = 'MenuButton' - -MenuButton.propTypes = { - children: PropTypes.node, - dataTest: PropTypes.string, - disabled: PropTypes.bool, - name: PropTypes.string, - onBlur: PropTypes.func, - onClick: PropTypes.func, - onFocus: PropTypes.func, -} - -export default MenuButton diff --git a/src/components/MenuButton/styles/MenuButton.module.css b/src/components/MenuButton/styles/MenuButton.module.css deleted file mode 100644 index 1ec3474a61..0000000000 --- a/src/components/MenuButton/styles/MenuButton.module.css +++ /dev/null @@ -1,47 +0,0 @@ -.menuButton { - display: inline-flex; - position: relative; - align-items: center; - justify-content: center; - font-size: 14px; - font-weight: 400; - text-transform: none; - padding: 6px var(--spacers-dp12); - border-radius: 3px; - color: var(--colors-grey900); - box-sizing: border-box; - line-height: 1.75; - background: none; - border: none; - transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; - cursor: pointer; -} - -.menuButton:hover:enabled { - background-color: var(--colors-grey200); -} - -.menuButton:disabled { - color: var(--colors-grey400); - cursor: not-allowed; -} - -.menuButton:active { - background-color: var(--colors-grey300); -} - -.menuButton:focus { - outline: 2px solid var(--colors-blue600); -} - -.menuButton:focus:not(:focus-visible) { - outline: none; -} - -.menuButton svg { - color: var(--colors-grey600); -} - -.menuButton:disabled svg { - color: var(--colors-grey400); -} diff --git a/src/components/VisualizationOptions/VisualizationOptionsManager.js b/src/components/VisualizationOptions/VisualizationOptionsManager.js index c3ee80f567..3bc6608ef0 100644 --- a/src/components/VisualizationOptions/VisualizationOptionsManager.js +++ b/src/components/VisualizationOptions/VisualizationOptionsManager.js @@ -4,6 +4,9 @@ import { hasCustomAxes, hasRelativeItems, isDualAxisType, + HoverMenuDropdown, + HoverMenuList, + HoverMenuListItem, VisualizationOptions, } from '@dhis2/analytics' import i18n from '@dhis2/d2-i18n' @@ -17,7 +20,6 @@ import { sGetDimensionItemsByAxis, sGetUiLayout, } from '../../reducers/ui.js' -import MenuButton from '../MenuButton/MenuButton.js' import UpdateVisualizationContainer from '../UpdateButton/UpdateVisualizationContainer.js' const VisualizationOptionsManager = ({ @@ -27,19 +29,10 @@ const VisualizationOptionsManager = ({ columns, series, }) => { - const [dialogIsOpen, setDialogIsOpen] = useState(false) - - const onClick = (handler) => () => { + const [selectedOptionConfigKey, setSelectedOptionConfigKey] = useState(null) + const onOptionsUpdate = (handler) => { handler() - onClose() - } - - const onClose = () => { - toggleVisualizationOptionsDialog() - } - - const toggleVisualizationOptionsDialog = () => { - setDialogIsOpen(!dialogIsOpen) + setSelectedOptionConfigKey(null) } const filteredSeries = series.filter((seriesItem) => @@ -65,19 +58,30 @@ const VisualizationOptionsManager = ({ return ( <> - - {i18n.t('Options')} - - {dialogIsOpen && ( + + {optionsConfig.map(({ label, key }) => ( + { + setSelectedOptionConfigKey(key) + }} + /> + ))} + + + {selectedOptionConfigKey && ( ( onOptionsUpdate(handler)} + onClose={() => setSelectedOptionConfigKey(null)} + initiallyActiveTabKey={selectedOptionConfigKey} /> )} /> diff --git a/src/components/VisualizationTypeSelector/VisualizationTypeSelector.js b/src/components/VisualizationTypeSelector/VisualizationTypeSelector.js index 757e629e51..44c89e2aed 100644 --- a/src/components/VisualizationTypeSelector/VisualizationTypeSelector.js +++ b/src/components/VisualizationTypeSelector/VisualizationTypeSelector.js @@ -1,7 +1,8 @@ -import { visTypeDisplayNames } from '@dhis2/analytics' +import { visTypeDisplayNames, ToolbarSidebar } from '@dhis2/analytics' import { useSetting } from '@dhis2/app-service-datastore' import i18n from '@dhis2/d2-i18n' import { Divider, Popper, Layer } from '@dhis2/ui' +import cx from 'classnames' import PropTypes from 'prop-types' import React, { useState, createRef } from 'react' import { connect } from 'react-redux' @@ -97,20 +98,31 @@ const UnconnectedVisualizationTypeSelector = ( return ( <> -
- - - {visTypeDisplayNames[visualizationType]} - - - - -
+ +
+ + + {visTypeDisplayNames[visualizationType]} + + + + +
+
{listIsOpen && ( diff --git a/src/components/VisualizationTypeSelector/styles/VisualizationTypeSelector.module.css b/src/components/VisualizationTypeSelector/styles/VisualizationTypeSelector.module.css index f87c1ce885..cdbcfef3ba 100644 --- a/src/components/VisualizationTypeSelector/styles/VisualizationTypeSelector.module.css +++ b/src/components/VisualizationTypeSelector/styles/VisualizationTypeSelector.module.css @@ -3,6 +3,10 @@ margin-left: auto; } +.arrowIcon.listIsOpen { + transform: rotate(180deg); +} + .button { padding: 7px var(--spacers-dp8); display: flex; @@ -10,10 +14,18 @@ justify-content: flex-start; background-color: var(--colors-white); cursor: pointer; + flex-grow: 1 +} + +.button:hover, +.button.listIsOpen { + background-color: var(--colors-grey200); } -.button > span { +.button > .selectedVizTypeLabel { font-size: 14px; + padding-top: 1px; + user-select: none; } .cardContainer { diff --git a/yarn.lock b/yarn.lock index a3d6ba9ab1..779743a32b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2028,10 +2028,10 @@ classnames "^2.3.1" prop-types "^15.7.2" -"@dhis2/analytics@^25.1.11": - version "25.1.11" - resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-25.1.11.tgz#04c1990798f1c33bebd16849dff4a81523d9e1ce" - integrity sha512-+aLYTbcVsxt5ZVLROJgvljFoLWK31jsS6xWzhwzWTQi+7WGVt5ONRUS45rZBYJas4FQj+SqPhCF6nXCssx7huA== +"@dhis2/analytics@^26.0.7": + version "26.0.7" + resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-26.0.7.tgz#d0883c74fc909359d1ce01e82c267ba99e8186a5" + integrity sha512-NJ//FeWWn6yy1bDK3lcMPdwOWVhLBQyh1vmj+S0/k86iKRfF+8tmZwinZLVLebzV3DRjSoWSPCzwU6zVDedjWg== dependencies: "@dhis2/d2-ui-rich-text" "^7.4.0" "@dhis2/multi-calendar-dates" "1.0.0"