marty 8.5.0 → 9.3.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintignore +1 -0
  3. data/.eslintrc.js +26 -0
  4. data/.gitignore +3 -0
  5. data/.gitlab-ci.yml +7 -0
  6. data/.prettierignore +14 -0
  7. data/.rubocop_todo.yml +1 -1
  8. data/Dockerfile.dummy +3 -0
  9. data/Makefile +1 -0
  10. data/app/assets/javascripts/marty/cable.js +7 -3
  11. data/app/assets/javascripts/marty/extjs/extensions/datetime_field/component.js +401 -0
  12. data/app/assets/javascripts/marty/extjs/extensions/datetime_field/field.js +140 -0
  13. data/app/assets/javascripts/marty/extjs/extensions/marty.js +845 -781
  14. data/app/assets/stylesheets/marty/codemirror/codemirror.css +215 -77
  15. data/app/assets/stylesheets/marty/codemirror/delorean.css +2 -2
  16. data/app/assets/stylesheets/marty/dark_mode.css +13 -3
  17. data/app/components/marty/auth_app/client/auth_app.js +107 -102
  18. data/app/components/marty/base_rule_view/client/base_rule_view.js +10 -8
  19. data/app/components/marty/data_grid_view/client/data_grid_edit.js +534 -519
  20. data/app/components/marty/form/client/form.js +3 -3
  21. data/app/components/marty/grid/client/grid.js +110 -87
  22. data/app/components/marty/import_view/client/import_view.js +18 -18
  23. data/app/components/marty/live_search_grid_panel/client/live_search_grid_panel.js +14 -13
  24. data/app/components/marty/main_auth_app/client/main_auth_app.js +42 -42
  25. data/app/components/marty/mcfly_grid_panel/client/mcfly_grid_panel.js +27 -18
  26. data/app/components/marty/new_posting_form/client/new_posting_form.js +3 -3
  27. data/app/components/marty/panel/client/panel.js +3 -3
  28. data/app/components/marty/posting_grid/client/posting_grid.js +24 -18
  29. data/app/components/marty/promise_view/client/promise_view.css +12 -12
  30. data/app/components/marty/promise_view/client/promise_view.js +46 -38
  31. data/app/components/marty/report_form/client/report_form.js +30 -28
  32. data/app/components/marty/report_select/client/report_select.js +28 -23
  33. data/app/components/marty/reporting/client/reporting.js +3 -3
  34. data/app/components/marty/script_form/client/script_form.js +29 -23
  35. data/app/components/marty/script_tester/client/script_tester.js +4 -5
  36. data/app/components/marty/scripting/client/scripting.js +40 -36
  37. data/app/components/marty/simple_app/client/simple_app.js +33 -24
  38. data/app/components/marty/simple_app/client/statusbar_ext.js +1 -1
  39. data/app/controllers/marty/rpc_controller.rb +3 -0
  40. data/app/models/marty/promise.rb +10 -2
  41. data/app/services/marty/data_grid/constraint.rb +2 -1
  42. data/app/services/marty/jobs/schedule.rb +2 -2
  43. data/app/services/marty/promises/delorean/create.rb +9 -2
  44. data/app/services/marty/promises/ruby/create.rb +7 -2
  45. data/config/initializers/delayed_job_config.rb +1 -0
  46. data/delorean/blame_report.dl +50 -58
  47. data/delorean/enum_report.dl +2 -3
  48. data/delorean/{marty_fields.dl → fields.dl} +16 -0
  49. data/delorean/styles.dl +216 -0
  50. data/delorean/table_report.dl +4 -4
  51. data/lib/marty/monkey.rb +17 -0
  52. data/lib/marty/promise_job.rb +9 -0
  53. data/lib/marty/promise_ruby_job.rb +8 -0
  54. data/lib/marty/version.rb +1 -1
  55. data/make-lint.mk +19 -0
  56. data/package.json +16 -0
  57. data/prettier.config.js +6 -0
  58. data/spec/controllers/diagnostic/controller_spec.rb +0 -1
  59. data/spec/controllers/rpc_controller_spec.rb +21 -7
  60. data/spec/dummy/delorean/data_report.dl +4 -4
  61. data/spec/dummy/delorean/fields.dl +1 -0
  62. data/spec/features/data_grid_spec.rb +37 -1
  63. data/spec/job_helper.rb +6 -0
  64. data/spec/lib/data_blame_spec.rb +4 -4
  65. data/spec/lib/data_importer_spec.rb +6 -4
  66. data/spec/models/promise_spec.rb +31 -0
  67. data/spec/spec_helper.rb +8 -0
  68. data/spec/support/download_helper.rb +53 -49
  69. data/spec/support/json_helper.rb +11 -0
  70. data/spec/support/shared_connection_db_helpers.rb +1 -0
  71. data/spec/support/suite.rb +20 -14
  72. data/yarn.lock +967 -0
  73. metadata +16 -4
  74. data/spec/dummy/delorean/marty_fields.dl +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6fd0c089c5ad585e2ee595e562468d11ba1bcb93561faf4af44b7efd657eead
