blazer 1.7.2 → 1.7.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of blazer might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d8af782cbd8374eb05295ae7fbd31766198adb1
4
- data.tar.gz: f825ed76228ddf5eee748c9f48f252a358b206d3
3
+ metadata.gz: 6bdae12ea224ba2311ce33fdbc05dffbbc938cee
4
+ data.tar.gz: 635a76501e3608e8a188cdfdc3186b497e6337fd
5
5
  SHA512:
6
- metadata.gz: 8010c7ef1b87607b5d1c19980358c615fec43e711c1d50fd621b052efaa64c5bba165032f006a4a47b299680431d91ae84b48bd7bdb873de1519ca5827a7b32f
7
- data.tar.gz: 84fffc2f2ea73319dc98df13ee7798b8d5411f1b44427a46db58d4a5cba2bf1896f759ef804ee925e253231cc8c1038f71759d16e2db62301bbb8159422d573b
6
+ metadata.gz: 9e81386804c7030a74a75f959f936e3ff0053c9e8e2a17f78cff84897850942f124a989f7258d429e836b0aeacf8a138f59e47ed5a35ac8686f37ecdfbd77222
7
+ data.tar.gz: f1c1da1a30477aae06877313f2130b6a6140962a31c29761938b04fad93baad8cb036fcd79a24f91c52212690f0cecd3dde7d563ecde799370fa61aac2a70353
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.7.3
2
+
3
+ - Fixed JavaScript errors
4
+ - Fixed query cancel error
5
+ - Return search results for "me" or "mine"
6
+ - Include sample data in email when bad data checks fail
7
+ - Fixed deprecation warnings
8
+
1
9
  ## 1.7.2
2
10
 
3
11
  - Cancel all queries on page nav
@@ -15,6 +15,7 @@
15
15
  //= require ./vue
16
16
  //= require ./routes
17
17
  //= require ./queries
18
+ //= require ./fuzzysearch
18
19
 
19
20
  Vue.config.devtools = false
20
21
 
@@ -74,139 +75,5 @@ function preventBackspaceNav() {
74
75
  })
75
76
  }
76
77
 
77
- var editor
78
-
79
- // http://stackoverflow.com/questions/11584061/
80
- function adjustHeight() {
81
- var lines = editor.getSession().getScreenLength()
82
- if (lines < 9) {
83
- lines = 9
84
- }
85
-
86
- var newHeight = (lines + 1) * 16
87
- $("#editor").height(newHeight.toString() + "px")
88
- editor.resize()
89
- }
90
-
91
- function getSQL() {
92
- var selectedText = editor.getSelectedText()
93
- var text = selectedText.length < 10 ? editor.getValue() : selectedText
94
- return text.replace(/\n/g, "\r\n")
95
- }
96
-
97
- function getErrorLine() {
98
- var error_line = /LINE (\d+)/g.exec($("#results").find('.alert-danger').text())
99
-
100
- if (error_line) {
101
- error_line = parseInt(error_line[1], 10)
102
- if (editor.getSelectedText().length >= 10) {
103
- error_line += editor.getSelectionRange().start.row
104
- }
105
- return error_line
106
- }
107
- }
108
-
109
- var error_line = null
110
-
111
- $(document).on("click", "#cancel", function (e) {
112
- e.preventDefault()
113
-
114
- cancelAllQueries()
115
-
116
- queryDone()
117
-
118
- $("#results").html("")
119
- })
120
-
121
- function queryDone() {
122
- $("#run").removeClass("hide")
123
- $("#cancel").addClass("hide")
124
- }
125
-
126
- $(document).on("click", "#run", function (e) {
127
- e.preventDefault()
128
-
129
- $(this).addClass("hide")
130
- $("#cancel").removeClass("hide")
131
-
132
- if (error_line) {
133
- editor.getSession().removeGutterDecoration(error_line - 1, "error")
134
- error_line = null
135
- }
136
-
137
- $("#results").html('<p class="text-muted">Loading...</p>')
138
-
139
- var data = $.extend({}, params, {statement: getSQL(), data_source: $("#query_data_source").val()})
140
-
141
- cancelAllQueries()
142
-
143
- runQuery(data, function (data) {
144
- queryDone()
145
-
146
- $("#results").html(data)
147
-
148
- error_line = getErrorLine()
149
- if (error_line) {
150
- editor.getSession().addGutterDecoration(error_line - 1, "error")
151
- editor.scrollToLine(error_line, true, true, function () {})
152
- editor.gotoLine(error_line, 0, true)
153
- editor.focus()
154
- }
155
- }, function (data) {
156
- // TODO show error
157
- queryDone()
158
- })
159
- })
160
-
161
- $(document).on("change", "#table_names", function () {
162
- var val = $(this).val()
163
- if (val.length > 0) {
164
- var dataSource = $("#query_data_source").val()
165
- editor.setValue(previewStatement[dataSource].replace("{table}", val), 1)
166
- $("#run").click()
167
- }
168
- })
169
-
170
- function showEditor() {
171
- editor = ace.edit("editor")
172
- editor.setTheme("ace/theme/twilight")
173
- editor.getSession().setMode("ace/mode/sql")
174
- editor.setOptions({
175
- enableBasicAutocompletion: false,
176
- enableSnippets: false,
177
- enableLiveAutocompletion: false,
178
- highlightActiveLine: false,
179
- fontSize: 12,
180
- minLines: 10
181
- })
182
- editor.renderer.setShowGutter(true)
183
- editor.renderer.setPrintMarginColumn(false)
184
- editor.renderer.setPadding(10)
185
- editor.getSession().setUseWrapMode(true)
186
- editor.commands.addCommand({
187
- name: 'run',
188
- bindKey: {win: 'Ctrl-Enter', mac: 'Command-Enter'},
189
- exec: function(editor) {
190
- $("#run").click()
191
- },
192
- readOnly: false // false if this command should not apply in readOnly mode
193
- })
194
- // fix command+L
195
- editor.commands.removeCommands(["gotoline", "find"])
196
-
197
- editor.getSession().on("change", function () {
198
- $("#query_statement").val(editor.getValue())
199
- adjustHeight()
200
- })
201
- adjustHeight()
202
- $("#editor").show()
203
- editor.focus()
204
- }
205
-
206
78
  preventBackspaceNav()
