+ )
+}
diff --git a/components/header-bar/src/debug-info/use-debug-info.js b/components/header-bar/src/debug-info/use-debug-info.js
new file mode 100644
index 0000000000..20bbb96794
--- /dev/null
+++ b/components/header-bar/src/debug-info/use-debug-info.js
@@ -0,0 +1,15 @@
+import { useConfig } from '@dhis2/app-runtime'
+
+export const useDebugInfo = () => {
+ const { appName, appVersion, systemInfo } = useConfig()
+
+ return {
+ app_name: appName || null,
+ app_version: appVersion?.full || null,
+ dhis2_version: systemInfo?.version || null,
+ dhis2_revision: systemInfo?.revision || null,
+ }
+}
+
+export const useFormattedDebugInfo = () =>
+ JSON.stringify(useDebugInfo(), undefined, 2)
diff --git a/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos.feature b/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos.feature
deleted file mode 100644
index 32a50f9715..0000000000
--- a/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos.feature
+++ /dev/null
@@ -1,29 +0,0 @@
-Feature: The HeaderBar displays instance and app infos
-
- Scenario: The HeaderBar displays both instance and app infos
- Given the HeaderBar has been supplied with an app name and version
- And the HeaderBar's profile menu is visible
- And the profile menu has successfully loaded the instance infos
- Then the instance infos should be displayed
- And the app infos should be displayed
-
- Scenario: The HeaderBar displays app infos and an instance infos loading message
- Given the HeaderBar has been supplied with an app name and version
- And the HeaderBar's profile menu is visible
- And the profile menu is loading the instance infos
- Then the app infos should be displayed
- And a message stating that the instance infos are being loaded should be displayed
-
- Scenario: The HeaderBar displays app infos and an instance infos error message
- Given the HeaderBar has been supplied with an app name and version
- And the HeaderBar's profile menu is visible
- And the profile menu failed loading the instance infos
- Then the app infos should be displayed
- And a message stating that loading the instance infos has failed should be displayed
-
- Scenario: The HeaderBar displays only instance infos
- Given the HeaderBar has not been supplied with an app version
- And the HeaderBar's profile menu is visible
- And the profile menu has successfully loaded the instance infos
- Then the instance infos should be displayed
- And the app infos should not be displayed
diff --git a/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos/index.js b/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos/index.js
deleted file mode 100644
index a96d88a322..0000000000
--- a/components/header-bar/src/features/the_headerbar_displays_instance_and_app_infos/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { Given, Then } from 'cypress-cucumber-preprocessor/steps'
-
-Given('the HeaderBar has been supplied with an app name and version', () => {})
-
-Given('the HeaderBar has not been supplied with an app version', () => {})
-
-Given("the HeaderBar's profile menu is visible", () => {})
-
-Given('the profile menu failed loading the instance infos', () => {})
-
-Given('the profile menu has successfully loaded the instance infos', () => {})
-
-Given('the profile menu is loading the instance infos', () => {})
-
-Then(
- 'a message stating that loading the instance infos has failed should be displayed',
- () => {}
-)
-
-Then(
- 'a message stating that the instance infos are being loaded should be displayed',
- () => {}
-)
-
-Then('the app infos should be displayed', () => {})
-
-Then('the app infos should not be displayed', () => {})
-
-Then('the instance infos should be displayed', () => {})
diff --git a/components/header-bar/src/features/the_headerbar_should_display_app_update_notification.feature b/components/header-bar/src/features/the_headerbar_should_display_app_update_notification.feature
new file mode 100644
index 0000000000..9a61ed53c7
--- /dev/null
+++ b/components/header-bar/src/features/the_headerbar_should_display_app_update_notification.feature
@@ -0,0 +1,22 @@
+Feature: The HeaderBar should display app update notification
+
+ Scenario: No app update is available
+ Given the HeaderBar is rendered without an available update
+ When the user opens the profile menu
+ Then the update notification should not be displayed
+
+ Scenario: An app update is available
+ Given the HeaderBar is rendered with an available update
+ When the user opens the profile menu
+ Then the update notification should be displayed
+
+ Scenario: A callback is executed when the user click on the update notification
+ Given the HeaderBar is rendered with an available update
+ When the user opens the profile menu
+ When the user clicks the update notification
+ Then a callback should display a test div
+
+ Scenario: An app update is available but not app name was specified
+ Given the HeaderBar is rendered with no app name and an available update
+ When the user opens the profile menu
+ Then the update notification should be displayed without app name
\ No newline at end of file
diff --git a/components/header-bar/src/features/the_headerbar_should_display_app_update_notification/index.js b/components/header-bar/src/features/the_headerbar_should_display_app_update_notification/index.js
new file mode 100644
index 0000000000..40e6122f18
--- /dev/null
+++ b/components/header-bar/src/features/the_headerbar_should_display_app_update_notification/index.js
@@ -0,0 +1,52 @@
+import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
+
+Given('the HeaderBar is rendered without an available update', () => {
+ cy.visitStory('HeaderBarTesting', 'default')
+})
+
+Given('the HeaderBar is rendered with an available update', () => {
+ cy.visitStory('HeaderBarTesting', 'With Update Available Notification')
+})
+
+Given(
+ 'the HeaderBar is rendered with no app name and an available update',
+ () => {
+ cy.visitStory(
+ 'HeaderBarTesting',
+ 'With Update Available Notification No App Name'
+ )
+ }
+)
+
+When('the user opens the profile menu', () => {
+ cy.get('[data-test="headerbar-profile"] > button').click()
+})
+
+Then('the update notification should not be displayed', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').should(
+ 'not.exist'
+ )
+})
+
+Then('the update notification should be displayed', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]')
+ .should('contain', 'New Data Visualizer version available')
+ .should('contain', 'Click to reload')
+})
+
+Then('the update notification should be displayed without app name', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]')
+ .should('contain', 'New app version available')
+ .should('contain', 'Click to reload')
+})
+
+When('the user clicks the update notification', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').click()
+})
+
+Then('the profile menu should not be shown', () => {
+ cy.get('[data-test="headerbar-profile-menu"]').should('not.exist')
+})
+Then('a callback should display a test div', () => {
+ cy.contains('The callback was successful').should('be.visible')
+})
diff --git a/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos.feature b/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos.feature
new file mode 100644
index 0000000000..1aacde9747
--- /dev/null
+++ b/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos.feature
@@ -0,0 +1,52 @@
+Feature: The HeaderBar should display debug version infos
+
+ Scenario: The debug version infos are displayed in the profile menu
+ Given the HeaderBar is rendered with an app name and app version in runtime context
+ When the user opens the profile menu
+ Then the instance version should be displayed
+ And the app's name and version should be displayed
+
+ Scenario: The debug version info modal is displayed when clicking on the menu item
+ Given the HeaderBar is rendered with an app name and app version in runtime context
+ When the user opens the profile menu
+ When the user clicks the debug info menu item
+ Then the debug info modal should be shown
+
+ Scenario: The debug version info modal displays debug info
+ Given the HeaderBar is rendered with an app name and app version in runtime context
+ When the user opens the profile menu
+ When the user clicks the debug info menu item
+ Then the debug info modal should contain debug info
+
+ Scenario: The debug version info should be copied to clipboard
+ Given the HeaderBar is rendered with an app name and app version in runtime context
+ When the user opens the profile menu
+ When the user clicks the debug info menu item
+ When the user clicks the copy debug info button
+ Then the debug info should be copied to clipboard
+ And the debug info copied to clipboard alert should be shown
+ And the debug info modal should not be shown
+
+ Scenario: The debug version infos are displayed with unknown dhis2 version in the profile menu
+ Given the HeaderBar is rendered without an instance version in runtime context
+ When the user opens the profile menu
+ Then the instance version should show as unknown
+ And the app's name and version should be displayed
+
+ Scenario: The debug version infos are displayed with unknown app name and version in the profile menu
+ Given the HeaderBar is rendered without app name or app version in runtime context
+ When the user opens the profile menu
+ Then the instance version should be displayed
+ And the unknown app with unknown version should be displayed
+
+ Scenario: The debug version infos are displayed with unknown app name in the profile menu
+ Given the HeaderBar is rendered without app name in runtime context
+ When the user opens the profile menu
+ Then the instance version should be displayed
+ And the unknown app with app's version should be displayed
+
+ Scenario: The debug version infos are displayed with unknown app version in the profile menu
+ Given the HeaderBar is rendered with an app name but without app version in runtime context
+ When the user opens the profile menu
+ Then the instance version should be displayed
+ And the app's name with unknown version should be displayed
\ No newline at end of file
diff --git a/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos/index.js b/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos/index.js
new file mode 100644
index 0000000000..b516685d84
--- /dev/null
+++ b/components/header-bar/src/features/the_headerbar_should_display_debug_version_infos/index.js
@@ -0,0 +1,130 @@
+import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
+
+Given(
+ 'the HeaderBar is rendered without an instance version in runtime context',
+ () => {
+ cy.visitStory('HeaderBarTesting', 'With Unknown Instance Version')
+ }
+)
+
+Given(
+ 'the HeaderBar is rendered with an app name and app version in runtime context',
+ () => {
+ cy.visitStory('HeaderBarTesting', 'default')
+ }
+)
+
+Given('the HeaderBar is rendered without app name in runtime context', () => {
+ cy.visitStory('HeaderBarTesting', 'With Unknown App Name')
+})
+
+Given(
+ 'the HeaderBar is rendered with an app name but without app version in runtime context',
+ () => {
+ cy.visitStory('HeaderBarTesting', 'With Unknown App Version')
+ }
+)
+
+Given(
+ 'the HeaderBar is rendered without app name or app version in runtime context',
+ () => {
+ cy.visitStory('HeaderBarTesting', 'With Unknown App Name And Version')
+ }
+)
+
+When('the user opens the profile menu', () => {
+ cy.get('[data-test="headerbar-profile"] > button').click()
+})
+
+Then("the app's name and version should be displayed", () => {
+ cy.get('[data-test="dhis2-ui-headerbar-appinfo"]').should(
+ 'contain',
+ 'TestApp 101.2.3-beta.4'
+ )
+})
+
+Then("the app's name with unknown version should be displayed", () => {
+ cy.get('[data-test="dhis2-ui-headerbar-appinfo"]').should(
+ 'contain',
+ 'TestApp version unknown'
+ )
+})
+
+Then("the unknown app with app's version should be displayed", () => {
+ cy.get('[data-test="dhis2-ui-headerbar-appinfo"]').should(
+ 'contain',
+ 'App 101.2.3-beta.4'
+ )
+})
+
+Then('the unknown app with unknown version should be displayed', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-appinfo"]').should(
+ 'contain',
+ 'App version unknown'
+ )
+})
+
+Then('the instance version should be displayed', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-instanceinfo"]').should(
+ 'contain',
+ 'DHIS2 2.39.2.1-SNAPSHOT'
+ )
+})
+
+Then('the instance version should show as unknown', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-instanceinfo"]').should(
+ 'contain',
+ 'DHIS2 version unknown'
+ )
+})
+
+When('the user clicks the debug info menu item', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-debuginfo"] > a').click()
+})
+
+Then('the debug info modal should be shown', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-debuginfomodal"]').should(
+ 'be.visible'
+ )
+})
+Then('the debug info modal should not be shown', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-debuginfomodal"]').should(
+ 'not.exist'
+ )
+})
+
+Then('the debug info modal should contain debug info', () => {
+ cy.get('[data-test="dhis2-ui-headerbar-debuginfotable"]')
+ .should(
+ 'contain',
+ '2.39.2.1-SNAPSHOT' // DHIS2 version
+ )
+ .should(
+ 'contain',
+ '6607c3c' // Revision
+ )
+ .should(
+ 'contain',
+ 'TestApp' // App name
+ )
+ .should(
+ 'contain',
+ '101.2.3-beta.4' // App version
+ )
+})
+
+When('the user clicks the copy debug info button', () => {
+ cy.contains('Copy debug info').click()
+})
+
+Then('the debug info should be copied to clipboard', () => {
+ cy.window().then((win) => {
+ win.navigator.clipboard.readText().then((text) => {
+ expect(text).to.contain('2.39.2.1-SNAPSHOT')
+ })
+ })
+})
+
+Then('the debug info copied to clipboard alert should be shown', () => {
+ cy.contains('Debug information copied to clipboard').should('exist')
+})
diff --git a/components/header-bar/src/header-bar-context.js b/components/header-bar/src/header-bar-context.js
new file mode 100644
index 0000000000..5fcc06e7c2
--- /dev/null
+++ b/components/header-bar/src/header-bar-context.js
@@ -0,0 +1,28 @@
+import PropTypes from 'prop-types'
+import React, { createContext, useContext } from 'react'
+
+const headerBarContext = createContext({
+ updateAvailable: false,
+ onApplyAvailableUpdate: () => {},
+})
+
+export const HeaderBarContextProvider = ({
+ updateAvailable,
+ onApplyAvailableUpdate,
+ children,
+}) => {
+ return (
+
+ {children}
+
+ )
+}
+HeaderBarContextProvider.propTypes = {
+ children: PropTypes.node,
+ updateAvailable: PropTypes.bool,
+ onApplyAvailableUpdate: PropTypes.func,
+}
+
+export const useHeaderBarContext = () => useContext(headerBarContext)
diff --git a/components/header-bar/src/header-bar.js b/components/header-bar/src/header-bar.js
index ae4f007f40..3ebb45b57e 100755
--- a/components/header-bar/src/header-bar.js
+++ b/components/header-bar/src/header-bar.js
@@ -3,6 +3,7 @@ import { colors } from '@dhis2/ui-constants'
import PropTypes from 'prop-types'
import React, { useMemo } from 'react'
import Apps from './apps.js'
+import { HeaderBarContextProvider } from './header-bar-context.js'
import { joinPath } from './join-path.js'
import i18n from './locales/index.js'
import { Logo } from './logo.js'
@@ -32,8 +33,14 @@ const query = {
},
}
-export const HeaderBar = ({ appName, className }) => {
+export const HeaderBar = ({
+ appName,
+ className,
+ updateAvailable,
+ onApplyAvailableUpdate,
+}) => {
const {
+ appName: configAppName,
baseUrl,
pwaEnabled,
headerbar: { showOnlineStatus } = {},
@@ -51,71 +58,88 @@ export const HeaderBar = ({ appName, className }) => {
icon: getPath(app.icon),
defaultAction: getPath(app.defaultAction),
}))
- }, [data])
+ }, [data, baseUrl])
// See https://jira.dhis2.org/browse/LIBS-180
if (!loading && !error) {
- // TODO: This will run every render which is probably wrong! Also, setting the global locale shouldn't be done in the headerbar
+ // TODO: This will run every render which is probably wrong!
+ // Also, setting the global locale shouldn't be done in the headerbar
const locale = data.user.settings.keyUiLocale || 'en'
i18n.setDefaultNamespace('default')
i18n.changeLanguage(locale)
}
return (
-
-