4
- data.tar.gz: 706faaa4fd4c52cdf947546fbe5362b6862335ff085c68a8a78b52c257e35380
3
+ metadata.gz: 7fd7c45cf6825476a774ee84fe6b3f9bff603e022747ecc5079cda8a037a869b
4
+ data.tar.gz: 48fdb90df6cb49e720fc4446975f8b55205eaa560a23af60a49b1d02769127cf
5
5
  SHA512:
6
- metadata.gz: 5350b886990d9c4efffa480d3727efed7f357208d966394ae637f7cfae110203046a768379d1b373f931cf8bcb85d982f97ef1e5c7e1240e5ddde3e2f4038324
7
- data.tar.gz: b4ac412e00641a7e5138036f9af8eac4c5c68fb48fd76c05296c195825a6eb3755659adf7287f92c70d0a058c645a7dacec675c2a590376e6ed2e786053cf6e0
6
+ metadata.gz: 81813549a4614fa1191c466a5506ec2d36796e21e6d45dec4eb8bf054e0614a01c1c2bf1a0539e2afdc980c81e22a32bcdce2749d27634bf65c6f491e058978d
7
+ data.tar.gz: be097e58e928782e89761d4980218e417c2df6c5fa9a28233c4449feed3df1a5492a244ce7211cb604471e7188e08d5b8e923921948b7614dcc6a873cab60af6
@@ -0,0 +1 @@
1
+ app/assets/javascripts/marty/codemirror/*
@@ -0,0 +1,26 @@
1
+ module.exports = {
2
+ env: {
3
+ browser: true,
4
+ es6: true,
5
+ },
6
+ extends: ["eslint:recommended", "prettier"],
7
+ globals: {
8
+ RailsApp: "writable",
9
+ ActionCable: "readonly",
10
+ Ext: "readonly",
11
+ CodeMirror: "readonly"
12
+ },
13
+ parserOptions: {
14
+ ecmaVersion: 6,
15
+ },
16
+ plugins: ["prettier"],
17
+ rules: {
18
+ "no-var": ["error"],
19
+ "prefer-const": ["error"],
20
+ "linebreak-style": ["error", "unix"],
21
+ "quotes": [2, "double", { "avoidEscape": true }],
22
+ "no-unused-vars": ["error", { "args": "after-used", "argsIgnorePattern": "^_" }],
23
+ "object-shorthand": ["error", "always"],
24
+ "no-constant-condition": ["error", { "checkLoops": false }]
25
+ }
26
+ };
data/.gitignore CHANGED
@@ -39,3 +39,6 @@ spec/dummy/.sass-cache
39
39
 
40
40
  # Ignore Gemfile.lock
41
41
  Gemfile.lock
42
+
43
+ # JS stuff
44
+ /node_modules
@@ -14,6 +14,7 @@ before_script:
14
14
  interruptible: true
15
15
  # Run only when there is an MR
16
16
  only:
17
+ - master
17
18
  - merge_requests
18
19
 
19
20
  stage: test
@@ -30,6 +31,12 @@ rubocop:
30
31
  script:
31
32
  - bundle exec rubocop
32
33
 
34
+ eslint-prettier:
35
+ extends: .base-test
36
+ script:
37
+ - yarn
38
+ - make lint-js
39
+
33
40
  rspec (controllers):
34
41
  extends: .base-test
35
42
  script:
@@ -0,0 +1,14 @@
1
+ # Files ignored by Prettier.
2
+ .gitignore
3
+ .dockerignore
4
+ .editorconfig
5
+ .prettierignore
6
+ .browserslistrc
7
+ .env.local*
8
+ .ssh-docker/*
9
+ yarn.lock
10
+ Makefile
11
+ Dockerfile
12
+ docker-compose.yml
13
+ docker-entrypoint.sh
14
+ app/assets/javascripts/marty/codemirror/**/*
@@ -1024,5 +1024,5 @@ Style/WordArray:
1024
1024
  # Cop supports --auto-correct.
