@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,356 @@
1
+ module.exports.default = [
2
+ // Pending tasks should first be sorted by their age, in descending numerical order.
3
+ // Changed the default task sort order to be based on pending age oldest > newest
4
+ {
5
+ _script: {
6
+ type: 'number',
7
+ script: {
8
+ lang: 'painless',
9
+ source: `
10
+ try {
11
+ boolean isReady = doc['is_ready'].value;
12
+ boolean isComplete = doc['is_complete'].value;
13
+
14
+ if (isReady == true && isComplete == false) {
15
+ return 1;
16
+ }
17
+
18
+ return 0;
19
+ } catch (Exception err) {
20
+ return 0;
21
+ }
22
+ `
23
+ },
24
+ order: 'desc'
25
+ }
26
+ },
27
+ // Then, they should be sorted by their task name, in ascending alphabetical order.
28
+ {
29
+ _script: {
30
+ type: 'string',
31
+ script: {
32
+ lang: 'painless',
33
+ source: `
34
+ try {
35
+ boolean isReady = doc['is_ready'].value;
36
+ boolean isComplete = doc['is_complete'].value;
37
+
38
+ if (isReady == true && isComplete == false) {
39
+ return doc['name'].value.raw;
40
+ }
41
+
42
+ return 'zzzzzzzz';
43
+ } catch (Exception err) {
44
+ return 'zzzzzzzz';
45
+ }
46
+ `
47
+ },
48
+ order: 'asc'
49
+ }
50
+ },
51
+ // Completed tasks should first be sorted by their task name in ascending alphabetical order
52
+ {
53
+ _script: {
54
+ type: 'number',
55
+ script: {
56
+ lang: 'painless',
57
+ source: `
58
+ try {
59
+ boolean isReady = doc['is_ready'].value;
60
+ boolean isComplete = doc['is_complete'].value;
61
+
62
+ if (isReady == true && isComplete == true) {
63
+ return 1;
64
+ }
65
+
66
+ return 0;
67
+ } catch (Exception err) {
68
+ return 0;
69
+ }
70
+ `
71
+ },
72
+ order: 'desc'
73
+ }
74
+ },
75
+ {
76
+ _script: {
77
+ type: 'string',
78
+ script: {
79
+ lang: 'painless',
80
+ source: `
81
+ try {
82
+ boolean isReady = doc['is_ready'].value;
83
+ boolean isComplete = doc['is_complete'].value;
84
+
85
+ if (isReady == true && isComplete == true) {
86
+ return doc['name'].value.raw;
87
+ }
88
+
89
+ return 'zzzzzzzz';
90
+ } catch (Exception err) {
91
+ return 'zzzzzzzz';
92
+ }
93
+ `
94
+ },
95
+ order: 'asc'
96
+ }
97
+ },
98
+ // and then by their completion date in descending chronological order.
99
+ {
100
+ _script: {
101
+ type: 'number',
102
+ script: {
103
+ lang: 'painless',
104
+ source: `
105
+ try {
106
+ boolean isReady = doc['is_ready'].value;
107
+ boolean isComplete = doc['is_complete'].value;
108
+
109
+ if (isReady == true && isComplete == true) {
110
+ return doc['completed_at'].value.millis;
111
+ }
112
+
113
+ return 0;
114
+ } catch (Exception err) {
115
+ return 0;
116
+ }
117
+ `
118
+ },
119
+ order: 'desc'
120
+ }
121
+ },
122
+ // New tasks should be sorted by their name in ascending alphabetical order
123
+ {
124
+ 'name.raw': { order: 'asc' }
125
+ },
126
+ // Use task id as tiebreaker
127
+ {
128
+ id: { order: 'asc' }
129
+ }
130
+ ];
131
+
132
+ module.exports.region = (order) => {
133
+ return {
134
+ region_name: {
135
+ order
136
+ }
137
+ };
138
+ };
139
+
140
+ module.exports.lastCommentDate = (order) => {
141
+ return {
142
+ 'last_comment_data.created_at': {
143
+ order
144
+ }
145
+ };
146
+ };
147
+
148
+ module.exports.owner = (order) => {
149
+ return {
150
+ _script: {
151
+ type: 'string',
152
+ script: {
153
+ lang: 'painless',
154
+ source: `
155
+ try {
156
+ String owner = doc['owner'].value;
157
+
158
+ if (owner != '' && owner != null) {
159
+ return owner.toLowerCase();
160
+ }
161
+ } catch (Exception err) {}
162
+
163
+ return '';
164
+ `
165
+ },
166
+ order
167
+ }
168
+ };
169
+ };
170
+
171
+ module.exports.status = (order) => {
172
+ return {
173
+ _script: {
174
+ type: 'string',
175
+ script: {
176
+ lang: 'painless',
177
+ source: `
178
+ try {
179
+ boolean isReady = doc['is_ready'].value;
180
+ boolean isComplete = doc['is_complete'].value;
181
+
182
+ if (isReady == true) {
183
+ if (isComplete == true) {
184
+ return 'completed';
185
+ }
186
+
187
+ return 'pending';
188
+ }
189
+
190
+ return 'new';
191
+ } catch (Exception err) {
192
+ return '';
193
+ }
194
+ `
195
+ },
196
+ order
197
+ }
198
+ };
199
+ };
200
+
201
+ module.exports.criticalPathStage = (order) => {
202
+ return {
203
+ _script: {
204
+ type: 'number',
205
+ script: {
206
+ lang: 'painless',
207
+ source: `
208
+ try {
209
+ def stageIndex = doc['critical_path.stage_index'].value;
210
+ if (stageIndex != null) {
211
+ return stageIndex;
212
+ }
213
+
214
+ return 9999999;
215
+ } catch (Exception err) {
216
+ return 9999999;
217
+ }
218
+ `
219
+ },
220
+ order
221
+ }
222
+ };
223
+ };
224
+
225
+ module.exports.projectId = (order) => {
226
+ return {
227
+ _script: {
228
+ type: 'number',
229
+ script: {
230
+ lang: 'painless',
231
+ source: `
232
+ def projectNumber = params._source.project_id;
233
+ projectNumber = /[^0-9]/.matcher(projectNumber).replaceAll('');
234
+ return Integer.parseInt(projectNumber);
235
+ `
236
+ },
237
+ order
238
+ }
239
+ };
240
+ };
241
+
242
+ module.exports.readyAt = (order) => {
243
+ return {
244
+ _script: {
245
+ type: 'number',
246
+ script: {
247
+ lang: 'painless',
248
+ source: `
249
+ try {
250
+ boolean isReady = doc['is_ready'].value;
251
+ boolean isComplete = doc['is_complete'].value;
252
+
253
+ if (isReady == true && isComplete == true && doc.containsKey('completed_at') && !doc['completed_at'].empty) {
254
+ return doc['completed_at'].value.millis;
255
+ } else if (isReady == true && doc.containsKey('ready_at') && !doc['ready_at'].empty) {
256
+ return doc['ready_at'].value.millis;
257
+ }
258
+
259
+ return doc['created_at'].value.millis;
260
+ } catch (Exception err) {
261
+ return 0;
262
+ }
263
+ `
264
+ },
265
+ order
266
+ }
267
+ };
268
+ };
269
+
270
+ module.exports.wasMarkedIncomplete = (order) => {
271
+ return {
272
+ _script: {
273
+ type: 'number',
274
+ script: {
275
+ lang: 'painless',
276
+ source: `
277
+ return doc['was_marked_incomplete'].empty
278
+ ? 0
279
+ : doc['was_marked_incomplete'].value ? 1 : 0;
280
+ `
281
+ },
282
+ order
283
+ }
284
+ };
285
+ };
286
+
287
+ module.exports.projectFieldNumeric = (order, value) => {
288
+ return {
289
+ _script: {
290
+ type: 'number',
291
+ script: {
292
+ lang: 'painless',
293
+ source: `
294
+ try {
295
+ def fields = params._source.fields;
296
+
297
+ for (int i=0; i<fields.size(); i++) {
298
+ if (fields[i].id.equals(params.value)) {
299
+ if (fields[i].number != null) {
300
+ return fields[i].number;
301
+ } else {
302
+ return -999999;
303
+ }
304
+ }
305
+ }
306
+
307
+ return -999999;
308
+ } catch (Exception err) {
309
+ return -999999;
310
+ }
311
+ `,
312
+ params: {
313
+ value
314
+ }
315
+ },
316
+ order
317
+ }
318
+ };
319
+ };
320
+
321
+ module.exports.projectFieldText = (order, value) => {
322
+ return {
323
+ _script: {
324
+ type: 'string',
325
+ script: {
326
+ lang: 'painless',
327
+ source: `
328
+ try {
329
+ String textInfo = '';
330
+ def fields = params._source.fields;
331
+
332
+ for (int i=0; i<fields.size(); i++) {
333
+ if (fields[i].id.equals(params.value)) {
334
+
335
+ if (fields[i].number != null) {
336
+ return '';
337
+ }
338
+
339
+ textInfo = fields[i].text == null ? '' : fields[i].text;
340
+ }
341
+
342
+ }
343
+
344
+ return textInfo;
345
+ } catch (Exception err) {
346
+ return '';
347
+ }
348
+ `,
349
+ params: {
350
+ value
351
+ }
352
+ },
353
+ order
354
+ }
355
+ };
356
+ };
package/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ declare namespace Utils {
2
+ namespace log {
3
+ export function info(msg: any): void;
4
+
5
+ export function warn(msg: any): void;
6
+
7
+ export function error(msg: any): void;
8
+ }
9
+ }
10
+
11
+ export = Utils;
package/index.js ADDED
@@ -0,0 +1,9 @@
1
+ const log = require('./lib/logger');
2
+ const fieldConditions = require('./lib/fieldConditions');
3
+ const taskPipeline = require('./lib/taskPipeline');
4
+
5
+ module.exports = {
6
+ log,
7
+ fieldConditions,
8
+ taskPipeline
9
+ };
@@ -0,0 +1,166 @@
1
+ module.exports.conditions = {
2
+ text: [
3
+ {
4
+ label: 'Equals',
5
+ value: 'is_equal'
6
+ },
7
+ {
8
+ label: "Doesn't Equal",
9
+ value: 'not_equal'
10
+ },
11
+ {
12
+ label: 'Is Empty',
13
+ value: 'is_empty'
14
+ },
15
+ {
16
+ label: 'Is Not Empty',
17
+ value: 'is_not_empty'
18
+ },
19
+ {
20
+ label: 'Contains Any',
21
+ value: 'contains_any'
22
+ },
23
+ {
24
+ label: 'Contains None',
25
+ value: 'contains_none'
26
+ }
27
+ ],
28
+ textarea: [
29
+ {
30
+ label: 'Equals',
31
+ value: 'is_equal'
32
+ },
33
+ {
34
+ label: "Doesn't Equal",
35
+ value: 'not_equal'
36
+ },
37
+ {
38
+ label: 'Is Empty',
39
+ value: 'is_empty'
40
+ },
41
+ {
42
+ label: 'Is Not Empty',
43
+ value: 'is_not_empty'
44
+ },
45
+ {
46
+ label: 'Contains Any',
47
+ value: 'contains_any'
48
+ },
49
+ {
50
+ label: 'Contains None',
51
+ value: 'contains_none'
52
+ }
53
+ ],
54
+ number: [
55
+ {
56
+ label: 'Equals',
57
+ value: 'is_equal'
58
+ },
59
+ {
60
+ label: "Doesn't Equal",
61
+ value: 'not_equal'
62
+ },
63
+ {
64
+ label: 'Greater Than',
65
+ value: 'greater_than'
66
+ },
67
+ {
68
+ label: 'Less Than',
69
+ value: 'less_than'
70
+ },
71
+ {
72
+ label: 'Greater Than or Equal To',
73
+ value: 'greater_than_or_equal'
74
+ },
75
+ {
76
+ label: 'Less Than or Equal To',
77
+ value: 'less_than_or_equal'
78
+ },
79
+ {
80
+ label: 'Between',
81
+ value: 'between'
82
+ },
83
+ {
84
+ label: 'Is Empty',
85
+ value: 'is_empty'
86
+ },
87
+ {
88
+ label: 'Is Not Empty',
89
+ value: 'is_not_empty'
90
+ }
91
+ ],
92
+ checkbox: [
93
+ {
94
+ label: 'Contains',
95
+ value: 'is_equal'
96
+ },
97
+ {
98
+ label: "Doesn't Contains",
99
+ value: 'not_equal'
100
+ },
101
+ {
102
+ label: 'Is Empty',
103
+ value: 'is_empty'
104
+ },
105
+ {
106
+ label: 'Is Not Empty',
107
+ value: 'is_not_empty'
108
+ }
109
+ ],
110
+ select: [
111
+ {
112
+ label: 'Equals',
113
+ value: 'is_equal'
114
+ },
115
+ {
116
+ label: "Doesn't Equal",
117
+ value: 'not_equal'
118
+ },
119
+ {
120
+ label: 'Is Empty',
121
+ value: 'is_empty'
122
+ },
123
+ {
124
+ label: 'Is Not Empty',
125
+ value: 'is_not_empty'
126
+ },
127
+ {
128
+ label: 'Is any of',
129
+ value: 'is_any_of'
130
+ }
131
+ ],
132
+ date: [
133
+ {
134
+ label: 'Equals',
135
+ value: 'is_equal'
136
+ },
137
+ {
138
+ label: "Doesn't Equal",
139
+ value: 'not_equal'
140
+ },
141
+ {
142
+ label: 'Before',
143
+ value: 'before'
144
+ },
145
+ {
146
+ label: 'After',
147
+ value: 'after'
148
+ },
149
+ {
150
+ label: 'Between',
151
+ value: 'between'
152
+ },
153
+ {
154
+ label: 'Is Empty',
155
+ value: 'is_empty'
156
+ },
157
+ {
158
+ label: 'Is Not Empty',
159
+ value: 'is_not_empty'
160
+ }
161
+ ]
162
+ };
163
+
164
+ module.exports.getConditions = (filedType) => {
165
+ return module.exports.conditions[filedType];
166
+ };
package/lib/logger.js ADDED
@@ -0,0 +1,48 @@
1
+ /* eslint-disable no-console */
2
+
3
+ /**
4
+ * Logs an info message.
5
+ * Takes either a string or a JSON object. And prepends [INFO]: to the message.
6
+ * If the input is a string it will be places within a JSON object in the Message property.
7
+ */
8
+ const info = (message) => {
9
+ if (typeof message === 'string') {
10
+ console.info('[INFO]:\n' + JSON.stringify({ Message: message }, null, 4));
11
+ } else {
12
+ console.info('[INFO]:\n' + JSON.stringify(message, null, 4));
13
+ }
14
+ };
15
+
16
+ /**
17
+ * Logs a warning message.
18
+ * Takes either a string or a JSON object. And prepends [WARNING]: to the message.
19
+ * If the input is a string it will be places within a JSON object in the Message property.
20
+ */
21
+ const warn = (message) => {
22
+ if (typeof message === 'string') {
23
+ console.warn(
24
+ '[WARNING]:\n' + JSON.stringify({ Message: message }, null, 4)
25
+ );
26
+ } else {
27
+ console.warn('[WARNING]:\n' + JSON.stringify(message, null, 4));
28
+ }
29
+ };
30
+
31
+ /**
32
+ * Logs an error message.
33
+ * Takes either a string or a JSON object. And prepends [ERROR]: to the message.
34
+ * If the input is a string it will be places within a JSON object in the Message property.
35
+ */
36
+ const error = (message) => {
37
+ if (typeof message === 'string') {
38
+ console.error('[ERROR]:\n' + JSON.stringify({ Message: message }, null, 4));
39
+ } else {
40
+ console.error('[ERROR]:\n' + JSON.stringify(message, null, 4));
41
+ }
42
+ };
43
+
44
+ module.exports = {
45
+ info,
46
+ warn,
47
+ error
48
+ };