@outliant/sunrise-utils 1.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.
Files changed (40) hide show
  1. package/.eslintignore +5 -0
  2. package/.eslintrc +53 -0
  3. package/.github/workflows/pr-dev-workflow.yml +16 -0
  4. package/.nvmrc +1 -0
  5. package/.release-it.js +26 -0
  6. package/.vscode/launch.json +24 -0
  7. package/.vscode/settings.json +7 -0
  8. package/CHANGELOG.md +12 -0
  9. package/README.md +19 -0
  10. package/changelog.hbs +13 -0
  11. package/helpers/es.js +6 -0
  12. package/helpers/projectFilter/projectFieldFilter.js +587 -0
  13. package/helpers/searchFilter.js +86 -0
  14. package/helpers/taskFilter/criticalPathFilter.js +144 -0
  15. package/helpers/taskFilter/index.js +228 -0
  16. package/helpers/taskFilter/onHoldFilter.js +101 -0
  17. package/helpers/taskFilter/ownerFilter.js +148 -0
  18. package/helpers/taskFilter/pathAgeFilter.js +18 -0
  19. package/helpers/taskFilter/regionFilter.js +82 -0
  20. package/helpers/taskFilter/statusFilter.js +177 -0
  21. package/helpers/taskFilter/taskFieldFilter.js +309 -0
  22. package/helpers/taskSortScript.js +356 -0
  23. package/index.d.ts +11 -0
  24. package/index.js +9 -0
  25. package/lib/fieldConditions.js +166 -0
  26. package/lib/logger.js +48 -0
  27. package/lib/taskPipeline.js +137 -0
  28. package/package.json +73 -0
  29. package/test/helpers/projectFilter/projectFieldFilter.spec.js +881 -0
  30. package/test/helpers/taskFilter/criticalPathFilter.spec.js +174 -0
  31. package/test/helpers/taskFilter/index.spec.js +339 -0
  32. package/test/helpers/taskFilter/onHoldFilter.spec.js +112 -0
  33. package/test/helpers/taskFilter/ownerFilter.spec.js +226 -0
  34. package/test/helpers/taskFilter/pathAgeFilter.spec.js +47 -0
  35. package/test/helpers/taskFilter/regionFilter.spec.js +131 -0
  36. package/test/helpers/taskFilter/statusFilter.spec.js +197 -0
  37. package/test/helpers/taskFilter/taskFieldFilter.spec.js +355 -0
  38. package/test/lib/fieldConditions.spec.js +17 -0
  39. package/test/lib/logger.spec.js +117 -0
  40. package/test/lib/taskPipeline.spec.js +162 -0
