@dhis2/analytics 24.10.1 → 25.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/CHANGELOG.md +12 -0
- package/build/cjs/__demo__/CalculationModal.stories.js +448 -0
- package/build/cjs/api/analytics/AnalyticsRequest.js +12 -1
- package/build/cjs/api/dimensions.js +1 -1
- package/build/cjs/api/expression.js +67 -0
- package/build/cjs/assets/DimensionItemIcons/CalculationIcon.js +25 -0
- package/build/cjs/assets/FormulaIcon.js +40 -0
- package/build/cjs/components/DataDimension/Calculation/CalculationModal.js +447 -0
- package/build/cjs/components/DataDimension/Calculation/DataElementOption.js +77 -0
- package/build/cjs/components/DataDimension/Calculation/DataElementSelector.js +306 -0
- package/build/cjs/components/DataDimension/Calculation/DndContext.js +213 -0
- package/build/cjs/components/DataDimension/Calculation/DragHandleIcon.js +23 -0
- package/build/cjs/components/DataDimension/Calculation/DraggingItem.js +58 -0
- package/build/cjs/components/DataDimension/Calculation/DropZone.js +58 -0
- package/build/cjs/components/DataDimension/Calculation/FormulaField.js +121 -0
- package/build/cjs/components/DataDimension/Calculation/FormulaItem.js +232 -0
- package/build/cjs/components/DataDimension/Calculation/MathOperatorSelector.js +57 -0
- package/build/cjs/components/DataDimension/Calculation/Operator.js +81 -0
- package/build/cjs/components/DataDimension/Calculation/styles/CalculationModal.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/DataElementOption.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/DataElementSelector.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/DraggingItem.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/DropZone.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/FormulaField.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/FormulaItem.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/MathOperatorSelector.style.js +13 -0
- package/build/cjs/components/DataDimension/Calculation/styles/Operator.style.js +13 -0
- package/build/cjs/components/DataDimension/DataDimension.js +22 -6
- package/build/cjs/components/DataDimension/DataTypeSelector.js +5 -3
- package/build/cjs/components/DataDimension/ItemSelector.js +111 -73
- package/build/cjs/components/TransferOption.js +13 -4
- package/build/cjs/components/styles/DimensionSelector.style.js +2 -2
- package/build/cjs/components/styles/TransferOption.style.js +2 -2
- package/build/cjs/index.js +6 -0
- package/build/cjs/locales/en/translations.json +32 -7
- package/build/cjs/modules/__tests__/expressions.spec.js +139 -0
- package/build/cjs/modules/__tests__/hash.spec.js +92 -0
- package/build/cjs/modules/__tests__/parseExpression.spec.js +46 -0
- package/build/cjs/modules/dataTypes.js +8 -1
- package/build/cjs/modules/dimensionListItem.js +82 -0
- package/build/cjs/modules/expressions.js +164 -0
- package/build/cjs/modules/hash.js +28 -0
- package/build/es/__demo__/CalculationModal.stories.js +440 -0
- package/build/es/api/analytics/AnalyticsRequest.js +11 -1
- package/build/es/api/dimensions.js +1 -1
- package/build/es/api/expression.js +57 -0
- package/build/es/assets/DimensionItemIcons/CalculationIcon.js +13 -0
- package/build/es/assets/FormulaIcon.js +30 -0
- package/build/es/components/DataDimension/Calculation/CalculationModal.js +418 -0
- package/build/es/components/DataDimension/Calculation/DataElementOption.js +60 -0
- package/build/es/components/DataDimension/Calculation/DataElementSelector.js +280 -0
- package/build/es/components/DataDimension/Calculation/DndContext.js +194 -0
- package/build/es/components/DataDimension/Calculation/DragHandleIcon.js +11 -0
- package/build/es/components/DataDimension/Calculation/DraggingItem.js +40 -0
- package/build/es/components/DataDimension/Calculation/DropZone.js +43 -0
- package/build/es/components/DataDimension/Calculation/FormulaField.js +98 -0
- package/build/es/components/DataDimension/Calculation/FormulaItem.js +207 -0
- package/build/es/components/DataDimension/Calculation/MathOperatorSelector.js +41 -0
- package/build/es/components/DataDimension/Calculation/Operator.js +64 -0
- package/build/es/components/DataDimension/Calculation/styles/CalculationModal.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/DataElementOption.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/DataElementSelector.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/DraggingItem.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/DropZone.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/FormulaField.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/FormulaItem.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/MathOperatorSelector.style.js +4 -0
- package/build/es/components/DataDimension/Calculation/styles/Operator.style.js +4 -0
- package/build/es/components/DataDimension/DataDimension.js +21 -6
- package/build/es/components/DataDimension/DataTypeSelector.js +6 -4
- package/build/es/components/DataDimension/ItemSelector.js +111 -73
- package/build/es/components/TransferOption.js +14 -5
- package/build/es/components/styles/DimensionSelector.style.js +2 -2
- package/build/es/components/styles/TransferOption.style.js +2 -2
- package/build/es/index.js +1 -1
- package/build/es/locales/en/translations.json +32 -7
- package/build/es/modules/__tests__/expressions.spec.js +136 -0
- package/build/es/modules/__tests__/hash.spec.js +88 -0
- package/build/es/modules/__tests__/parseExpression.spec.js +43 -0
- package/build/es/modules/dataTypes.js +6 -0
- package/build/es/modules/dimensionListItem.js +61 -0
- package/build/es/modules/expressions.js +131 -0
- package/build/es/modules/hash.js +12 -0
- package/package.json +6 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _expressions = require("../expressions.js");
|
|
4
|
+
|
|
5
|
+
const invalidTestExpressions = [{
|
|
6
|
+
message: 'Formula is empty. Add items to the formula from the lists on the left.',
|
|
7
|
+
expressions: ['']
|
|
8
|
+
}, // {
|
|
9
|
+
// message: 'Consecutive math operators',
|
|
10
|
+
// expressions: ['5+-', '5+++', '4+9-*', '5++9'],
|
|
11
|
+
// },
|
|
12
|
+
{
|
|
13
|
+
message: 'Consecutive data elements',
|
|
14
|
+
expressions: ['#{cYeuwXTCPkU}#{Jtf34kNZhzP}']
|
|
15
|
+
}, {
|
|
16
|
+
message: 'Starts or ends with a math operator',
|
|
17
|
+
expressions: ['+', '+1', '1-2/', '*((#{cYeuwXTCPkU}*#{Jtf34kNZhzP})))']
|
|
18
|
+
}, {
|
|
19
|
+
message: 'Empty parentheses',
|
|
20
|
+
expressions: ['#{cYeuwXTCPkU}*()']
|
|
21
|
+
}, {
|
|
22
|
+
message: 'Missing left parenthesis (',
|
|
23
|
+
expressions: [')', '5)', '((#{cYeuwXTCPkU}*#{P3jJH5Tu5VC.S34ULMcHMca})))']
|
|
24
|
+
}, {
|
|
25
|
+
message: 'Missing right parenthesis )',
|
|
26
|
+
expressions: ['(', '(5', '((#{cYeuwXTCPkU}*#{Jtf34kNZhzP})']
|
|
27
|
+
}];
|
|
28
|
+
const validTestExpressions = ['5+9', '((#{cYeuwXTCPkU}*#{Jtf34kNZhzP}))#{iKGjnOOaPlE}', '#{P3jJH5Tu5VC.S34ULMcHMca}*#{Jtf34kNZhzP}', '(5)+9', '(5+9)', '10/-5'];
|
|
29
|
+
describe('validateExpression', () => {
|
|
30
|
+
invalidTestExpressions.forEach(_ref => {
|
|
31
|
+
let {
|
|
32
|
+
expressions,
|
|
33
|
+
message
|
|
34
|
+
} = _ref;
|
|
35
|
+
expressions.forEach(exp => {
|
|
36
|
+
test("Fails: ".concat(message), () => {
|
|
37
|
+
expect((0, _expressions.validateExpression)(exp)).toEqual({
|
|
38
|
+
status: _expressions.INVALID_EXPRESSION,
|
|
39
|
+
message
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
validTestExpressions.forEach(exp => {
|
|
45
|
+
test("Passes validation: ".concat(exp), () => {
|
|
46
|
+
expect((0, _expressions.validateExpression)(exp)).toEqual(undefined);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('parseArrayToExpression', () => {
|
|
51
|
+
test('exp 1', () => {
|
|
52
|
+
const expressionArray = [{
|
|
53
|
+
label: 'abc123',
|
|
54
|
+
value: '#{abc123}',
|
|
55
|
+
type: _expressions.EXPRESSION_TYPE_DATA
|
|
56
|
+
}, {
|
|
57
|
+
label: '+',
|
|
58
|
+
value: '+',
|
|
59
|
+
type: _expressions.EXPRESSION_TYPE_OPERATOR
|
|
60
|
+
}, {
|
|
61
|
+
label: 'def456.xyz999',
|
|
62
|
+
value: '#{def456.xyz999}',
|
|
63
|
+
type: _expressions.EXPRESSION_TYPE_DATA
|
|
64
|
+
}, {
|
|
65
|
+
label: '/',
|
|
66
|
+
value: '/',
|
|
67
|
+
type: _expressions.EXPRESSION_TYPE_OPERATOR
|
|
68
|
+
}, {
|
|
69
|
+
label: '10',
|
|
70
|
+
value: '10',
|
|
71
|
+
type: _expressions.EXPRESSION_TYPE_NUMBER
|
|
72
|
+
}];
|
|
73
|
+
const expected = '#{abc123}+#{def456.xyz999}/10';
|
|
74
|
+
expect((0, _expressions.parseArrayToExpression)(expressionArray)).toEqual(expected);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('parseExpressionToArray', () => {
|
|
78
|
+
test('exp 1', () => {
|
|
79
|
+
const expression = '#{abc123}/10*99';
|
|
80
|
+
const expected = [{
|
|
81
|
+
label: 'abc123',
|
|
82
|
+
value: '#{abc123}',
|
|
83
|
+
type: _expressions.EXPRESSION_TYPE_DATA
|
|
84
|
+
}, {
|
|
85
|
+
label: '/',
|
|
86
|
+
value: '/',
|
|
87
|
+
type: _expressions.EXPRESSION_TYPE_OPERATOR
|
|
88
|
+
}, {
|
|
89
|
+
label: '10',
|
|
90
|
+
value: '10',
|
|
91
|
+
type: _expressions.EXPRESSION_TYPE_NUMBER
|
|
92
|
+
}, {
|
|
93
|
+
label: '×',
|
|
94
|
+
value: '*',
|
|
95
|
+
type: _expressions.EXPRESSION_TYPE_OPERATOR
|
|
96
|
+
}, {
|
|
97
|
+
label: '99',
|
|
98
|
+
value: '99',
|
|
99
|
+
type: _expressions.EXPRESSION_TYPE_NUMBER
|
|
100
|
+
}];
|
|
101
|
+
expect((0, _expressions.parseExpressionToArray)(expression)).toEqual(expected);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('getItemIdsFromExpression', () => {
|
|
105
|
+
test('exp 1', () => {
|
|
106
|
+
const expression = '#{abc123}/10*99';
|
|
107
|
+
const expected = ['abc123'];
|
|
108
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
109
|
+
});
|
|
110
|
+
test('exp 2', () => {
|
|
111
|
+
const expression = '#{abc123}/10*#{def456}';
|
|
112
|
+
const expected = ['abc123', 'def456'];
|
|
113
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
114
|
+
});
|
|
115
|
+
test('exp 3', () => {
|
|
116
|
+
const expression = '#{abc123}/10*#{def456.xyz999}';
|
|
117
|
+
const expected = ['abc123', 'def456.xyz999'];
|
|
118
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
119
|
+
});
|
|
120
|
+
test('exp 4', () => {
|
|
121
|
+
const expression = '#{abc123}/10*#{def456.xyz999}+#{ghi789}';
|
|
122
|
+
const expected = ['abc123', 'def456.xyz999', 'ghi789'];
|
|
123
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
124
|
+
});
|
|
125
|
+
test('exp 5', () => {
|
|
126
|
+
const expression = '#{abc123}/10*#{def456.xyz999}+#{ghi789}+#{jkl000}';
|
|
127
|
+
const expected = ['abc123', 'def456.xyz999', 'ghi789', 'jkl000'];
|
|
128
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
129
|
+
});
|
|
130
|
+
test('exp 6', () => {
|
|
131
|
+
const expression = '5/10';
|
|
132
|
+
const expected = [];
|
|
133
|
+
expect((0, _expressions.getItemIdsFromExpression)(expression)).toEqual(expected);
|
|
134
|
+
});
|
|
135
|
+
test('exp 6', () => {
|
|
136
|
+
const expected = [];
|
|
137
|
+
expect((0, _expressions.getItemIdsFromExpression)()).toEqual(expected);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _dataTypes = require("../dataTypes.js");
|
|
4
|
+
|
|
5
|
+
var _hash = require("../hash.js");
|
|
6
|
+
|
|
7
|
+
describe('getHash', () => {
|
|
8
|
+
const textInput = 'Raymond Luxury Yacht';
|
|
9
|
+
it('accepts a string and returns a hash', () => {
|
|
10
|
+
const hash = (0, _hash.getHash)(textInput);
|
|
11
|
+
expect(typeof hash).toBe('string');
|
|
12
|
+
expect(hash).not.toBe(textInput);
|
|
13
|
+
});
|
|
14
|
+
it('is deterministic', () => {
|
|
15
|
+
expect((0, _hash.getHash)(textInput)).toBe((0, _hash.getHash)(textInput));
|
|
16
|
+
});
|
|
17
|
+
it('returns undefined for invalid input', () => {
|
|
18
|
+
const unsupportedTypes = ['', 1, true, null, undefined, {}, []];
|
|
19
|
+
unsupportedTypes.forEach(type => expect((0, _hash.getHash)(type)).toBe(undefined));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('getExpressionHashFromVisualization', () => {
|
|
23
|
+
const edi1 = {
|
|
24
|
+
id: 'OdiHJayrsKo',
|
|
25
|
+
dimensionItemType: _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM,
|
|
26
|
+
expression: '#{abc} * 10'
|
|
27
|
+
};
|
|
28
|
+
const edi2 = {
|
|
29
|
+
id: 'Uvn6LCg7dVU',
|
|
30
|
+
dimensionItemType: _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM,
|
|
31
|
+
expression: '#{abc} * 20'
|
|
32
|
+
};
|
|
33
|
+
const dxWithEdi = {
|
|
34
|
+
dimension: 'dx',
|
|
35
|
+
items: [edi1, edi2]
|
|
36
|
+
};
|
|
37
|
+
it('generates a hash (columns)', () => {
|
|
38
|
+
expect(typeof (0, _hash.getExpressionHashFromVisualization)({
|
|
39
|
+
columns: [dxWithEdi],
|
|
40
|
+
rows: [],
|
|
41
|
+
filters: []
|
|
42
|
+
})).toBe('string');
|
|
43
|
+
});
|
|
44
|
+
it('generates a hash (rows)', () => {
|
|
45
|
+
expect(typeof (0, _hash.getExpressionHashFromVisualization)({
|
|
46
|
+
columns: [],
|
|
47
|
+
rows: [dxWithEdi],
|
|
48
|
+
filters: []
|
|
49
|
+
})).toBe('string');
|
|
50
|
+
});
|
|
51
|
+
it('generates a hash (filters)', () => {
|
|
52
|
+
expect(typeof (0, _hash.getExpressionHashFromVisualization)({
|
|
53
|
+
columns: [],
|
|
54
|
+
rows: [],
|
|
55
|
+
filters: [dxWithEdi]
|
|
56
|
+
})).toBe('string');
|
|
57
|
+
});
|
|
58
|
+
it('does not generate a hash when there are no dimensions', () => {
|
|
59
|
+
expect((0, _hash.getExpressionHashFromVisualization)({
|
|
60
|
+
columns: [],
|
|
61
|
+
rows: [],
|
|
62
|
+
filters: []
|
|
63
|
+
})).toBe(undefined);
|
|
64
|
+
});
|
|
65
|
+
it('does not generate a hash when there are no EDI dimensions', () => {
|
|
66
|
+
expect((0, _hash.getExpressionHashFromVisualization)({
|
|
67
|
+
columns: [{
|
|
68
|
+
id: 'OdiHJayrsKo',
|
|
69
|
+
dimensionItemType: 'INDICATOR'
|
|
70
|
+
}],
|
|
71
|
+
rows: [],
|
|
72
|
+
filters: []
|
|
73
|
+
})).toBe(undefined);
|
|
74
|
+
});
|
|
75
|
+
it('sorts the edi objects by id before generating the hash to optimize caching', () => {
|
|
76
|
+
expect((0, _hash.getExpressionHashFromVisualization)({
|
|
77
|
+
columns: [{
|
|
78
|
+
dimension: 'dx',
|
|
79
|
+
items: [edi1, edi2]
|
|
80
|
+
}],
|
|
81
|
+
rows: [],
|
|
82
|
+
filters: []
|
|
83
|
+
})).toBe((0, _hash.getExpressionHashFromVisualization)({
|
|
84
|
+
columns: [{
|
|
85
|
+
dimension: 'dx',
|
|
86
|
+
items: [edi2, edi1]
|
|
87
|
+
}],
|
|
88
|
+
rows: [],
|
|
89
|
+
filters: []
|
|
90
|
+
}));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _expressions = require("../expressions.js");
|
|
4
|
+
|
|
5
|
+
test('matches numbers and operators', () => {
|
|
6
|
+
expect((0, _expressions.parseExpression)('1+2-3*4/5')).toEqual(['1', '+', '2', '-', '3', '*', '4', '/', '5']);
|
|
7
|
+
});
|
|
8
|
+
test('matches #{} with letters, numbers and operators', () => {
|
|
9
|
+
expect((0, _expressions.parseExpression)('#{abc123}+100-200*300/400')).toEqual(['#{abc123}', '+', '100', '-', '200', '*', '300', '/', '400']);
|
|
10
|
+
});
|
|
11
|
+
test('matches numbers and operators with brackets', () => {
|
|
12
|
+
expect((0, _expressions.parseExpression)('1+(2-3)*4/5')).toEqual(['1', '+', '(', '2', '-', '3', ')', '*', '4', '/', '5']);
|
|
13
|
+
});
|
|
14
|
+
test('matches #{} with letters, numbers and operators with brackets', () => {
|
|
15
|
+
expect((0, _expressions.parseExpression)('(100-200)+#{abc123}*300/400')).toEqual(['(', '100', '-', '200', ')', '+', '#{abc123}', '*', '300', '/', '400']);
|
|
16
|
+
});
|
|
17
|
+
test('matches #{} with numbers and operators with brackets', () => {
|
|
18
|
+
expect((0, _expressions.parseExpression)('#{123}+(10-200)*3000/40000')).toEqual(['#{123}', '+', '(', '10', '-', '200', ')', '*', '3000', '/', '40000']);
|
|
19
|
+
});
|
|
20
|
+
test('matches #{} with letters and numbers only', () => {
|
|
21
|
+
expect((0, _expressions.parseExpression)('#{abc123}')).toEqual(['#{abc123}']);
|
|
22
|
+
});
|
|
23
|
+
test('matches #{} with numbers only', () => {
|
|
24
|
+
expect((0, _expressions.parseExpression)('#{123}')).toEqual(['#{123}']);
|
|
25
|
+
});
|
|
26
|
+
test('matches #{} with letters only', () => {
|
|
27
|
+
expect((0, _expressions.parseExpression)('#{abc}')).toEqual(['#{abc}']);
|
|
28
|
+
});
|
|
29
|
+
test('matches #{} with no input', () => {
|
|
30
|
+
expect((0, _expressions.parseExpression)('')).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
test('matches multiple #{} with operators', () => {
|
|
33
|
+
expect((0, _expressions.parseExpression)('#{abc123}+#{def456}')).toEqual(['#{abc123}', '+', '#{def456}']);
|
|
34
|
+
});
|
|
35
|
+
test('matches multiple #{} containing dots with operators', () => {
|
|
36
|
+
expect((0, _expressions.parseExpression)('#{abc123.xyz999}+#{def456.xyz999}')).toEqual(['#{abc123.xyz999}', '+', '#{def456.xyz999}']);
|
|
37
|
+
});
|
|
38
|
+
test('matches multiple #{} with operators with brackets', () => {
|
|
39
|
+
expect((0, _expressions.parseExpression)('(#{abc123}/#{def456})*#{ghi789}')).toEqual(['(', '#{abc123}', '/', '#{def456}', ')', '*', '#{ghi789}']);
|
|
40
|
+
});
|
|
41
|
+
test('matches on decimal numbers', () => {
|
|
42
|
+
expect((0, _expressions.parseExpression)('#{abc123}*1.2/#{def456}')).toEqual(['#{abc123}', '*', '1.2', '/', '#{def456}']);
|
|
43
|
+
});
|
|
44
|
+
test('matches on decimal numbers with #{} containing dots', () => {
|
|
45
|
+
expect((0, _expressions.parseExpression)('1.2+#{abc123.xyz999}')).toEqual(['1.2', '+', '#{abc123.xyz999}']);
|
|
46
|
+
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.dataTypeMap = exports.TOTALS = exports.SUB_GROUP_METRIC = exports.SUB_GROUP_DETAIL = exports.DIMENSION_TYPE_PROGRAM_INDICATOR = exports.DIMENSION_TYPE_PROGRAM_DATA_ELEMENT = exports.DIMENSION_TYPE_PROGRAM_ATTRIBUTE = exports.DIMENSION_TYPE_PERIOD = exports.DIMENSION_TYPE_ORGANISATION_UNIT_GROUP_SET = exports.DIMENSION_TYPE_ORGANISATION_UNIT = exports.DIMENSION_TYPE_INDICATOR = exports.DIMENSION_TYPE_EVENT_DATA_ITEM = exports.DIMENSION_TYPE_DATA_SET = exports.DIMENSION_TYPE_DATA_ELEMENT_OPERAND = exports.DIMENSION_TYPE_DATA_ELEMENT_GROUP_SET = exports.DIMENSION_TYPE_DATA_ELEMENT = exports.DIMENSION_TYPE_DATA = exports.DIMENSION_TYPE_CATEGORY_OPTION_GROUP_SET = exports.DIMENSION_TYPE_CATEGORY = exports.DIMENSION_TYPE_ALL = exports.DETAIL = exports.DEFAULT_DATATYPE_ID = void 0;
|
|
6
|
+
exports.dataTypeMap = exports.TOTALS = exports.SUB_GROUP_METRIC = exports.SUB_GROUP_DETAIL = exports.DIMENSION_TYPE_PROGRAM_INDICATOR = exports.DIMENSION_TYPE_PROGRAM_DATA_ELEMENT = exports.DIMENSION_TYPE_PROGRAM_ATTRIBUTE = exports.DIMENSION_TYPE_PERIOD = exports.DIMENSION_TYPE_ORGANISATION_UNIT_GROUP_SET = exports.DIMENSION_TYPE_ORGANISATION_UNIT = exports.DIMENSION_TYPE_INDICATOR = exports.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM = exports.DIMENSION_TYPE_EVENT_DATA_ITEM = exports.DIMENSION_TYPE_DATA_SET = exports.DIMENSION_TYPE_DATA_ELEMENT_OPERAND = exports.DIMENSION_TYPE_DATA_ELEMENT_GROUP_SET = exports.DIMENSION_TYPE_DATA_ELEMENT = exports.DIMENSION_TYPE_DATA = exports.DIMENSION_TYPE_CATEGORY_OPTION_GROUP_SET = exports.DIMENSION_TYPE_CATEGORY = exports.DIMENSION_TYPE_ALL = exports.DETAIL = exports.DEFAULT_DATATYPE_ID = void 0;
|
|
7
7
|
exports.defaultGroupDetail = defaultGroupDetail;
|
|
8
8
|
exports.defaultGroupId = defaultGroupId;
|
|
9
9
|
|
|
@@ -43,6 +43,8 @@ const DIMENSION_TYPE_ORGANISATION_UNIT = 'ORGANISATION_UNIT';
|
|
|
43
43
|
exports.DIMENSION_TYPE_ORGANISATION_UNIT = DIMENSION_TYPE_ORGANISATION_UNIT;
|
|
44
44
|
const DIMENSION_TYPE_ORGANISATION_UNIT_GROUP_SET = 'ORGANISATION_UNIT_GROUP_SET';
|
|
45
45
|
exports.DIMENSION_TYPE_ORGANISATION_UNIT_GROUP_SET = DIMENSION_TYPE_ORGANISATION_UNIT_GROUP_SET;
|
|
46
|
+
const DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM = 'EXPRESSION_DIMENSION_ITEM';
|
|
47
|
+
exports.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM = DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM;
|
|
46
48
|
const TOTALS = 'totals';
|
|
47
49
|
exports.TOTALS = TOTALS;
|
|
48
50
|
const DETAIL = 'detail';
|
|
@@ -120,6 +122,11 @@ const dataTypeMap = {
|
|
|
120
122
|
getItemName: () => _index.default.t('Program indicator'),
|
|
121
123
|
getGroupEmptyLabel: () => _index.default.t('No programs found'),
|
|
122
124
|
getGroupLoadingLabel: () => _index.default.t('Loading programs')
|
|
125
|
+
},
|
|
126
|
+
[DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM]: {
|
|
127
|
+
id: DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM,
|
|
128
|
+
getName: () => _index.default.t('Calculations'),
|
|
129
|
+
getItemName: () => _index.default.t('Calculation')
|
|
123
130
|
}
|
|
124
131
|
};
|
|
125
132
|
exports.dataTypeMap = dataTypeMap;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getTooltipText = exports.getIcon = void 0;
|
|
7
|
+
|
|
8
|
+
var _ui = require("@dhis2/ui");
|
|
9
|
+
|
|
10
|
+
var _react = _interopRequireDefault(require("react"));
|
|
11
|
+
|
|
12
|
+
var _DataElementIcon = _interopRequireDefault(require("../assets/DimensionItemIcons/DataElementIcon.js"));
|
|
13
|
+
|
|
14
|
+
var _GenericIcon = _interopRequireDefault(require("../assets/DimensionItemIcons/GenericIcon.js"));
|
|
15
|
+
|
|
16
|
+
var _CalculationIcon = _interopRequireDefault(require("./../assets/DimensionItemIcons/CalculationIcon.js"));
|
|
17
|
+
|
|
18
|
+
var _dataSets = require("./dataSets.js");
|
|
19
|
+
|
|
20
|
+
var _dataTypes = require("./dataTypes.js");
|
|
21
|
+
|
|
22
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
+
|
|
24
|
+
const getTooltipText = _ref => {
|
|
25
|
+
var _dataTypes$type;
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
type,
|
|
29
|
+
expression
|
|
30
|
+
} = _ref;
|
|
31
|
+
|
|
32
|
+
if (type === _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM && expression) {
|
|
33
|
+
return _dataTypes.dataTypeMap[_dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM].getItemName();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
switch (type) {
|
|
37
|
+
case _dataTypes.DIMENSION_TYPE_DATA_ELEMENT_OPERAND:
|
|
38
|
+
return _dataTypes.dataTypeMap[_dataTypes.DIMENSION_TYPE_DATA_ELEMENT].getItemName();
|
|
39
|
+
|
|
40
|
+
case _dataSets.REPORTING_RATE:
|
|
41
|
+
return _dataTypes.dataTypeMap[_dataTypes.DIMENSION_TYPE_DATA_SET].getItemName();
|
|
42
|
+
|
|
43
|
+
case _dataTypes.DIMENSION_TYPE_PROGRAM_DATA_ELEMENT:
|
|
44
|
+
case _dataTypes.DIMENSION_TYPE_PROGRAM_ATTRIBUTE:
|
|
45
|
+
return _dataTypes.dataTypeMap[_dataTypes.DIMENSION_TYPE_EVENT_DATA_ITEM].getItemName();
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
return (_dataTypes$type = _dataTypes.dataTypeMap[type]) === null || _dataTypes$type === void 0 ? void 0 : _dataTypes$type.getItemName();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
exports.getTooltipText = getTooltipText;
|
|
53
|
+
|
|
54
|
+
const getIcon = type => {
|
|
55
|
+
switch (type) {
|
|
56
|
+
case _dataTypes.DIMENSION_TYPE_INDICATOR:
|
|
57
|
+
return /*#__PURE__*/_react.default.createElement(_ui.IconDimensionIndicator16, null);
|
|
58
|
+
|
|
59
|
+
case _dataTypes.DIMENSION_TYPE_DATA_ELEMENT_OPERAND:
|
|
60
|
+
case _dataTypes.DIMENSION_TYPE_DATA_ELEMENT:
|
|
61
|
+
return _DataElementIcon.default;
|
|
62
|
+
|
|
63
|
+
case _dataSets.REPORTING_RATE:
|
|
64
|
+
return /*#__PURE__*/_react.default.createElement(_ui.IconDimensionDataSet16, null);
|
|
65
|
+
|
|
66
|
+
case _dataTypes.DIMENSION_TYPE_EVENT_DATA_ITEM:
|
|
67
|
+
case _dataTypes.DIMENSION_TYPE_PROGRAM_DATA_ELEMENT:
|
|
68
|
+
case _dataTypes.DIMENSION_TYPE_PROGRAM_ATTRIBUTE:
|
|
69
|
+
return /*#__PURE__*/_react.default.createElement(_ui.IconDimensionEventDataItem16, null);
|
|
70
|
+
|
|
71
|
+
case _dataTypes.DIMENSION_TYPE_PROGRAM_INDICATOR:
|
|
72
|
+
return /*#__PURE__*/_react.default.createElement(_ui.IconDimensionProgramIndicator16, null);
|
|
73
|
+
|
|
74
|
+
case _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM:
|
|
75
|
+
return _CalculationIcon.default;
|
|
76
|
+
|
|
77
|
+
default:
|
|
78
|
+
return _GenericIcon.default;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.getIcon = getIcon;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.validateExpression = exports.parseExpressionToArray = exports.parseExpression = exports.parseArrayToExpression = exports.getOperators = exports.getItemIdsFromExpression = exports.VALID_EXPRESSION = exports.INVALID_EXPRESSION = exports.EXPRESSION_TYPE_OPERATOR = exports.EXPRESSION_TYPE_NUMBER = exports.EXPRESSION_TYPE_DATA = void 0;
|
|
7
|
+
|
|
8
|
+
var _index = _interopRequireDefault(require("../locales/index.js"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
|
|
12
|
+
const EXPRESSION_TYPE_NUMBER = 'EXPRESSION_TYPE_NUMBER';
|
|
13
|
+
exports.EXPRESSION_TYPE_NUMBER = EXPRESSION_TYPE_NUMBER;
|
|
14
|
+
const EXPRESSION_TYPE_OPERATOR = 'EXPRESSION_TYPE_OPERATOR';
|
|
15
|
+
exports.EXPRESSION_TYPE_OPERATOR = EXPRESSION_TYPE_OPERATOR;
|
|
16
|
+
const EXPRESSION_TYPE_DATA = 'EXPRESSION_TYPE_DATA';
|
|
17
|
+
exports.EXPRESSION_TYPE_DATA = EXPRESSION_TYPE_DATA;
|
|
18
|
+
const VALID_EXPRESSION = 'OK';
|
|
19
|
+
exports.VALID_EXPRESSION = VALID_EXPRESSION;
|
|
20
|
+
const INVALID_EXPRESSION = 'ERROR';
|
|
21
|
+
exports.INVALID_EXPRESSION = INVALID_EXPRESSION;
|
|
22
|
+
|
|
23
|
+
const getOperators = () => [{
|
|
24
|
+
value: '+',
|
|
25
|
+
label: '+',
|
|
26
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
27
|
+
}, {
|
|
28
|
+
value: '-',
|
|
29
|
+
label: '-',
|
|
30
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
31
|
+
}, {
|
|
32
|
+
value: '*',
|
|
33
|
+
label: '×',
|
|
34
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
35
|
+
}, {
|
|
36
|
+
value: '/',
|
|
37
|
+
label: '/',
|
|
38
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
39
|
+
}, {
|
|
40
|
+
value: '(',
|
|
41
|
+
label: '(',
|
|
42
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
43
|
+
}, {
|
|
44
|
+
value: ')',
|
|
45
|
+
label: ')',
|
|
46
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
47
|
+
}, {
|
|
48
|
+
value: '',
|
|
49
|
+
label: _index.default.t('Number'),
|
|
50
|
+
type: EXPRESSION_TYPE_NUMBER
|
|
51
|
+
}];
|
|
52
|
+
|
|
53
|
+
exports.getOperators = getOperators;
|
|
54
|
+
|
|
55
|
+
const parseExpression = input => {
|
|
56
|
+
const regex = /(#{[a-zA-Z0-9#.]+}|[+\-*/()])|(\d+(\.\d+)?)/g;
|
|
57
|
+
return input.match(regex) || [];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
exports.parseExpression = parseExpression;
|
|
61
|
+
|
|
62
|
+
const parseExpressionToArray = function () {
|
|
63
|
+
let expression = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
64
|
+
let metadata = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
65
|
+
return parseExpression(expression).map(value => {
|
|
66
|
+
if (value.startsWith('#{') && value.endsWith('}')) {
|
|
67
|
+
var _metadata$find;
|
|
68
|
+
|
|
69
|
+
const id = value.slice(2, -1);
|
|
70
|
+
const label = ((_metadata$find = metadata.find(item => item.id === id)) === null || _metadata$find === void 0 ? void 0 : _metadata$find.name) || id;
|
|
71
|
+
return {
|
|
72
|
+
value,
|
|
73
|
+
label,
|
|
74
|
+
type: EXPRESSION_TYPE_DATA
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isNaN(value)) {
|
|
79
|
+
return {
|
|
80
|
+
value,
|
|
81
|
+
label: getOperators().find(op => op.value === value).label,
|
|
82
|
+
type: EXPRESSION_TYPE_OPERATOR
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
value,
|
|
88
|
+
label: value,
|
|
89
|
+
type: EXPRESSION_TYPE_NUMBER
|
|
90
|
+
};
|
|
91
|
+
}) || [];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
exports.parseExpressionToArray = parseExpressionToArray;
|
|
95
|
+
|
|
96
|
+
const parseArrayToExpression = function () {
|
|
97
|
+
let input = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
98
|
+
return input.map(item => item.value).join('');
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
exports.parseArrayToExpression = parseArrayToExpression;
|
|
102
|
+
|
|
103
|
+
const validateExpression = expression => {
|
|
104
|
+
let result;
|
|
105
|
+
const leftParenthesisCount = expression.split('(').length - 1;
|
|
106
|
+
const rightParenthesisCount = expression.split(')').length - 1;
|
|
107
|
+
|
|
108
|
+
if (!expression) {
|
|
109
|
+
// empty formula
|
|
110
|
+
result = {
|
|
111
|
+
status: INVALID_EXPRESSION,
|
|
112
|
+
message: _index.default.t('Formula is empty. Add items to the formula from the lists on the left.')
|
|
113
|
+
}; // TODO: reimplement this but allow negative values, e.g. 10 / -5
|
|
114
|
+
// } else if (/[-+/*]{2,}/.test(expression)) {
|
|
115
|
+
// // two math operators next to each other
|
|
116
|
+
// result = {
|
|
117
|
+
// status: INVALID_EXPRESSION,
|
|
118
|
+
// message: i18n.t('Consecutive math operators'),
|
|
119
|
+
// }
|
|
120
|
+
} else if (/}#/.test(expression)) {
|
|
121
|
+
// two data elements next to each other
|
|
122
|
+
result = {
|
|
123
|
+
status: INVALID_EXPRESSION,
|
|
124
|
+
message: _index.default.t('Consecutive data elements')
|
|
125
|
+
};
|
|
126
|
+
} else if (/^[+\-*/]|[+\-*/]$/.test(expression)) {
|
|
127
|
+
// starting or ending with a math operator
|
|
128
|
+
result = {
|
|
129
|
+
status: INVALID_EXPRESSION,
|
|
130
|
+
message: _index.default.t('Starts or ends with a math operator')
|
|
131
|
+
};
|
|
132
|
+
} else if (/\(\)/.test(expression)) {
|
|
133
|
+
// contains an empty set of parentheses
|
|
134
|
+
result = {
|
|
135
|
+
status: INVALID_EXPRESSION,
|
|
136
|
+
message: _index.default.t('Empty parentheses')
|
|
137
|
+
};
|
|
138
|
+
} else if (leftParenthesisCount > rightParenthesisCount) {
|
|
139
|
+
// ( but no )
|
|
140
|
+
result = {
|
|
141
|
+
status: INVALID_EXPRESSION,
|
|
142
|
+
message: _index.default.t('Missing right parenthesis )')
|
|
143
|
+
};
|
|
144
|
+
} else if (rightParenthesisCount > leftParenthesisCount) {
|
|
145
|
+
// ) but no (
|
|
146
|
+
result = {
|
|
147
|
+
status: INVALID_EXPRESSION,
|
|
148
|
+
message: _index.default.t('Missing left parenthesis (')
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
exports.validateExpression = validateExpression;
|
|
156
|
+
|
|
157
|
+
const getItemIdsFromExpression = function () {
|
|
158
|
+
let expression = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
159
|
+
const regex = /#{([a-zA-Z0-9#]+.*?)}/g;
|
|
160
|
+
const matches = expression.match(regex);
|
|
161
|
+
return matches ? matches.map(match => match.slice(2, -1)) : [];
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
exports.getItemIdsFromExpression = getItemIdsFromExpression;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getHash = exports.getExpressionHashFromVisualization = void 0;
|
|
7
|
+
|
|
8
|
+
var _sha = _interopRequireDefault(require("crypto-js/sha1"));
|
|
9
|
+
|
|
10
|
+
var _dataTypes = require("./dataTypes.js");
|
|
11
|
+
|
|
12
|
+
var _layoutGetAllItems2 = require("./layout/layoutGetAllItems.js");
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
+
|
|
16
|
+
const isValidValue = value => typeof value === 'string' && value.length;
|
|
17
|
+
|
|
18
|
+
const getHash = value => isValidValue(value) ? (0, _sha.default)(value).toString() : undefined;
|
|
19
|
+
|
|
20
|
+
exports.getHash = getHash;
|
|
21
|
+
|
|
22
|
+
const getExpressionHashFromVisualization = visualization => {
|
|
23
|
+
var _layoutGetAllItems;
|
|
24
|
+
|
|
25
|
+
return getHash((_layoutGetAllItems = (0, _layoutGetAllItems2.layoutGetAllItems)(visualization)) === null || _layoutGetAllItems === void 0 ? void 0 : _layoutGetAllItems.filter(item => item.dimensionItemType === _dataTypes.DIMENSION_TYPE_EXPRESSION_DIMENSION_ITEM && isValidValue(item.expression)).sort((i1, i2) => i1.id < i2.id ? -1 : i1.id > i2.id ? 1 : 0).map(edi => edi.expression).join(''));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
exports.getExpressionHashFromVisualization = getExpressionHashFromVisualization;
|