@dhis2/analytics 26.13.2 → 26.13.4
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.
- package/build/cjs/components/FileMenu/GetLinkDialog.js +6 -7
- package/build/cjs/components/FileMenu/__tests__/GetLinkDialog.spec.js +65 -16
- package/build/cjs/components/FileMenu/utils.js +4 -3
- package/build/cjs/components/RichText/Parser/MdParser.js +18 -0
- package/build/cjs/components/RichText/Parser/__tests__/MdParser.spec.js +2 -2
- package/build/cjs/visualizations/util/__tests__/getFilterText.spec.js +11 -15
- package/build/cjs/visualizations/util/getFilterText.js +8 -0
- package/build/es/components/FileMenu/GetLinkDialog.js +6 -7
- package/build/es/components/FileMenu/__tests__/GetLinkDialog.spec.js +65 -16
- package/build/es/components/FileMenu/utils.js +4 -3
- package/build/es/components/RichText/Parser/MdParser.js +18 -0
- package/build/es/components/RichText/Parser/__tests__/MdParser.spec.js +2 -2
- package/build/es/visualizations/util/__tests__/getFilterText.spec.js +11 -15
- package/build/es/visualizations/util/getFilterText.js +9 -1
- package/package.json +1 -1
|
@@ -20,12 +20,11 @@ const GetLinkDialog = _ref => {
|
|
|
20
20
|
onClose
|
|
21
21
|
} = _ref;
|
|
22
22
|
const {
|
|
23
|
+
apiVersion,
|
|
23
24
|
baseUrl
|
|
24
25
|
} = (0, _appRuntime.useConfig)();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const appBaseUrl = new URL(baseUrl, self.location.href);
|
|
28
|
-
const appUrl = new URL((0, _utils.appPathFor)(type, id), appBaseUrl);
|
|
26
|
+
const appBaseUrl = new URL(baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`, self.location.href).href;
|
|
27
|
+
const appUrl = new URL((0, _utils.appPathFor)(type, id, apiVersion), appBaseUrl).href;
|
|
29
28
|
return /*#__PURE__*/_react.default.createElement(_ui.Modal, {
|
|
30
29
|
onClose: onClose
|
|
31
30
|
}, /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
@@ -35,12 +34,12 @@ const GetLinkDialog = _ref => {
|
|
|
35
34
|
}, _index.default.t('Open in this app')), /*#__PURE__*/_react.default.createElement("div", {
|
|
36
35
|
className: `jsx-${_GetLinkDialogStyles.styles.__hash}` + " " + "link-container"
|
|
37
36
|
}, /*#__PURE__*/_react.default.createElement("a", {
|
|
38
|
-
href: appUrl
|
|
37
|
+
href: appUrl,
|
|
39
38
|
className: `jsx-${_GetLinkDialogStyles.styles.__hash}`
|
|
40
|
-
}, appUrl
|
|
39
|
+
}, appUrl), /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
41
40
|
icon: /*#__PURE__*/_react.default.createElement(_ui.IconCopy24, null),
|
|
42
41
|
small: true,
|
|
43
|
-
onClick: () => navigator.clipboard.writeText(appUrl
|
|
42
|
+
onClick: () => navigator.clipboard.writeText(appUrl)
|
|
44
43
|
}))), /*#__PURE__*/_react.default.createElement(_ui.ModalActions, null, /*#__PURE__*/_react.default.createElement(_ui.ButtonStrip, null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
|
|
45
44
|
onClick: onClose,
|
|
46
45
|
secondary: true
|
|
@@ -4,17 +4,49 @@ var _ui = require("@dhis2/ui");
|
|
|
4
4
|
var _enzyme = require("enzyme");
|
|
5
5
|
var _react = _interopRequireDefault(require("react"));
|
|
6
6
|
var _GetLinkDialog = require("../GetLinkDialog.js");
|
|
7
|
-
var _utils = require("../utils.js");
|
|
8
7
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
-
const testBaseUrl = 'http://
|
|
8
|
+
const testBaseUrl = 'http://host.tld/test/';
|
|
9
|
+
const mockUseConfig = jest.fn(() => ({
|
|
10
|
+
apiVersion: 42,
|
|
11
|
+
baseUrl: testBaseUrl
|
|
12
|
+
}));
|
|
10
13
|
jest.mock('@dhis2/app-runtime', () => ({
|
|
11
|
-
useConfig: () => (
|
|
12
|
-
baseUrl: testBaseUrl
|
|
13
|
-
})
|
|
14
|
+
useConfig: () => mockUseConfig()
|
|
14
15
|
}));
|
|
16
|
+
const tests = [{
|
|
17
|
+
type: 'visualization',
|
|
18
|
+
baseUrl: 'http://host.tld',
|
|
19
|
+
id: 'dv-id-1',
|
|
20
|
+
expected: 'http://host.tld/dhis-web-data-visualizer/#/dv-id-1'
|
|
21
|
+
}, {
|
|
22
|
+
type: 'visualization',
|
|
23
|
+
baseUrl: testBaseUrl,
|
|
24
|
+
id: 'dv-id-2',
|
|
25
|
+
expected: 'http://host.tld/test/dhis-web-data-visualizer/#/dv-id-2'
|
|
26
|
+
}, {
|
|
27
|
+
type: 'eventVisualization',
|
|
28
|
+
baseUrl: 'http://host.tld/other-path/',
|
|
29
|
+
id: 'll-id-1',
|
|
30
|
+
expected: 'http://host.tld/other-path/dhis-web-line-listing/#/ll-id-1'
|
|
31
|
+
}, {
|
|
32
|
+
type: 'eventVisualization',
|
|
33
|
+
apiVersion: 41,
|
|
34
|
+
baseUrl: 'http://host.tld/other-path',
|
|
35
|
+
id: 'll-id-2',
|
|
36
|
+
expected: 'http://host.tld/other-path/api/apps/line-listing/#/ll-id-2'
|
|
37
|
+
}, {
|
|
38
|
+
type: 'map',
|
|
39
|
+
baseUrl: testBaseUrl,
|
|
40
|
+
id: 'map-id-1',
|
|
41
|
+
expected: 'http://host.tld/test/dhis-web-maps/#/map-id-1'
|
|
42
|
+
}, {
|
|
43
|
+
type: 'map',
|
|
44
|
+
baseUrl: '../',
|
|
45
|
+
id: 'map-id-2',
|
|
46
|
+
expected: 'http://localhost/dhis-web-maps/#/map-id-2'
|
|
47
|
+
}];
|
|
15
48
|
describe('The FileMenu - GetLinkDialog component', () => {
|
|
16
49
|
let shallowGetLinkDialog;
|
|
17
|
-
let props;
|
|
18
50
|
const onClose = jest.fn();
|
|
19
51
|
const getGetLinkDialogComponent = props => {
|
|
20
52
|
if (!shallowGetLinkDialog) {
|
|
@@ -24,21 +56,38 @@ describe('The FileMenu - GetLinkDialog component', () => {
|
|
|
24
56
|
};
|
|
25
57
|
beforeEach(() => {
|
|
26
58
|
shallowGetLinkDialog = undefined;
|
|
27
|
-
props = {
|
|
28
|
-
type: 'visualization',
|
|
29
|
-
id: 'get-link-test-id',
|
|
30
|
-
onClose
|
|
31
|
-
};
|
|
32
59
|
});
|
|
33
60
|
it('renders a Modal component', () => {
|
|
34
|
-
expect(getGetLinkDialogComponent(
|
|
61
|
+
expect(getGetLinkDialogComponent({
|
|
62
|
+
type: tests[0].type,
|
|
63
|
+
id: tests[0].id
|
|
64
|
+
}).find(_ui.Modal)).toHaveLength(1);
|
|
35
65
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
66
|
+
test.each(tests)('renders a <a> tag containing the correct app path and id', _ref => {
|
|
67
|
+
let {
|
|
68
|
+
apiVersion,
|
|
69
|
+
baseUrl,
|
|
70
|
+
type,
|
|
71
|
+
id,
|
|
72
|
+
expected
|
|
73
|
+
} = _ref;
|
|
74
|
+
mockUseConfig.mockReturnValueOnce({
|
|
75
|
+
apiVersion: apiVersion || 42,
|
|
76
|
+
baseUrl
|
|
77
|
+
});
|
|
78
|
+
const href = getGetLinkDialogComponent({
|
|
79
|
+
type,
|
|
80
|
+
id,
|
|
81
|
+
onClose
|
|
82
|
+
}).find('a').prop('href');
|
|
83
|
+
expect(href).toMatch(expected);
|
|
39
84
|
});
|
|
40
85
|
it('calls the onClose callback when the Close button is clicked', () => {
|
|
41
|
-
getGetLinkDialogComponent(
|
|
86
|
+
getGetLinkDialogComponent({
|
|
87
|
+
type: tests[0].type,
|
|
88
|
+
id: tests[0].id,
|
|
89
|
+
onClose
|
|
90
|
+
}).find(_ui.Button).at(1).simulate('click');
|
|
42
91
|
expect(onClose).toHaveBeenCalled();
|
|
43
92
|
});
|
|
44
93
|
});
|
|
@@ -28,14 +28,15 @@ const labelForFileType = fileType => {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
exports.labelForFileType = labelForFileType;
|
|
31
|
-
const appPathFor = (fileType, id) => {
|
|
31
|
+
const appPathFor = (fileType, id, apiVersion) => {
|
|
32
32
|
switch (fileType) {
|
|
33
33
|
case FILE_TYPE_VISUALIZATION:
|
|
34
34
|
return `dhis-web-data-visualizer/#/${id}`;
|
|
35
35
|
case FILE_TYPE_MAP:
|
|
36
|
-
return `dhis-web-maps
|
|
36
|
+
return `dhis-web-maps/#/${id}`;
|
|
37
37
|
case FILE_TYPE_EVENT_VISUALIZATION:
|
|
38
|
-
|
|
38
|
+
// VERSION-TOGGLE: remove when 42 is the lowest supported version
|
|
39
|
+
return apiVersion >= 42 ? `dhis-web-line-listing/#/${id}` : `api/apps/line-listing/#/${id}`;
|
|
39
40
|
default:
|
|
40
41
|
return `${window.location.search}${window.location.hash}`;
|
|
41
42
|
}
|
|
@@ -87,6 +87,24 @@ class MdParser {
|
|
|
87
87
|
breaks: true
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
// From: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
|
|
91
|
+
// Remember the old renderer if overridden, or proxy to the default renderer.
|
|
92
|
+
const defaultRender = md.renderer.rules.link_open || (
|
|
93
|
+
// eslint-disable-next-line max-params
|
|
94
|
+
(tokens, idx, options, env, self) => {
|
|
95
|
+
return self.renderToken(tokens, idx, options);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// eslint-disable-next-line max-params
|
|
99
|
+
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
|
100
|
+
// Add a new 'target' and 'rel' attributes, or replace the value of the existing ones.
|
|
101
|
+
tokens[idx].attrSet('target', '_blank');
|
|
102
|
+
tokens[idx].attrSet('rel', 'noreferrer');
|
|
103
|
+
|
|
104
|
+
// Pass the token to the default renderer.
|
|
105
|
+
return defaultRender(tokens, idx, options, env, self);
|
|
106
|
+
};
|
|
107
|
+
|
|
90
108
|
// *bold* -> <strong>bold</strong>
|
|
91
109
|
md.inline.ruler.push('strong', parse(codes.bold.name));
|
|
92
110
|
|
|
@@ -16,13 +16,13 @@ describe('MdParser class', () => {
|
|
|
16
16
|
// nested italic/bold combinations not allowed
|
|
17
17
|
['_italic with *bold* inside_', '<em>italic with *bold* inside</em>'], ['*bold with _italic_ inside*', '<strong>bold with _italic_ inside</strong>'], ['text with : and :)', 'text with : and <span>\u{1F642}</span>'], ['(parenthesis and :))', '(parenthesis and <span>\u{1F642}</span>)'], [':((parenthesis:))', '<span>\u{1F641}</span>(parenthesis<span>\u{1F642}</span>)'], [':+1+1', '<span>\u{1F44D}</span>+1'], ['-1:-1', '-1<span>\u{1F44E}</span>'],
|
|
18
18
|
// links
|
|
19
|
-
['example.com/path', '<a href="http://example.com/path">example.com/path</a>'],
|
|
19
|
+
['[Test link](https://host.tld/path/link)', '<a href="https://host.tld/path/link" target="_blank" rel="noreferrer">Test link</a>'], ['example.com/path', '<a href="http://example.com/path" target="_blank" rel="noreferrer">example.com/path</a>'],
|
|
20
20
|
// not recognized links with italic marker inside not converted
|
|
21
21
|
['example_with_underscore.com/path', 'example_with_underscore.com/path'], ['example_with_underscore.com/path_with_underscore', 'example_with_underscore.com/path_with_underscore'],
|
|
22
22
|
// markers around non-recognized links
|
|
23
23
|
['link example_with_underscore.com/path should _not_ be converted', 'link example_with_underscore.com/path should <em>not</em> be converted'], ['link example_with_underscore.com/path should *not* be converted', 'link example_with_underscore.com/path should <strong>not</strong> be converted'],
|
|
24
24
|
// italic marker inside links not converted
|
|
25
|
-
['example.com/path_with_underscore', '<a href="http://example.com/path_with_underscore">example.com/path_with_underscore</a>'], ['_italic_ and *bold* with a example.com/link_with_underscore', '<em>italic</em> and <strong>bold</strong> with a <a href="http://example.com/link_with_underscore">example.com/link_with_underscore</a>'], ['example.com/path with *bold* after :)', '<a href="http://example.com/path">example.com/path</a> with <strong>bold</strong> after <span>\u{1F642}</span>'], ['_before_ example.com/path_with_underscore *after* :)', '<em>before</em> <a href="http://example.com/path_with_underscore">example.com/path_with_underscore</a> <strong>after</strong> <span>\u{1F642}</span>'],
|
|
25
|
+
['example.com/path_with_underscore', '<a href="http://example.com/path_with_underscore" target="_blank" rel="noreferrer">example.com/path_with_underscore</a>'], ['_italic_ and *bold* with a example.com/link_with_underscore', '<em>italic</em> and <strong>bold</strong> with a <a href="http://example.com/link_with_underscore" target="_blank" rel="noreferrer">example.com/link_with_underscore</a>'], ['example.com/path with *bold* after :)', '<a href="http://example.com/path" target="_blank" rel="noreferrer">example.com/path</a> with <strong>bold</strong> after <span>\u{1F642}</span>'], ['_before_ example.com/path_with_underscore *after* :)', '<em>before</em> <a href="http://example.com/path_with_underscore" target="_blank" rel="noreferrer">example.com/path_with_underscore</a> <strong>after</strong> <span>\u{1F642}</span>'],
|
|
26
26
|
// italic/bold markers right after non-word characters
|
|
27
27
|
['_If % of ART retention rate after 12 months >90(%)_: Sustain the efforts.', '<em>If % of ART retention rate after 12 months >90(%)</em>: Sustain the efforts.'], ['*If % of ART retention rate after 12 months >90(%)*: Sustain the efforts.', '<strong>If % of ART retention rate after 12 months >90(%)</strong>: Sustain the efforts.']];
|
|
28
28
|
inlineTests.forEach(test => {
|
|
@@ -114,24 +114,20 @@ describe('getFilterText', () => {
|
|
|
114
114
|
filters.push({
|
|
115
115
|
dimension: 'pe',
|
|
116
116
|
items: [{
|
|
117
|
-
id: '
|
|
118
|
-
|
|
117
|
+
id: '201801'
|
|
118
|
+
}, {
|
|
119
|
+
id: 'LAST_3_MONTHS'
|
|
120
|
+
}, {
|
|
121
|
+
id: 'LAST_MONTH'
|
|
119
122
|
}]
|
|
120
123
|
});
|
|
121
|
-
metaData.dimensions.pe = ['
|
|
122
|
-
metaData.items
|
|
123
|
-
name: '
|
|
124
|
-
uid: '_LAST_2_MONTHS_'
|
|
125
|
-
};
|
|
126
|
-
metaData.items._201801_ = {
|
|
127
|
-
name: '01 of 2018',
|
|
128
|
-
uid: '_201801_'
|
|
124
|
+
metaData.dimensions.pe = ['202501', '202502', '202503', '202504', '201801'];
|
|
125
|
+
metaData.items['201801'] = {
|
|
126
|
+
name: 'January 2018'
|
|
129
127
|
};
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
134
|
-
expect((0, _getFilterText.default)(filters, metaData)).toEqual('Clinics, Hospital - 01 of 2018, 02 of 2018');
|
|
128
|
+
|
|
129
|
+
// Relative period names come from relativePeriods.js
|
|
130
|
+
expect((0, _getFilterText.default)(filters, metaData)).toEqual('Clinics, Hospital - January 2018, Last 3 months, Last month');
|
|
135
131
|
});
|
|
136
132
|
});
|
|
137
133
|
});
|
|
@@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = _default;
|
|
7
|
+
var _relativePeriods = require("../../components/PeriodDimension/utils/relativePeriods.js");
|
|
7
8
|
var _getOuLevelAndGroupText = require("../../modules/getOuLevelAndGroupText.js");
|
|
9
|
+
var _dimensionGetItemIds = require("../../modules/layout/dimensionGetItemIds.js");
|
|
8
10
|
var _dimensionGetItems = require("../../modules/layout/dimensionGetItems.js");
|
|
9
11
|
var _dimensionIs = require("../../modules/layout/dimensionIs.js");
|
|
10
12
|
var _index = require("../../modules/ouIdHelper/index.js");
|
|
@@ -25,6 +27,12 @@ function _default(filters, metaData) {
|
|
|
25
27
|
return _index.ouIdHelper.hasGroupPrefix(id) || _index.ouIdHelper.hasLevelPrefix(id);
|
|
26
28
|
})) {
|
|
27
29
|
titleFragments.push((0, _getOuLevelAndGroupText.getOuLevelAndGroupText)(filter, metaData));
|
|
30
|
+
} else if ((0, _dimensionIs.dimensionIs)(filter, _predefinedDimensions.DIMENSION_ID_PERIOD)) {
|
|
31
|
+
const relativePeriodNames = (0, _relativePeriods.getRelativePeriodsName)();
|
|
32
|
+
titleFragments.push((0, _dimensionGetItemIds.dimensionGetItemIds)(filter).map(id => {
|
|
33
|
+
var _metaData$items$id;
|
|
34
|
+
return relativePeriodNames[id] || ((_metaData$items$id = metaData.items[id]) === null || _metaData$items$id === void 0 ? void 0 : _metaData$items$id.name) || id;
|
|
35
|
+
}).join(', '));
|
|
28
36
|
} else {
|
|
29
37
|
const filterItems = metaData.dimensions[filter.dimension];
|
|
30
38
|
if (Array.isArray(filterItems)) {
|
|
@@ -13,12 +13,11 @@ export const GetLinkDialog = _ref => {
|
|
|
13
13
|
onClose
|
|
14
14
|
} = _ref;
|
|
15
15
|
const {
|
|
16
|
+
apiVersion,
|
|
16
17
|
baseUrl
|
|
17
18
|
} = useConfig();
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const appBaseUrl = new URL(baseUrl, self.location.href);
|
|
21
|
-
const appUrl = new URL(appPathFor(type, id), appBaseUrl);
|
|
19
|
+
const appBaseUrl = new URL(baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`, self.location.href).href;
|
|
20
|
+
const appUrl = new URL(appPathFor(type, id, apiVersion), appBaseUrl).href;
|
|
22
21
|
return /*#__PURE__*/React.createElement(Modal, {
|
|
23
22
|
onClose: onClose
|
|
24
23
|
}, /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
@@ -28,12 +27,12 @@ export const GetLinkDialog = _ref => {
|
|
|
28
27
|
}, i18n.t('Open in this app')), /*#__PURE__*/React.createElement("div", {
|
|
29
28
|
className: `jsx-${styles.__hash}` + " " + "link-container"
|
|
30
29
|
}, /*#__PURE__*/React.createElement("a", {
|
|
31
|
-
href: appUrl
|
|
30
|
+
href: appUrl,
|
|
32
31
|
className: `jsx-${styles.__hash}`
|
|
33
|
-
}, appUrl
|
|
32
|
+
}, appUrl), /*#__PURE__*/React.createElement(Button, {
|
|
34
33
|
icon: /*#__PURE__*/React.createElement(IconCopy24, null),
|
|
35
34
|
small: true,
|
|
36
|
-
onClick: () => navigator.clipboard.writeText(appUrl
|
|
35
|
+
onClick: () => navigator.clipboard.writeText(appUrl)
|
|
37
36
|
}))), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(ButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
|
|
38
37
|
onClick: onClose,
|
|
39
38
|
secondary: true
|
|
@@ -2,16 +2,48 @@ import { Button, Modal } from '@dhis2/ui';
|
|
|
2
2
|
import { shallow } from 'enzyme';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { GetLinkDialog } from '../GetLinkDialog.js';
|
|
5
|
-
|
|
6
|
-
const
|
|
5
|
+
const testBaseUrl = 'http://host.tld/test/';
|
|
6
|
+
const mockUseConfig = jest.fn(() => ({
|
|
7
|
+
apiVersion: 42,
|
|
8
|
+
baseUrl: testBaseUrl
|
|
9
|
+
}));
|
|
7
10
|
jest.mock('@dhis2/app-runtime', () => ({
|
|
8
|
-
useConfig: () => (
|
|
9
|
-
baseUrl: testBaseUrl
|
|
10
|
-
})
|
|
11
|
+
useConfig: () => mockUseConfig()
|
|
11
12
|
}));
|
|
13
|
+
const tests = [{
|
|
14
|
+
type: 'visualization',
|
|
15
|
+
baseUrl: 'http://host.tld',
|
|
16
|
+
id: 'dv-id-1',
|
|
17
|
+
expected: 'http://host.tld/dhis-web-data-visualizer/#/dv-id-1'
|
|
18
|
+
}, {
|
|
19
|
+
type: 'visualization',
|
|
20
|
+
baseUrl: testBaseUrl,
|
|
21
|
+
id: 'dv-id-2',
|
|
22
|
+
expected: 'http://host.tld/test/dhis-web-data-visualizer/#/dv-id-2'
|
|
23
|
+
}, {
|
|
24
|
+
type: 'eventVisualization',
|
|
25
|
+
baseUrl: 'http://host.tld/other-path/',
|
|
26
|
+
id: 'll-id-1',
|
|
27
|
+
expected: 'http://host.tld/other-path/dhis-web-line-listing/#/ll-id-1'
|
|
28
|
+
}, {
|
|
29
|
+
type: 'eventVisualization',
|
|
30
|
+
apiVersion: 41,
|
|
31
|
+
baseUrl: 'http://host.tld/other-path',
|
|
32
|
+
id: 'll-id-2',
|
|
33
|
+
expected: 'http://host.tld/other-path/api/apps/line-listing/#/ll-id-2'
|
|
34
|
+
}, {
|
|
35
|
+
type: 'map',
|
|
36
|
+
baseUrl: testBaseUrl,
|
|
37
|
+
id: 'map-id-1',
|
|
38
|
+
expected: 'http://host.tld/test/dhis-web-maps/#/map-id-1'
|
|
39
|
+
}, {
|
|
40
|
+
type: 'map',
|
|
41
|
+
baseUrl: '../',
|
|
42
|
+
id: 'map-id-2',
|
|
43
|
+
expected: 'http://localhost/dhis-web-maps/#/map-id-2'
|
|
44
|
+
}];
|
|
12
45
|
describe('The FileMenu - GetLinkDialog component', () => {
|
|
13
46
|
let shallowGetLinkDialog;
|
|
14
|
-
let props;
|
|
15
47
|
const onClose = jest.fn();
|
|
16
48
|
const getGetLinkDialogComponent = props => {
|
|
17
49
|
if (!shallowGetLinkDialog) {
|
|
@@ -21,21 +53,38 @@ describe('The FileMenu - GetLinkDialog component', () => {
|
|
|
21
53
|
};
|
|
22
54
|
beforeEach(() => {
|
|
23
55
|
shallowGetLinkDialog = undefined;
|
|
24
|
-
props = {
|
|
25
|
-
type: 'visualization',
|
|
26
|
-
id: 'get-link-test-id',
|
|
27
|
-
onClose
|
|
28
|
-
};
|
|
29
56
|
});
|
|
30
57
|
it('renders a Modal component', () => {
|
|
31
|
-
expect(getGetLinkDialogComponent(
|
|
58
|
+
expect(getGetLinkDialogComponent({
|
|
59
|
+
type: tests[0].type,
|
|
60
|
+
id: tests[0].id
|
|
61
|
+
}).find(Modal)).toHaveLength(1);
|
|
32
62
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
test.each(tests)('renders a <a> tag containing the correct app path and id', _ref => {
|
|
64
|
+
let {
|
|
65
|
+
apiVersion,
|
|
66
|
+
baseUrl,
|
|
67
|
+
type,
|
|
68
|
+
id,
|
|
69
|
+
expected
|
|
70
|
+
} = _ref;
|
|
71
|
+
mockUseConfig.mockReturnValueOnce({
|
|
72
|
+
apiVersion: apiVersion || 42,
|
|
73
|
+
baseUrl
|
|
74
|
+
});
|
|
75
|
+
const href = getGetLinkDialogComponent({
|
|
76
|
+
type,
|
|
77
|
+
id,
|
|
78
|
+
onClose
|
|
79
|
+
}).find('a').prop('href');
|
|
80
|
+
expect(href).toMatch(expected);
|
|
36
81
|
});
|
|
37
82
|
it('calls the onClose callback when the Close button is clicked', () => {
|
|
38
|
-
getGetLinkDialogComponent(
|
|
83
|
+
getGetLinkDialogComponent({
|
|
84
|
+
type: tests[0].type,
|
|
85
|
+
id: tests[0].id,
|
|
86
|
+
onClose
|
|
87
|
+
}).find(Button).at(1).simulate('click');
|
|
39
88
|
expect(onClose).toHaveBeenCalled();
|
|
40
89
|
});
|
|
41
90
|
});
|
|
@@ -19,14 +19,15 @@ export const labelForFileType = fileType => {
|
|
|
19
19
|
return fileType;
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
-
export const appPathFor = (fileType, id) => {
|
|
22
|
+
export const appPathFor = (fileType, id, apiVersion) => {
|
|
23
23
|
switch (fileType) {
|
|
24
24
|
case FILE_TYPE_VISUALIZATION:
|
|
25
25
|
return `dhis-web-data-visualizer/#/${id}`;
|
|
26
26
|
case FILE_TYPE_MAP:
|
|
27
|
-
return `dhis-web-maps
|
|
27
|
+
return `dhis-web-maps/#/${id}`;
|
|
28
28
|
case FILE_TYPE_EVENT_VISUALIZATION:
|
|
29
|
-
|
|
29
|
+
// VERSION-TOGGLE: remove when 42 is the lowest supported version
|
|
30
|
+
return apiVersion >= 42 ? `dhis-web-line-listing/#/${id}` : `api/apps/line-listing/#/${id}`;
|
|
30
31
|
default:
|
|
31
32
|
return `${window.location.search}${window.location.hash}`;
|
|
32
33
|
}
|
|
@@ -80,6 +80,24 @@ export class MdParser {
|
|
|
80
80
|
breaks: true
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
+
// From: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
|
|
84
|
+
// Remember the old renderer if overridden, or proxy to the default renderer.
|
|
85
|
+
const defaultRender = md.renderer.rules.link_open || (
|
|
86
|
+
// eslint-disable-next-line max-params
|
|
87
|
+
(tokens, idx, options, env, self) => {
|
|
88
|
+
return self.renderToken(tokens, idx, options);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line max-params
|
|
92
|
+
md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
|
|
93
|
+
// Add a new 'target' and 'rel' attributes, or replace the value of the existing ones.
|
|
94
|
+
tokens[idx].attrSet('target', '_blank');
|
|
95
|
+
tokens[idx].attrSet('rel', 'noreferrer');
|
|
96
|
+
|
|
97
|
+
// Pass the token to the default renderer.
|
|
98
|
+
return defaultRender(tokens, idx, options, env, self);
|
|
99
|
+
};
|
|
100
|
+
|
|
83
101
|
// *bold* -> <strong>bold</strong>
|
|
84
102
|
md.inline.ruler.push('strong', parse(codes.bold.name));
|
|
85
103
|
|
|
@@ -14,13 +14,13 @@ describe('MdParser class', () => {
|
|
|
14
14
|
// nested italic/bold combinations not allowed
|
|
15
15
|
['_italic with *bold* inside_', '<em>italic with *bold* inside</em>'], ['*bold with _italic_ inside*', '<strong>bold with _italic_ inside</strong>'], ['text with : and :)', 'text with : and <span>\u{1F642}</span>'], ['(parenthesis and :))', '(parenthesis and <span>\u{1F642}</span>)'], [':((parenthesis:))', '<span>\u{1F641}</span>(parenthesis<span>\u{1F642}</span>)'], [':+1+1', '<span>\u{1F44D}</span>+1'], ['-1:-1', '-1<span>\u{1F44E}</span>'],
|
|
16
16
|
// links
|
|
17
|
-
['example.com/path', '<a href="http://example.com/path">example.com/path</a>'],
|
|
17
|
+
['[Test link](https://host.tld/path/link)', '<a href="https://host.tld/path/link" target="_blank" rel="noreferrer">Test link</a>'], ['example.com/path', '<a href="http://example.com/path" target="_blank" rel="noreferrer">example.com/path</a>'],
|
|
18
18
|
// not recognized links with italic marker inside not converted
|
|
19
19
|
['example_with_underscore.com/path', 'example_with_underscore.com/path'], ['example_with_underscore.com/path_with_underscore', 'example_with_underscore.com/path_with_underscore'],
|
|
20
20
|
// markers around non-recognized links
|
|
21
21
|
['link example_with_underscore.com/path should _not_ be converted', 'link example_with_underscore.com/path should <em>not</em> be converted'], ['link example_with_underscore.com/path should *not* be converted', 'link example_with_underscore.com/path should <strong>not</strong> be converted'],
|
|
22
22
|
// italic marker inside links not converted
|
|
23
|
-
['example.com/path_with_underscore', '<a href="http://example.com/path_with_underscore">example.com/path_with_underscore</a>'], ['_italic_ and *bold* with a example.com/link_with_underscore', '<em>italic</em> and <strong>bold</strong> with a <a href="http://example.com/link_with_underscore">example.com/link_with_underscore</a>'], ['example.com/path with *bold* after :)', '<a href="http://example.com/path">example.com/path</a> with <strong>bold</strong> after <span>\u{1F642}</span>'], ['_before_ example.com/path_with_underscore *after* :)', '<em>before</em> <a href="http://example.com/path_with_underscore">example.com/path_with_underscore</a> <strong>after</strong> <span>\u{1F642}</span>'],
|
|
23
|
+
['example.com/path_with_underscore', '<a href="http://example.com/path_with_underscore" target="_blank" rel="noreferrer">example.com/path_with_underscore</a>'], ['_italic_ and *bold* with a example.com/link_with_underscore', '<em>italic</em> and <strong>bold</strong> with a <a href="http://example.com/link_with_underscore" target="_blank" rel="noreferrer">example.com/link_with_underscore</a>'], ['example.com/path with *bold* after :)', '<a href="http://example.com/path" target="_blank" rel="noreferrer">example.com/path</a> with <strong>bold</strong> after <span>\u{1F642}</span>'], ['_before_ example.com/path_with_underscore *after* :)', '<em>before</em> <a href="http://example.com/path_with_underscore" target="_blank" rel="noreferrer">example.com/path_with_underscore</a> <strong>after</strong> <span>\u{1F642}</span>'],
|
|
24
24
|
// italic/bold markers right after non-word characters
|
|
25
25
|
['_If % of ART retention rate after 12 months >90(%)_: Sustain the efforts.', '<em>If % of ART retention rate after 12 months >90(%)</em>: Sustain the efforts.'], ['*If % of ART retention rate after 12 months >90(%)*: Sustain the efforts.', '<strong>If % of ART retention rate after 12 months >90(%)</strong>: Sustain the efforts.']];
|
|
26
26
|
inlineTests.forEach(test => {
|
|
@@ -111,24 +111,20 @@ describe('getFilterText', () => {
|
|
|
111
111
|
filters.push({
|
|
112
112
|
dimension: 'pe',
|
|
113
113
|
items: [{
|
|
114
|
-
id: '
|
|
115
|
-
|
|
114
|
+
id: '201801'
|
|
115
|
+
}, {
|
|
116
|
+
id: 'LAST_3_MONTHS'
|
|
117
|
+
}, {
|
|
118
|
+
id: 'LAST_MONTH'
|
|
116
119
|
}]
|
|
117
120
|
});
|
|
118
|
-
metaData.dimensions.pe = ['
|
|
119
|
-
metaData.items
|
|
120
|
-
name: '
|
|
121
|
-
uid: '_LAST_2_MONTHS_'
|
|
122
|
-
};
|
|
123
|
-
metaData.items._201801_ = {
|
|
124
|
-
name: '01 of 2018',
|
|
125
|
-
uid: '_201801_'
|
|
126
|
-
};
|
|
127
|
-
metaData.items._201802_ = {
|
|
128
|
-
name: '02 of 2018',
|
|
129
|
-
uid: '_201802_'
|
|
121
|
+
metaData.dimensions.pe = ['202501', '202502', '202503', '202504', '201801'];
|
|
122
|
+
metaData.items['201801'] = {
|
|
123
|
+
name: 'January 2018'
|
|
130
124
|
};
|
|
131
|
-
|
|
125
|
+
|
|
126
|
+
// Relative period names come from relativePeriods.js
|
|
127
|
+
expect(getFilterText(filters, metaData)).toEqual('Clinics, Hospital - January 2018, Last 3 months, Last month');
|
|
132
128
|
});
|
|
133
129
|
});
|
|
134
130
|
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { getRelativePeriodsName } from '../../components/PeriodDimension/utils/relativePeriods.js';
|
|
1
2
|
import { getOuLevelAndGroupText } from '../../modules/getOuLevelAndGroupText.js';
|
|
3
|
+
import { dimensionGetItemIds } from '../../modules/layout/dimensionGetItemIds.js';
|
|
2
4
|
import { dimensionGetItems } from '../../modules/layout/dimensionGetItems.js';
|
|
3
5
|
import { dimensionIs } from '../../modules/layout/dimensionIs.js';
|
|
4
6
|
import { ouIdHelper } from '../../modules/ouIdHelper/index.js';
|
|
5
|
-
import { DIMENSION_ID_ORGUNIT } from '../../modules/predefinedDimensions.js';
|
|
7
|
+
import { DIMENSION_ID_ORGUNIT, DIMENSION_ID_PERIOD } from '../../modules/predefinedDimensions.js';
|
|
6
8
|
export default function (filters, metaData) {
|
|
7
9
|
if (!Array.isArray(filters) || !filters.length) {
|
|
8
10
|
return '';
|
|
@@ -19,6 +21,12 @@ export default function (filters, metaData) {
|
|
|
19
21
|
return ouIdHelper.hasGroupPrefix(id) || ouIdHelper.hasLevelPrefix(id);
|
|
20
22
|
})) {
|
|
21
23
|
titleFragments.push(getOuLevelAndGroupText(filter, metaData));
|
|
24
|
+
} else if (dimensionIs(filter, DIMENSION_ID_PERIOD)) {
|
|
25
|
+
const relativePeriodNames = getRelativePeriodsName();
|
|
26
|
+
titleFragments.push(dimensionGetItemIds(filter).map(id => {
|
|
27
|
+
var _metaData$items$id;
|
|
28
|
+
return relativePeriodNames[id] || ((_metaData$items$id = metaData.items[id]) === null || _metaData$items$id === void 0 ? void 0 : _metaData$items$id.name) || id;
|
|
29
|
+
}).join(', '));
|
|
22
30
|
} else {
|
|
23
31
|
const filterItems = metaData.dimensions[filter.dimension];
|
|
24
32
|
if (Array.isArray(filterItems)) {
|