@dhis2/analytics 26.4.0 → 26.4.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 (17) hide show
  1. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationModal.js +13 -4
  2. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationThread.js +3 -0
  3. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationList.js +3 -0
  4. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +15 -4
  5. package/build/cjs/components/Interpretations/common/Interpretation/Interpretation.js +7 -2
  6. package/build/cjs/components/Interpretations/common/Interpretation/useLike.js +12 -2
  7. package/build/cjs/visualizations/config/adapters/dhis_highcharts/subtitle/index.js +3 -2
  8. package/build/cjs/visualizations/config/adapters/dhis_highcharts/title/index.js +3 -2
  9. package/build/es/components/Interpretations/InterpretationModal/InterpretationModal.js +13 -4
  10. package/build/es/components/Interpretations/InterpretationModal/InterpretationThread.js +3 -0
  11. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationList.js +3 -0
  12. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +15 -4
  13. package/build/es/components/Interpretations/common/Interpretation/Interpretation.js +7 -2
  14. package/build/es/components/Interpretations/common/Interpretation/useLike.js +12 -2
  15. package/build/es/visualizations/config/adapters/dhis_highcharts/subtitle/index.js +3 -2
  16. package/build/es/visualizations/config/adapters/dhis_highcharts/title/index.js +3 -2
  17. package/package.json +1 -1
@@ -73,7 +73,7 @@ const InterpretationModal = _ref2 => {
73
73
  });
74
74
  const interpretation = data === null || data === void 0 ? void 0 : data.interpretation;
75
75
  const shouldRenderModalContent = !error && interpretation;
76
- const shouldCssHideModal = loading || isVisualizationLoading;
76
+ const loadingInProgress = loading || isVisualizationLoading;
77
77
  const handleClose = () => {
78
78
  if (isDirty) {
79
79
  onInterpretationUpdate();
@@ -89,6 +89,14 @@ const InterpretationModal = _ref2 => {
89
89
  id: interpretationId
90
90
  });
91
91
  };
92
+ const onLikeToggled = _ref3 => {
93
+ let {
94
+ likedBy
95
+ } = _ref3;
96
+ setIsDirty(true);
97
+ interpretation.likedBy = likedBy;
98
+ interpretation.likes = likedBy.length;
99
+ };
92
100
  const onInterpretationDeleted = () => {
93
101
  setIsDirty(false);
94
102
  onInterpretationUpdate();
@@ -101,11 +109,11 @@ const InterpretationModal = _ref2 => {
101
109
  });
102
110
  }
103
111
  }, [interpretationId, refetch]);