@@ -0,0 +1,355 @@
1
+ 'use strict';
2
+
3
+ /* eslint-env node, mocha */
4
+ const { expect } = require('chai');
5
+
6
+ // To test
7
+ const taskFieldFilter = require('../../../helpers/taskFilter/taskFieldFilter');
8
+
9
+ describe('taskFieldFilter', function () {
10
+ const filters = [
11
+ {
12
+ input: {
13
+ condition: 'is_equal',
14
+ field_id: '',
15
+ type: 'last_comment',
16
+ field_type: 'textarea',
17
+ value: 'test',
18
+ second_value: ''
19
+ },
20
+ output: { query_string: { fields: ['last_comment'], query: '*test*' } }
21
+ },
22
+ {
23
+ input: {
24
+ condition: 'is_equal',
25
+ field_id: '',
26
+ type: 'last_comment',
27
+ field_type: 'text',
28
+ value: 'test',
29
+ second_value: ''
30
+ },
31
+ output: {
32
+ bool: { must: [{ term: { last_comment: { value: 'test' } } }] }
33
+ }
34
+ },
35
+ {
36
+ input: {
37
+ condition: 'not_equal',
38
+ field_id: '',
39
+ type: 'last_comment',
40
+ field_type: 'textarea',
41
+ value: 'test',
42
+ second_value: ''
43
+ },
44
+ output: {
45
+ bool: {
46
+ must_not: {
47
+ query_string: { fields: ['last_comment'], query: '*test*' }
48
+ }
49
+ }
50
+ }
51
+ },
52
+ {
53
+ input: {
54
+ condition: 'is_empty',
55
+ field_id: '',
56
+ type: 'last_comment',
57
+ field_type: 'textarea',
58
+ value: '',
59
+ second_value: ''
60
+ },
61
+ output: {
62
+ bool: {
63
+ should: [
64
+ { bool: { must_not: [{ exists: { field: 'last_comment' } }] } },
65
+ {
66
+ bool: {
67
+ must_not: [{ wildcard: { last_comment: { value: '?*' } } }]
68
+ }
69
+ },
70
+ { term: { last_comment: { value: '' } } }
71
+ ]
72
+ }
73
+ }
74
+ },
75
+ {
76
+ input: {
77
+ condition: 'is_not_empty',
78
+ field_id: '',
79
+ type: 'last_comment',
80
+ field_type: 'textarea',
81
+ value: '',
82
+ second_value: ''
83
+ },
84
+ output: {
85
+ bool: {
86
+ must: [
87
+ { exists: { field: 'last_comment' } },
88
+ { wildcard: { last_comment: { value: '?*' } } },
89
+ { bool: { must_not: [{ term: { last_comment: { value: '' } } }] } }
90
+ ]
91
+ }
92
+ }
93
+ },
94
+ {
95
+ input: {
96
+ condition: 'is_any_of',
97
+ field_id: '',
98
+ type: 'last_comment',
99
+ field_type: 'textarea',
100
+ value: ['test1', 'test2'],
101
+ second_value: ''
102
+ },
103
+ output: { terms: { last_comment: ['test1', 'test2'] } }
104
+ },
105
+ {
106
+ input: {
107
+ condition: 'is_any_of',
108
+ field_id: '',
109
+ type: 'last_comment',
110
+ field_type: 'textarea',
111
+ value: 'test1;test2',
112
+ second_value: ''
113
+ },
114
+ output: { terms: { last_comment: ['test1', 'test2'] } }
115
+ },
116
+ {
117
+ input: {
118
+ condition: 'is_equal',
119
+ field_id: '',
120
+ type: 'created_at',
121
+ field_type: 'date',
122
+ value: 1675296000000,
123
+ second_value: ''
124
+ },
125
+ output: {
126
+ range: { created_at: { gte: 1675267200000, lte: 1675353599999 } }
127
+ }
128
+ },
129
+ {
130
+ input: {
131
+ condition: 'is_equal',
132
+ field_id: '',
133
+ type: 'created_at',
134
+ field_type: 'number',
135
+ value: 1,
136
+ second_value: ''
137
+ },
138
+ output: { bool: { must: [{ term: { created_at: { value: 1 } } }] } }
139
+ },
140
+ {
141
+ input: {
142
+ condition: 'not_equal',
143
+ field_id: '',
144
+ type: 'created_at',
145
+ field_type: 'date',
146
+ value: 1675296000000,
147
+ second_value: ''
148
+ },
149
+ output: {
150
+ bool: {
151
+ must_not: {
152
+ range: { created_at: { gte: 1675267200000, lte: 1675353599999 } }
153
+ }
154
+ }
155
+ }
156
+ },
157
+ {
158
+ input: {
159
+ condition: 'not_equal',
160
+ field_id: '',
161
+ type: 'created_at',
162
+ field_type: 'number',
163
+ value: 1,
164
+ second_value: ''
165
+ },
166
+ output: {
167
+ bool: {
168
+ must_not: { bool: { must: [{ term: { created_at: { value: 1 } } }] } }
169
+ }
170
+ }
171
+ },
172
+ {
173
+ input: {
174
+ condition: 'before',
175
+ field_id: '',
176
+ type: 'created_at',
177
+ field_type: 'date',
178
+ value: 1675296000000,
179
+ second_value: ''
180
+ },
181
+ output: { range: { created_at: { lt: 1675267200000 } } }
182
+ },
183
+ {
184
+ input: {
185
+ condition: 'before',
186
+ field_id: '',
187
+ type: 'created_at',
188
+ field_type: 'number',
189
+ value: 1,
190
+ second_value: ''
191
+ },
192
+ output: { range: { created_at: { lt: 1 } } }
193
+ },
194
+ {
195
+ input: {
196
+ condition: 'after',
197
+ field_id: '',
198
+ type: 'created_at',
199
+ field_type: 'date',
200
+ value: 1675296000000,
201
+ second_value: ''
202
+ },
203
+ output: { range: { created_at: { gt: 1675353599999 } } }
204
+ },
205
+ {
206
+ input: {
207
+ condition: 'after',
208
+ field_id: '',
209
+ type: 'created_at',
210
+ field_type: 'number',
211
+ value: 1,
212
+ second_value: ''
213
+ },
214
+ output: { range: { created_at: { gt: 1 } } }
215
+ },
216
+ {
217
+ input: {
218
+ condition: 'between',
219
+ field_id: '',
220
+ type: 'created_at',
221
+ field_type: 'date',
222
+ value: 1675296000000,
223
+ second_value: 1677196800000
224
+ },
225
+ output: {
226
+ range: { created_at: { gte: 1675267200000, lte: 1677254399999 } }
227
+ }
228
+ },
229
+ {
230
+ input: {
231
+ condition: 'between',
232
+ field_id: '',
233
+ type: 'created_at',
234
+ field_type: 'number',
235
+ value: 1,
236
+ second_value: 100
237
+ },
238
+ output: { range: { created_at: { gte: 1, lte: 100 } } }
239
+ },
240
+ {
241
+ input: {
242
+ condition: 'between',
243
+ field_id: '',
244
+ type: 'created_at',
245
+ field_type: 'unknwon_type',
246
+ value: 1675296000000,
247
+ second_value: 1677196800000
248
+ },
249
+ output: null
250
+ },
251
+ {
252
+ input: {
253
+ condition: 'is_empty',
254
+ field_id: '',
255
+ type: 'created_at',
256
+ field_type: 'date',
257
+ value: null,
258
+ second_value: ''
259
+ },
260
+ output: {
261
+ bool: {
262
+ should: [
263
+ { bool: { must_not: [{ exists: { field: 'created_at' } }] } }
264
+ ]
265
+ }
266
+ }
267
+ },
268
+ {
269
+ input: {
270
+ condition: 'is_not_empty',
271
+ field_id: '',
272
+ type: 'created_at',
273
+ field_type: 'date',
274
+ value: null,
275
+ second_value: ''
276
+ },
277
+ output: { bool: { must: [{ exists: { field: 'created_at' } }] } }
278
+ },
279
+ {
280
+ input: {
281
+ condition: 'unknown_condition',
282
+ field_id: '',
283
+ type: 'created_at',
284
+ field_type: 'date',
285
+ value: null,
286
+ second_value: ''
287
+ },
288
+ output: null
289
+ },
290
+ {
291
+ input: {
292
+ condition: 'less_than_or_equal',
293
+ field_id: '',
294
+ type: 'created_at',
295
+ field_type: 'number',
296
+ value: '1',
297
+ second_value: ''
298
+ },
299
+ output: { range: { created_at: { lte: 1 } } }
300
+ },
301
+ {
302
+ input: {
303
+ condition: 'greater_than_or_equal',
304
+ field_id: '',
305
+ type: 'created_at',
306
+ field_type: 'number',
307
+ value: '1',
308
+ second_value: ''
309
+ },
310
+ output: { range: { created_at: { gte: 1 } } }
311
+ },
312
+ {
313
+ input: {
314
+ condition: 'less_than_or_equal',
315
+ field_id: '',
316
+ type: 'created_at',
317
+ field_type: 'date',
318
+ value: 1675296000000,
319
+ second_value: ''
320
+ },
321
+ output: { range: { created_at: { lte: 1675353599999 } } }
322
+ },
323
+ {
324
+ input: {
325
+ condition: 'greater_than_or_equal',
326
+ field_id: '',
327
+ type: 'created_at',
328
+ field_type: 'date',
329
+ value: 1675296000000,
330
+ second_value: ''
331
+ },
332
+ output: { range: { created_at: { gte: 1675353599999 } } }
333
+ },
334
+ {
335
+ input: {
336
+ condition: 'greater_than_or_equal',
337
+ field_id: '',
338
+ type: 'created_at',
339
+ field_type: 'unknwon_type',
340
+ value: 1675296000000,
341
+ second_value: ''
342
+ },
343
+ output: null
344
+ }
345
+ ];
346
+
347
+ filters.forEach((filter) => {
348
+ it(`${filter.input.condition}: ${JSON.stringify(
349
+ filter.input.value
350
+ )}`, (done) => {
351
+ expect(taskFieldFilter(filter.input)).to.deep.equal(filter.output);
352
+ done();
353
+ });
354
+ });
355
+ });
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ /* eslint-env node, mocha */
4
+ const { expect } = require('chai');
5
+
6
+ // To test
7
+ const fieldConditions = require('../../lib/fieldConditions');
8
+
9
+ describe('fieldConditions', function () {
10
+ describe('getConditions', () => {
11
+ it('should be able to get specific field type conditions', (done) => {
12
+ const conditions = fieldConditions.getConditions('text');
13
+ expect(conditions).to.deep.equal(fieldConditions.conditions.text);
14
+ done();
15
+ });
16
+ });
17
+ });
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+
3
+ /* eslint-env node, mocha */
4
+ const chai = require('chai');
5
+ const testConsole = require('test-console');
6
+
7
+ // To test
8
+ const logger = require('../../lib/logger');
9
+
10
+ const assert = chai.assert;
11
+
12
+ describe('logger', function () {
13
+ describe('info', () => {
14
+ it('should log an info text on stdout', (done) => {
15
+ const output = testConsole.stdout.inspectSync(() => {
16
+ logger.info('All is well!');
17
+ });
18
+
19
+ try {
20
+ assert.deepEqual(output, [
21
+ '[INFO]:\n{\n "Message": "All is well!"\n}\n'
22
+ ]);
23
+
24
+ done();
25
+ } catch (e) {
26
+ done(e);
27
+ }
28
+ });
29
+
30
+ it('should log an info object on stdout', (done) => {
31
+ const output = testConsole.stdout.inspectSync(() => {
32
+ logger.info({ propertyOne: 'propertyOne', propertyTwo: 'propertyTwo' });
33
+ });
34
+
35
+ try {
36
+ assert.deepEqual(output, [
37
+ '[INFO]:\n{\n "propertyOne": "propertyOne",\n "propertyTwo": "propertyTwo"\n}\n'
38
+ ]);
39
+
40
+ done();
41
+ } catch (e) {
42
+ done(e);
43
+ }
44
+ });
45
+ });
46
+
47
+ describe('warn', () => {
48
+ it('Should log a warning text on stderr', (done) => {
49
+ const output = testConsole.stderr.inspectSync(() => {
50
+ logger.warn('A bit worried');
51
+ });
52
+
53
+ try {
54
+ assert.deepEqual(output, [
55
+ '[WARNING]:\n{\n "Message": "A bit worried"\n}\n'
56
+ ]);
57
+
58
+ done();
59
+ } catch (e) {
60
+ done(e);
61
+ }
62
+ });
63
+
64
+ it('should log an warning object on stderr', (done) => {
65
+ const output = testConsole.stderr.inspectSync(() => {
66
+ logger.warn({ propertyOne: 'propertyOne', propertyTwo: 'propertyTwo' });
67
+ });
68
+
69
+ try {
70
+ assert.deepEqual(output, [
71
+ '[WARNING]:\n{\n "propertyOne": "propertyOne",\n "propertyTwo": "propertyTwo"\n}\n'
72
+ ]);
73
+
74
+ done();
75
+ } catch (e) {
76
+ done(e);
77
+ }
78
+ });
79
+ });
80
+
81
+ describe('error', () => {
82
+ it('should log an error text on stderr', (done) => {
83
+ const output = testConsole.stderr.inspectSync(() => {
84
+ logger.error('HEEEELLP!!!');
85
+ });
86
+
87
+ try {
88
+ assert.deepEqual(output, [
89
+ '[ERROR]:\n{\n "Message": "HEEEELLP!!!"\n}\n'
90
+ ]);
91
+
92
+ done();
93
+ } catch (e) {
94
+ done(e);
95
+ }
96
+ });
97
+
98
+ it('should log an error object on stderr', (done) => {
99
+ const output = testConsole.stderr.inspectSync(() => {
100
+ logger.error({
101
+ propertyOne: 'propertyOne',
102
+ propertyTwo: 'propertyTwo'
103
+ });
104
+ });
105
+
106
+ try {
107
+ assert.deepEqual(output, [
108
+ '[ERROR]:\n{\n "propertyOne": "propertyOne",\n "propertyTwo": "propertyTwo"\n}\n'
109
+ ]);
110
+
111
+ done();
112
+ } catch (e) {
113
+ done(e);
114
+ }
115
+ });
116
+ });
117
+ });
@@ -0,0 +1,162 @@
1
+ 'use strict';
2
+
3
+ /* eslint-env node, mocha */
4
+ const { expect } = require('chai');
5
+
6
+ // To test
7
+ const taskPipeline = require('../../lib/taskPipeline');
8
+
9
+ // Helpers
10
+ const taskFilterHelper = require('../../helpers/taskFilter');
11
+
12
+ describe('taskPipeline', function () {
13
+ const testOrgId = 'test-org';
14
+ const testDepartmentId = 'test-department';
15
+
16
+ describe('taskStatusOptions', () => {
17
+ it('should be equal to taskStatusOptions in task filter helper', (done) => {
18
+ expect(taskPipeline.taskStatusOptions).to.deep.equal(
19
+ taskFilterHelper.taskStatusOptions
20
+ );
21
+ done();
22
+ });
23
+ });
24
+
25
+ describe('defaultCustomColumns', () => {
26
+ it('should be equal to defaultCustomColumns in task filter helper', (done) => {
27
+ expect(taskPipeline.defaultCustomColumns).to.deep.equal(
28
+ taskFilterHelper.defaultCustomColumns
29
+ );
30
+ done();
31
+ });
32
+ });
33
+
34
+ describe('buildFiltersQuery', () => {
35
+ it('should format filter correctly with project filter', (done) => {
36
+ const filter = taskPipeline.buildFiltersQuery(
37
+ testOrgId,
38
+ testDepartmentId,
39
+ [],
40
+ { projectId: 'test-project' }
41
+ );
42
+ expect(filter).to.deep.equal({
43
+ bool: {
44
+ must: [
45
+ { term: { organization_id: { value: 'test-org' } } },
46
+ { term: { department_id: { value: 'test-department' } } },
47
+ { term: { project_id: { value: 'test-project' } } }
48
+ ]
49
+ }
50
+ });
51
+ done();
52
+ });
53
+
54
+ it('should add default on_hold filter if not present', (done) => {
55
+ const filter = taskPipeline.buildFiltersQuery(
56
+ testOrgId,
57
+ testDepartmentId,
58
+ [
59
+ {
60
+ condition: 'is_equal',
61
+ field_id: '',
62
+ type: 'status',
63
+ field_type: 'select',
64
+ value: 'pending',
65
+ second_value: ''
66
+ }
67
+ ],
68
+ { projectId: 'test-project' }
69
+ );
70
+
71
+ expect(filter).to.deep.equal({
72
+ bool: {
73
+ must: [
74
+ { term: { organization_id: { value: 'test-org' } } },
75
+ { term: { department_id: { value: 'test-department' } } },
76
+ { term: { project_id: { value: 'test-project' } } },
77
+ {
78
+ bool: {
79
+ must: [
80
+ { term: { is_ready: true } },
81
+ { term: { is_complete: false } }
82
+ ]
83
+ }
84
+ },
85
+ {
86
+ bool: {
87
+ should: [
88
+ { term: { on_hold: false } },
89
+ { bool: { must_not: { exists: { field: 'on_hold' } } } }
90
+ ]
91
+ }
92
+ }
93
+ ]
94
+ }
95
+ });
96
+ done();
97
+ });
98
+
99
+ it('should not add default on_hold filter if present', (done) => {
100
+ const filter = taskPipeline.buildFiltersQuery(
101
+ testOrgId,
102
+ testDepartmentId,
103
+ [
104
+ {
105
+ condition: 'is_equal',
106
+ field_id: '',
107
+ type: 'status',
108
+ field_type: 'select',
109
+ value: 'on_hold',
110
+ second_value: ''
111
+ }
112
+ ]
113
+ );
114
+
115
+ expect(filter).to.deep.equal({
116
+ bool: {
117
+ must: [
118
+ { term: { organization_id: { value: 'test-org' } } },
119
+ { term: { department_id: { value: 'test-department' } } },
120
+ { bool: { must: [{ term: { on_hold: true } }] } }
121
+ ]
122
+ }
123
+ });
124
+ done();
125
+ });
126
+
127
+ it('should handle unknown filter', (done) => {
128
+ const filter = taskPipeline.buildFiltersQuery(
129
+ testOrgId,
130
+ testDepartmentId,
131
+ [
132
+ {
133
+ condition: 'unknown_condition',
134
+ field_id: '',
135
+ type: 'unknown_type',
136
+ field_type: 'number',
137
+ value: 'on_hold',
138
+ second_value: ''
139
+ }
140
+ ]
141
+ );
142
+
143
+ expect(filter).to.deep.equal({
144
+ bool: {
145
+ must: [
146
+ { term: { organization_id: { value: 'test-org' } } },
147
+ { term: { department_id: { value: 'test-department' } } },
148
+ {
149
+ bool: {
150
+ should: [
151
+ { term: { on_hold: false } },
152
+ { bool: { must_not: { exists: { field: 'on_hold' } } } }
153
+ ]
154
+ }
155
+ }
156
+ ]
157
+ }
158
+ });
159
+ done();
160
+ });
161
+ });
162
+ });