@dhis2/analytics 26.13.3 → 27.0.0
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/FileMenu.js +1 -2
- package/build/cjs/components/FileMenu/RenameDialog.js +10 -66
- package/build/cjs/components/FileMenu/__tests__/RenameDialog.spec.js +65 -33
- package/build/cjs/components/FileMenu/__tests__/utils.spec.js +239 -0
- package/build/cjs/components/FileMenu/utils.js +59 -3
- package/build/cjs/index.js +14 -0
- package/build/cjs/locales/en/translations.json +2 -0
- package/build/cjs/modules/visTypes.js +32 -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/FileMenu.js +1 -2
- package/build/es/components/FileMenu/RenameDialog.js +12 -68
- package/build/es/components/FileMenu/__tests__/RenameDialog.spec.js +64 -32
- package/build/es/components/FileMenu/__tests__/utils.spec.js +237 -0
- package/build/es/components/FileMenu/utils.js +56 -1
- package/build/es/index.js +2 -2
- package/build/es/locales/en/translations.json +2 -0
- package/build/es/modules/visTypes.js +30 -1
- package/build/es/visualizations/util/__tests__/getFilterText.spec.js +11 -15
- package/build/es/visualizations/util/getFilterText.js +9 -1
- package/package.json +3 -3
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.visTypeIcons = exports.visTypeDisplayNames = exports.isYearOverYear = exports.isVerticalType = exports.isTwoCategoryChartType = exports.isStacked = exports.isSingleValue = exports.isOutlierTable = exports.isMultiType = exports.isLegendSetType = exports.isDualAxisType = exports.isColumnBasedType = exports.getDisplayNameByVisType = exports.defaultVisType = exports.VIS_TYPE_YEAR_OVER_YEAR_LINE = exports.VIS_TYPE_YEAR_OVER_YEAR_COLUMN = exports.VIS_TYPE_STACKED_COLUMN = exports.VIS_TYPE_STACKED_BAR = exports.VIS_TYPE_STACKED_AREA = exports.VIS_TYPE_SINGLE_VALUE = exports.VIS_TYPE_SCATTER = exports.VIS_TYPE_RADAR = exports.VIS_TYPE_PIVOT_TABLE = exports.VIS_TYPE_PIE = exports.VIS_TYPE_OUTLIER_TABLE = exports.VIS_TYPE_LINE_LIST = exports.VIS_TYPE_LINE = exports.VIS_TYPE_GROUP_CHARTS = exports.VIS_TYPE_GROUP_ALL = exports.VIS_TYPE_GAUGE = exports.VIS_TYPE_COLUMN = exports.VIS_TYPE_BUBBLE = exports.VIS_TYPE_BAR = exports.VIS_TYPE_AREA = void 0;
|
|
6
|
+
exports.visTypeIcons = exports.visTypeDisplayNames = exports.isYearOverYear = exports.isVerticalType = exports.isTwoCategoryChartType = exports.isStacked = exports.isSingleValue = exports.isOutlierTable = exports.isMultiType = exports.isLegendSetType = exports.isDualAxisType = exports.isColumnBasedType = exports.getDisplayNameByVisType = exports.getApiEndpointByVisType = exports.defaultVisType = exports.VIS_TYPE_YEAR_OVER_YEAR_LINE = exports.VIS_TYPE_YEAR_OVER_YEAR_COLUMN = exports.VIS_TYPE_STACKED_COLUMN = exports.VIS_TYPE_STACKED_BAR = exports.VIS_TYPE_STACKED_AREA = exports.VIS_TYPE_SINGLE_VALUE = exports.VIS_TYPE_SCATTER = exports.VIS_TYPE_RADAR = exports.VIS_TYPE_PIVOT_TABLE = exports.VIS_TYPE_PIE = exports.VIS_TYPE_OUTLIER_TABLE = exports.VIS_TYPE_MAP = exports.VIS_TYPE_LINE_LIST = exports.VIS_TYPE_LINE = exports.VIS_TYPE_GROUP_CHARTS = exports.VIS_TYPE_GROUP_ALL = exports.VIS_TYPE_GAUGE = exports.VIS_TYPE_COLUMN = exports.VIS_TYPE_BUBBLE = exports.VIS_TYPE_BAR = exports.VIS_TYPE_AREA = void 0;
|
|
7
7
|
var _ui = require("@dhis2/ui");
|
|
8
8
|
var _index = _interopRequireDefault(require("../locales/index.js"));
|
|
9
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -27,6 +27,7 @@ const VIS_TYPE_BUBBLE = exports.VIS_TYPE_BUBBLE = 'BUBBLE';
|
|
|
27
27
|
const VIS_TYPE_GROUP_ALL = exports.VIS_TYPE_GROUP_ALL = 'ALL';
|
|
28
28
|
const VIS_TYPE_GROUP_CHARTS = exports.VIS_TYPE_GROUP_CHARTS = 'CHARTS';
|
|
29
29
|
const VIS_TYPE_OUTLIER_TABLE = exports.VIS_TYPE_OUTLIER_TABLE = 'OUTLIER_TABLE';
|
|
30
|
+
const VIS_TYPE_MAP = exports.VIS_TYPE_MAP = 'MAP';
|
|
30
31
|
const visTypeDisplayNames = exports.visTypeDisplayNames = {
|
|
31
32
|
[VIS_TYPE_PIVOT_TABLE]: _index.default.t('Pivot table'),
|
|
32
33
|
[VIS_TYPE_AREA]: _index.default.t('Area'),
|
|
@@ -46,7 +47,8 @@ const visTypeDisplayNames = exports.visTypeDisplayNames = {
|
|
|
46
47
|
[VIS_TYPE_SINGLE_VALUE]: _index.default.t('Single value'),
|
|
47
48
|
[VIS_TYPE_OUTLIER_TABLE]: _index.default.t('Outlier table'),
|
|
48
49
|
[VIS_TYPE_GROUP_ALL]: _index.default.t('All types'),
|
|
49
|
-
[VIS_TYPE_GROUP_CHARTS]: _index.default.t('All charts')
|
|
50
|
+
[VIS_TYPE_GROUP_CHARTS]: _index.default.t('All charts'),
|
|
51
|
+
[VIS_TYPE_MAP]: _index.default.t('Map')
|
|
50
52
|
};
|
|
51
53
|
const visTypeIcons = exports.visTypeIcons = {
|
|
52
54
|
[VIS_TYPE_PIVOT_TABLE]: _ui.IconVisualizationPivotTable24,
|
|
@@ -67,6 +69,26 @@ const visTypeIcons = exports.visTypeIcons = {
|
|
|
67
69
|
[VIS_TYPE_SINGLE_VALUE]: _ui.IconVisualizationSingleValue24,
|
|
68
70
|
[VIS_TYPE_OUTLIER_TABLE]: _ui.IconVisualizationOutlierTable24
|
|
69
71
|
};
|
|
72
|
+
const visTypeApiEndpoints = {
|
|
73
|
+
[VIS_TYPE_PIVOT_TABLE]: 'visualizations',
|
|
74
|
+
[VIS_TYPE_AREA]: 'visualizations',
|
|
75
|
+
[VIS_TYPE_STACKED_AREA]: 'visualizations',
|
|
76
|
+
[VIS_TYPE_BAR]: 'visualizations',
|
|
77
|
+
[VIS_TYPE_STACKED_BAR]: 'visualizations',
|
|
78
|
+
[VIS_TYPE_COLUMN]: 'visualizations',
|
|
79
|
+
[VIS_TYPE_YEAR_OVER_YEAR_COLUMN]: 'visualizations',
|
|
80
|
+
[VIS_TYPE_STACKED_COLUMN]: 'visualizations',
|
|
81
|
+
[VIS_TYPE_GAUGE]: 'visualizations',
|
|
82
|
+
[VIS_TYPE_LINE]: 'visualizations',
|
|
83
|
+
[VIS_TYPE_YEAR_OVER_YEAR_LINE]: 'visualizations',
|
|
84
|
+
[VIS_TYPE_PIE]: 'visualizations',
|
|
85
|
+
[VIS_TYPE_RADAR]: 'visualizations',
|
|
86
|
+
[VIS_TYPE_SCATTER]: 'visualizations',
|
|
87
|
+
[VIS_TYPE_SINGLE_VALUE]: 'visualizations',
|
|
88
|
+
[VIS_TYPE_OUTLIER_TABLE]: 'visualizations',
|
|
89
|
+
[VIS_TYPE_LINE_LIST]: 'eventVisualizations',
|
|
90
|
+
[VIS_TYPE_MAP]: 'maps'
|
|
91
|
+
};
|
|
70
92
|
const getDisplayNameByVisType = visType => {
|
|
71
93
|
const displayName = visTypeDisplayNames[visType];
|
|
72
94
|
if (!displayName) {
|
|
@@ -75,6 +97,14 @@ const getDisplayNameByVisType = visType => {
|
|
|
75
97
|
return displayName;
|
|
76
98
|
};
|
|
77
99
|
exports.getDisplayNameByVisType = getDisplayNameByVisType;
|
|
100
|
+
const getApiEndpointByVisType = visType => {
|
|
101
|
+
const apiEndpoint = visTypeApiEndpoints[visType];
|
|
102
|
+
if (!apiEndpoint) {
|
|
103
|
+
throw new Error(`${visType} is not a valid visualization type`);
|
|
104
|
+
}
|
|
105
|
+
return apiEndpoint;
|
|
106
|
+
};
|
|
107
|
+
exports.getApiEndpointByVisType = getApiEndpointByVisType;
|
|
78
108
|
const stackedTypes = [VIS_TYPE_STACKED_COLUMN, VIS_TYPE_STACKED_BAR, VIS_TYPE_STACKED_AREA];
|
|
79
109
|
const yearOverYearTypes = [VIS_TYPE_YEAR_OVER_YEAR_LINE, VIS_TYPE_YEAR_OVER_YEAR_COLUMN];
|
|
80
110
|
const dualAxisTypes = [VIS_TYPE_COLUMN, VIS_TYPE_BAR, VIS_TYPE_LINE, VIS_TYPE_AREA];
|
|
@@ -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)) {
|
|
@@ -48,8 +48,7 @@ export const FileMenu = _ref => {
|
|
|
48
48
|
type: fileType,
|
|
49
49
|
object: fileObject,
|
|
50
50
|
onClose: onDialogClose,
|
|
51
|
-
onRename: onRename
|
|
52
|
-
onError: onError
|
|
51
|
+
onRename: onRename
|
|
53
52
|
});
|
|
54
53
|
case 'translate':
|
|
55
54
|
return /*#__PURE__*/React.createElement(TranslationDialog, {
|
|
@@ -1,75 +1,25 @@
|
|
|
1
1
|
import _JSXStyle from "styled-jsx/style";
|
|
2
|
-
import { useDataMutation } from '@dhis2/app-runtime';
|
|
3
2
|
import { Modal, ModalTitle, ModalContent, ModalActions, ButtonStrip, Button, InputField, TextAreaField } from '@dhis2/ui';
|
|
4
3
|
import PropTypes from 'prop-types';
|
|
5
|
-
import React, {
|
|
4
|
+
import React, { useState } from 'react';
|
|
6
5
|
import i18n from '../../locales/index.js';
|
|
7
6
|
import { modalStyles } from './FileMenu.styles.js';
|
|
8
|
-
import { supportedFileTypes,
|
|
9
|
-
const
|
|
10
|
-
const payload = [{
|
|
11
|
-
op: 'add',
|
|
12
|
-
path: '/name',
|
|
13
|
-
value: name
|
|
14
|
-
}];
|
|
15
|
-
if (description) {
|
|
16
|
-
payload.push({
|
|
17
|
-
op: 'add',
|
|
18
|
-
path: '/description',
|
|
19
|
-
value: description
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
return payload;
|
|
23
|
-
};
|
|
24
|
-
const getMutation = type => ({
|
|
25
|
-
resource: endpointFromFileType(type),
|
|
26
|
-
id: _ref => {
|
|
27
|
-
let {
|
|
28
|
-
id
|
|
29
|
-
} = _ref;
|
|
30
|
-
return id;
|
|
31
|
-
},
|
|
32
|
-
type: 'json-patch',
|
|
33
|
-
data: _ref2 => {
|
|
34
|
-
let {
|
|
35
|
-
name,
|
|
36
|
-
description
|
|
37
|
-
} = _ref2;
|
|
38
|
-
return formatPayload(name, description);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
export const RenameDialog = _ref3 => {
|
|
7
|
+
import { supportedFileTypes, labelForFileType } from './utils.js';
|
|
8
|
+
export const RenameDialog = _ref => {
|
|
42
9
|
let {
|
|
43
10
|
type,
|
|
44
11
|
object,
|
|
45
12
|
onClose,
|
|
46
|
-
onRename
|
|
47
|
-
|
|
48
|
-
} = _ref3;
|
|
13
|
+
onRename
|
|
14
|
+
} = _ref;
|
|
49
15
|
const [name, setName] = useState(object.name);
|
|
50
16
|
const [description, setDescription] = useState(object.description);
|
|
51
|
-
const mutation = useMemo(() => getMutation(type), [type]);
|
|
52
|
-
const [mutate, {
|
|
53
|
-
loading
|
|
54
|
-
}] = useDataMutation(mutation, {
|
|
55
|
-
onError: error => {
|
|
56
|
-
onError(error);
|
|
57
|
-
onClose();
|
|
58
|
-
},
|
|
59
|
-
onComplete: () => {
|
|
60
|
-
onRename({
|
|
61
|
-
name,
|
|
62
|
-
description
|
|
63
|
-
});
|
|
64
|
-
onClose();
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
17
|
const renameObject = () => {
|
|
68
|
-
|
|
69
|
-
id: object.id,
|
|
18
|
+
onRename({
|
|
70
19
|
name,
|
|
71
20
|
description
|
|
72
21
|
});
|
|
22
|
+
onClose();
|
|
73
23
|
};
|
|
74
24
|
return /*#__PURE__*/React.createElement(Modal, {
|
|
75
25
|
onClose: onClose,
|
|
@@ -82,49 +32,43 @@ export const RenameDialog = _ref3 => {
|
|
|
82
32
|
className: `jsx-${modalStyles.__hash}` + " " + "modal-content"
|
|
83
33
|
}, /*#__PURE__*/React.createElement(InputField, {
|
|
84
34
|
label: i18n.t('Name'),
|
|
85
|
-
disabled: loading,
|
|
86
35
|
required: true,
|
|
87
36
|
value: name,
|
|
88
|
-
onChange:
|
|
37
|
+
onChange: _ref2 => {
|
|
89
38
|
let {
|
|
90
39
|
value
|
|
91
|
-
} =
|
|
40
|
+
} = _ref2;
|
|
92
41
|
return setName(value);
|
|
93
42
|
},
|
|
94
43
|
dataTest: "file-menu-rename-modal-name"
|
|
95
44
|
}), /*#__PURE__*/React.createElement(TextAreaField, {
|
|
96
45
|
label: i18n.t('Description'),
|
|
97
|
-
disabled: loading,
|
|
98
46
|
value: description,
|
|
99
47
|
rows: 3,
|
|
100
|
-
onChange:
|
|
48
|
+
onChange: _ref3 => {
|
|
101
49
|
let {
|
|
102
50
|
value
|
|
103
|
-
} =
|
|
51
|
+
} = _ref3;
|
|
104
52
|
return setDescription(value);
|
|
105
53
|
},
|
|
106
54
|
dataTest: "file-menu-rename-modal-description"
|
|
107
55
|
}))), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(ButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
|
|
108
56
|
onClick: onClose,
|
|
109
|
-
disabled: loading,
|
|
110
57
|
secondary: true,
|
|
111
58
|
dataTest: "file-menu-rename-modal-cancel"
|
|
112
59
|
}, i18n.t('Cancel')), /*#__PURE__*/React.createElement(Button, {
|
|
113
60
|
onClick: renameObject,
|
|
114
|
-
disabled: loading,
|
|
115
61
|
primary: true,
|
|
116
62
|
dataTest: "file-menu-rename-modal-rename"
|
|
117
63
|
}, i18n.t('Rename')))));
|
|
118
64
|
};
|
|
119
65
|
RenameDialog.propTypes = {
|
|
120
|
-
id: PropTypes.string,
|
|
121
66
|
object: PropTypes.shape({
|
|
122
|
-
id: PropTypes.string.isRequired,
|
|
123
67
|
description: PropTypes.string,
|
|
68
|
+
id: PropTypes.string,
|
|
124
69
|
name: PropTypes.string
|
|
125
70
|
}),
|
|
126
71
|
type: PropTypes.oneOf(supportedFileTypes),
|
|
127
72
|
onClose: PropTypes.func,
|
|
128
|
-
onError: PropTypes.func,
|
|
129
73
|
onRename: PropTypes.func
|
|
130
74
|
};
|
|
@@ -1,51 +1,83 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import { render, fireEvent, screen, within } from '@testing-library/react';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { RenameDialog } from '../RenameDialog.js';
|
|
5
6
|
describe('The FileMenu - RenameDialog component', () => {
|
|
6
|
-
let shallowRenameDialog;
|
|
7
|
-
let props;
|
|
8
7
|
const onClose = jest.fn();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const onRename = jest.fn();
|
|
9
|
+
const props = {
|
|
10
|
+
type: 'visualization',
|
|
11
|
+
object: {
|
|
12
|
+
id: 'rename-test'
|
|
13
|
+
},
|
|
14
|
+
onClose,
|
|
15
|
+
onRename
|
|
14
16
|
};
|
|
15
17
|
beforeEach(() => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type: 'visualization',
|
|
19
|
-
object: {
|
|
20
|
-
id: 'rename-test'
|
|
21
|
-
},
|
|
22
|
-
onClose
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
it('renders a Modal component', () => {
|
|
26
|
-
expect(getRenameDialogComponent(props).find(Modal)).toHaveLength(1);
|
|
18
|
+
jest.resetAllMocks();
|
|
19
|
+
jest.clearAllMocks();
|
|
27
20
|
});
|
|
28
|
-
it('renders a
|
|
29
|
-
|
|
21
|
+
it('renders a Modal component with the correct heading', () => {
|
|
22
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, props));
|
|
23
|
+
expect(screen.getAllByTestId('file-menu-rename-modal')).toHaveLength(1);
|
|
24
|
+
expect(screen.getByRole('heading')).toHaveTextContent('Rename visualization');
|
|
30
25
|
});
|
|
31
26
|
it('renders a InputField for name', () => {
|
|
32
|
-
|
|
27
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, props));
|
|
28
|
+
expect(screen.getByTestId('file-menu-rename-modal-name')).toBeInTheDocument();
|
|
29
|
+
expect(screen.getByText('Name')).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByText('Name')).toBeVisible();
|
|
33
31
|
});
|
|
34
32
|
it('renders a InputField for name with prefilled value if name is in object prop', () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, _extends({}, props, {
|
|
34
|
+
object: {
|
|
35
|
+
...props.object,
|
|
36
|
+
name: 'Vis test'
|
|
37
|
+
}
|
|
38
|
+
})));
|
|
39
|
+
const ancestorElement = screen.getByTestId('file-menu-rename-modal-name');
|
|
40
|
+
const inputElement = within(ancestorElement).getByRole('textbox');
|
|
41
|
+
expect(inputElement).toBeInTheDocument();
|
|
42
|
+
expect(inputElement).toHaveValue('Vis test');
|
|
38
43
|
});
|
|
39
44
|
it('renders a TextAreaField for description', () => {
|
|
40
|
-
|
|
45
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, props));
|
|
46
|
+
|
|
47
|
+
// Locate the label by its text
|
|
48
|
+
const labelElement = screen.getByText('Description');
|
|
49
|
+
|
|
50
|
+
// Find the textarea element within the same container as the label
|
|
51
|
+
const descriptionField = labelElement.closest('div').querySelector('textarea');
|
|
52
|
+
expect(descriptionField).toBeInTheDocument();
|
|
53
|
+
expect(descriptionField).toBeVisible();
|
|
41
54
|
});
|
|
42
55
|
it('renders a TextAreaField for description with prefilled value if description is in object prop', () => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, _extends({}, props, {
|
|
57
|
+
object: {
|
|
58
|
+
...props.object,
|
|
59
|
+
description: 'Long explanation of the visualization'
|
|
60
|
+
}
|
|
61
|
+
})));
|
|
62
|
+
|
|
63
|
+
// Locate the label by its text
|
|
64
|
+
const labelElement = screen.getByText('Description');
|
|
65
|
+
|
|
66
|
+
// Find the textarea element within the same container as the label
|
|
67
|
+
const descriptionField = labelElement.closest('div').querySelector('textarea');
|
|
68
|
+
expect(descriptionField).toBeInTheDocument();
|
|
69
|
+
expect(descriptionField).toHaveValue('Long explanation of the visualization');
|
|
70
|
+
});
|
|
71
|
+
it('calls the onClose callback when the Cancel button is clicked', async () => {
|
|
72
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, props));
|
|
73
|
+
await fireEvent.click(screen.getByTestId('file-menu-rename-modal-cancel'));
|
|
74
|
+
expect(onClose).toHaveBeenCalled();
|
|
75
|
+
expect(onRename).not.toHaveBeenCalled();
|
|
46
76
|
});
|
|
47
|
-
it('calls the
|
|
48
|
-
|
|
77
|
+
it('calls the onRename callback when the Rename button is clicked', async () => {
|
|
78
|
+
render(/*#__PURE__*/React.createElement(RenameDialog, props));
|
|
79
|
+
await fireEvent.click(screen.getByTestId('file-menu-rename-modal-rename'));
|
|
80
|
+
expect(onRename).toHaveBeenCalled();
|
|
49
81
|
expect(onClose).toHaveBeenCalled();
|
|
50
82
|
});
|
|
51
83
|
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { preparePayloadForSaveAs, preparePayloadForSave } from '../utils.js';
|
|
2
|
+
describe('utils', () => {
|
|
3
|
+
describe('preparePayloadForSaveAs', () => {
|
|
4
|
+
it('removes unnecessary properties from the visualization object', () => {
|
|
5
|
+
const visualization = {
|
|
6
|
+
id: '123',
|
|
7
|
+
created: '2023-01-01',
|
|
8
|
+
createdBy: 'user1',
|
|
9
|
+
user: 'user2',
|
|
10
|
+
name: 'Existing Name',
|
|
11
|
+
description: 'Existing Description',
|
|
12
|
+
type: 'PIVOT_TABLE'
|
|
13
|
+
};
|
|
14
|
+
const result = preparePayloadForSaveAs({
|
|
15
|
+
visualization
|
|
16
|
+
});
|
|
17
|
+
expect(result).not.toHaveProperty('id');
|
|
18
|
+
expect(result).not.toHaveProperty('created');
|
|
19
|
+
expect(result).not.toHaveProperty('createdBy');
|
|
20
|
+
expect(result).not.toHaveProperty('user');
|
|
21
|
+
});
|
|
22
|
+
it('sets the name to the provided name', () => {
|
|
23
|
+
const visualization = {
|
|
24
|
+
type: 'PIVOT_TABLE'
|
|
25
|
+
};
|
|
26
|
+
const name = 'New Name';
|
|
27
|
+
const result = preparePayloadForSaveAs({
|
|
28
|
+
visualization,
|
|
29
|
+
name
|
|
30
|
+
});
|
|
31
|
+
expect(result.name).toBe(name);
|
|
32
|
+
});
|
|
33
|
+
it('sets the name to the existing name if no new name is provided', () => {
|
|
34
|
+
const visualization = {
|
|
35
|
+
name: 'Existing Name',
|
|
36
|
+
type: 'MAP'
|
|
37
|
+
};
|
|
38
|
+
const result = preparePayloadForSaveAs({
|
|
39
|
+
visualization
|
|
40
|
+
});
|
|
41
|
+
expect(result.name).toBe('Existing Name');
|
|
42
|
+
});
|
|
43
|
+
it('sets the name to a default value if no name is provided', () => {
|
|
44
|
+
const visualization = {
|
|
45
|
+
type: 'LINE_LIST'
|
|
46
|
+
};
|
|
47
|
+
const result = preparePayloadForSaveAs({
|
|
48
|
+
visualization
|
|
49
|
+
});
|
|
50
|
+
const expectedName = `Untitled Line list, ${new Date().toLocaleDateString(undefined, {
|
|
51
|
+
year: 'numeric',
|
|
52
|
+
month: 'short',
|
|
53
|
+
day: '2-digit'
|
|
54
|
+
})}`;
|
|
55
|
+
expect(result.name).toBe(expectedName);
|
|
56
|
+
});
|
|
57
|
+
it('sets the description to the provided description', () => {
|
|
58
|
+
const visualization = {
|
|
59
|
+
description: 'Existing Description',
|
|
60
|
+
type: 'PIVOT_TABLE'
|
|
61
|
+
};
|
|
62
|
+
const description = 'New Description';
|
|
63
|
+
const result = preparePayloadForSaveAs({
|
|
64
|
+
visualization,
|
|
65
|
+
description
|
|
66
|
+
});
|
|
67
|
+
expect(result.description).toBe(description);
|
|
68
|
+
});
|
|
69
|
+
it('keeps the existing description if no new description is provided', () => {
|
|
70
|
+
const visualization = {
|
|
71
|
+
description: 'Existing Description',
|
|
72
|
+
type: 'PIVOT_TABLE'
|
|
73
|
+
};
|
|
74
|
+
const result = preparePayloadForSaveAs({
|
|
75
|
+
visualization
|
|
76
|
+
});
|
|
77
|
+
expect(result.description).toBe('Existing Description');
|
|
78
|
+
});
|
|
79
|
+
it('sets the description to undefined if no description is provided and none exists', () => {
|
|
80
|
+
const visualization = {
|
|
81
|
+
type: 'PIVOT_TABLE'
|
|
82
|
+
};
|
|
83
|
+
const result = preparePayloadForSaveAs({
|
|
84
|
+
visualization
|
|
85
|
+
});
|
|
86
|
+
expect(result.description).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('preparePayloadForSave', () => {
|
|
90
|
+
const mockEngine = {
|
|
91
|
+
query: jest.fn()
|
|
92
|
+
};
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
jest.clearAllMocks();
|
|
95
|
+
});
|
|
96
|
+
it('fetches subscribers and adds them to the visualization', async () => {
|
|
97
|
+
const visualization = {
|
|
98
|
+
id: '123',
|
|
99
|
+
type: 'BAR',
|
|
100
|
+
name: 'Existing Name',
|
|
101
|
+
description: 'Existing Description'
|
|
102
|
+
};
|
|
103
|
+
mockEngine.query.mockResolvedValue({
|
|
104
|
+
ao: {
|
|
105
|
+
subscribers: ['user1', 'user2']
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const result = await preparePayloadForSave({
|
|
109
|
+
visualization,
|
|
110
|
+
engine: mockEngine
|
|
111
|
+
});
|
|
112
|
+
expect(mockEngine.query).toHaveBeenCalledWith({
|
|
113
|
+
ao: {
|
|
114
|
+
resource: 'visualizations',
|
|
115
|
+
id: expect.any(Function),
|
|
116
|
+
params: {
|
|
117
|
+
fields: 'subscribers'
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, {
|
|
121
|
+
variables: {
|
|
122
|
+
id: '123'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
expect(result.subscribers).toEqual(['user1', 'user2']);
|
|
126
|
+
});
|
|
127
|
+
it('sets the name to the provided name', async () => {
|
|
128
|
+
const visualization = {
|
|
129
|
+
id: '123',
|
|
130
|
+
type: 'MAP',
|
|
131
|
+
name: 'Existing name'
|
|
132
|
+
};
|
|
133
|
+
const name = 'New Name';
|
|
134
|
+
mockEngine.query.mockResolvedValue({
|
|
135
|
+
ao: {
|
|
136
|
+
subscribers: []
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const result = await preparePayloadForSave({
|
|
140
|
+
visualization,
|
|
141
|
+
name,
|
|
142
|
+
engine: mockEngine
|
|
143
|
+
});
|
|
144
|
+
expect(result.name).toBe(name);
|
|
145
|
+
});
|
|
146
|
+
it('sets the name to the existing name if no new name is provided', async () => {
|
|
147
|
+
const visualization = {
|
|
148
|
+
id: '123',
|
|
149
|
+
type: 'LINE_LIST',
|
|
150
|
+
name: 'Existing Name'
|
|
151
|
+
};
|
|
152
|
+
mockEngine.query.mockResolvedValue({
|
|
153
|
+
ao: {
|
|
154
|
+
subscribers: []
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const result = await preparePayloadForSave({
|
|
158
|
+
visualization,
|
|
159
|
+
engine: mockEngine
|
|
160
|
+
});
|
|
161
|
+
expect(result.name).toBe('Existing Name');
|
|
162
|
+
});
|
|
163
|
+
it('sets the name to a default value if no name is provided', async () => {
|
|
164
|
+
const visualization = {
|
|
165
|
+
id: '123',
|
|
166
|
+
type: 'BAR'
|
|
167
|
+
};
|
|
168
|
+
mockEngine.query.mockResolvedValue({
|
|
169
|
+
ao: {
|
|
170
|
+
subscribers: []
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const result = await preparePayloadForSave({
|
|
174
|
+
visualization,
|
|
175
|
+
engine: mockEngine
|
|
176
|
+
});
|
|
177
|
+
const expectedName = `Untitled Bar, ${new Date().toLocaleDateString(undefined, {
|
|
178
|
+
year: 'numeric',
|
|
179
|
+
month: 'short',
|
|
180
|
+
day: '2-digit'
|
|
181
|
+
})}`;
|
|
182
|
+
expect(result.name).toBe(expectedName);
|
|
183
|
+
});
|
|
184
|
+
it('sets the description to the provided description', async () => {
|
|
185
|
+
const visualization = {
|
|
186
|
+
id: '123',
|
|
187
|
+
type: 'YEAR_OVER_YEAR_LINE',
|
|
188
|
+
description: 'Existing Description'
|
|
189
|
+
};
|
|
190
|
+
const description = 'New Description';
|
|
191
|
+
mockEngine.query.mockResolvedValue({
|
|
192
|
+
ao: {
|
|
193
|
+
subscribers: []
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
const result = await preparePayloadForSave({
|
|
197
|
+
visualization,
|
|
198
|
+
description,
|
|
199
|
+
engine: mockEngine
|
|
200
|
+
});
|
|
201
|
+
expect(result.description).toBe(description);
|
|
202
|
+
});
|
|
203
|
+
it('keeps the existing description if no new description is provided', async () => {
|
|
204
|
+
const visualization = {
|
|
205
|
+
id: '123',
|
|
206
|
+
type: 'COLUMN',
|
|
207
|
+
description: 'Existing Description'
|
|
208
|
+
};
|
|
209
|
+
mockEngine.query.mockResolvedValue({
|
|
210
|
+
ao: {
|
|
211
|
+
subscribers: []
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
const result = await preparePayloadForSave({
|
|
215
|
+
visualization,
|
|
216
|
+
engine: mockEngine
|
|
217
|
+
});
|
|
218
|
+
expect(result.description).toBe('Existing Description');
|
|
219
|
+
});
|
|
220
|
+
it('sets the description to undefined if no description is provided and none exists', async () => {
|
|
221
|
+
const visualization = {
|
|
222
|
+
id: '123',
|
|
223
|
+
type: 'BAR'
|
|
224
|
+
};
|
|
225
|
+
mockEngine.query.mockResolvedValue({
|
|
226
|
+
ao: {
|
|
227
|
+
subscribers: []
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const result = await preparePayloadForSave({
|
|
231
|
+
visualization,
|
|
232
|
+
engine: mockEngine
|
|
233
|
+
});
|
|
234
|
+
expect(result.description).toBeUndefined();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
});
|