1025
1025
  # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
1026
1026
  # URISchemes: http, https
1027
- Metrics/LineLength:
1027
+ Layout/LineLength:
1028
1028
  Max: 100
@@ -49,6 +49,9 @@ RUN export VERSION="node_${NODE_VER}" DISTRO="$(lsb_release -s -c)" && \
49
49
  apt-get -o Acquire::Check-Valid-Until=false update && \
50
50
  apt-get install -qq -y --no-install-recommends nodejs
51
51
 
52
+ # Install Yarn
53
+ RUN curl -o- -L https://yarnpkg.com/install.sh | bash
54
+
52
55
  # Install chrome for integration tests
53
56
  RUN curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
54
57
  && dpkg -i google-chrome.deb || true \
data/Makefile CHANGED
@@ -1,2 +1,3 @@
1
1
  include make-app.mk
2
+ include make-lint.mk
2
3
 
@@ -5,8 +5,12 @@
5
5
  this.RailsApp || (this.RailsApp = {});
6
6
 
7
7
  if (window.location.port === "") {
8
- RailsApp.cable = ActionCable.createConsumer(`ws://${window.location.hostname}/cable`);
8
+ RailsApp.cable = ActionCable.createConsumer(
9
+ `ws://${window.location.hostname}/cable`
10
+ );
9
11
  } else {
10
- RailsApp.cable = ActionCable.createConsumer(`ws://${window.location.hostname}:${window.location.port}/cable`);
12
+ RailsApp.cable = ActionCable.createConsumer(
13
+ `ws://${window.location.hostname}:${window.location.port}/cable`
14
+ );
11
15
  }
