@dhis2-ui/header-bar 8.4.16 → 8.5.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/build/cjs/__e2e__/header-bar.stories.e2e.js +40 -0
  2. package/build/cjs/__e2e__/stories/common.js +99 -32
  3. package/build/cjs/__e2e__/stories/with-debug-info-edge-cases.js +45 -0
  4. package/build/cjs/__e2e__/stories/with-update-available-notification.js +38 -0
  5. package/build/cjs/apps.js +1 -1
  6. package/build/cjs/debug-info/debug-info-menu-item.js +67 -0
  7. package/build/cjs/debug-info/debug-info-modal.js +59 -0
  8. package/build/cjs/debug-info/debug-info-table.js +47 -0
  9. package/build/cjs/debug-info/use-debug-info.js +28 -0
  10. package/build/cjs/features/the_headerbar_should_display_app_update_notification/index.js +34 -0
  11. package/build/cjs/features/the_headerbar_should_display_app_update_notification.feature +22 -0
  12. package/build/cjs/features/the_headerbar_should_display_debug_version_infos/index.js +69 -0
  13. package/build/cjs/features/the_headerbar_should_display_debug_version_infos.feature +52 -0
  14. package/build/cjs/header-bar-context.js +46 -0
  15. package/build/cjs/header-bar.js +22 -11
  16. package/build/cjs/header-bar.stories.js +70 -72
  17. package/build/cjs/locales/en/translations.json +12 -1
  18. package/build/cjs/profile/use-on-doc-click.js +30 -0
  19. package/build/cjs/profile/use-on-doc-click.test.js +42 -0
  20. package/build/cjs/profile-menu/index.js +18 -0
  21. package/build/cjs/{profile → profile-menu}/profile-header.js +0 -0
  22. package/build/cjs/{profile → profile-menu}/profile-menu.js +23 -15
  23. package/build/cjs/profile-menu/update-notification.js +70 -0
  24. package/build/cjs/profile.js +52 -62
  25. package/build/es/__e2e__/header-bar.stories.e2e.js +5 -3
  26. package/build/es/__e2e__/stories/common.js +96 -33
  27. package/build/es/__e2e__/stories/with-debug-info-edge-cases.js +22 -0
  28. package/build/es/__e2e__/stories/with-update-available-notification.js +19 -0
  29. package/build/es/apps.js +1 -1
  30. package/build/es/debug-info/debug-info-menu-item.js +48 -0
  31. package/build/es/debug-info/debug-info-modal.js +41 -0
  32. package/build/es/debug-info/debug-info-table.js +35 -0
  33. package/build/es/debug-info/use-debug-info.js +15 -0
  34. package/build/es/features/the_headerbar_should_display_app_update_notification/index.js +31 -0
  35. package/build/es/features/the_headerbar_should_display_app_update_notification.feature +22 -0
  36. package/build/es/features/the_headerbar_should_display_debug_version_infos/index.js +66 -0
  37. package/build/es/features/the_headerbar_should_display_debug_version_infos.feature +52 -0
  38. package/build/es/header-bar-context.js +25 -0
  39. package/build/es/header-bar.js +21 -11
  40. package/build/es/header-bar.stories.js +65 -71
  41. package/build/es/locales/en/translations.json +12 -1
  42. package/build/es/profile/use-on-doc-click.js +20 -0
  43. package/build/es/profile/use-on-doc-click.test.js +38 -0
  44. package/build/es/profile-menu/index.js +1 -0
  45. package/build/es/{profile → profile-menu}/profile-header.js +0 -0
  46. package/build/es/{profile → profile-menu}/profile-menu.js +23 -17
  47. package/build/es/profile-menu/update-notification.js +51 -0
  48. package/build/es/profile.js +49 -64
  49. package/package.json +15 -13
  50. package/build/cjs/features/the_headerbar_displays_instance_and_app_infos/index.js +0 -15
  51. package/build/cjs/features/the_headerbar_displays_instance_and_app_infos.feature +0 -29
  52. package/build/es/features/the_headerbar_displays_instance_and_app_infos/index.js +0 -12
  53. package/build/es/features/the_headerbar_displays_instance_and_app_infos.feature +0 -29
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.UpdateNotification = UpdateNotification;
7
+
8
+ var _style = _interopRequireDefault(require("styled-jsx/style"));
9
+
10
+ var _menu = require("@dhis2-ui/menu");
11
+
12
+ var _appRuntime = require("@dhis2/app-runtime");
13
+
14
+ var _uiConstants = require("@dhis2/ui-constants");
15
+
16
+ var _propTypes = _interopRequireDefault(require("prop-types"));
17
+
18
+ var _react = _interopRequireDefault(require("react"));
19
+
20
+ var _headerBarContext = require("../header-bar-context.js");
21
+
22
+ var _index = _interopRequireDefault(require("../locales/index.js"));
23
+
24
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
+
26
+ function UpdateNotification(_ref) {
27
+ let {
28
+ hideProfileMenu
29
+ } = _ref;
30
+ const {
31
+ appName
32
+ } = (0, _appRuntime.useConfig)();
33
+ const {
34
+ updateAvailable,
35
+ onApplyAvailableUpdate
36
+ } = (0, _headerBarContext.useHeaderBarContext)();
37
+
38
+ const onClick = () => {
39
+ hideProfileMenu();
40
+ onApplyAvailableUpdate === null || onApplyAvailableUpdate === void 0 ? void 0 : onApplyAvailableUpdate();
41
+ };
42
+
43
+ const updateNotificationLabel = /*#__PURE__*/_react.default.createElement("div", {
44
+ className: _style.default.dynamic([["4135170305", [_uiConstants.colors.blue600]]]) + " " + "root"
45
+ }, /*#__PURE__*/_react.default.createElement("div", {
46
+ className: _style.default.dynamic([["4135170305", [_uiConstants.colors.blue600]]]) + " " + "badge"
47
+ }), /*#__PURE__*/_react.default.createElement("div", {
48
+ className: _style.default.dynamic([["4135170305", [_uiConstants.colors.blue600]]]) + " " + "spacer"
49
+ }), /*#__PURE__*/_react.default.createElement("div", {
50
+ className: _style.default.dynamic([["4135170305", [_uiConstants.colors.blue600]]]) + " " + "message"
51
+ }, appName ? _index.default.t('New {{appName}} version available', {
52
+ appName
53
+ }) : _index.default.t('New app version available'), /*#__PURE__*/_react.default.createElement("br", {
54
+ className: _style.default.dynamic([["4135170305", [_uiConstants.colors.blue600]]])
55
+ }), _index.default.t('Click to reload')), /*#__PURE__*/_react.default.createElement(_style.default, {
56
+ id: "4135170305",
57
+ dynamic: [_uiConstants.colors.blue600]
58
+ }, [".root.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;line-height:17px;}", ".badge.__jsx-style-dynamic-selector{display:inline-block;width:12px;height:12px;margin:0 8px;border-radius:6px;background-color:".concat(_uiConstants.colors.blue600, ";}"), ".spacer.__jsx-style-dynamic-selector{display:inline-block;width:8px;}", ".message.__jsx-style-dynamic-selector{display:inline-block;}"]));
59
+
60
+ return updateAvailable ? /*#__PURE__*/_react.default.createElement(_menu.MenuItem, {
61
+ dense: true,
62
+ onClick: onClick,
63
+ label: updateNotificationLabel,
64
+ dataTest: "dhis2-ui-headerbar-updatenotification"
65
+ }) : null;
66
+ }
67
+
68
+ UpdateNotification.propTypes = {
69
+ hideProfileMenu: _propTypes.default.func.isRequired
70
+ };
@@ -11,78 +11,68 @@ var _userAvatar = require("@dhis2-ui/user-avatar");
11
11
 
