aleph_analytics 0.2.0 → 0.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 (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
@@ -23,11 +23,23 @@
23
23
  span
24
24
  font-size: small
25
25
 
26
+ .version-item
27
+ padding-left: 4px
28
+ padding-top: 2px
29
+
30
+ .octicon
31
+ padding-right: 3px
32
+
26
33
  .current-version
27
34
  padding: 15px
28
35
  background-color: lighten($slate-blue, 15%)
29
36
  border-bottom: 1px solid lighten($navbar-inverse-bg, 5%)
30
37
 
38
+ .scheduled-info
39
+ padding: 15px
40
+ background-color: lighten($slate-blue, 30%)
41
+ border-bottom: 1px solid lighten($navbar-inverse-bg, 15%)
42
+
31
43
  .github-links
32
44
  padding: 15px
33
45
  background-color: lighten($slate-blue, 25%)
@@ -85,7 +85,7 @@ $woods-green: #3F8000
85
85
  $background-outer: #ECF7F4
86
86
  $slate-blue: #80A6BF
87
87
  $highlight-blue: #00026D
88
- //$highlight-blue: tomato
88
+ $dark-slate-blue: darken($slate-blue, 20%) !default
89
89
 
90
90
  // Tag colors
91
91
  $engagement-tag-color: $red
@@ -1,5 +1,5 @@
1
1
  class AlertMailer < ActionMailer::Base
2
- default from: ALERTS_CONFIG['from']
2
+ default from: EMAIL_CONFIG['from']
3
3
 
4
4
  def alert_failing_email(alert)
5
5
  @alert = alert
@@ -0,0 +1,10 @@
1
+ class QueryMailer < ActionMailer::Base
2
+ default from: EMAIL_CONFIG['from']
3
+
4
+ def query_result_email(query)
5
+ @query = query
6
+ @presigned_url = AwsS3.presigned_url(@query.latest_result_key, "result_for_query_#{@query.id}.csv", 3600 * 24)
7
+ Rails.logger.error("Could not generate presigned_url for query id = #{@query.id}, make sure #{@query.latest_result_object_url} exists?") unless @presigned_url.present?
8
+ mail(to: @query.email, subject: "Scheduled Aleph query '#{@query.title}'")
9
+ end
10
+ end
data/app/models/query.rb CHANGED
@@ -20,8 +20,10 @@ class Query < ActiveRecord::Base
20
20
  delegate :version, :author_name, :results, to: :latest_query_version, prefix: :latest, allow_nil: true
21
21
  delegate :id, to: :latest_query_version, prefix: true, allow_nil: true
22
22
  delegate :to_csv, to: :latest_completed_result, allow_nil: true
23
+ delegate :user, to: :latest_query_version
23
24
 
24
25
  scope :with_role, ->(role) { includes(:query_roles).where(query_roles: { role: role }) }
26
+ scope :scheduled, -> { where(scheduled_flag: true) }
25
27
 
26
28
  LOCATIONS_FOR_ATTRIBUTES = {
27
29
  title: { association: :base, column: :title, type: :text },
@@ -36,6 +38,12 @@ class Query < ActiveRecord::Base
36
38
 
37
39
  paginate_with LOCATIONS_FOR_ATTRIBUTES
38
40
 
41
+ def self.run_scheduled
42
+ scheduled.each do |query|
43
+ Resque.enqueue(ScheduledQueryExecution, query.id, query.user.role)
44
+ end
45
+ end
46
+
39
47
  def latest_completed_result
40
48
  latest_results.completed.last
41
49
  end
@@ -48,10 +56,22 @@ class Query < ActiveRecord::Base
48
56
  end
49
57
  end
50
58
 
59
+ def send_result_email
60
+ QueryMailer.query_result_email(self).deliver_now!
61
+ end
62
+
51
63
  def latest_query_version
52
64
  query_versions.last
53
65
  end
54
66
 
67
+ def latest_result_key
68
+ @latest_result_key ||= "latest_#{AwsS3::S3_FOLDER}/query_#{id}.csv"
69
+ end
70
+
71
+ def latest_result_object_url
72
+ @latest_result_object_url ||= "https://s3.amazonaws.com/#{AwsS3::S3_BUCKET}/#{latest_result_key}"
73
+ end
74
+
55
75
  def roles
56
76
  query_roles.map(&:role).uniq
57
77
  end
@@ -77,7 +97,7 @@ class Query < ActiveRecord::Base
77
97
 
78
98
  def summary
79
99
  Summarizer.new(query_versions).reduce(version: 0, comments: 0) do |qv|
80
- { versions: 1, comments: qv.comment.blank? ? 0 : 1}
100
+ { versions: 1, comments: qv.comment.blank? ? 0 : 1 }
81
101
  end
82
102
  end
83
103
 
data/app/models/result.rb CHANGED
@@ -24,6 +24,7 @@ class Result < ActiveRecord::Base
24
24
 
25
25
  def mark_complete_with_count(row_count)
26
26
  update_attributes!(status: 'complete', row_count: row_count, completed_at: Time.now)
27
+ copy_latest_result
27
28
  end
28
29
 
29
30
  def mark_failed!(message)
@@ -34,10 +35,6 @@ class Result < ActiveRecord::Base
34
35
  super || ongoing_row_count
35
36
  end
36
37
 
37
- def result_csv
38
- @result_csv ||= ResultCsv.new(id)
39
- end
40
-
41
38
  def redis_result_row_count
42
39
  @redis_result_row_count ||= RedisResultRowCount.new(self)
43
40
  end
@@ -50,6 +47,12 @@ class Result < ActiveRecord::Base
50
47
  duration(:created_at, :started_at)
51
48
  end
52
49
 
50
+ def copy_latest_result
51
+ if AwsS3.s3_enabled? && query.present? && query.scheduled_flag
52
+ AwsS3.copy(current_result_s3_key, query.latest_result_key)
53
+ end
54
+ end
55
+
53
56
  private
54
57
 
55
58
  def duration(start_field, end_field)
@@ -64,4 +67,8 @@ class Result < ActiveRecord::Base
64
67
  0
65
68
  end
66
69
  end
70
+
71
+ def current_result_s3_key
72
+ @result_key ||= CsvHelper::Aws.new(id).key
73
+ end
67
74
  end
@@ -0,0 +1,23 @@
1
+ class ScheduledQueryExecution
2
+ @queue = :query_exec
3
+
4
+ def self.perform(query_id, role)
5
+ query = Query.find(query_id)
6
+
7
+ interaction = Interaction::ResultCreation.new(
8
+ query_version_id: query.latest_query_version.id,
9
+ owner: query.user
10
+ )
11
+
12
+ result = interaction.execute
13
+
14
+ if interaction.errors.any?
15
+ query.error(interaction.errors.join(', '))
16
+ else
17
+ query.add_result(result)
18
+ query.save!
19
+ QueryExecution.perform(result.id, role)
20
+ query.send_result_email if query.email.present?
21
+ end
22
+ end
23
+ end
@@ -3,6 +3,6 @@ class QuerySerializer < ActiveModel::Serializer
3
3
  object.performant_tag_list
4
4
  end
5
5
 
6
- attributes :id, :title, :created_at, :updated_at, :tags, :roles
6
+ attributes :id, :title, :created_at, :updated_at, :tags, :roles, :latest_result_object_url, :email, :scheduled_flag
7
7
  has_one :version
8
8
  end
@@ -42,6 +42,8 @@
42
42
  = render partial: 'running_results/index'
43
43
  %script#comments-template{type: 'text/ng-template'}
44
44
  = render partial: 'queries/comments'
45
+ %script#scheduled-template{type: 'text/ng-template'}
46
+ = render partial: 'queries/scheduled'
45
47
  :javascript
46
48
  window.flash = #{flash.to_hash.to_json};
47
49
  %body{ 'ng-controller' => 'BodyController',
@@ -80,7 +82,7 @@
80
82
  %uib-alert.alert-fade-out.ellipsis{ 'ng-repeat' => 'alert in alerts',
81
83
  'type' => '{{alert.type}}',
82
84
  'close' => 'dismiss()',
83
- 'dismiss-on-timeout' => 9000,
85
+ 'dismiss-on-timeout' => 5000,
84
86
  'ng-bind' => 'alert.message' }
85
87
  %div.content.container-fluid
86
88
  = yield
@@ -1,5 +1,11 @@
1
1
  .comments
2
+ %span.control-btn.glyphicon.pull-right.subdued-clickable{ 'ng-click' => 'queryDetailsCtrl.updateCommentDialogAndClose()',
3
+ 'ng-class' => "{ 'glyphicon-remove': queryDetailsCtrl.query.isPristine(), 'glyphicon-save': queryDetailsCtrl.query.isDirty()}",
4
+ 'uib-tooltip' => "{{queryDetailsCtrl.query.isDirty() ? 'Save' : 'Close'}}",
5
+ 'tooltip-placement' => 'top' }
6
+ %span.control-btn.glyphicon.glyphicon-refresh.pull-right.subdued-clickable{ 'ng-click' => 'queryDetailsCtrl.query.revert()',
7
+ 'uib-tooltip' => 'Refresh',
8
+ 'ng-if' => 'queryDetailsCtrl.query.isDirty()',
9
+ 'tooltip-placement' => 'top' }
2
10
  %textarea.form-control{ 'ng-model' => 'queryDetailsCtrl.query.item.version.comment',
3
- 'placeholder' => 'Add a comment',
4
- 'ng-blur' => 'queryDetailsCtrl.updateQuery()' }
5
- .btn-group
11
+ 'placeholder' => 'Add a comment' }
@@ -14,16 +14,16 @@
14
14
  .ellipsis{ 'ng-bind' => 'query.title' }
15
15
  .col-md-4
16
16
  %div#author
17
- %a{ 'href' => '#',
17
+ %a.column-spacer{ 'href' => '#',
18
18
  'ng-bind' => 'query.latest_author_name',
19
19
  'ng-click' => "queryIdxCtrl.pagination.setSearch('author:' + query.latest_author_name, true)",
20
20
  'uib-tooltip' => "Filter by {{query.latest_author_name}}",
21
21
  'tooltip-delay' => 700,
22
22
  'tooltip-placement' => 'top' }
23
23
  %div#updated-at
24
- %span{ 'ng-bind' => 'query.updated_at | date:dateFormat: "UTC"' }
24
+ %span.column-spacer{ 'ng-bind' => 'query.updated_at | date:dateFormat: "UTC"' }
25
25
  %div#created-at
26
- %span{ 'ng-bind' => 'query.created_at | date:dateFormat: "UTC"' }
26
+ %span.column-spacer{ 'ng-bind' => 'query.created_at | date:dateFormat: "UTC"' }
27
27
  .col-md-2
28
28
  %span.label.tag{ 'ng-repeat' => 'tag in query.tags | limitTo:5 | orderBy',
29
29
  'ng-bind' => 'tag',
@@ -10,17 +10,17 @@
10
10
  .col-md-4
11
11
  %div#author
12
12
  %strong
13
- %a{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("author")', 'title' => 'Sort By Author' }
13
+ %a.column-spacer{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("author")', 'title' => 'Sort By Author' }
14
14
  AUTHOR
15
15
  .glyphicon.glyphicon-sort.tiny-icon
16
16
  %div#updated-at
17
17
  %strong
18
- %a{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("updated_at")', 'title' => 'Sort By Updated' }
18
+ %a.column-spacer{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("updated_at")', 'title' => 'Sort By Updated' }
19
19
  UPDATED
20
20
  .glyphicon.glyphicon-sort.tiny-icon
21
21
  %div#created-at
22
22
  %strong
23
- %a{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("created_at")', 'title' => 'Sort By Created' }
23
+ %a.column-spacer{ 'ng-click' => 'queryIdxCtrl.pagination.setSort("created_at")', 'title' => 'Sort By Created' }
24
24
  CREATED
25
25
  .glyphicon.glyphicon-sort.tiny-icon
26
26
  .col-md-2
@@ -1,9 +1,9 @@
1
- .panel.panel-default.no-border
1
+ .panel.panel-default
2
2
  %form{ 'ng-submit' => 'queryDetailsCtrl.updateQuery()',
3
3
  'name' => 'queryDetailsCtrl.form',
4
4
  'id' => 'form',
5
5
  'novalidate' => '' }
6
- = text_field_tag :query_title, '', placeholder: 'Query title', 'ng-model' => 'queryDetailsCtrl.query.item.title', 'ng-blur' => 'queryDetailsCtrl.updateQuery()', class: 'query-title-form'
6
+ = text_field_tag :query_title, '', placeholder: 'Query title', 'ng-model' => 'queryDetailsCtrl.query.item.title', 'ng-blur' => 'queryDetailsCtrl.updateTitle()', class: 'query-title-form'
7
7
  %div{ 'uib-popover' => 'Read Only!',
8
8
  'popover-trigger' => 'mouseenter',
9
9
  'popover-popup-delay' => 500,
@@ -31,22 +31,32 @@
31
31
  'tooltip-append-to-body' => 'true',
32
32
  'tooltip-popup-delay' => 800 }
33
33
  %span.glyphicon.glyphicon-trash.glyphicons-lg.glyphicon-low
34
- %span.btn-group#query-btns.pull-right
35
- %button.btn.btn-sm.btn-warning{ 'uib-tooltip' => 'Click to comment',
36
- 'tooltip-append-to-body' => 'true',
37
- 'tooltip-placement' => 'top',
38
- 'tooltip-popup-delay' => 800,
39
- 'uib-popover-template' => "'comments-template'",
40
- 'popover-is-open' => 'queryDetailsCtrl.commentDialogOpen',
41
- 'popover-title' => 'Comment',
42
- 'ng-click' => 'queryDetailsCtrl.toggleCommentDialog()' }
34
+ %span.btn-group.white-btns.pull-right
35
+ %button.btn.btn-sm{ 'uib-tooltip' => 'Schedule',
36
+ 'tooltip-append-to-body' => 'true',
37
+ 'tooltip-placement' => 'top',
38
+ 'tooltip-popup-delay' => 800,
39
+ 'uib-popover-template' => "'scheduled-template'",
40
+ 'popover-title' => 'Schedule Query',
41
+ 'popover-is-open' => 'queryDetailsCtrl.scheduleDialogOpen',
42
+ 'ng-click' => 'queryDetailsCtrl.toggleScheduleDialog()' }
43
+ %span.glyphicon.glyphicon-time.glyphicons-lg.glyphicon-low
44
+ %span.btn-group.white-btns.pull-right
45
+ %button.btn.btn-sm{ 'uib-tooltip' => 'Comment',
46
+ 'tooltip-append-to-body' => 'true',
47
+ 'tooltip-placement' => 'top',
48
+ 'tooltip-popup-delay' => 800,
49
+ 'uib-popover-template' => "'comments-template'",
50
+ 'popover-is-open' => 'queryDetailsCtrl.commentDialogOpen',
51
+ 'popover-title' => 'Comment',
52
+ 'ng-click' => 'queryDetailsCtrl.toggleCommentDialog()' }
43
53
  %span.glyphicon.glyphicon-comment.glyphicons-lg.glyphicon-low
44
- %span.btn-group#clone-btn.pull-right
45
- %button.btn.btn-sm.btn-info{ 'uib-tooltip' => 'Clone',
46
- 'tooltip-append-to-body' => 'true',
47
- 'tooltip-placement' => 'top',
48
- 'tooltip-popup-delay' => 800,
49
- 'ng-click' => 'queryDetailsCtrl.cloneQuery()' }
54
+ %span.btn-group.white-btns.pull-right
55
+ %button.btn.btn-sm{ 'uib-tooltip' => 'Clone',
56
+ 'tooltip-append-to-body' => 'true',
57
+ 'tooltip-placement' => 'top',
58
+ 'tooltip-popup-delay' => 800,
59
+ 'ng-click' => 'queryDetailsCtrl.cloneQuery()' }
50
60
  %span.glyphicon.glyphicon-duplicate.glyphicons-lg.glyphicon-low
51
61
  .row
52
62
  .col-md-4
@@ -73,16 +83,16 @@
73
83
  .panel-heading.bold Tags
74
84
  %tags-input{ 'ng-model' => 'queryDetailsCtrl.query.item.tags',
75
85
  'template' => 'tag-template',
76
- 'on-tag-added' => 'queryDetailsCtrl.updateQuery()',
77
- 'on-tag-removed' => 'queryDetailsCtrl.updateQuery()' }
86
+ 'on-tag-added' => 'queryDetailsCtrl.updateTagsAndRoles()',
87
+ 'on-tag-removed' => 'queryDetailsCtrl.updateTagsAndRoles()' }
78
88
  %auto-complete{'source' => 'queryDetailsCtrl.loadTags($query)'}
79
89
  .col-md-4
80
90
  .panel.panel-default.tag-panel.small-font
81
91
  .panel-heading.bold Roles
82
92
  %tags-input{ 'ng-model' => 'queryDetailsCtrl.query.item.roles',
83
93
  'template' => 'role-template',
84
- 'on-tag-added' => 'queryDetailsCtrl.updateQuery()',
85
- 'on-tag-removed' => 'queryDetailsCtrl.updateQuery()',
94
+ 'on-tag-added' => 'queryDetailsCtrl.updateTagsAndRoles()',
95
+ 'on-tag-removed' => 'queryDetailsCtrl.updateTagsAndRoles()',
86
96
  'placeholder' => 'Add a role',
87
97
  'add-from-autocomplete-only' => 'true' }
88
98
  %auto-complete{'source' => 'queryDetailsCtrl.loadRoles($query)'}
@@ -3,24 +3,42 @@
3
3
  .current-version
4
4
  %strong Current Version: {{qvSidebarCtrl.query.item.version.version}}
5
5
  %p
6
- .octicon.octicon-calendar
7
- {{qvSidebarCtrl.query.item.version.created_at | date:dateFormat: "UTC"}}
8
- %br
9
- .octicon.octicon-pencil
10
- {{qvSidebarCtrl.query.item.version.author_name}}
6
+ .version-item
7
+ .octicon.octicon-calendar
8
+ {{qvSidebarCtrl.query.item.version.created_at | date:dateFormat: "UTC"}}
9
+ .version-item
10
+ .octicon.octicon-pencil
11
+ {{qvSidebarCtrl.query.item.version.author_name}}
12
+ .row{ 'ng-if' => 'qvSidebarCtrl.queryIsPersistedAsScheduled()' }
13
+ .scheduled-info
14
+ .version-item
15
+ .octicon.octicon-clock
16
+ Scheduled
17
+ .version-item
18
+ .octicon.octicon-clippy
19
+ %a{ 'href' => '',
20
+ 'text' => 'qvSidebarCtrl.query.item.latest_result_object_url',
21
+ 'supported' => 'supported',
22
+ 'on-copied' => 'qvSidebarCtrl.alertResultLinkCopied()',
23
+ 'clipboard' => '',
24
+ 'tooltip-append-to-body' => 'true',
25
+ 'uib-tooltip' => 'Copy latest result s3 URL',
26
+ 'tooltip-placement' => 'left' }
27
+ Result S3 URL
11
28
  .row{ 'ng-if' => 'qvSidebarCtrl.githubIsEnabled()' }
12
29
  .github-links
13
- %span.octicon.octicon-mark-github
14
- %a{'ng-href' => '{{qvSidebarCtrl.githubHistory}}'} Git History
15
- %br
16
- %span.octicon.octicon-mark-github
17
- %a{'ng-href' => '{{qvSidebarCtrl.githubCommit}}'} Git Commit
18
- %br
19
- %span.octicon.octicon-mark-github
20
- %span{ 'ng-if' => 'qvSidebarCtrl.selectedVersions.length !== 2',
21
- 'style' => 'opacity:0.5' } Git Compare
22
- %a{ 'ng-if' => 'qvSidebarCtrl.selectedVersions.length === 2',
23
- 'ng-href' => '{{qvSidebarCtrl.githubCompare}}' } Git Compare
30
+ .version-item
31
+ .octicon.octicon-mark-github
32
+ %a{'ng-href' => '{{qvSidebarCtrl.githubHistory}}'} Git History
33
+ .version-item
34
+ .octicon.octicon-mark-github
35
+ %a{'ng-href' => '{{qvSidebarCtrl.githubCommit}}'} Git Commit
36
+ .version-item
37
+ .octicon.octicon-mark-github
38
+ %span{ 'ng-if' => 'qvSidebarCtrl.selectedVersions.length !== 2',
39
+ 'style' => 'opacity:0.5' } Git Compare
40
+ %a{ 'ng-if' => 'qvSidebarCtrl.selectedVersions.length === 2',
41
+ 'ng-href' => '{{qvSidebarCtrl.githubCompare}}' } Git Compare
24
42
  .row
25
43
  .versions
26
44
  %ul
@@ -0,0 +1,31 @@
1
+ .scheduled
2
+ .row.container.control-bar
3
+ %span.glyphicon.pull-right.control-btn.subdued-clickable{ 'ng-click' => 'queryDetailsCtrl.updateScheduleDialogAndClose()',
4
+ 'ng-class' => "{ 'glyphicon-remove': queryDetailsCtrl.query.isPristine(), 'glyphicon-save': queryDetailsCtrl.query.isDirty()}",
5
+ 'uib-tooltip' => "{{queryDetailsCtrl.query.isDirty() ? 'Save' : 'Close'}}",
6
+ 'tooltip-placement' => 'top' }
7
+ %span.glyphicon.glyphicon-refresh.pull-right.control-btn.subdued-clickable{ 'ng-click' => 'queryDetailsCtrl.query.revert()',
8
+ 'uib-tooltip' => 'Refresh',
9
+ 'ng-if' => 'queryDetailsCtrl.query.isDirty()',
10
+ 'tooltip-placement' => 'top' }
11
+ .row.container.toggle-bar
12
+ .col-sm-3
13
+ .col-sm-1.pad1
14
+ Off
15
+ .col-sm-4.toggle-center
16
+ %label.switch.switch-section
17
+ %input{ 'type' => 'checkbox',
18
+ 'ng-model' => 'queryDetailsCtrl.query.item.scheduled_flag' }
19
+ %span.slider.round
20
+ .col-sm-1.pad1
21
+ On
22
+ .col-sm-3
23
+ .row.container.email-bar
24
+ .col-sm-1.email-label
25
+ %span.glyphicon.glyphicon-envelope.glyphicons-lg.glyphicon-low
26
+ .col-sm-11.email-input-col
27
+ %form{ name: 'queryEmailForm', id: 'queryEmailForm', novalidate: '' }
28
+ %input.input-xs{ 'type' => 'text',
29
+ 'ng-model' => 'queryDetailsCtrl.query.item.email',
30
+ 'class' => 'form-control',
31
+ 'placeholder' => 'Email' }
@@ -0,0 +1,7 @@
1
+ %head
2
+ %meta{content: 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
3
+ %body
4
+ %h1= "Your Aleph query has run as scheduled"
5
+ = link_to("Download result", @presigned_url)
6
+ %br
7
+ = link_to('Go to this query', query_url(@query.id))
@@ -34,4 +34,7 @@ Rails.application.configure do
34
34
 
35
35
  # Raises error for missing translations
36
36
  # config.action_view.raise_on_missing_translations = true
37
+
38
+ # Propagate errors raised within `after_rollback`/`after_commit` callbacks
39
+ config.active_record.raise_in_transactional_callbacks = true
37
40
  end