aleph_analytics 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +1 -0
  4. data/app/assets/javascripts/angular/controllers/controllers.js.es6 +9 -2
  5. data/app/assets/javascripts/angular/directives/query/query_details_directive.js.es6 +54 -6
  6. data/app/assets/javascripts/angular/directives/query/query_version_sidebar_directive.js.es6 +8 -0
  7. data/app/assets/javascripts/angular/services/query/query.js.es6 +16 -5
  8. data/app/assets/javascripts/angular/services/query/query_request_transformers.js.es6 +1 -1
  9. data/app/assets/javascripts/angular/services/query/tags_roles_comparator.js.es6 +32 -0
  10. data/app/assets/javascripts/angular/services/services.js.es6 +1 -0
  11. data/app/assets/stylesheets/alert_bar.css.sass +3 -3
  12. data/app/assets/stylesheets/application.css.sass +1 -0
  13. data/app/assets/stylesheets/comments.css.sass +4 -0
  14. data/app/assets/stylesheets/queries.css.sass +12 -9
  15. data/app/assets/stylesheets/results.css.sass +0 -2
  16. data/app/assets/stylesheets/scheduled.css.sass +39 -0
  17. data/app/assets/stylesheets/shared.css.sass +67 -0
  18. data/app/assets/stylesheets/sidebar.css.sass +12 -0
  19. data/app/assets/stylesheets/variables.css.sass +1 -1
  20. data/app/mailers/alert_mailer.rb +1 -1
  21. data/app/mailers/query_mailer.rb +10 -0
  22. data/app/models/query.rb +21 -1
  23. data/app/models/result.rb +11 -4
  24. data/app/models/scheduled_query_execution.rb +23 -0
  25. data/app/serializers/query_serializer.rb +1 -1
  26. data/app/views/layouts/application.html.haml +3 -1
  27. data/app/views/queries/_comments.html.haml +9 -3
  28. data/app/views/queries/_index_item.html.haml +3 -3
  29. data/app/views/queries/_index_sort_bar.html.haml +3 -3
  30. data/app/views/queries/_query_details.html.haml +31 -21
  31. data/app/views/queries/_query_version_sidebar.html.haml +34 -16
  32. data/app/views/queries/_scheduled.html.haml +31 -0
  33. data/app/views/query_mailer/query_result_email.html.haml +7 -0
  34. data/config/environments/development.rb +3 -0
  35. data/config/example/{alerts.yml → email.yml} +0 -0
  36. data/config/initializers/01_internalize_configurations.rb +6 -6
  37. data/db/migrate/20190131003650_add_set_latest_result_to_queries.rb +5 -0
  38. data/db/migrate/20190205234108_add_query_scheduling_columns.rb +13 -0
  39. data/lib/aws_s3.rb +44 -3
  40. data/lib/clock.rb +1 -0
  41. data/lib/csv_helper/aws.rb +3 -18
  42. data/lib/interaction/query_interaction.rb +3 -0
  43. data/lib/interaction/query_update.rb +3 -0
  44. data/public/assets/.sprockets-manifest-331daedd75cbbd8f5318863713f13576.json +1 -0
  45. data/public/assets/angular/controllers/{controllers.js-45fce398a9c2c371df9ffc32e8dbed84.es6 → controllers.js-f00a5ac91d427dcb9694fc1849f5bbd1.es6} +9 -2
  46. data/public/assets/angular/directives/query/{query_details_directive.js-9ed5b4d1ee4b86889d0de38bc93bac26.es6 → query_details_directive.js-a6604f8ceb6af34a2e97360c6ed459f6.es6} +54 -6
  47. data/public/assets/angular/directives/query/{query_version_sidebar_directive.js-b19ba8a9bf4e66c5740e9b9f9495cee1.es6 → query_version_sidebar_directive.js-282fe948431cbd43335f8d99503fc87a.es6} +8 -0
  48. data/public/assets/angular/services/query/{query.js-7b6228d0a5c1a6ea76242f4aa49aafd0.es6 → query.js-0dd29232f8dbf0527a1324d509a8a74b.es6} +16 -5
  49. data/public/assets/angular/services/query/{query_request_transformers.js-522901477c7848324cd5c014005a85c8.es6 → query_request_transformers.js-110a99334386d4391d47d48df8b57ddf.es6} +1 -1
  50. data/public/assets/angular/services/query/tags_roles_comparator.js-d1e086bdbad13b7e1ed60fa24c660a71.es6 +32 -0
  51. data/public/assets/angular/services/{services.js-855551e8fa01a9a3c05115c4c9fdf7db.es6 → services.js-5230e6db8f737e8378ef2a17c2fc847e.es6} +1 -0
  52. data/public/assets/{application-8bc9d85ca89b3c85e03f7d06948d2e87.js → application-55739fd5c21580dfacbf85238f9e5575.js} +23 -23
  53. data/public/assets/{application-b3586e5b2749cef985bebb24246f95b6.css → application-a3b45a0034f70e5f423c4e0427ca5ccf.css} +1 -1
  54. data/public/assets/resque_web/{application-4218536633ae4c535133fe1455d54cbc.js → application-91fe987abb3becd4e530ec6a4a6a3da7.js} +4 -4
  55. metadata +23 -16
  56. data/lib/tasks/resque.rake +0 -22
  57. data/public/assets/.sprockets-manifest-61519c86aab355aa148c9e7c78293a9e.json +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b835017996e863027ccbad3617742ffd680cfcd