12
12
  var _propTypes = _interopRequireDefault(require("prop-types"));
13
13
 
14
- var _react = _interopRequireDefault(require("react"));
14
+ var _react = _interopRequireWildcard(require("react"));
15
15
 
16
- var _profileMenu = require("./profile/profile-menu.js");
16
+ var _debugInfoModal = require("./debug-info/debug-info-modal.js");
17
17
 
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
-
20
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
21
-
22
- class Profile extends _react.default.Component {
23
- constructor() {
24
- super(...arguments);
18
+ var _index = require("./profile-menu/index.js");
25
19
 
26
- _defineProperty(this, "state", {
27
- show: false
28
- });
20
+ var _useOnDocClick = require("./profile/use-on-doc-click.js");
29
21
 
30
- _defineProperty(this, "onDocClick", evt => {
31
- if (this.elContainer && !this.elContainer.contains(evt.target)) {
32
- this.setState({
33
- show: false
34
- });
35
- }
36
- });
22
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
37
23
 
38
- _defineProperty(this, "handleToggle", () => this.setState({
39
- show: !this.state.show
40
- }));
41
- }
24
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
42
25
 
43
- componentDidMount() {
44
- document.addEventListener('click', this.onDocClick);
45
- }
46
-
47
- componentWillUnmount() {
48
- document.removeEventListener('click', this.onDocClick);
49
- }
50
-
51
- render() {
52
- const {
53
- name,
54
- email,
55
- avatarId,
56
- helpUrl
57
- } = this.props;
58
- return /*#__PURE__*/_react.default.createElement("div", {
59
- ref: c => this.elContainer = c,
60
- "data-test": "headerbar-profile",
61
- className: "jsx-2642719072" + " " + "headerbar-profile"
62
- }, /*#__PURE__*/_react.default.createElement("button", {
63
- onClick: this.handleToggle,
64
- className: "jsx-2642719072" + " " + "headerbar-profile-btn"
65
- }, /*#__PURE__*/_react.default.createElement(_userAvatar.UserAvatar, {
66
- avatarId: avatarId,
67
- name: name,
68
- dataTest: "headerbar-profile-icon",
69
- medium: true
70
- })), this.state.show ? /*#__PURE__*/_react.default.createElement(_profileMenu.ProfileMenu, {
71
- avatarId: avatarId,
72
- name: name,
73
- email: email,
74
- helpUrl: helpUrl
75
- }) : null, /*#__PURE__*/_react.default.createElement(_style.default, {
76
- id: "2642719072"
77
- }, [".headerbar-profile.jsx-2642719072{position:relative;width:36px;height:36px;min-width:36px;min-height:36px;margin:2px 12px 0 24px;}", ".headerbar-profile-btn.jsx-2642719072{background:transparent;padding:0;border:0;cursor:pointer;width:100%;height:100%;}", ".headerbar-profile-btn.jsx-2642719072:focus{outline:1px dotted white;}"]));
78
- }
26
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
79
27
 
80
- }
28
+ const Profile = _ref => {
29
+ let {
30
+ name,
31
+ email,
32
+ avatarId,
33
+ helpUrl
34
+ } = _ref;
35
+ const [showProfileMenu, setShowProfileMenu] = (0, _react.useState)(false);
36
+ const [showDebugInfoModal, setShowDebugInfoModal] = (0, _react.useState)(false);
37
+ const hideProfileMenu = (0, _react.useCallback)(() => setShowProfileMenu(false), [setShowProfileMenu]);
38
+ const toggleProfileMenu = (0, _react.useCallback)(() => setShowProfileMenu(show => !show), [setShowProfileMenu]);
39
+ const containerRef = (0, _react.useRef)(null);
40
+ (0, _useOnDocClick.useOnDocClick)(containerRef, hideProfileMenu);
41
+ return /*#__PURE__*/_react.default.createElement("div", {
42
+ ref: containerRef,
43
+ "data-test": "headerbar-profile",
44
+ className: "jsx-2213392235" + " " + "headerbar-profile"
45
+ }, /*#__PURE__*/_react.default.createElement("button", {
46
+ onClick: toggleProfileMenu,
47
+ className: "jsx-2213392235" + " " + "headerbar-profile-btn"
48
+ }, /*#__PURE__*/_react.default.createElement(_userAvatar.UserAvatar, {
49
+ avatarId: avatarId,
50
+ name: name,
51
+ dataTest: "headerbar-profile-icon",
52
+ medium: true
53
+ })), showProfileMenu && /*#__PURE__*/_react.default.createElement(_index.ProfileMenu, {
54
+ avatarId: avatarId,
55
+ name: name,
56
+ email: email,
57
+ helpUrl: helpUrl,
58
+ hideProfileMenu: hideProfileMenu,
59
+ showDebugInfoModal: () => {
60
+ setShowDebugInfoModal(true);
61
+ }
62
+ }), showDebugInfoModal && /*#__PURE__*/_react.default.createElement(_debugInfoModal.DebugInfoModal, {
63
+ onClose: () => {
64
+ setShowDebugInfoModal(false);
65
+ }
66
+ }), /*#__PURE__*/_react.default.createElement(_style.default, {
67
+ id: "2213392235"
68
+ }, [".headerbar-profile.jsx-2213392235{position:relative;width:36px;height:36px;min-width:36px;min-height:36px;margin:2px 12px 0 24px;}", ".headerbar-profile-btn.jsx-2213392235{background:transparent;padding:0;border:0;cursor:pointer;width:100%;height:100%;}", ".headerbar-profile-btn.jsx-2213392235:focus{outline:1px dotted white;}"]));
69
+ };
81
70
 
