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
@@ -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