4
- data.tar.gz: 567308aed9dec7a7ab5c34ef296f1ee6276d4503
3
+ metadata.gz: 9d4c390667cb9196104ad61049e9028d01b906ca
4
+ data.tar.gz: 5a4d2383a969bdb45929b8b696e491f61f42867c
5
5
  SHA512:
6
- metadata.gz: ee415ff8e6d34fd5275000d91564a19052156b7ea456a5af370cfbd546ef5d3a27760feeeb0e122fc1ea9251efb5fe5df7ed155beee3dcfff4c4a5e24e2db32f
7
- data.tar.gz: 723ef552f7f7661ae409e4d1a6d1dc6cee7188666584a78462bdd9d893cbd17ba5c9476895cc93c9e7653fb106119bb4ab3baa8b614607c814f8a2e96cf76a2e
6
+ metadata.gz: e88f4a7c419aa95cff8f1ded63c50c1da317022a82e3a8242458d55f4f66789d86ffe559ae2278b1c66e47f4e1a75ef44203af9e0a40a8bc4a3fca10f7f7faa9
7
+ data.tar.gz: f5e2da4929c25d8831812e452566e7f1ab68aeeed4dc95dde2d2ebcef7a5a682958a68be9ba121b1d2b36e6c41e6e618f9cb50381a3f4298cf1b12c3c5dc497c
data/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file using [Semantic Versioning](http://semver.org/).
3
3
 
4
+ ## [0.3.0] - 2010-02-26
5
+ ### Features
6
+ - [Scheduled Query Execution](https://github.com/lumoslabs/aleph/issues/42)
7
+ - Fixed s3 location for latest result (useful for GoogleSheet integration)
8
+
9
+ ### Fixed
10
+ - Fix roles and tag dirty aware comparators on the Query model
11
+
4
12
  ## [0.2.0] - 2017-09-12
5
13
  ### Features
6
14
  - [Surface Running Queries](https://github.com/lumoslabs/aleph/issues/45)
data/README.md CHANGED
@@ -134,6 +134,7 @@ You can manage your env variables in a .env file
134
134
 
135
135
  ## Links
136
136
 
137
+ - [Feature Notes](docs/FEATURES.md)
137
138
  - [Rubygem](https://rubygems.org/gems/aleph_analytics)
138
139
  - [aleph-user group](https://groups.google.com/forum/#!forum/aleph-user)
139
140
 
@@ -42,13 +42,20 @@
42
42
  function ($scope, $rootScope) {
43
43
  $scope.alerts = [];
44
44
 
45
+ function addAlert(alert) {
46
+ var latest = _.last($scope.alerts);
47
+ if ($scope.alerts.length == 0 || latest.message != alert.message || latest.type != alert.type) {
48
+ $scope.alerts.push(alert);
49
+ }
50
+ }
51
+
45
52
  $scope.dismiss = function dismiss() {
46
53
  $scope.alerts.length = 0;
47
54
  };
48
55
 
49
56
  $rootScope.$on('$routeChangeSuccess', () => {
50
57
  if ($scope.scheduledAlert) {
51
- $scope.alerts.push($scope.scheduledAlert);
58
+ addAlert($scope.scheduledAlert);
52
59
  $scope.scheduledAlert = null;
53
60
  } else {
54
61
  $scope.dismiss();
@@ -60,7 +67,7 @@
60
67
  });
61
68
 
62
69
  $rootScope.$on('setAlert', (event, alert) => {
63
- $scope.alerts.push(alert);
70
+ addAlert(alert);
64
71
  });
65
72
  }
66
73
  ]);
@@ -14,7 +14,7 @@
14
14
  this._Query = Query;
15
15
 
16
16
  RoleModel.initCollection();
17
- this._closeCommentDialog();
17
+ this._closeDialogBoxes();
18
18
  }
19
19
 
20
20
  openRepl() {
@@ -25,11 +25,34 @@
25
25
  .finally(this._closeCommentDialog.bind(this));
26
26
  }
27
27
 
28
- updateQuery() {
29
- this.query.save()
30
- .then(this._setPristine.bind(this))
31
- .then(this._handler.success.bind(this._handler, 'update', false))
32
- .finally(this._closeCommentDialog.bind(this));
28
+ updateTitle() {
29
+ if(this.query.isDirty()) {
30
+ this._updateQuery()
31
+ .then(this._setPristine.bind(this))
32
+ .finally(this._closeDialogBoxes.bind(this));
33
+ }
34
+ }
35
+
36
+ updateTagsAndRoles() {
37
+ if(this.query.isDirty()) {
38
+ this._updateQuery().finally(this._closeDialogBoxes.bind(this));
39
+ }
40
+ }
41
+
42
+ updateCommentDialogAndClose() {
43
+ if(this.query.isDirty()) {
44
+ this._updateQuery().finally(this._closeCommentDialog.bind(this));
45
+ } else {
46
+ this._closeCommentDialog();
47
+ }
48
+ }
49
+
50
+ updateScheduleDialogAndClose() {
51
+ if(this.query.isDirty()) {
52
+ this._updateQuery().finally(this._closeScheduleDialog.bind(this));
53
+ } else {
54
+ this._closeScheduleDialog();
55
+ }
33
56
  }
34
57
 
35
58
  runQuery() {
@@ -59,13 +82,38 @@
59
82
 
60
83
  toggleCommentDialog() {
61
84
  this.commentDialogOpen = !this.commentDialogOpen;
85
+ if(this.commentDialogOpen == true) {
86
+ this._closeScheduleDialog();
87
+ }
88
+ }
89
+
90
+ toggleScheduleDialog() {
91
+ this.scheduleDialogOpen = !this.scheduleDialogOpen;
92
+ if(this.scheduleDialogOpen == true) {
93
+ this._closeCommentDialog();
94
+ }
62
95
  }
63
96
 
64
97
  // private methods
98
+ _updateQuery() {
99
+ return this.query.save()
100
+ .then(this._internalizeQueryItem.bind(this))
101
+ .then(this._handler.success.bind(this._handler, 'update', false));
102
+ }
103
+
104
+ _closeDialogBoxes() {
105
+ this._closeScheduleDialog();
106
+ this._closeCommentDialog();
107
+ }
108
+
65
109
  _closeCommentDialog() {
66
110
  this.commentDialogOpen = false;
67
111
  }
68
112
 
113
+ _closeScheduleDialog() {
114
+ this.scheduleDialogOpen = false;
115
+ }
116
+
69
117
  _setPristine(query) {
70
118
  this.form.$setPristine();
71
119
  return query;
@@ -28,6 +28,14 @@
28
28
  }
29
29
  }
30
30
 
31
+ queryIsPersistedAsScheduled() {
32
+ return (this.query.isPristine() && this.query.item.scheduled_flag) || (this.query.isDirty() && !this.query.item.scheduled_flag);
33
+ }
34
+
35
+ alertResultLinkCopied() {
36
+ this._alertFlash.emitSuccess('S3 URL copied to clipboard!');
37
+ }
38
+
31
39
  loadQueryByVersion(queryVersionId) {
32
40
  this._$location.path('/queries/' + this.query.item.id + '/query_versions/' + queryVersionId);
33
41
  }
@@ -1,7 +1,7 @@
1
1
  !(angular => {
2
2
  'use strict';
3
3
 
4
- function QueryModelImports(QueryResource, ParameterMethods, StandardModel, $q) {
4
+ function QueryModelImports(QueryResource, ParameterMethods, StandardModel, TagsAndRolesComparator, $q) {
5
5
 
6
6
  return class Query extends StandardModel {
7
7
 
@@ -12,17 +12,28 @@
12
12
  {
13
13
  title: '',
14
14
  tags: [],
15
+ roles: [],
15
16
  version: {
16
17
  body: '',
18
+ comment: '',
17
19
  parameters: []
18
- }
20
+ },
21
+ scheduled_flag: false,
22
+ email: ''
19
23
  },
20
24
  [
21
25
  'title',
22
26
  'version.body',
27
+ 'version.comment',
23
28
  'roles',
24
- 'tags'
25
- ]
29
+ 'tags',
30
+ 'scheduled_flag',
31
+ 'email'
32
+ ],
33
+ {
34
+ tags: ((l, r) => TagsAndRolesComparator.compare(l, r)),
35
+ roles: ((l, r) => TagsAndRolesComparator.compare(l, r))
36
+ }
26
37
  );
27
38
  }
28
39
 
@@ -49,7 +60,7 @@
49
60
  };
50
61
  }
51
62
 
52
- QueryModelImports.$inject = ['QueryResource', 'ParameterMethods', 'StandardModel', '$q'];
63
+ QueryModelImports.$inject = ['QueryResource', 'ParameterMethods', 'StandardModel', 'TagsAndRolesComparator', '$q'];
53
64
  angular.module('alephServices.query', []).service('Query', QueryModelImports);
54
65
 
55
66
  }(angular));
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  function QueryRequestTransformers() {
5
- const saveFields = ['id', 'title', 'body', 'tags', 'result_id', 'version', 'roles'];
5
+ const saveFields = ['id', 'title', 'body', 'tags', 'result_id', 'version', 'roles', 'email', 'scheduled_flag'];
6
6
 
7
7
  // see https://github.com/mbenford/ngTagsInput
8
8
  function transformNgTagsInput(fieldName, query) {
@@ -0,0 +1,32 @@
1
+ !(angular => {
2
+ 'use strict';
3
+
4
+ class TagsAndRolesComparator {
5
+ compare(left, right) {
6
+ if(left === undefined && right === undefined) {
7
+ return true;
8
+ } else if(left === undefined) {
9
+ return false;
10
+ } else if(right === undefined) {
11
+ return false;
12
+ }
13
+
14
+ if(left.length != right.length) {
15
+ return false;
16
+ }
17
+
18
+ var unwrappedLeft = _.map(left, value => {
19
+ return _.isObject(value) ? value['text'] : value;
20
+ });
21
+
22
+ var unwrappedRight = _.map(right, value => {
23
+ return _.isObject(value) ? value['text'] : value;
24
+ });
25
+
26
+ return _.difference(unwrappedLeft, unwrappedRight).length == 0;
27
+ }
28
+ }
29
+
30
+ angular.module('alephServices.tagsAndRolesComparator', []).service('TagsAndRolesComparator', TagsAndRolesComparator);
31
+
32
+ }(angular));
@@ -13,6 +13,7 @@
13
13
  'alephServices.queryTab',
14
14
  'alephServices.query',
15
15
  'alephServices.queryLoader',
16
+ 'alephServices.tagsAndRolesComparator',
16
17
 
17
18
  // visualzations
18
19
  'alephServices.visualizationService',
@@ -4,10 +4,10 @@
4
4
 
5
5
  .alert-fade-out
6
6
  -webkit-animation-name: fade-out
7
- -webkit-animation-duration: 10s
7
+ -webkit-animation-duration: 6s
8
8
  animation-name: fade-out
9
- animation-duration: 10s
9
+ animation-duration: 6s
10
10
  animation-timing-function: ease-in
11
11
  margin: 0px
12
12
  padding: 0px
13
- border-radius: 0px 0px 15px 0px
13
+ border-radius: 0px 0px 0px 0px
@@ -25,6 +25,7 @@
25
25
  @import 'visualizations'
26
26
  @import 'sidebar'
27
27
  @import 'comments'
28
+ @import 'scheduled'
28
29
  @import 'shared'
29
30
  @import 'sort_bar'
30
31
  @import 'index_components'
@@ -5,3 +5,7 @@
5
5
  height: 150px
6
6
  font-size: small
7
7
 
8
+ .control-btn
9
+ font-size: x-small
10
+ padding-right: 5px
11
+ padding-bottom: 10px
@@ -24,6 +24,12 @@
24
24
  pre
25
25
  border-radius: 0px
26
26
 
27
+ .query-title-form
28
+ border: none
29
+ width: 100%
30
+ font-size: 2em
31
+ font-weight: bold
32
+
27
33
  .query-title-form.ng-dirty
28
34
  background-color: $gray-lighter
29
35
 
@@ -95,19 +101,16 @@ tags-input .tags .tag-item
95
101
  border: none
96
102
  box-shadow: none
97
103
 
98
- #query_title
99
- width: 100%
100
- font-size: 2em
101
- font-weight: bold
102
104
 
103
- #query-btns
104
- margin: 0 0 0
105
-
106
- #clone-btn
107
- margin-right: 15px
105
+ .white-btns
106
+ margin-left: 10px
107
+ color: $dark-slate-blue
108
108
 
109
109
  .white-background
110
110
  background-color: #FFFFFF
111
111
 
112
112
  .result-panel
113
113
  margin-bottom: 0px
114
+
115
+ .column-spacer
116
+ display: table-cell
@@ -21,5 +21,3 @@ result
21
21
 
22
22
  .high-row-count
23
23
  min-height: 300px
24
-
25
-
@@ -0,0 +1,39 @@
1
+ .scheduled
2
+ $schedule-box-width: 275px
3
+
4
+ .well-sized
5
+ min-width: 400px
6
+
7
+ .toggle-center
8
+ margin: auto
9
+ width: 60px
10
+
11
+ .pad1
12
+ padding: 1px
13
+
14
+ .control-btn
15
+ font-size: x-small
16
+ padding-right: 5px
17
+
18
+ .control-bar
19
+ width: $schedule-box-width
20
+ padding-top: 0px
21
+
22
+ .toggle-bar
23
+ width: $schedule-box-width
24
+ padding-top: 5px
25
+
26
+ .email-bar
27
+ width: $schedule-box-width
28
+ padding-top: 15px
29
+ padding-bottom: 20px
30
+
31
+ .email-label
32
+ padding: 2px
33
+
34
+ .email-label[disabled]
35
+ color: grey
36
+
37
+ .email-input-col
38
+ padding-left: 7px
39
+ padding-right: 6px
@@ -48,6 +48,9 @@ body
48
48
  .small-font
49
49
  font-size: small
50
50
 
51
+ .x-small-font
52
+ font-size: x-small
53
+
51
54
  .info-box
52
55
  background-color: $gray-lighter
53
56
  border: 1px solid $gray-light
@@ -159,6 +162,12 @@ a.navbar-text.active
159
162
  &:active
160
163
  opacity: $opacity-high
161
164
 
165
+ .subdued-clickable
166
+ color: $dark-slate-blue
167
+ cursor: pointer
168
+ &:hover
169
+ color: black
170
+
162
171
  // pulsating stuff
163
172
 
164
173
  // Chrome, Safari, Opera
@@ -200,3 +209,61 @@ a.navbar-text.active
200
209
  animation-duration: 3s
201
210
  animation-direction: alternate
202
211
  animation-iteration-count: 3
212
+
213
+
214
+ /* css for slider toggle switch */
215
+ .switch
216
+ position: relative
217
+ display: inline-block
218
+ width: 28px
219
+ height: 18px
220
+
221
+ $slider-checked: lighten($slate-blue, 5%) !default
222
+ $slider-bg: lighten(#ccc, 5%) !default
223
+
224
+ /* Hide default HTML checkbox */
225
+ .switch input
226
+ opacity: 0
227
+ width: 0
228
+ height: 0
229
+
230
+ /* The slider */
231
+ .slider
232
+ position: absolute
233
+ cursor: pointer
234
+ top: 0
235
+ left: 0
236
+ right: 0
237
+ bottom: 0
238
+ background-color: $slider-bg
239
+ -webkit-transition: .4s
240
+ transition: .4s
241
+
242
+ .slider:before
243
+ position: absolute
244
+ content: ""
245
+ height: 14px
246
+ width: 14px
247
+ left: 2px
248
+ bottom: 2px
249
+ background-color: white
250
+ -webkit-transition: .4s
251
+ transition: .4s
252
+
253
+ input:checked + .slider
254
+ background-color: $slider-checked
255
+
256
+ input:focus + .slider
257
+ box-shadow: 0 0 0px $slider-checked
258
+
259
+ input:checked + .slider:before
260
+ -webkit-transform: translateX(10px)
261
+ -ms-transform: translateX(10px)
262
+ transform: translateX(10px)
263
+
264
+ /* Rounded sliders */
265
+ .slider.round
266
+ border-radius: 5px
267
+
268
+ .slider.round:before
269
+ border-radius: 25%