82
- exports.default = Profile;
83
71
  Profile.propTypes = {
84
72
  name: _propTypes.default.string.isRequired,
85
73
  avatarId: _propTypes.default.string,
86
74
  email: _propTypes.default.string,
87
75
  helpUrl: _propTypes.default.string
88
- };
76
+ };
77
+ var _default = Profile;
78
+ exports.default = _default;
@@ -1,7 +1,7 @@
1
- import { HeaderBar } from '../index.js';
1
+ import { HeaderBar as component } from '../index.js';
2
2
  export default {
3
3
  title: 'HeaderBarTesting',
4
- component: HeaderBar
4
+ component
5
5
  };
6
6
  export { Default } from './stories/default.js';
7
7
  export { ShowOnlineStatus } from './stories/show-online-status.js';
@@ -16,4 +16,6 @@ export { UserHasWebInterpretationAuthority } from './stories/user-has-web-interp
16
16
  export { UserHasWebMessagingAuthority } from './stories/user-has-web-messaging-authority.js';
17
17
  export { UserHasNoAuthorities } from './stories/user-has-no-authorities.js';
18
18
  export { ZeroUnreadInterpretations } from './stories/zero-unread-interpretations.js';
19
- export { ZeroUnreadMessages } from './stories/zero-unread-messages.js';
19
+ export { ZeroUnreadMessages } from './stories/zero-unread-messages.js';
20
+ export { WithUpdateAvailableNotification, WithUpdateAvailableNotificationNoAppName } from './stories/with-update-available-notification.js';
21
+ export { WithUnknownInstanceVersion, WithUnknownAppNameAndVersion, WithUnknownAppName, WithUnknownAppVersion } from './stories/with-debug-info-edge-cases.js';
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable react/display-name */
2
- import { CustomDataProvider, Provider } from '@dhis2/app-runtime';
3
- import React from 'react';
2
+ import { CustomDataProvider, Provider, useAlerts } from '@dhis2/app-runtime';
3
+ import PropTypes from 'prop-types';
4
+ import React, { useEffect } from 'react';
4
5
  export const defaultModules = [{
5
6
  name: 'dhis-web-dashboard',
6
7
  namespace: '/dhis-web-dashboard',
@@ -264,36 +265,6 @@ export const modulesWithSpecialCharacters = [{
264
265
  }];
265
266
  export const applicationTitle = 'Foobar';
266
267
  export const dataProviderData = {
267
- 'system/info': {
268
- contextPath: 'https://debug.dhis2.org/dev',
269
- userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
270
- calendar: 'iso8601',
271
- dateFormat: 'yyyy-mm-dd',
272
- serverDate: '2021-10-06T08:06:15.256',
273
- serverTimeZoneId: 'Etc/UTC',
274
- serverTimeZoneDisplayName: 'Coordinated Universal Time',
275
- lastAnalyticsTableSuccess: '2021-09-18T10:24:03.536',
276
- intervalSinceLastAnalyticsTableSuccess: '429 h, 42 m, 11 s',
277
- lastAnalyticsTableRuntime: '520835',
278
- lastSystemMonitoringSuccess: '2019-03-26T17:07:15.418',
279
- version: '2.38-SNAPSHOT',
280
- revision: '6607c3c',
281
- buildTime: '2021-10-05T17:13:00.000',
282
- jasperReportsVersion: '6.3.1',
283
- environmentVariable: 'DHIS2_HOME',
284
- databaseInfo: {
285
- spatialSupport: true
286
- },
287
- encryption: false,
288
- emailConfigured: false,
289
- redisEnabled: false,
290
- systemId: 'eed3d451-4ff5-4193-b951-ffcc68954299',
291
- systemName: 'DHIS 2 Demo - Sierra Leone',
292
- instanceBaseUrl: 'https://debug.dhis2.org/dev',
293
- clusterHostname: '',
294
- isMetadataVersionEnabled: true,
295
- metadataSyncEnabled: false
296
- },
297
268
  'systemSettings/applicationTitle': {
298
269
  applicationTitle
299
270
  },
@@ -328,11 +299,103 @@ export const createDecoratorCustomDataProviderHeaderBar = function () {
328
299
  };
329
300
  };
330
301
  export const providerConfig = {
302
+ appName: 'TestApp',
303
+ appVersion: {
304
+ full: '101.2.3-beta.4',
305
+ major: 101,
306
+ minor: 2,
307
+ patch: 3,
308
+ tag: 'beta.4'
309
+ },
310
+ serverVersion: {
311
+ full: '2.39.2.1-SNAPSHOT',
312
+ major: 2,
313
+ minor: 39,
314
+ patch: 2,
315
+ hotfix: 1,
316
+ tag: 'SNAPSHOT'
317
+ },
318
+ systemInfo: {
319
+ contextPath: 'https://debug.dhis2.org/dev',
320
+ userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
321
+ calendar: 'iso8601',
322
+ dateFormat: 'yyyy-mm-dd',
323
+ serverDate: '2021-10-06T08:06:15.256',
324
+ serverTimeZoneId: 'Etc/UTC',
325
+ serverTimeZoneDisplayName: 'Coordinated Universal Time',
326
+ lastAnalyticsTableSuccess: '2021-09-18T10:24:03.536',
327
+ intervalSinceLastAnalyticsTableSuccess: '429 h, 42 m, 11 s',
328
+ lastAnalyticsTableRuntime: '520835',
329
+ lastSystemMonitoringSuccess: '2019-03-26T17:07:15.418',
330
+ version: '2.39.2.1-SNAPSHOT',
331
+ revision: '6607c3c',
332
+ buildTime: '2021-10-05T17:13:00.000',
333
+ jasperReportsVersion: '6.3.1',
334
+ environmentVariable: 'DHIS2_HOME',
335
+ databaseInfo: {
336
+ spatialSupport: true
337
+ },
338
+ encryption: false,
339
+ emailConfigured: false,
340
+ redisEnabled: false,
341
+ systemId: 'eed3d451-4ff5-4193-b951-ffcc68954299',
342
+ systemName: 'DHIS 2 Demo - Sierra Leone',
343
+ instanceBaseUrl: 'https://debug.dhis2.org/dev',
344
+ clusterHostname: '',
345
+ isMetadataVersionEnabled: true,
346
+ metadataSyncEnabled: false
347
+ },
331
348
  baseUrl: 'https://domain.tld/',
332
349
  apiVersion: ''
333
350
  };
351
+
352
+ const MockAlert = _ref => {
353
+ let {
354
+ alert
355
+ } = _ref;
356
+ useEffect(() => {
357
+ var _alert$options;
358
+
359
+ if ((_alert$options = alert.options) !== null && _alert$options !== void 0 && _alert$options.duration) {
360
+ var _alert$options2;
361
+
362
+ setTimeout(() => alert.remove(), (_alert$options2 = alert.options) === null || _alert$options2 === void 0 ? void 0 : _alert$options2.duration);
363
+ }
364
+ }, [alert]);
365
+ return /*#__PURE__*/React.createElement("div", {
366
+ style: {
367
+ backgroundColor: '#CCC',
368
+ padding: 8
369
+ }
370
+ }, alert.message);
371
+ };
372
+
373
+ MockAlert.propTypes = {
374
+ alert: PropTypes.shape({
375
+ message: PropTypes.string,
376
+ options: PropTypes.shape({
377
+ duration: PropTypes.number
378
+ }),
379
+ remove: PropTypes.func
380
+ })
381
+ };
382
+
383
+ const MocklAlertStack = () => {
384
+ const alerts = useAlerts();
385
+ return /*#__PURE__*/React.createElement("div", {
386
+ style: {
387
+ position: 'absolute',
388
+ bottom: 16,
389
+ right: 16
390
+ }
391
+ }, alerts.map(alert => /*#__PURE__*/React.createElement(MockAlert, {
392
+ key: alert.id,
393
+ alert: alert
394
+ })));
395
+ };
396
+
334
397
  export const createDecoratorProvider = config => {
335
398
  return fn => /*#__PURE__*/React.createElement(Provider, {
336
399
  config: config || providerConfig
337
- }, fn());
400
+ }, fn(), /*#__PURE__*/React.createElement(MocklAlertStack, null));
338
401
  };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { HeaderBar } from '../../header-bar.js';