12
- }).call(this);
16
+ }.call(this));
@@ -0,0 +1,401 @@
1
+ /*
2
+ * File: DateTimePicker.js
3
+ *
4
+ * This file requires use of the Ext JS library, under independent license.
5
+ * This is part of the UX for DateTimeField developed by Guilherme Portela
6
+ */
7
+
8
+ Ext.define("Ext.ux.DateTimePicker", {
9
+ extend: "Ext.picker.Date",
10
+ alias: "widget.datetimepicker",
11
+ requires: [
12
+ "Ext.picker.Date",
13
+ "Ext.slider.Single",
14
+ "Ext.form.field.Time",
15
+ "Ext.form.Label"
16
+ ],
17
+ // <locale>
18
+ /**
19
+ * @cfg {String} todayText
20
+ * The default text that will be displayed in the calendar to pick the curent date.
21
+ */
22
+ todayText: "Current Date",
23
+ // </locale>
24
+ // <locale>
25
+ /**
26
+ * @cfg {String} hourText
27
+ * The default text displayed above the hour slider
28
+ */
29
+ hourText: "Hour",
30
+ // </locale>
31
+ // <locale>
32
+ /**
33
+ * @cfg {String} minuteText
34
+ * The default text displayed above the minute slider
35
+ */
36
+ minuteText: "Minutes",
37
+ // </locale>
38
+
39
+ /**
40
+ * @cfg {Object} hourSliderConfig
41
+ * A config object that will be applied to the hour slider. Any of the config options available for
42
+ * {@link Ext.slider.Single} can be specified here.
43
+ */
44
+
45
+ /**
46
+ * @cfg {Object} minuteSliderConfig
47
+ * A config object that will be applied to the minute slider. Any of the config options available for
48
+ * {@link Ext.slider.Single} can be specified here.
49
+ */
50
+
51
+ /**
52
+ * @cfg {Object} timePickerConfig
53
+ * A config object that will be applied to the time picker. Any of the config options available for
54
+ * {@link Ext.panel.Panel} can be specified here.
55
+ */
56
+
57
+ initEvents() {
58
+ const me = this,
59
+ eDate = Ext.Date,
60
+ day = eDate.DAY;
61
+
62
+ Ext.apply(me.keyNavConfig, {
63
+ up: (e) => {
64
+ if (e.ctrlKey) {
65
+ if (e.shiftKey) {
66
+ me.minuteSlider.setValue(me.minuteSlider.getValue() + 1);
67
+ } else {
68
+ me.showNextYear();
69
+ }
70
+ } else {
71
+ if (e.shiftKey) {
72
+ me.hourSlider.setValue(me.hourSlider.getValue() + 1);
73
+ } else {
74
+ me.update(eDate.add(me.activeDate, day, -7));
75
+ }
76
+ }
77
+ },
78
+
79
+ down: (e) => {
80
+ if (e.ctrlKey) {
81
+ if (e.shiftKey) {
82
+ me.minuteSlider.setValue(me.minuteSlider.getValue() - 1);
83
+ } else {
84
+ me.showPrevYear();
85
+ }
86
+ } else {
87
+ if (e.shiftKey) {
88
+ me.hourSlider.setValue(me.hourSlider.getValue() - 1);
89
+ } else {
90
+ me.update(eDate.add(me.activeDate, day, 7));
91
+ }
92
+ }
93
+ }
94
+ });
95
+ me.callParent();
96
+ },
97
+
98
+ initComponent() {
99
+ const me = this;
100
+
101
+ if (typeof me.value === "string") {
102
+ me.value = Ext.Date.parse(me.value, me.format);
103
+ } else if (!me.value) {
104
+ me.value = new Date();
105
+ }
106
+
107
+ const dtAux = me.value;
108
+
109
+ dtAux.setSeconds(0);
110
+
111
+ me.timeFormat = me.format.indexOf("h") !== -1 ? "h" : "H";
112
+ me.hourSlider = new Ext.slider.Single(
113
+ Ext.Object.merge(
114
+ {
115
+ fieldLabel: me.hourText,
116
+ labelAlign: "top",
117
+ labelSeparator: " ",
118
+ padding: "0 0 10 17",
119
+ focusable: false,
120
+ value: 0,
121
+ minValue: 0,
122
+ maxValue: 23,
123
+ vertical: true,
124
+ tipText: (thumb) => {
125
+ const value = thumb.value;
126
+
127
+ if (me.timeFormat === "H") {
128
+ return value || "0";
129
+ } else {
130
+ return value && value - 12 <= 0 ? value : Math.abs(value - 12);
131
+ }
132
+ }
133
+ },
134
+ me.hourSliderConfig
135
+ )
136
+ );
137
+
138
+ me.minuteSlider = new Ext.slider.Single(
139
+ Ext.Object.merge(
140
+ {
141
+ fieldLabel: me.minuteText,
142
+ labelAlign: "top",
143
+ labelSeparator: " ",
144
+ padding: "0 10 10 0",
145
+ focusable: false,
146
+ value: 0,
147
+ increment: 1,
148
+ minValue: 0,
149
+ maxValue: 59,
150
+ vertical: true
151
+ },
152
+ me.minuteSliderConfig
153
+ )
154
+ );
155
+
156
+ me.timePicker = new Ext.panel.Panel(
157
+ Ext.Object.merge(
158
+ {
159
+ layout: {
160
+ type: "hbox",
161
+ align: "stretch"
162
+ },
163
+ border: false,
164
+ defaults: {
165
+ flex: 1
166
+ },
167
+ width: 130,
168
+ floating: true,
169
+ dockedItems: [
170
+ {
171
+ xtype: "toolbar",
172
+ dock: "top",
173
+ ui: "footer",
174
+ items: [
175
+ "->",
176
+ {
177
+ xtype: "label",
178
+ text: me.timeFormat == "h" ? "12:00 AM" : "00:00"
179
+ },
180
+ "->"
181
+ ]
182
+ }
183
+ ],
184
+ items: [me.hourSlider, me.minuteSlider],
185
+ onMouseDown: (e) => {
186
+ e.preventDefault();
187
+ }
188
+ },
189
+ me.timePickerConfig
190
+ )
191
+ );
192
+
193
+ me.callParent();
194
+ me.ownerCt = me.up("[floating]");
195
+ me.timePicker.ownerCt = me.ownerCt;
196
+ me.registerWithOwnerCt();
197
+ me.timePicker.registerWithOwnerCt();
198
+ me.setValue(new Date(dtAux));
199
+ me.hourSlider.addListener("change", me.changeTimeValue, me);
200
+ me.minuteSlider.addListener("change", me.changeTimeValue, me);
201
+ },
202
+
203
+ handleTabClick(e) {
204
+ this.handleDateClick(e, this.activeCell.firstChild, true);
205
+ },
206
+
207
+ getSelectedDate(date) {
208
+ const me = this,
209
+ t = Ext.Date.clearTime(date, true).getTime(),
210
+ cells = me.cells,
211
+ cls = me.selectedCls,
212
+ cellItems = cells.elements,
213
+ cLen = cellItems.length;
214
+
215
+ let cell, c;
216
+
217
+ cells.removeCls(cls);
218
+
219
+ for (c = 0; c < cLen; c++) {
220
+ cell = cellItems[c].firstChild;
221
+ if (cell.dateValue === t) {
222
+ return cell;
223
+ }
224
+ }
225
+ return null;
226
+ },
227
+
228
+ changeTimeValue(slider) {
229
+ const me = this,
230
+ label = me.timePicker.down("label"),
231
+ minutePrefix = me.minuteSlider.getValue() < 10 ? "0" : "";
232
+
233
+ let hourDisplay = me.hourSlider.getValue(),
234
+ pickerValue,
235
+ timeSufix,
236
+ auxValue;
237
+
238
+ if (me.timeFormat == "h") {
239
+ timeSufix = me.hourSlider.getValue() < 12 ? " AM" : " PM";
240
+ hourDisplay =
241
+ me.hourSlider.getValue() < 13 ? hourDisplay : hourDisplay - 12;
242
+ hourDisplay = hourDisplay || "12";
243
+ }
244
+
245
+ const hourPrefix = hourDisplay < 10 ? "0" : "";
246
+
247
+ label.setText(
248
+ hourPrefix +
249
+ hourDisplay +
250
+ ":" +
251
+ minutePrefix +
252
+ me.minuteSlider.getValue() +
253
+ (timeSufix || "")
254
+ );
255
+
256
+ if (me.pickerField && (pickerValue = me.pickerField.getValue())) {
257
+ auxValue = new Date(
258
+ pickerValue[slider == me.hourSlider ? "setHours" : "setMinutes"](
259
+ slider.getValue()
260
+ )
261
+ );
262
+ me.pickerField.setValue(auxValue);
263
+ me.pickerField.fireEvent("select", me.pickerField, auxValue);
264
+ }
265
+ },
266
+
267
+ afterShow(animateTarget, callback, scope) {
268
+ const me = this;
269
+
270
+ me.callParent([animateTarget, callback, scope]);
271
+ me.timePicker.show();
272
+
273
+ // this is a workaround for the classic theme, where the time
274
+ // panel would have a transparent background with the classic theme.
275
+ const timePickerToolbarEl = me.timePicker.down("toolbar").getEl();
276
+ const backgroundColor = timePickerToolbarEl.getStyle("background-color");
277
+ if (backgroundColor == "transparent") {
278
+ timePickerToolbarEl.setStyle(
279
+ "background-color",
280
+ timePickerToolbarEl.getStyle("border-color")
281
+ );
282
+ }
283
+ },
284
+
285
+ afterSetPosition(x, y) {
286
+ this.callParent([x, y]);
287
+ this.alignTimePicker();
288
+ },
289
+
290
+ alignTimePicker() {
291
+ const me = this,
292
+ el = me.el,
293
+ alignTo = me.getTimePickerSide(),
294
+ xPos = alignTo == "tl" ? -1 * me.timePicker.getWidth() - 5 : 5;
295
+
296
+ me.timePicker.setHeight(el.getHeight());
297
+ me.timePicker.showBy(me, alignTo, [xPos, 0]);
298
+ },
299
+
300
+ onHide() {
301
+ const me = this;
302
+ me.timePicker.hide();
303
+ me.callParent();
304
+ },
305
+
306
+ beforeDestroy() {
307
+ const me = this;
308
+
309
+ if (me.rendered) {
310
+ Ext.destroy(me.timePicker, me.minuteSlider, me.hourSlider);
311
+ }
312
+ me.callParent();
313
+ },
314
+
315
+ getTimePickerSide() {
316
+ const el = this.el,
317
+ body = Ext.getBody(),
318
+ bodyWidth = body.getViewSize().width;
319
+
320
+ return bodyWidth < el.getX() + el.getWidth() + 140 ? "tl" : "tr";
321
+ },
322
+
323
+ setValue(value) {
324
+ value = value || new Date();
325
+
326
+ value.setSeconds(0);
327
+ this.value = new Date(value);
328
+ return this.update(this.value);
329
+ },
330
+
331
+ selectToday() {
332
+ const me = this,
333
+ btn = me.todayBtn,
334
+ handler = me.handler,
335
+ auxDate = new Date();
336
+
337
+ if (btn && !btn.disabled) {
338
+ me.setValue(new Date(auxDate.setSeconds(0)));
339
+ me.fireEvent("select", me, me.value);
340
+ if (handler) {
341
+ handler.call(me.scope || me, me, me.value);
342
+ }
343
+ me.onSelect();
344
+ }
345
+ return me;
346
+ },
347
+
348
+ handleDateClick(e, t, /*private*/ blockStopEvent) {
349
+ const me = this,
350
+ handler = me.handler,
351
+ hourSet = me.timePicker.items.items[0].getValue(),
352
+ minuteSet = me.timePicker.items.items[1].getValue(),
353
+ auxDate = new Date(t.dateValue);
354
+
355
+ if (blockStopEvent !== true) {
356
+ e.stopEvent();
357
+ }
358
+
359
+ if (
360
+ !me.disabled &&
361
+ t.dateValue &&
362
+ !Ext.fly(t.parentNode).hasCls(me.disabledCellCls)
363
+ ) {
364
+ me.doCancelFocus = me.focusOnSelect === false;
365
+ auxDate.setHours(hourSet, minuteSet, 0);
366
+ me.setValue(new Date(auxDate));
367
+ delete me.doCancelFocus;
368
+ me.fireEvent("select", me, me.value);
369
+ if (handler) {
370
+ handler.call(me.scope || me, me, me.value);
371
+ }
372
+ me.onSelect();
373
+ }
374
+ },
375
+
376
+ selectedUpdate(date) {
377
+ const me = this,
378
+ dateOnly = Ext.Date.clearTime(date, true);
379
+
380
+ this.callParent([dateOnly]);
381
+ me.updateSliders();
382
+ },
383
+
384
+ fullUpdate(date) {
385
+ const me = this,
386
+ dateOnly = Ext.Date.clearTime(date, true);
387
+
388
+ this.callParent([dateOnly]);
389
+ me.updateSliders();
390
+ },
391
+
392
+ updateSliders() {
393
+ const me = this,
394
+ currentDate = (me.pickerField && me.pickerField.getValue()) || new Date();
395
+
396
+ if (me.timePicker.rendered) {
397
+ me.hourSlider.setValue(currentDate.getHours());
398
+ me.minuteSlider.setValue(currentDate.getMinutes());
399
+ }
400
+ }
401
+ });