207
79
 
208
- function updatePreviewSelect() {
209
- var dataSource = $("#query_data_source").val()
210
- $("#tables").load(Routes.blazer_tables_queries_path({data_source: dataSource}))
211
- $("#view-schema").attr("href", Routes.blazer_schema_queries_path({data_source: dataSource}))
212
- }
@@ -0,0 +1,24 @@
1
+ // https://github.com/bevacqua/fuzzysearch
2
+ // Copyright 2015 Nicolas Bevacqua
3
+ // MIT License
4
+
5
+ function fuzzysearch (needle, haystack) {
6
+ var hlen = haystack.length;
7
+ var nlen = needle.length;
8
+ if (nlen > hlen) {
9
+ return false;
10
+ }
11
+ if (nlen === hlen) {
12
+ return needle === haystack;
13
+ }
14
+ outer: for (var i = 0, j = 0; i < nlen; i++) {
15
+ var nch = needle.charCodeAt(i);
16
+ while (j < hlen) {
17
+ if (haystack.charCodeAt(j++) === nch) {
18
+ continue outer;
19
+ }
20
+ }
21
+ return false;
22
+ }
23
+ return true;
24
+ }
@@ -30,7 +30,7 @@ function runNext() {
30
30
 
31
31
  function runQueryHelper(query) {
32
32
  var xhr = $.ajax({
33
- url: Routes.blazer_run_queries_path(),
33
+ url: Routes.run_queries_path(),
34
34
  method: "POST",
35
35
  data: query.data,
36
36
  dataType: "html"
@@ -89,7 +89,7 @@ function cancelQuery(query) {
89
89
  }
90
90
 
91
91
  // tell server
92
- var path = Routes.blazer_cancel_queries_path()
92
+ var path = Routes.cancel_queries_path()
93
93
  var data = {run_id: query.run_id, data_source: query.data_source}
94
94
  if (navigator.sendBeacon) {
95
95
  navigator.sendBeacon(path, csrfProtect(data))
@@ -103,5 +103,5 @@ function csrfProtect(payload) {
103
103
  var param = $("meta[name=csrf-param]").attr("content")
104
104
  var token = $("meta[name=csrf-token]").attr("content")
105
105
  if (param && token) payload[param] = token
106
- return new Blob([JSON.stringify(payload)], {type : "application/json charset=utf-8"})
106
+ return new Blob([JSON.stringify(payload)], {type : "application/json; charset=utf-8"})
107
107
  }
@@ -1 +1,26 @@
1
- <%= JsRoutes.generate(include: /blazer/) %>
1
+ <%#= JsRoutes.generate(engine: Blazer::Engine, prefix: Blazer::Engine.app.url_helpers.root_path) %>
2
+
3
+ // temp fix
4
+ var Routes = {
5
+ run_queries_path: function() {
6
+ return gon.root_path + "queries/run"
7
+ },
8
+ cancel_queries_path: function() {
9
+ return gon.root_path + "queries/cancel"
10
+ },
11
+ schema_queries_path: function(params) {
12
+ return gon.root_path + "queries/schema?data_source=" + params.data_source
13
+ },
14
+ tables_queries_path: function(params) {
15
+ return gon.root_path + "queries/tables?data_source=" + params.data_source
16
+ },
17
+ queries_path: function() {
18
+ return gon.root_path + "queries"
19
+ },
20
+ query_path: function(id) {
21
+ return gon.root_path + "queries/" + id
22
+ },
23
+ dashboard_path: function(id) {
24
+ return gon.root_path + "dashboards/" + id
25
+ }
26
+ }
@@ -66,7 +66,6 @@ input.search:focus {
66
66
  }
67
67
 
68
68
  #editor {
69
- display: none;
70
69
  height: 160px;
71
70
  }
72
71
 
@@ -93,7 +92,7 @@ input.search:focus {
93
92
  text-align: left;
94
93
  }
95
94
 
96
- .dashboard a {
95
+ .dashboard {
97
96
  font-weight: bold;
98
97
  }
99
98
 
@@ -178,3 +177,16 @@ input.search:focus {
178
177
  [v-cloak] {
179
178
  display: none;
180
179
  }
180
+
181
+ .chart-container {
182
+ padding-top: 10px;
183
+ clear: both;
184
+ }
185
+
186
+ .chart-container h4 {
187
+ text-align: center;
188
+ }
189
+
190
+ .chart-container h4 a {
191
+ color: inherit;
192
+ }
@@ -19,6 +19,7 @@ module Blazer
19
19
  if Blazer.before_action
20
20
  before_action Blazer.before_action.to_sym
21
21
  end
22
+ before_action :set_js_routes
22
23
 
23
24
  layout "blazer/application"
24
25
 
@@ -101,5 +102,11 @@ module Blazer
101
102
  action = resource.persisted? ? :edit : :new
102
103
  render action, status: :unprocessable_entity
103
104
  end
105
+
106
+ def set_js_routes
107
+ gon.push(
108
+ root_path: root_path
109
+ )
110
+ end
104
111
  end
105
112
  end
@@ -3,7 +3,7 @@ module Blazer
3
3
  before_action :set_dashboard, only: [:show, :edit, :update, :destroy, :refresh]
4
4
 
5
5
  def index
6
- @dashboards = Blazer::Dashboard.order(:name)
6
+ redirect_to root_path(filter: "dashboards")
7
7
  end
8
8
 
9
9
  def new
@@ -3,9 +3,13 @@ module Blazer
3
3
  before_action :set_query, only: [:show, :edit, :update, :destroy, :refresh]
4
4
 
5
5
  def home
6
- set_queries(1000)
6
+ if params[:filter] == "dashboards"
7
+ @queries = []
8
+ else
9
+ set_queries(1000)
10
+ end
7
11
 
8
- if params[:filter]
12
+ if params[:filter] && params[:filter] != "dashboards"
9
13
  @dashboards = [] # TODO show my dashboards
10
14
  else
11
15
  @dashboards = Blazer::Dashboard.order(:name)
@@ -176,8 +180,7 @@ module Blazer
176
180
  end
177
181
 
178
182
  def tables
179
- @tables = Blazer.data_sources[params[:data_source]].tables
180
- render partial: "tables", layout: false
183
+ render json: Blazer.data_sources[params[:data_source]].tables
181
184
  end
182
185
 
183
186
  def schema
@@ -3,13 +3,18 @@ module Blazer
3
3
  include ActionView::Helpers::TextHelper
4
4
 
5
5
  default from: Blazer.from_email if Blazer.from_email
6
+ layout false
6
7
 
7
- def state_change(check, state, state_was, rows_count, error)
8
+ def state_change(check, state, state_was, rows_count, error, columns, rows, column_types, check_type)
8
9
  @check = check
9
10
  @state = state
10
11
  @state_was = state_was
11
12
  @rows_count = rows_count
12
13
  @error = error
14
+ @columns = columns
15
+ @rows = rows
16
+ @column_types = column_types
17
+ @check_type = check_type
13
18
  mail to: check.emails, reply_to: check.emails, subject: "Check #{state.titleize}: #{check.query.name}"
14
19
  end
15
20
 
@@ -58,7 +58,7 @@ module Blazer
58
58
 
59
59
  # do not notify on creation, except when not passing
60
60
  if (state_was != "new" || state != "passing") && state != state_was && emails.present?
61
- Blazer::CheckMailer.state_change(self, state, state_was, result.rows.size, message).deliver_later
61
+ Blazer::CheckMailer.state_change(self, state, state_was, result.rows.size, message, result.columns, result.rows.first(10).as_json, result.column_types, check_type).deliver_later
62
62
  end
63
63
  save! if changed?
64
64
  end
@@ -1,6 +1,37 @@
1
- <p><%= link_to "View", query_url(@check.query_id) %></p>
2
- <% if @error %>
3
- <p><%= @error %></p>
4
- <% elsif @rows_count > 0 %>
5
- <p><%= pluralize(@rows_count, "row") %></p>
6
- <% end %>
1
+ <html>
2
+ <head>
3
+ </head>
4
+ <body style="font-family: 'Helvetica Neue', Arial, Helvetica; font-size: 14px; color: #333;">
5
+ <p><%= link_to "View", query_url(@check.query_id) %></p>
6
+ <% if @error %>
7
+ <p><%= @error %></p>
8
+ <% elsif @rows_count > 0 && @check_type == "bad_data" %>
9
+ <p><%= pluralize(@rows_count, "row") %></p>
10
+ <p><strong>Sample</strong></p>
11
+ <table style="width: 100%; border-spacing: 0; border-collapse: collapse;">
12
+ <thead>
13
+ <% @columns.first(5).each do |column| %>
14
+ <th style="padding: 8px; line-height: 1.4; text-align: left; vertical-align: bottom; border-bottom: 2px solid #ddd; width: <%= (100 / @columns.size).round(2) %>%;">
15
+ <%= column %>
16
+ </th>
17
+ <% end %>
18
+ </thead>
19
+ <tbody>
20
+ <% @rows.first(10).each do |row| %>
21
+ <tr>
22
+ <% @columns.first(5).each_with_index do |column, i| %>
23
+ <td style="padding: 8px; line-height: 1.4; vertical-align: top; border-top: 1px solid #ddd;">
24
+ <% value = row[i] %>
25
+ <% if @column_types[i] == "time" && value.to_s.length > 10 %>
26
+ <% value = Time.parse(value).in_time_zone(Blazer.time_zone) rescue value %>
27
+ <% end %>
28
+ <%= value %>
29
+ </td>
30
+ <% end %>
31
+ </tr>
32
+ <% end %>
33
+ </tbody>
34
+ </table>
35
+ <% end %>
36
+ </body>
37
+ </html>
@@ -28,8 +28,8 @@
28
28
  <%= render partial: "blazer/variables", locals: {action: dashboard_path(@dashboard)} %>
29
29
 
30
30
  <% @queries.each_with_index do |query, i| %>
31
- <div style="padding-top: 10px; clear: both;">
32
- <h4 style="text-align: center;"><%= link_to query.friendly_name, query_path(query, variable_params), target: "_blank", style: "color: inherit;" %></h4>
31
+ <div class="chart-container">
32
+ <h4><%= link_to query.friendly_name, query_path(query, variable_params), target: "_blank" %></h4>
33
33
  <div id="chart-<%= i %>" class="chart">
34
34
  <p class="text-muted">Loading...</p>
35
35
  </div>
@@ -2,69 +2,232 @@
2
2
  <div class="alert alert-danger"><%= @query.errors.full_messages.first %></div>
3
3
  <% end %>
4
4
 
5
- <%= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {class: "the_form", autocomplete: "off"} do |f| %>
6
- <div class="row">
7
- <div id="statement-box" class="col-xs-8">
8
- <div class= "form-group">
9
- <%= f.hidden_field :statement %>
10
- <div id="editor-container">
11
- <div id="editor"><%= @query.statement %></div>
5
+ <div id="app" v-cloak>
6
+ <%= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {class: "the_form", autocomplete: "off"} do |f| %>
7
+ <div class="row">
8
+ <div id="statement-box" class="col-xs-8">
9
+ <div class= "form-group">
10
+ <%= f.hidden_field :statement %>
11
+ <div id="editor-container">
12
+ <div id="editor" :style="{ height: editorHeight }"><%= @query.statement %></div>
13
+ </div>
14
+ </div>
15
+ <div class="form-group text-right">
16
+ <div class="pull-left" style="margin-top: 9px;">
17
+ <%= link_to "Back", :back %>
18
+ </div>
19
+ <a :href="dataSourcePath" target="_blank" style="margin-right: 10px;">Schema</a>
20
+ <%= f.select :data_source, Blazer.data_sources.values.select { |ds| q = @query.dup; q.data_source = ds.id; q.editable?(blazer_user) }.map { |ds| [ds.name, ds.id] }, {}, class: ("hide" if Blazer.data_sources.size == 1), style: "width: 140px;" %>
21
+ <div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;">
22
+ <select id="table_names" style="width: 240px;" placeholder="Preview table"></select>
23
+ </div>
24
+ <a v-on:click="run" v-if="!running" class="btn btn-info" style="vertical-align: top; width: 70px;">Run</a>
25
+ <a v-on:click="cancel" v-if="running" class="btn btn-danger" style="vertical-align: top; width: 70px;">Cancel</a>
12
26
  </div>
13
27
  </div>
14
- <div class="form-group text-right">
15
- <div class="pull-left" style="margin-top: 9px;">
16
- <%= link_to "Back", :back %>
28
+ <div class="col-xs-4">
29
+ <div class="form-group">
30
+ <%= f.label :name %>
31
+ <%= f.text_field :name, class: "form-control" %>
17
32
  </div>
18
- <%= link_to "Schema", "#", target: "_blank", id: "view-schema", style: "margin-right: 10px;" %>
19
- <%= f.select :data_source, Blazer.data_sources.values.select { |ds| q = @query.dup; q.data_source = ds.id; q.editable?(blazer_user) }.map { |ds| [ds.name, ds.id] }, {}, class: ("hide" if Blazer.data_sources.size == 1), style: "width: 140px;" %>
20
- <div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;" class="hide">
21
- <%= render partial: "tables" %>
33
+ <div class="form-group">
34
+ <%= f.label :description %>
35
+ <%= f.text_area :description, placeholder: "Optional", style: "height: 80px;", class: "form-control" %>
36
+ </div>
37
+ <div class="text-right">
38
+ <%= f.submit "For Enter Press", class: "hide" %>
39
+ <% if @query.persisted? %>
40
+ <%= link_to "Delete", query_path(@query), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
41
+ <%= f.submit "Fork", class: "btn btn-info" %>
42
+ <% end %>
43
+ <%= f.submit @query.persisted? ? "Update" : "Create", class: "btn btn-success" %>
22
44
  </div>
23
- <script>
24
- updatePreviewSelect();
25
- $("#query_data_source").selectize().change(updatePreviewSelect);
26
- </script>
27
- <%= link_to "Run", "#", class: "btn btn-info", id: "run", style: "vertical-align: top; width: 70px;" %>
28
- <%= link_to "Cancel", "#", class: "btn btn-danger hide", id: "cancel", style: "vertical-align: top; width: 70px;" %>
29
- </div>
30
- </div>
31
- <div class="col-xs-4">
32
- <div class="form-group">
33
- <%= f.label :name %>
34
- <%= f.text_field :name, class: "form-control" %>
35
- </div>
36
- <div class="form-group">
37
- <%= f.label :description %>
38
- <%= f.text_area :description, placeholder: "Optional", style: "height: 80px;", class: "form-control" %>
39
- </div>
40
- <div class="text-right">
41
- <%= f.submit "For Enter Press", class: "hide" %>
42
45
  <% if @query.persisted? %>
43
- <%= link_to "Delete", query_path(@query), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
44
- <%= f.submit "Fork", class: "btn btn-info" %>
46
+ <% dashboards_count = @query.dashboards.count %>
47
+ <% checks_count = @query.checks.count %>
48
+ <% words = [] %>
49
+ <% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
50
+ <% words << pluralize(checks_count, "check") if checks_count > 0 %>
51
+ <% if words.any? %>
52
+ <div class="alert alert-info" style="margin-top: 10px; padding: 8px 12px;">
53
+ Part of <%= words.to_sentence %>. Be careful when editing.
54
+ </div>
55
+ <% end %>
45
56
  <% end %>
46
- <%= f.submit @query.persisted? ? "Update" : "Create", class: "btn btn-success" %>
47
57
  </div>
48
- <% if @query.persisted? %>
49
- <% dashboards_count = @query.dashboards.count %>
50
- <% checks_count = @query.checks.count %>
51
- <% words = [] %>
52
- <% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
53
- <% words << pluralize(checks_count, "check") if checks_count > 0 %>
54
- <% if words.any? %>
55
- <div class="alert alert-info" style="margin-top: 10px; padding: 8px 12px;">
56
- Part of <%= words.to_sentence %>. Be careful when editing.
57
- </div>
58
- <% end %>
59
- <% end %>
60
58
  </div>
61
- </div>
62
- <% end %>
59
+ <% end %>
63
60
 
64
- <div id="results"></div>
61
+ <div id="results">
62
+ <p class="text-muted" v-if="running">Loading...</p>
63
+ <div id="results-html" v-if="!running"></div>
64
+ </div>
65
+ </div>
65
66
 
66
67
  <script>
67
68
  var params = <%= raw blazer_json_escape(variable_params.to_json) %>;
68
69
  var previewStatement = <%= raw blazer_json_escape(Hash[Blazer.data_sources.map { |k, v| [k, v.preview_statement] }].to_json) %>;
69
- showEditor();
70
+
71
+ var app = new Vue({
72
+ el: "#app",
73
+ data: {
74
+ running: false,
75
+ results: "",
76
+ dataSource: "",
77
+ selectize: null,
78
+ editorHeight: "180px"
79
+ },
80
+ computed: {
81
+ dataSourcePath: function() {
82
+ return Routes.schema_queries_path({data_source: this.dataSource})
83
+ }
84
+ },
85
+ methods: {
86
+ run: function(e) {
87
+ this.running = true
88
+ this.results = ""
89
+ cancelAllQueries()
90
+
91
+ var data = $.extend({}, params, {statement: this.getSQL(), data_source: $("#query_data_source").val()})
92
+
93
+ var _this = this
94
+
95
+ runQuery(data, function (data) {
96
+ _this.running = false
97
+ _this.showResults(data)
98
+
99
+ errorLine = _this.getErrorLine()
100
+ if (errorLine) {
101
+ editor.getSession().addGutterDecoration(errorLine - 1, "error")
102
+ editor.scrollToLine(errorLine, true, true, function () {})
103
+ editor.gotoLine(errorLine, 0, true)
104
+ editor.focus()
105
+ }
106
+ }, function (data) {
107
+ _this.running = false
108
+ _this.showResults(data)
109
+ })
110
+ },
111
+ cancel: function(e) {
112
+ this.running = false
113
+ cancelAllQueries()
114
+ },
115
+ updateDataSource: function(dataSource) {
116
+ this.dataSource = dataSource
117
+ var _this = this
118
+
119
+ $.getJSON(Routes.tables_queries_path({data_source: this.dataSource}), function(data) {
120
+ var newOptions = []
121
+ for (var i = 0; i < data.length; i++) {
122
+ newOptions.push({text: data[i], value: data[i]})
123
+ }
124
+ var selectize = _this.selectize
125
+ selectize.clearOptions()
126
+ selectize.addOption(newOptions)
127
+ selectize.refreshOptions(false)
128
+ })
129
+ },
130
+ showEditor: function() {
131
+ var _this = this
132
+
133
+ editor = ace.edit("editor")
134
+ editor.setTheme("ace/theme/twilight")
135
+ editor.getSession().setMode("ace/mode/sql")
136
+ editor.setOptions({
137
+ enableBasicAutocompletion: false,
138
+ enableSnippets: false,
139
+ enableLiveAutocompletion: false,
140
+ highlightActiveLine: false,
141
+ fontSize: 12,
142
+ minLines: 10
143
+ })
144
+ editor.renderer.setShowGutter(true)
145
+ editor.renderer.setPrintMarginColumn(false)
146
+ editor.renderer.setPadding(10)
147
+ editor.getSession().setUseWrapMode(true)
148
+ editor.commands.addCommand({
149
+ name: "run",
150
+ bindKey: {win: "Ctrl-Enter", mac: "Command-Enter"},
151
+ exec: function(editor) {
152
+ _this.run()
153
+ },
154
+ readOnly: false // false if this command should not apply in readOnly mode
155
+ })
156
+ // fix command+L
157
+ editor.commands.removeCommands(["gotoline", "find"])
158
+
159
+ this.editor = editor
160
+
161
+ editor.getSession().on("change", function () {
162
+ $("#query_statement").val(editor.getValue())
163
+ _this.adjustHeight()
164
+ })
165
+ this.adjustHeight()
166
+ editor.focus()
167
+ },
168
+ adjustHeight: function() {
169
+ // http://stackoverflow.com/questions/11584061/
170
+ var editor = this.editor
171
+ var lines = editor.getSession().getScreenLength()
172
+ if (lines < 9) {
173
+ lines = 9
174
+ }
175
+
176
+ this.editorHeight = ((lines + 1) * 16).toString() + "px"
177
+
178
+ Vue.nextTick(function () {
179
+ editor.resize()
180
+ })
181
+ },
182
+ getSQL: function() {
183
+ var selectedText = editor.getSelectedText()
184
+ var text = selectedText.length < 10 ? editor.getValue() : selectedText
185
+ return text.replace(/\n/g, "\r\n")
186
+ },
187
+ getErrorLine: function() {
188
+ var editor = this.editor
189
+ var errorLine = this.results.substring(0, 100).includes("alert-danger") && /LINE (\d+)/g.exec(this.results)
190
+
191
+ if (errorLine) {
192
+ errorLine = parseInt(errorLine[1], 10)
193
+ if (editor.getSelectedText().length >= 10) {
194
+ errorLine += editor.getSelectionRange().start.row
195
+ }
196
+ return errorLine
197
+ }
198
+ },
199
+ showResults(data) {
200
+ // can't do it the Vue way due to script tags in results
201
+ // this.results = data
202
+
203
+ Vue.nextTick(function () {
204
+ $("#results-html").html(data)
205
+ })
206
+ }
207
+ },
208
+ mounted: function() {
209
+ var _this = this
210
+
211
+ var $select = $("#table_names").selectize({})
212
+ var selectize = $select[0].selectize
213
+ selectize.on("change", function(val) {
214
+ editor.setValue(previewStatement[_this.dataSource].replace("{table}", val), 1)
215
+ _this.run()
216
+ selectize.clear(true)
217
+ selectize.blur()
218
+ })
219
+ this.selectize = selectize
220
+
221
+ this.updateDataSource($("#query_data_source").val())
222
+
223
+ var $dsSelect = $("#query_data_source").selectize({})
224
+ var dsSelectize = $dsSelect[0].selectize
225
+ dsSelectize.on("change", function(val) {
226
+ _this.updateDataSource(val)
227
+ dsSelectize.blur()
228
+ })
229
+
230
+ this.showEditor()
231
+ }
232
+ })
70
233
  </script>
@@ -38,7 +38,7 @@
38
38
  <tbody class="list" v-cloak>
39
39
  <tr v-for="query in visibleItems">
40
40
  <td>
41
- <span :class="{dashboard: query.dashboard}"><a :href="itemPath(query)">{{ query.name }}</a></span>
41
+ <a :href="itemPath(query)" :class="{dashboard: query.dashboard}">{{ query.name }}</a>
42
42
  <span class="vars">{{ query.vars }}</span>
43
43
  </td>
44
44
  <td class="creator">{{ query.creator }}</td>
@@ -51,10 +51,14 @@
51
51
 
52
52
  <script>
53
53
  var prepareSearch = function (list) {
54
- var i, q
54
+ var i, q, searchStr
55
55
  for (i = 0; i < list.length; i++) {
56
56
  q = list[i]
57
- q.searchStr = prepareQuery(q.name + q.creator)
57
+ searchStr = q.name + q.creator
58
+ if (q.creator === "You") {
59
+ searchStr += "mine me"
60
+ }
61
+ q.searchStr = prepareQuery(searchStr)
58
62
  }
59
63
  }
60
64
 
@@ -82,7 +86,7 @@
82
86
  if (this.more) {
83
87
  var _this = this
84
88
 
85
- $.getJSON(Routes.blazer_queries_path(), function (data) {
89
+ $.getJSON(Routes.queries_path(), function (data) {
86
90
  var i, j, newValues, val, size = 500;
87
91
 
88
92
  var newValues = []
@@ -113,6 +117,7 @@
113
117
  if (this.searchTerm.length > 0) {
114
118
  var term = prepareQuery(this.searchTerm)
115
119
  var items = []
120
+ var fuzzyItems = []
116
121
  for (i = 0; i < this.listItems.length; i++) {
117
122
  q = this.listItems[i]
118
123
  if (q.searchStr.indexOf(term) !== -1) {
@@ -120,9 +125,11 @@
120
125
  if (items.length == pageSize) {
121
126
  break
122
127
  }
128
+ } else if (fuzzysearch(term, q.searchStr)) {
129
+ fuzzyItems.push(q)
123
130
  }
124
131
  }
125
- return items
132
+ return items.concat(fuzzyItems).slice(0, pageSize)
126
133
  } else {
127
134
  return this.listItems.slice(0, pageSize)
128
135
  }
@@ -131,9 +138,9 @@
131
138
  methods: {
132
139
  itemPath: function (item) {
133
140
  if (item.dashboard) {
134
- return Routes.blazer_dashboard_path(item.to_param)
141
+ return Routes.dashboard_path(item.to_param)
135
142
  } else {
136
- return Routes.blazer_query_path(item.to_param)
143
+ return Routes.query_path(item.to_param)
137
144
  }
138
145
  }
139
146
  }
@@ -116,7 +116,7 @@ module Blazer
116
116
 
117
117
  def set_timeout(timeout)
118
118
  if postgresql? || redshift?
119
- select_all("SET statement_timeout = #{timeout.to_i * 1000}")
119
+ select_all("SET #{use_transaction? ? "LOCAL " : ""}statement_timeout = #{timeout.to_i * 1000}")
120
120
  elsif mysql?
121
121
  select_all("SET max_execution_time = #{timeout.to_i * 1000}")
122
122
  else
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "1.7.2"
2
+ VERSION = "1.7.3"
3
3
  end
@@ -6,7 +6,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
6
6
  t.text :description
7
7
  t.text :statement
8
8
  t.string :data_source
9
- t.timestamps
9
+ t.timestamps null: false
10
10
  end
11
11
 
12
12
  create_table :blazer_audits do |t|
@@ -20,14 +20,14 @@ class <%= migration_class_name %> < ActiveRecord::Migration
20
20
  create_table :blazer_dashboards do |t|
21
21
  t.references :creator
22
22
  t.text :name
23
- t.timestamps
23
+ t.timestamps null: false
24
24
  end
25
25
 
26
26
  create_table :blazer_dashboard_queries do |t|
27
27
  t.references :dashboard
28
28
  t.references :query
29
29
  t.integer :position
30
- t.timestamps
30
+ t.timestamps null: false
31
31
  end
32
32
 
33
33
  create_table :blazer_checks do |t|
@@ -39,7 +39,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
39
39
  t.string :check_type
40
40
  t.text :message
41
41
  t.timestamp :last_run_at
42
- t.timestamps
42
+ t.timestamps null: false
43
43
  end
44
44
  end
45
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 1.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-31 00:00:00.000000000 Z
11
+ date: 2016-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -139,6 +139,7 @@ files:
139
139
  - app/assets/javascripts/blazer/bootstrap.js
140
140
  - app/assets/javascripts/blazer/chartkick.js
141
141
  - app/assets/javascripts/blazer/daterangepicker.js
142
+ - app/assets/javascripts/blazer/fuzzysearch.js
142
143
  - app/assets/javascripts/blazer/highlight.pack.js
143
144
  - app/assets/javascripts/blazer/jquery.js
144
145
  - app/assets/javascripts/blazer/jquery.stickytableheaders.js
@@ -177,11 +178,9 @@ files:
177
178
  - app/views/blazer/checks/new.html.erb
178
179
  - app/views/blazer/dashboards/_form.html.erb
179
180
  - app/views/blazer/dashboards/edit.html.erb
180
- - app/views/blazer/dashboards/index.html.erb
181
181
  - app/views/blazer/dashboards/new.html.erb
182
182
  - app/views/blazer/dashboards/show.html.erb
183
183
  - app/views/blazer/queries/_form.html.erb
184
- - app/views/blazer/queries/_tables.html.erb
185
184
  - app/views/blazer/queries/edit.html.erb
186
185
  - app/views/blazer/queries/home.html.erb
187
186
  - app/views/blazer/queries/new.html.erb
@@ -1,19 +0,0 @@
1
- <% blazer_title "Dashboards" %>
2
-
3
- <p style="float: right;"><%= link_to "New Dashboard", new_dashboard_path, class: "btn btn-info" %></p>
4
- <%= render partial: "blazer/nav" %>
5
-
6
- <table class="table">
7
- <thead>
8
- <tr>
9
- <th>Dashboard</th>
10
- </tr>
11
- </thead>
12
- <tbody>
13
- <% @dashboards.each do |dashboard| %>
14
- <tr>
15
- <td><%= link_to dashboard.name, dashboard %></td>
16
- </tr>
17
- <% end %>
18
- </tbody>
19
- </table>
@@ -1,5 +0,0 @@
1
- <%= select_tag :table_names, options_for_select([["Preview table", nil]] + (@tables || [])), style: "width: 240px;" %>
2
-
3
- <script>
4
- $("#table_names").selectize({}).parent().removeClass("hide");
5
- </script>