3
+ import { createDecoratorCustomDataProviderHeaderBar, createDecoratorProvider, providerConfig } from './common.js';
4
+ export const WithUnknownInstanceVersion = () => /*#__PURE__*/React.createElement(HeaderBar, null);
5
+ WithUnknownInstanceVersion.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
6
+ systemInfo: { ...providerConfig.systemInfo,
7
+ version: undefined
8
+ }
9
+ })];
10
+ export const WithUnknownAppVersion = () => /*#__PURE__*/React.createElement(HeaderBar, null);
11
+ WithUnknownAppVersion.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
12
+ appVersion: undefined
13
+ })];
14
+ export const WithUnknownAppName = () => /*#__PURE__*/React.createElement(HeaderBar, null);
15
+ WithUnknownAppName.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
16
+ appName: undefined
17
+ })];
18
+ export const WithUnknownAppNameAndVersion = () => /*#__PURE__*/React.createElement(HeaderBar, null);
19
+ WithUnknownAppNameAndVersion.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
20
+ appName: undefined,
21
+ appVersion: undefined
22
+ })];
@@ -0,0 +1,19 @@
1
+ import React, { useState } from 'react';
2
+ import { HeaderBar } from '../../header-bar.js';
3
+ import { createDecoratorCustomDataProviderHeaderBar, createDecoratorProvider, providerConfig } from './common.js';
4
+ export const WithUpdateAvailableNotification = () => {
5
+ const [modalOpen, setModalOpen] = useState(false);
6
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(HeaderBar, {
7
+ updateAvailable: true,
8
+ onApplyAvailableUpdate: () => setModalOpen(true)
9
+ }), modalOpen && /*#__PURE__*/React.createElement("div", null, "The callback was successful"));
10
+ };
11
+ WithUpdateAvailableNotification.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
12
+ appName: 'Data Visualizer'
13
+ })];
14
+ export const WithUpdateAvailableNotificationNoAppName = () => /*#__PURE__*/React.createElement(HeaderBar, {
15
+ updateAvailable: true
16
+ });
17
+ WithUpdateAvailableNotificationNoAppName.decorators = [createDecoratorCustomDataProviderHeaderBar(), createDecoratorProvider({ ...providerConfig,
18
+ appName: undefined
19
+ })];
package/build/es/apps.js CHANGED
@@ -167,7 +167,7 @@ const Apps = _ref7 => {
167
167
  useEffect(() => {
168
168
  document.addEventListener('click', onDocClick);
169
169
  return () => document.removeEventListener('click', onDocClick);
170
- }, []);
170
+ }, [onDocClick]);
171
171
  return /*#__PURE__*/React.createElement("div", {
172
172
  ref: containerEl,
173
173
  "data-test": "headerbar-apps",
@@ -0,0 +1,48 @@
1
+ import _JSXStyle from "styled-jsx/style";
2
+ import { MenuItem } from '@dhis2-ui/menu';
3
+ import { colors } from '@dhis2/ui-constants';
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+ import i18n from '../locales/index.js';
7
+ import { useDebugInfo } from './use-debug-info.js';
8
+ export const DebugInfoMenuItem = _ref => {
9
+ let {
10
+ hideProfileMenu,
11
+ showDebugInfoModal
12
+ } = _ref;
13
+ const debugInfo = useDebugInfo();
14
+
15
+ const openDebugModal = () => {
16
+ hideProfileMenu();
17
+ showDebugInfoModal();
18
+ };
19
+
20
+ const debugInfoLabel = /*#__PURE__*/React.createElement("div", {
21
+ className: _JSXStyle.dynamic([["3534786758", [colors.grey700]]]) + " " + "root"
22
+ }, /*#__PURE__*/React.createElement("div", {
23
+ "data-test": "dhis2-ui-headerbar-instanceinfo",
24
+ className: _JSXStyle.dynamic([["3534786758", [colors.grey700]]]) + " " + "instance-info version"
25
+ }, debugInfo.dhis2_version ? i18n.t('DHIS2 {{dhis2Version}}', {
26
+ dhis2Version: debugInfo.dhis2_version
27
+ }) : i18n.t('DHIS2 version unknown')), /*#__PURE__*/React.createElement("div", {
28
+ "data-test": "dhis2-ui-headerbar-appinfo",
29
+ className: _JSXStyle.dynamic([["3534786758", [colors.grey700]]]) + " " + "version"
30
+ }, debugInfo.app_name ? debugInfo.app_version ? "".concat(debugInfo.app_name, " ").concat(debugInfo.app_version) : i18n.t('{{appName}} version unknown', {
31
+ appName: debugInfo.app_name
32
+ }) : debugInfo.app_version ? i18n.t('App {{appVersion}}', {
33
+ appVersion: debugInfo.app_version
34
+ }) : i18n.t('App version unknown')), /*#__PURE__*/React.createElement(_JSXStyle, {
35
+ id: "3534786758",
36
+ dynamic: [colors.grey700]
37
+ }, [".root.__jsx-style-dynamic-selector{color:".concat(colors.grey700, ";font-style:italic;font-size:14px;line-height:17px;}"), ".instance-info.__jsx-style-dynamic-selector{margin-bottom:4px;}", ".version.__jsx-style-dynamic-selector{white-space:no-wrap;}"]));
38
+ return /*#__PURE__*/React.createElement(MenuItem, {
39
+ dense: true,
40
+ onClick: openDebugModal,
41
+ label: debugInfoLabel,
42
+ dataTest: "dhis2-ui-headerbar-debuginfo"
43
+ });
44
+ };
45
+ DebugInfoMenuItem.propTypes = {
46
+ hideProfileMenu: PropTypes.func.isRequired,
47
+ showDebugInfoModal: PropTypes.func.isRequired
48
+ };
@@ -0,0 +1,41 @@
1
+ import { Button, ButtonStrip } from '@dhis2-ui/button';
2
+ import { Modal, ModalActions, ModalContent, ModalTitle } from '@dhis2-ui/modal';
3
+ import { useAlert } from '@dhis2/app-runtime';
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+ import i18n from '../locales/index.js';
7
+ import { DebugInfoTable } from './debug-info-table.js';
8
+ import { useFormattedDebugInfo } from './use-debug-info.js';
9
+ export function DebugInfoModal(_ref) {
10
+ let {
11
+ onClose
12
+ } = _ref;
13
+ const debugInfo = useFormattedDebugInfo();
14
+ const {
15
+ show: showClipboardAlert
16
+ } = useAlert('Debug information copied to clipboard', {
17
+ duration: 3000
18
+ });
19
+
20
+ const copyDebugInfo = () => {
21
+ navigator.clipboard.writeText(debugInfo);
22
+ onClose();
23
+ showClipboardAlert();
24
+ };
25
+
26
+ return /*#__PURE__*/React.createElement(Modal, {
27
+ position: "middle",
28
+ dataTest: "dhis2-ui-headerbar-debuginfomodal"
29
+ }, /*#__PURE__*/React.createElement(ModalTitle, null, i18n.t('Debug info')), /*#__PURE__*/React.createElement(ModalContent, null, /*#__PURE__*/React.createElement(DebugInfoTable, null)), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(ButtonStrip, {
30
+ end: true
31
+ }, /*#__PURE__*/React.createElement(Button, {
32
+ onClick: () => onClose()
33
+ }, i18n.t('Close')), /*#__PURE__*/React.createElement(Button, {
34
+ primary: true,
35
+ onClick: copyDebugInfo,
36
+ dataTest: "dhis2-ui-headerbar-debuginfomodal-copybutton"
37
+ }, i18n.t('Copy debug info')))));
38
+ }
39
+ DebugInfoModal.propTypes = {
40
+ onClose: PropTypes.func.isRequired
41
+ };
@@ -0,0 +1,35 @@
1
+ import _JSXStyle from "styled-jsx/style";
2
+ import { colors } from '@dhis2/ui-constants';
3
+ import React from 'react';
4
+ import { useDebugInfo } from './use-debug-info.js';
5
+
6
+ const formatDebugInfoKey = key => {
7
+ const tokens = key.split('_');
8
+ return tokens.map(token => {
9
+ if (token.toLowerCase() === 'dhis2') {
10
+ return 'DHIS2';
11
+ } else {
12
+ return token[0].toUpperCase() + token.substr(1).toLowerCase();
13
+ }
14
+ }).join(' ');
15
+ };
16
+
17
+ export function DebugInfoTable() {
18
+ const debugInfo = useDebugInfo();
19
+ return /*#__PURE__*/React.createElement("table", {
20
+ 'data-test': 'dhis2-ui-headerbar-debuginfotable',
21
+ className: _JSXStyle.dynamic([["865651843", [colors.grey700]]])
22
+ }, /*#__PURE__*/React.createElement("tbody", {
23
+ className: _JSXStyle.dynamic([["865651843", [colors.grey700]]])
24
+ }, Object.keys(debugInfo).map(key => /*#__PURE__*/React.createElement("tr", {
25
+ key: key,
26
+ className: _JSXStyle.dynamic([["865651843", [colors.grey700]]])
27
+ }, /*#__PURE__*/React.createElement("td", {
28
+ className: _JSXStyle.dynamic([["865651843", [colors.grey700]]]) + " " + "debug-info-key"
29
+ }, formatDebugInfoKey(key)), /*#__PURE__*/React.createElement("td", {
30
+ className: _JSXStyle.dynamic([["865651843", [colors.grey700]]])
31
+ }, debugInfo[key])))), /*#__PURE__*/React.createElement(_JSXStyle, {
32
+ id: "865651843",
33
+ dynamic: [colors.grey700]
34
+ }, ["table.__jsx-style-dynamic-selector{white-space:pre-wrap;font-size:14px;line-height:1.2;color:".concat(colors.grey700, ";font-famile:Menlo,Courier,monospace !important;}"), "td.__jsx-style-dynamic-selector{padding:3px 16px 3px 0;}", ".debug-info-key.__jsx-style-dynamic-selector{font-weight:bold;}"]));
35
+ }
@@ -0,0 +1,15 @@
1
+ import { useConfig } from '@dhis2/app-runtime';
2
+ export const useDebugInfo = () => {
3
+ const {
4
+ appName,
5
+ appVersion,
6
+ systemInfo
7
+ } = useConfig();
8
+ return {
9
+ app_name: appName || null,
10
+ app_version: (appVersion === null || appVersion === void 0 ? void 0 : appVersion.full) || null,
11
+ dhis2_version: (systemInfo === null || systemInfo === void 0 ? void 0 : systemInfo.version) || null,
12
+ dhis2_revision: (systemInfo === null || systemInfo === void 0 ? void 0 : systemInfo.revision) || null
13
+ };
14
+ };
15
+ export const useFormattedDebugInfo = () => JSON.stringify(useDebugInfo(), undefined, 2);
@@ -0,0 +1,31 @@
1
+ import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps';
2
+ Given('the HeaderBar is rendered without an available update', () => {
3
+ cy.visitStory('HeaderBarTesting', 'default');
4
+ });
5
+ Given('the HeaderBar is rendered with an available update', () => {
6
+ cy.visitStory('HeaderBarTesting', 'With Update Available Notification');
7
+ });
8
+ Given('the HeaderBar is rendered with no app name and an available update', () => {
9
+ cy.visitStory('HeaderBarTesting', 'With Update Available Notification No App Name');
10
+ });
11
+ When('the user opens the profile menu', () => {
12
+ cy.get('[data-test="headerbar-profile"] > button').click();
13
+ });
14
+ Then('the update notification should not be displayed', () => {
15
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').should('not.exist');
16
+ });
17
+ Then('the update notification should be displayed', () => {
18
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').should('contain', 'New Data Visualizer version available').should('contain', 'Click to reload');
19
+ });
20
+ Then('the update notification should be displayed without app name', () => {
21
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').should('contain', 'New app version available').should('contain', 'Click to reload');
22
+ });
23
+ When('the user clicks the update notification', () => {
24
+ cy.get('[data-test="dhis2-ui-headerbar-updatenotification"]').click();
25
+ });
26
+ Then('the profile menu should not be shown', () => {
27
+ cy.get('[data-test="headerbar-profile-menu"]').should('not.exist');
28
+ });
29
+ Then('a callback should display a test div', () => {
30
+ cy.contains('The callback was successful').should('be.visible');
31
+ });
@@ -0,0 +1,22 @@
1
+ Feature: The HeaderBar should display app update notification
2
+
3
+ Scenario: No app update is available
4
+ Given the HeaderBar is rendered without an available update
5
+ When the user opens the profile menu
6
+ Then the update notification should not be displayed
7
+
8
+ Scenario: An app update is available
9
+ Given the HeaderBar is rendered with an available update
10
+ When the user opens the profile menu
11
+ Then the update notification should be displayed
12
+
13
+ Scenario: A callback is executed when the user click on the update notification
14
+ Given the HeaderBar is rendered with an available update
15
+ When the user opens the profile menu
16
+ When the user clicks the update notification
17
+ Then a callback should display a test div
18
+
19
+ Scenario: An app update is available but not app name was specified
20
+ Given the HeaderBar is rendered with no app name and an available update
21
+ When the user opens the profile menu
22
+ Then the update notification should be displayed without app name