104
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, shouldCssHideModal && /*#__PURE__*/_react.default.createElement(_ui.Layer, null, /*#__PURE__*/_react.default.createElement(_ui.CenteredContent, null, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, null))), /*#__PURE__*/_react.default.createElement(_ui.Modal, {
112
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, loadingInProgress && /*#__PURE__*/_react.default.createElement(_ui.Layer, null, /*#__PURE__*/_react.default.createElement(_ui.CenteredContent, null, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, null))), /*#__PURE__*/_react.default.createElement(_ui.Modal, {
105
113
  fluid: true,
106
114
  onClose: handleClose,
107
115
  className: (0, _classnames.default)(modalCSS.className, {
108
- hidden: shouldCssHideModal
116
+ hidden: loadingInProgress
109
117
  }),
110
118
  dataTest: "interpretation-modal"
111
119
  }, /*#__PURE__*/_react.default.createElement("h1", {
@@ -143,7 +151,8 @@ const InterpretationModal = _ref2 => {
143
151
  onInterpretationDeleted: onInterpretationDeleted,
144
152
  onThreadUpdated: onThreadUpdated,
145
153
  initialFocus: initialFocus,
146
- downloadMenuComponent: downloadMenuComponent
154
+ downloadMenuComponent: downloadMenuComponent,
155
+ onLikeToggled: onLikeToggled
147
156
  }))))), /*#__PURE__*/_react.default.createElement(_ui.ModalActions, null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
148
157
  disabled: fetching,
149
158
  onClick: handleClose
@@ -23,6 +23,7 @@ const InterpretationThread = _ref => {
23
23
  fetching,
24
24
  interpretation,
25
25
  onInterpretationDeleted,
26
+ onLikeToggled,
26
27
  initialFocus,
27
28
  onThreadUpdated,
28
29
  downloadMenuComponent: DownloadMenu,
@@ -57,6 +58,7 @@ const InterpretationThread = _ref => {
57
58
  }, /*#__PURE__*/_react.default.createElement(_index.Interpretation, {
58
59
  currentUser: currentUser,
59
60
  interpretation: interpretation,
61
+ onLikeToggled: onLikeToggled,
60
62
  onReplyIconClick: interpretationAccess.comment ? () => {
61
63
  var _focusRef$current;
62
64
  return (_focusRef$current = focusRef.current) === null || _focusRef$current === void 0 ? void 0 : _focusRef$current.focus();
@@ -89,6 +91,7 @@ InterpretationThread.propTypes = {
89
91
  fetching: _propTypes.default.bool.isRequired,
90
92
  interpretation: _propTypes.default.object.isRequired,
91
93
  onInterpretationDeleted: _propTypes.default.func.isRequired,
94
+ onLikeToggled: _propTypes.default.func.isRequired,
92
95
  dashboardRedirectUrl: _propTypes.default.string,
93
96
  downloadMenuComponent: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]),
94
97
  initialFocus: _propTypes.default.bool,
@@ -28,6 +28,7 @@ const InterpretationList = _ref => {
28
28
  currentUser,
29
29
  interpretations,
30
30
  onInterpretationClick,
31
+ onLikeToggled,
31
32
  onReplyIconClick,
32
33
  refresh,
33
34
  disabled,
@@ -65,6 +66,7 @@ const InterpretationList = _ref => {
65
66
  interpretation: interpretation,
66
67
  currentUser: currentUser,
67
68
  onClick: onInterpretationClick,
69
+ onLikeToggled: onLikeToggled,
68
70
  onReplyIconClick: onReplyIconClick,
69
71
  onDeleted: refresh,
70
72
  onUpdated: refresh,
@@ -81,6 +83,7 @@ InterpretationList.propTypes = {
81
83
  interpretations: _propTypes.default.array.isRequired,
82
84
  refresh: _propTypes.default.func.isRequired,
83
85
  onInterpretationClick: _propTypes.default.func.isRequired,
86
+ onLikeToggled: _propTypes.default.func.isRequired,
84
87
  onReplyIconClick: _propTypes.default.func.isRequired,
85
88
  dashboardRedirectUrl: _propTypes.default.string,
86
89
  disabled: _propTypes.default.bool
@@ -44,14 +44,15 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
44
44
  dashboardRedirectUrl
45
45
  } = _ref2;
46
46
  const [isExpanded, setIsExpanded] = (0, _react.useState)(true);
47
+ const [interpretations, setInterpretations] = (0, _react.useState)([]);
47
48
  const showNoTimeDimensionHelpText = type === 'eventVisualization' && !visualizationHasTimeDimension;
48
49
  const {
49
- data,
50
50
  loading,
51
51
  fetching,
52
52
  refetch
53
53
  } = (0, _appRuntime.useDataQuery)(interpretationsQuery, {
54
- lazy: true
54
+ lazy: true,
55
+ onComplete: data => setInterpretations(data.interpretations.interpretations)
55
56
  });
56
57
  const onCompleteAction = (0, _react.useCallback)(() => {
57
58
  refetch({
@@ -70,6 +71,15 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
70
71
  });
71
72
  }
72
73
  }, [type, id, renderId, refetch]);
74
+ const onLikeToggled = _ref3 => {
75
+ let {
76
+ id,
77
+ likedBy
78
+ } = _ref3;
79
+ const interpretation = interpretations.find(interp => interp.id === id);
80
+ interpretation.likedBy = likedBy;
81
+ interpretation.likes = likedBy.length;
82
+ };
73
83
  return /*#__PURE__*/_react.default.createElement("div", {
74
84
  className: _style.default.dynamic([["4120713286", [_ui.spacers.dp16, _ui.colors.grey400, _ui.colors.white, _ui.spacers.dp32, _ui.colors.grey900]]]) + " " + ((0, _classnames.default)('container', {
75
85
  expanded: isExpanded
@@ -91,7 +101,7 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
91
101
  className: _style.default.dynamic([["4120713286", [_ui.spacers.dp16, _ui.colors.grey400, _ui.colors.white, _ui.spacers.dp32, _ui.colors.grey900]]]) + " " + "loader"
92
102
  }, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, {
93
103
  small: true
94
- })), data && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_InterpretationForm.InterpretationForm, {
104
+ })), interpretations && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_InterpretationForm.InterpretationForm, {
95
105
  currentUser: currentUser,
96
106
  type: type,
97
107
  id: id,
@@ -100,8 +110,9 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
100
110
  showNoTimeDimensionHelpText: showNoTimeDimensionHelpText
101
111
  }), /*#__PURE__*/_react.default.createElement(_InterpretationList.InterpretationList, {
102
112
  currentUser: currentUser,
103
- interpretations: data.interpretations.interpretations,
113
+ interpretations: interpretations,
104
114
  onInterpretationClick: onInterpretationClick,
115
+ onLikeToggled: onLikeToggled,
105
116
  onReplyIconClick: onReplyIconClick,
106
117
  refresh: onCompleteAction,
107
118
  disabled: disabled,
@@ -25,7 +25,8 @@ const Interpretation = _ref => {
25
25
  disabled,
26
26
  onReplyIconClick,
27
27
  dashboardRedirectUrl,
28
- isInThread
28
+ isInThread,
29
+ onLikeToggled
29
30
  } = _ref;
30
31
  const [isUpdateMode, setIsUpdateMode] = (0, _react.useState)(false);
31
32
  const [showSharingDialog, setShowSharingDialog] = (0, _react.useState)(false);
@@ -36,7 +37,10 @@ const Interpretation = _ref => {
36
37
  } = (0, _useLike.useLike)({
37
38
  interpretation,
38
39
  currentUser,
39
- onComplete: onUpdated
40
+ onComplete: likedBy => onLikeToggled({
41
+ id: interpretation.id,
42
+ likedBy
43
+ })
40
44
  });
41
45
  const shouldShowButton = Boolean(!!onClick && !disabled & !dashboardRedirectUrl);
42
46
  const interpretationAccess = (0, _index.getInterpretationAccess)(interpretation, currentUser);
@@ -123,6 +127,7 @@ Interpretation.propTypes = {
123
127
  currentUser: _propTypes.default.object.isRequired,
124
128
  interpretation: _propTypes.default.object.isRequired,
125
129
  onDeleted: _propTypes.default.func.isRequired,
130
+ onLikeToggled: _propTypes.default.func.isRequired,
126
131
  onReplyIconClick: _propTypes.default.func.isRequired,
127
132
  onUpdated: _propTypes.default.func.isRequired,
128
133
  dashboardRedirectUrl: _propTypes.default.string,
@@ -24,12 +24,22 @@ const useLike = _ref => {
24
24
  const [like, {
25
25
  loading: likeLoading
26
26
  }] = (0, _appRuntime.useDataMutation)(likeMutationRef.current, {
27
- onComplete
27
+ onComplete: () => {
28
+ const newLikedBy = interpretation.likedBy.concat({
29
+ id: currentUser.id
30
+ });
31
+ setIsLikedByCurrentUser(true);
32
+ onComplete(newLikedBy);
33
+ }
28
34
  });
29
35
  const [unlike, {
30
36
  loading: unlikeLoading
31
37
  }] = (0, _appRuntime.useDataMutation)(unlikeMutationRef.current, {
32
- onComplete
38
+ onComplete: () => {
39
+ const newLikedBy = interpretation.likedBy.filter(lb => lb.id !== currentUser.id);
40
+ setIsLikedByCurrentUser(false);
41
+ onComplete(newLikedBy);
42
+ }
33
43
  });
34
44
  const [isLikedByCurrentUser, setIsLikedByCurrentUser] = (0, _react.useState)(false);
35
45
  const toggleLike = () => {
@@ -37,8 +37,9 @@ function _default(series, layout, metaData, dashboard) {
37
37
  }
38
38
 
39
39
  // DHIS2-578: allow for optional custom subtitle
40
- if ((0, _isString.default)(layout.subtitle)) {
41
- subtitle.text = layout.subtitle;
40
+ const customSubtitle = layout.subtitle && layout.displaySubtitle || layout.subtitle;
41
+ if ((0, _isString.default)(customSubtitle) && customSubtitle.length) {
42
+ subtitle.text = customSubtitle;
42
43
  } else {
43
44
  const filterTitle = (0, _getFilterText.default)(layout.filters, metaData);
44
45
  switch (layout.type) {
@@ -38,8 +38,9 @@ function _default(layout, metaData, dashboard) {
38
38
  if (layout.hideTitle) {
39
39
  return title;
40
40
  }
41
- if ((0, _isString.default)(layout.title) && layout.title.length) {
42
- title.text = layout.title;
41
+ const customTitle = layout.title && layout.displayTitle || layout.title;
42
+ if ((0, _isString.default)(customTitle) && customTitle.length) {
43
+ title.text = customTitle;
43
44
  } else {
44
45
  switch (layout.type) {
45
46
  case _visTypes.VIS_TYPE_GAUGE:
@@ -64,7 +64,7 @@ const InterpretationModal = _ref2 => {
64
64
  });
65
65
  const interpretation = data === null || data === void 0 ? void 0 : data.interpretation;
66
66
  const shouldRenderModalContent = !error && interpretation;
67
- const shouldCssHideModal = loading || isVisualizationLoading;
67
+ const loadingInProgress = loading || isVisualizationLoading;
68
68
  const handleClose = () => {
69
69
  if (isDirty) {
70
70
  onInterpretationUpdate();
@@ -80,6 +80,14 @@ const InterpretationModal = _ref2 => {
80
80
  id: interpretationId
81
81
  });
82
82
  };
83
+ const onLikeToggled = _ref3 => {
84
+ let {
85
+ likedBy
86
+ } = _ref3;
87
+ setIsDirty(true);
88
+ interpretation.likedBy = likedBy;
89
+ interpretation.likes = likedBy.length;
90
+ };
83
91
  const onInterpretationDeleted = () => {
84
92
  setIsDirty(false);
85
93
  onInterpretationUpdate();
@@ -92,11 +100,11 @@ const InterpretationModal = _ref2 => {
92
100
  });
93
101
  }
94
102
  }, [interpretationId, refetch]);
95
- return /*#__PURE__*/React.createElement(React.Fragment, null, shouldCssHideModal && /*#__PURE__*/React.createElement(Layer, null, /*#__PURE__*/React.createElement(CenteredContent, null, /*#__PURE__*/React.createElement(CircularLoader, null))), /*#__PURE__*/React.createElement(Modal, {
103
+ return /*#__PURE__*/React.createElement(React.Fragment, null, loadingInProgress && /*#__PURE__*/React.createElement(Layer, null, /*#__PURE__*/React.createElement(CenteredContent, null, /*#__PURE__*/React.createElement(CircularLoader, null))), /*#__PURE__*/React.createElement(Modal, {
96
104
  fluid: true,
97
105
  onClose: handleClose,
98
106
  className: cx(modalCSS.className, {
99
- hidden: shouldCssHideModal
107
+ hidden: loadingInProgress
100
108
  }),
101
109
  dataTest: "interpretation-modal"
102
110
  }, /*#__PURE__*/React.createElement("h1", {
@@ -134,7 +142,8 @@ const InterpretationModal = _ref2 => {
134
142
  onInterpretationDeleted: onInterpretationDeleted,
135
143
  onThreadUpdated: onThreadUpdated,
136
144
  initialFocus: initialFocus,
137
- downloadMenuComponent: downloadMenuComponent
145
+ downloadMenuComponent: downloadMenuComponent,
146
+ onLikeToggled: onLikeToggled
138
147
  }))))), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(Button, {
139
148
  disabled: fetching,
140
149
  onClick: handleClose
@@ -14,6 +14,7 @@ const InterpretationThread = _ref => {
14
14
  fetching,
15
15
  interpretation,
16
16
  onInterpretationDeleted,
17
+ onLikeToggled,
17
18
  initialFocus,
18
19
  onThreadUpdated,
19
20
  downloadMenuComponent: DownloadMenu,
@@ -48,6 +49,7 @@ const InterpretationThread = _ref => {
48
49
  }, /*#__PURE__*/React.createElement(Interpretation, {
49
50
  currentUser: currentUser,
50
51
  interpretation: interpretation,
52
+ onLikeToggled: onLikeToggled,
51
53
  onReplyIconClick: interpretationAccess.comment ? () => {
52
54
  var _focusRef$current;
53
55
  return (_focusRef$current = focusRef.current) === null || _focusRef$current === void 0 ? void 0 : _focusRef$current.focus();
@@ -79,6 +81,7 @@ InterpretationThread.propTypes = {
79
81
  fetching: PropTypes.bool.isRequired,
80
82
  interpretation: PropTypes.object.isRequired,
81
83
  onInterpretationDeleted: PropTypes.func.isRequired,
84
+ onLikeToggled: PropTypes.func.isRequired,
82
85
  dashboardRedirectUrl: PropTypes.string,
83
86
  downloadMenuComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
84
87
  initialFocus: PropTypes.bool,
@@ -21,6 +21,7 @@ export const InterpretationList = _ref => {
21
21
  currentUser,
22
22
  interpretations,
23
23
  onInterpretationClick,
24
+ onLikeToggled,
24
25
  onReplyIconClick,
25
26
  refresh,
26
27
  disabled,
@@ -58,6 +59,7 @@ export const InterpretationList = _ref => {
58
59
  interpretation: interpretation,
59
60
  currentUser: currentUser,
60
61
  onClick: onInterpretationClick,
62
+ onLikeToggled: onLikeToggled,
61
63
  onReplyIconClick: onReplyIconClick,
62
64
  onDeleted: refresh,
63
65
  onUpdated: refresh,
@@ -73,6 +75,7 @@ InterpretationList.propTypes = {
73
75
  interpretations: PropTypes.array.isRequired,
74
76
  refresh: PropTypes.func.isRequired,
75
77
  onInterpretationClick: PropTypes.func.isRequired,
78
+ onLikeToggled: PropTypes.func.isRequired,
76
79
  onReplyIconClick: PropTypes.func.isRequired,
77
80
  dashboardRedirectUrl: PropTypes.string,
78
81
  disabled: PropTypes.bool
@@ -35,14 +35,15 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
35
35
  dashboardRedirectUrl
36
36
  } = _ref2;
37
37
  const [isExpanded, setIsExpanded] = useState(true);
38
+ const [interpretations, setInterpretations] = useState([]);
38
39
  const showNoTimeDimensionHelpText = type === 'eventVisualization' && !visualizationHasTimeDimension;
39
40
  const {
40
- data,
41
41
  loading,
42
42
  fetching,
43
43
  refetch
44
44
  } = useDataQuery(interpretationsQuery, {
45
- lazy: true
45
+ lazy: true,
46
+ onComplete: data => setInterpretations(data.interpretations.interpretations)
46
47
  });
47
48
  const onCompleteAction = useCallback(() => {
48
49
  refetch({
@@ -61,6 +62,15 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
61
62
  });
62
63
  }
63
64
  }, [type, id, renderId, refetch]);
65
+ const onLikeToggled = _ref3 => {
66
+ let {
67
+ id,
68
+ likedBy
69
+ } = _ref3;
70
+ const interpretation = interpretations.find(interp => interp.id === id);
71
+ interpretation.likedBy = likedBy;
72
+ interpretation.likes = likedBy.length;
73
+ };
64
74
  return /*#__PURE__*/React.createElement("div", {
65
75
  className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + (cx('container', {
66
76
  expanded: isExpanded
@@ -82,7 +92,7 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
82
92
  className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "loader"
83
93
  }, /*#__PURE__*/React.createElement(CircularLoader, {
84
94
  small: true
85
- })), data && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
95
+ })), interpretations && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
86
96
  currentUser: currentUser,
87
97
  type: type,
88
98
  id: id,
@@ -91,8 +101,9 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
91
101
  showNoTimeDimensionHelpText: showNoTimeDimensionHelpText
92
102
  }), /*#__PURE__*/React.createElement(InterpretationList, {
93
103
  currentUser: currentUser,
94
- interpretations: data.interpretations.interpretations,
104
+ interpretations: interpretations,
95
105
  onInterpretationClick: onInterpretationClick,
106
+ onLikeToggled: onLikeToggled,
96
107
  onReplyIconClick: onReplyIconClick,
97
108
  refresh: onCompleteAction,
98
109
  disabled: disabled,
@@ -16,7 +16,8 @@ export const Interpretation = _ref => {
16
16
  disabled,
17
17
  onReplyIconClick,
18
18
  dashboardRedirectUrl,
19
- isInThread
19
+ isInThread,
20
+ onLikeToggled
20
21
  } = _ref;
21
22
  const [isUpdateMode, setIsUpdateMode] = useState(false);
22
23
  const [showSharingDialog, setShowSharingDialog] = useState(false);
@@ -27,7 +28,10 @@ export const Interpretation = _ref => {
27
28
  } = useLike({
28
29
  interpretation,
29
30
  currentUser,
30
- onComplete: onUpdated
31
+ onComplete: likedBy => onLikeToggled({
32
+ id: interpretation.id,
33
+ likedBy
34
+ })
31
35
  });
32
36
  const shouldShowButton = Boolean(!!onClick && !disabled & !dashboardRedirectUrl);
33
37
  const interpretationAccess = getInterpretationAccess(interpretation, currentUser);
@@ -113,6 +117,7 @@ Interpretation.propTypes = {
113
117
  currentUser: PropTypes.object.isRequired,
114
118
  interpretation: PropTypes.object.isRequired,
115
119
  onDeleted: PropTypes.func.isRequired,
120
+ onLikeToggled: PropTypes.func.isRequired,
116
121
  onReplyIconClick: PropTypes.func.isRequired,
117
122
  onUpdated: PropTypes.func.isRequired,
118
123
  dashboardRedirectUrl: PropTypes.string,
@@ -18,12 +18,22 @@ const useLike = _ref => {
18
18
  const [like, {
19
19
  loading: likeLoading
20
20
  }] = useDataMutation(likeMutationRef.current, {
21
- onComplete
21
+ onComplete: () => {
22
+ const newLikedBy = interpretation.likedBy.concat({
23
+ id: currentUser.id
24
+ });
25
+ setIsLikedByCurrentUser(true);
26
+ onComplete(newLikedBy);
27
+ }
22
28
  });
23
29
  const [unlike, {
24
30
  loading: unlikeLoading
25
31
  }] = useDataMutation(unlikeMutationRef.current, {
26
- onComplete
32
+ onComplete: () => {
33
+ const newLikedBy = interpretation.likedBy.filter(lb => lb.id !== currentUser.id);
34
+ setIsLikedByCurrentUser(false);
35
+ onComplete(newLikedBy);
36
+ }
27
37
  });
28
38
  const [isLikedByCurrentUser, setIsLikedByCurrentUser] = useState(false);
29
39
  const toggleLike = () => {
@@ -30,8 +30,9 @@ export default function (series, layout, metaData, dashboard) {
30
30
  }
31
31
 
32
32
  // DHIS2-578: allow for optional custom subtitle
33
- if (isString(layout.subtitle)) {
34
- subtitle.text = layout.subtitle;
33
+ const customSubtitle = layout.subtitle && layout.displaySubtitle || layout.subtitle;
34
+ if (isString(customSubtitle) && customSubtitle.length) {
35
+ subtitle.text = customSubtitle;
35
36
  } else {
36
37
  const filterTitle = getFilterText(layout.filters, metaData);
37
38
  switch (layout.type) {
@@ -31,8 +31,9 @@ export default function (layout, metaData, dashboard) {
31
31
  if (layout.hideTitle) {
32
32
  return title;
33
33
  }
34
- if (isString(layout.title) && layout.title.length) {
35
- title.text = layout.title;
34
+ const customTitle = layout.title && layout.displayTitle || layout.title;
35
+ if (isString(customTitle) && customTitle.length) {
36
+ title.text = customTitle;
36
37
  } else {
37
38
  switch (layout.type) {
38
39
  case VIS_TYPE_GAUGE:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhis2/analytics",
3
- "version": "26.4.0",
3
+ "version": "26.4.1",
4
4
  "main": "./build/cjs/index.js",
5
5
  "module": "./build/es/index.js",
6
6
  "exports": {