sql-jarvis 2.1 → 2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/blazer/Sortable.js +1489 -1489
- data/app/assets/javascripts/blazer/ace.js +2 -0
- data/app/assets/javascripts/blazer/ace/mode-ruby.js +498 -0
- data/app/assets/javascripts/blazer/ace/theme-ambiance.js +184 -0
- data/app/assets/javascripts/blazer/stupidtable.js +2 -0
- data/app/assets/stylesheets/blazer/application.css +10 -2
- data/app/assets/stylesheets/blazer/main.css +4 -0
- data/app/controllers/blazer/base_controller.rb +11 -2
- data/app/controllers/blazer/queries_controller.rb +173 -142
- data/app/models/blazer/query.rb +9 -0
- data/app/views/blazer/_variables.html.haml +3 -4
- data/app/views/blazer/dashboards/show.html.haml +14 -13
- data/app/views/blazer/queries/_chart.html.haml +52 -0
- data/app/views/blazer/queries/_form.html.haml +59 -15
- data/app/views/blazer/queries/run.html.haml +23 -55
- data/app/views/blazer/queries/show.html.haml +55 -30
- data/lib/blazer.rb +12 -0
- data/lib/blazer/adapters/sql_adapter.rb +3 -3
- data/lib/blazer/data_source.rb +4 -0
- data/lib/blazer/excel_parser.rb +1 -5
- data/lib/blazer/run_integration.rb +24 -0
- data/lib/blazer/version.rb +1 -1
- data/lib/generators/blazer/templates/config.yml.tt +1 -0
- data/lib/generators/blazer/templates/install.rb.tt +2 -0
- metadata +7 -3
data/app/models/blazer/query.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Blazer
|
2
2
|
class Query < Record
|
3
3
|
serialize :assignee_ids, Array
|
4
|
+
serialize :team_ids, Array
|
4
5
|
|
5
6
|
belongs_to :creator, Blazer::BELONGS_TO_OPTIONAL.merge(class_name: Blazer.user_class.to_s) if Blazer.user_class
|
6
7
|
has_many :checks, dependent: :destroy
|
@@ -8,6 +9,7 @@ module Blazer
|
|
8
9
|
has_many :dashboards, through: :dashboard_queries
|
9
10
|
has_many :audits
|
10
11
|
|
12
|
+
before_validation :statement_format
|
11
13
|
validates :statement, presence: true
|
12
14
|
|
13
15
|
scope :named, -> { where("blazer_queries.name <> ''") }
|
@@ -42,5 +44,12 @@ module Blazer
|
|
42
44
|
def variables
|
43
45
|
Blazer.extract_vars(statement)
|
44
46
|
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def statement_format
|
51
|
+
self.statement.gsub!(/\n/, '')
|
52
|
+
end
|
53
|
+
|
45
54
|
end
|
46
55
|
end
|
@@ -3,10 +3,8 @@
|
|
3
3
|
#{blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name}
|
4
4
|
var now = moment.tz(timeZone)
|
5
5
|
var format = "YYYY-MM-DD"
|
6
|
+
function toDate(time) { return moment.tz(time.format(format), timeZone) }
|
6
7
|
|
7
|
-
function toDate(time) {
|
8
|
-
return moment.tz(time.format(format), timeZone)
|
9
|
-
}
|
10
8
|
%form#bind.form-inline{:action => action, :method => "get", :style => "margin-bottom: 15px;"}
|
11
9
|
- date_vars = ["start_time", "end_time"]
|
12
10
|
- if (date_vars - @bind_vars).empty?
|
@@ -16,7 +14,7 @@
|
|
16
14
|
- @bind_vars.each_with_index do |var, i|
|
17
15
|
= label_tag var, var
|
18
16
|
- if (data = @smart_vars[var])
|
19
|
-
= select_tag var, options_for_select(
|
17
|
+
= select_tag var, options_for_select(data, selected: params[var]), style: "margin-right: 20px; width: 200px; display: none;", multiple: true
|
20
18
|
:javascript
|
21
19
|
$("##{var}").selectize({
|
22
20
|
create: true
|
@@ -100,3 +98,4 @@
|
|
100
98
|
submitIfCompleted($("#start_time").closest("form"))
|
101
99
|
}
|
102
100
|
%input.btn.btn-success{:style => "vertical-align: top;", :type => "submit", :value => "Run"}/
|
101
|
+
%hr
|
@@ -17,17 +17,18 @@
|
|
17
17
|
= render partial: "blazer/variables", locals: {action: dashboard_path(@dashboard)}
|
18
18
|
- else
|
19
19
|
%div{:style => "padding-bottom: 15px;"}
|
20
|
-
|
21
|
-
.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
.dashboard
|
21
|
+
- @queries.each_with_index do |query, i|
|
22
|
+
.chart-container
|
23
|
+
%h4= link_to query.friendly_name, query_path(query, variable_params), target: "_blank"
|
24
|
+
.chart{:id => "chart-#{i}"}
|
25
|
+
%p.text-muted Loading...
|
26
|
+
:javascript
|
27
|
+
#{blazer_js_var "data", {statement: query.statement, query_id: query.id, data_source: query.data_source, only_chart: true}}
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
runQuery(data, function (data) {
|
30
|
+
$("#chart-#{i}").html(data)
|
31
|
+
$("#chart-#{i} table").stupidtable()
|
32
|
+
}, function (message) {
|
33
|
+
$("#chart-#{i}").addClass("query-error").html(message)
|
34
|
+
});
|
@@ -0,0 +1,52 @@
|
|
1
|
+
- values = rows.first
|
2
|
+
- chart_id = SecureRandom.hex
|
3
|
+
- column_types = result.column_types
|
4
|
+
- chart_type = result.chart_type
|
5
|
+
- chart_options = { id: chart_id, height: '40vh' }
|
6
|
+
|
7
|
+
- if ["line", "line2"].include?(chart_type)
|
8
|
+
- chart_options.merge!(min: nil)
|
9
|
+
- if chart_type == "scatter"
|
10
|
+
- chart_options.merge!(library: {tooltips: {intersect: false}})
|
11
|
+
- elsif ["bar", "bar2"].include?(chart_type)
|
12
|
+
- chart_options.merge!(library: {tooltips: {intersect: false, axis: 'x'}})
|
13
|
+
- elsif chart_type != "pie"
|
14
|
+
- if column_types.size == 2 || forecast
|
15
|
+
- chart_options.merge!(library: {tooltips: {intersect: false, axis: 'x'}})
|
16
|
+
- else
|
17
|
+
- chart_options.merge!(library: {tooltips: {intersect: false}})
|
18
|
+
- series_library = {}
|
19
|
+
- target_index = columns.index { |k| k.downcase == "target" }
|
20
|
+
- if target_index
|
21
|
+
- series_library[target_index - 1] = {pointStyle: "line", hitRadius: 5, borderColor: "#109618", pointBackgroundColor: "#109618", backgroundColor: "#109618"}
|
22
|
+
- if forecast
|
23
|
+
- color = "#54a3ee"
|
24
|
+
- series_library[1] = {borderDash: [8], borderColor: color, pointBackgroundColor: color, backgroundColor: color, pointHoverBackgroundColor: color}
|
25
|
+
- elsif chart_type == "line"
|
26
|
+
- chart_data = columns[1..-1].each_with_index.map{ |k, i| {name: blazer_series_name(k), data: rows.map{ |r| [r[0], r[i + 1]] }, library: series_library[i]} }
|
27
|
+
= line_chart chart_data, chart_options
|
28
|
+
- elsif chart_type == "line2"
|
29
|
+
= line_chart rows.group_by { |r| v = r[1]; (boom[columns[1]] || {})[v.to_s] || v }.each_with_index.map { |(name, v), i| {name: blazer_series_name(name), data: v.map { |v2| [v2[0], v2[2]] }, library: series_library[i]} }, chart_options
|
30
|
+
- elsif chart_type == "pie"
|
31
|
+
= pie_chart rows.map { |r| [(boom[columns[0]] || {})[r[0].to_s] || r[0], r[1]] }, chart_options
|
32
|
+
- elsif chart_type == "bar"
|
33
|
+
= column_chart (values.size - 1).times.map { |i| name = columns[i + 1]; {name: blazer_series_name(name), data: rows.first(20).map { |r| [(boom[columns[0]] || {})[r[0].to_s] || r[0], r[i + 1]] } } }, chart_options
|
34
|
+
- elsif chart_type == "bar2"
|
35
|
+
- first_20 = rows.group_by { |r| r[0] }.values.first(20).flatten(1)
|
36
|
+
- labels = first_20.map { |r| r[0] }.uniq
|
37
|
+
- series = first_20.map { |r| r[1] }.uniq
|
38
|
+
- labels.each do |l|
|
39
|
+
- series.each do |s|
|
40
|
+
- first_20 << [l, s, 0] unless first_20.find { |r| r[0] == l && r[1] == s }
|
41
|
+
= column_chart first_20.group_by { |r| v = r[1]; (boom[columns[1]] || {})[v.to_s] || v }.each_with_index.map { |(name, v), i| {name: blazer_series_name(name), data: v.sort_by { |r2| labels.index(r2[0]) }.map { |v2| v3 = v2[0]; [(boom[columns[0]] || {})[v3.to_s] || v3, v2[2]] }} }, chart_options
|
42
|
+
- elsif chart_type == "scatter"
|
43
|
+
= scatter_chart rows, xtitle: columns[0], ytitle: columns[1], **chart_options
|
44
|
+
- elsif only_chart
|
45
|
+
- if rows.size == 1 && rows.first.size == 1
|
46
|
+
- v = rows.first.first
|
47
|
+
- if v.is_a?(String) && v == ""
|
48
|
+
.text-muted empty string
|
49
|
+
- else
|
50
|
+
%p{style: "font-size: 160px;"}= blazer_format_value(columns.first, v)
|
51
|
+
- else
|
52
|
+
- @no_chart = true
|
@@ -1,23 +1,30 @@
|
|
1
1
|
- if @query.errors.any?
|
2
2
|
.alert.alert-danger= @query.errors.full_messages.first
|
3
3
|
#app{"v-cloak" => ""}
|
4
|
-
= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {autocomplete: "off"} do |f|
|
4
|
+
= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {autocomplete: "off", class: 'sql-query'} do |f|
|
5
5
|
.row
|
6
6
|
#statement-box.col-xs-8
|
7
7
|
.form-group
|
8
8
|
= f.hidden_field :statement
|
9
9
|
#editor-container
|
10
|
-
#editor{
|
11
|
-
.form-group.text-right{:
|
12
|
-
.pull-left{:
|
10
|
+
#editor{style: "{ height: editorHeight }"}= @query.statement.to_s.gsub("\n", '')
|
11
|
+
.form-group.text-right{style: "margin-bottom: 8px;"}
|
12
|
+
.pull-left{style: "margin-top: 8px;"}
|
13
13
|
= link_to "Back", :back
|
14
|
-
|
14
|
+
= link_to 'Schema', 'schemaPath', style: 'margin-left: 40px;', target: :blank
|
15
|
+
- if Blazer.integration
|
16
|
+
= link_to 'Integration', '#integration-session', style: 'margin-left: 40px;', data: { toggle: :collapse }
|
15
17
|
= 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;"
|
16
|
-
#tables{:
|
17
|
-
%select#table_names{:
|
18
|
-
%a.btn.btn-info{:
|
19
|
-
%a.btn.btn-danger{:
|
20
|
-
|
18
|
+
#tables{style: "display: inline-block; width: 250px; margin-right: 10px;"}
|
19
|
+
%select#table_names{placeholder: "Preview table", style: "width: 240px;"}
|
20
|
+
%a.btn.btn-info{style: "vertical-align: top; width: 70px;", "v-if" => "!running", "v-on:click" => "run"} Run
|
21
|
+
%a.btn.btn-danger{style: "vertical-align: top; width: 70px;", "v-if" => "running", "v-on:click" => "cancel"} Cancel
|
22
|
+
- if Blazer.integration
|
23
|
+
#integration-session.collapse
|
24
|
+
%hr
|
25
|
+
= f.hidden_field :integration
|
26
|
+
#integration-editor{style: 'height: 200px'}
|
27
|
+
%hr
|
21
28
|
= render partial: "tips"
|
22
29
|
.col-xs-4
|
23
30
|
.form-group
|
@@ -30,6 +37,10 @@
|
|
30
37
|
.form-group
|
31
38
|
= f.label :assignees
|
32
39
|
= f.collection_select :assignee_ids, @assignees, :first, :last, {}, { placeholder: "Assignees", style: "height: 80px;", class: "form-control", multiple: true }
|
40
|
+
- if @teams.any?
|
41
|
+
.form-group
|
42
|
+
= f.label :teams
|
43
|
+
= f.collection_select :team_ids, @teams, :first, :last, {}, { placeholder: "Teams", style: "height: 80px;", class: "form-control", multiple: true }
|
33
44
|
.form-group.text-right
|
34
45
|
= f.submit "For Enter Press", class: "hide"
|
35
46
|
- if @query.persisted?
|
@@ -48,6 +59,7 @@
|
|
48
59
|
#results
|
49
60
|
%p.text-muted{"v-if" => "running"} Loading...
|
50
61
|
#results-html{":class" => "{ 'query-error': error }", "v-if" => "!running"}
|
62
|
+
|
51
63
|
:javascript
|
52
64
|
#{blazer_js_var "params", variable_params}
|
53
65
|
#{blazer_js_var "previewStatement", Hash[Blazer.data_sources.map { |k, v| [k, (v.preview_statement rescue "")] }]}
|
@@ -77,7 +89,11 @@
|
|
77
89
|
this.error = false
|
78
90
|
cancelAllQueries()
|
79
91
|
|
80
|
-
var data = $.extend({}, params, {
|
92
|
+
var data = $.extend({}, params, {
|
93
|
+
statement: this.getSQL(),
|
94
|
+
integration: $('#integration').val(),
|
95
|
+
data_source: $("#query_data_source").val()
|
96
|
+
})
|
81
97
|
|
82
98
|
var _this = this
|
83
99
|
|
@@ -121,9 +137,27 @@
|
|
121
137
|
selectize.refreshOptions(false)
|
122
138
|
})
|
123
139
|
},
|
140
|
+
showIntegrationEditor: function() {
|
141
|
+
if ($('#integration-editor').length) {
|
142
|
+
integrationEditor = ace.edit("integration-editor")
|
143
|
+
integrationEditor.setTheme("ace/theme/twilight")
|
144
|
+
integrationEditor.getSession().setMode("ace/mode/ruby")
|
145
|
+
integrationEditor.setOptions({
|
146
|
+
fontSize: 12,
|
147
|
+
minLines: 10,
|
148
|
+
enableSnippets: false,
|
149
|
+
highlightActiveLine: false,
|
150
|
+
enableLiveAutocompletion: true,
|
151
|
+
enableBasicAutocompletion: true
|
152
|
+
})
|
153
|
+
integrationEditor.renderer.setShowGutter(true)
|
154
|
+
integrationEditor.renderer.setPrintMarginColumn(false)
|
155
|
+
integrationEditor.renderer.setPadding(10)
|
156
|
+
integrationEditor.getSession().setUseWrapMode(true)
|
157
|
+
}
|
158
|
+
},
|
124
159
|
showEditor: function() {
|
125
160
|
var _this = this
|
126
|
-
|
127
161
|
editor = ace.edit("editor")
|
128
162
|
editor.setTheme("ace/theme/twilight")
|
129
163
|
editor.getSession().setMode("ace/mode/sql")
|
@@ -223,7 +257,8 @@
|
|
223
257
|
lines = 9
|
224
258
|
}
|
225
259
|
|
226
|
-
this.editorHeight = ((lines + 1) * 16).toString()
|
260
|
+
this.editorHeight = ((lines + 1) * 16).toString();
|
261
|
+
$('#editor').height(this.editorHeight);
|
227
262
|
|
228
263
|
Vue.nextTick(function () {
|
229
264
|
editor.resize()
|
@@ -277,7 +312,8 @@
|
|
277
312
|
dsSelectize.blur()
|
278
313
|
})
|
279
314
|
|
280
|
-
this.showEditor()
|
315
|
+
this.showEditor();
|
316
|
+
// this.showIntegrationEditor();
|
281
317
|
}
|
282
318
|
})
|
283
319
|
|
@@ -292,7 +328,7 @@
|
|
292
328
|
}
|
293
329
|
|
294
330
|
$(document).ready(function() {
|
295
|
-
$('#query_assignee_ids').select2();
|
331
|
+
$('#query_assignee_ids, #query_team_ids').select2();
|
296
332
|
setInterval(function() {
|
297
333
|
var lastVersion = $('#query_statement').val();
|
298
334
|
if (localStorage.getItem('lastVersion') !== lastVersion) {
|
@@ -308,3 +344,11 @@
|
|
308
344
|
return false;
|
309
345
|
}
|
310
346
|
});
|
347
|
+
|
348
|
+
(function () {
|
349
|
+
$('.sql-query').one('change', function () {
|
350
|
+
window.onbeforeunload = function () {
|
351
|
+
return 'Form protection';
|
352
|
+
};
|
353
|
+
});
|
354
|
+
})();
|
@@ -20,32 +20,12 @@
|
|
20
20
|
- if @forecast_error
|
21
21
|
.alert.alert-danger= @forecast_error
|
22
22
|
- if @rows.any?
|
23
|
-
-
|
24
|
-
|
25
|
-
- column_types = @result.column_types
|
26
|
-
- chart_type = @result.chart_type
|
27
|
-
- chart_options = {id: chart_id}
|
28
|
-
- if ["line", "line2"].include?(chart_type)
|
29
|
-
- chart_options.merge!(min: nil)
|
30
|
-
- if chart_type == "scatter"
|
31
|
-
- chart_options.merge!(library: {tooltips: {intersect: false}})
|
32
|
-
- elsif ["bar", "bar2"].include?(chart_type)
|
33
|
-
- chart_options.merge!(library: {tooltips: {intersect: false, axis: 'x'}})
|
34
|
-
- elsif chart_type != "pie"
|
35
|
-
- if column_types.size == 2 || @forecast
|
36
|
-
- chart_options.merge!(library: {tooltips: {intersect: false, axis: 'x'}})
|
37
|
-
- else
|
38
|
-
- chart_options.merge!(library: {tooltips: {intersect: false}})
|
39
|
-
- series_library = {}
|
40
|
-
- target_index = @columns.index { |k| k.downcase == "target" }
|
41
|
-
- if target_index
|
42
|
-
- series_library[target_index - 1] = {pointStyle: "line", hitRadius: 5, borderColor: "#109618", pointBackgroundColor: "#109618", backgroundColor: "#109618"}
|
43
|
-
- if @forecast
|
44
|
-
- color = "#54a3ee"
|
45
|
-
- series_library[1] = {borderDash: [8], borderColor: color, pointBackgroundColor: color, backgroundColor: color, pointHoverBackgroundColor: color}
|
23
|
+
#main-chart
|
24
|
+
= render 'chart', rows: @rows, columns: @columns, result: @result, forecast: @forecast, only_chart: @only_chart, boom: @boom
|
46
25
|
- if blazer_maps? && @markers.any?
|
47
|
-
#map{style: "height:
|
26
|
+
#map{style: "height: 500px; width: 100%"}
|
48
27
|
:javascript
|
28
|
+
$('#map').html('');
|
49
29
|
L.mapbox.accessToken = '#{Blazer.mapbox_access_token}';
|
50
30
|
var map = L.mapbox.map('map', 'ankane.ioo8nki0');
|
51
31
|
#{blazer_js_var "markers", @markers}
|
@@ -71,34 +51,12 @@
|
|
71
51
|
}
|
72
52
|
featureLayer.setGeoJSON(geojson);
|
73
53
|
map.fitBounds(featureLayer.getBounds());
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
= pie_chart @rows.map { |r| [(@boom[@columns[0]] || {})[r[0].to_s] || r[0], r[1]] }, chart_options
|
81
|
-
- elsif chart_type == "bar"
|
82
|
-
= column_chart (values.size - 1).times.map { |i| name = @columns[i + 1]; {name: blazer_series_name(name), data: @rows.first(20).map { |r| [(@boom[@columns[0]] || {})[r[0].to_s] || r[0], r[i + 1]] } } }, chart_options
|
83
|
-
- elsif chart_type == "bar2"
|
84
|
-
- first_20 = @rows.group_by { |r| r[0] }.values.first(20).flatten(1)
|
85
|
-
- labels = first_20.map { |r| r[0] }.uniq
|
86
|
-
- series = first_20.map { |r| r[1] }.uniq
|
87
|
-
- labels.each do |l|
|
88
|
-
- series.each do |s|
|
89
|
-
- first_20 << [l, s, 0] unless first_20.find { |r| r[0] == l && r[1] == s }
|
90
|
-
= column_chart first_20.group_by { |r| v = r[1]; (@boom[@columns[1]] || {})[v.to_s] || v }.each_with_index.map { |(name, v), i| {name: blazer_series_name(name), data: v.sort_by { |r2| labels.index(r2[0]) }.map { |v2| v3 = v2[0]; [(@boom[@columns[0]] || {})[v3.to_s] || v3, v2[2]] }} }, chart_options
|
91
|
-
- elsif chart_type == "scatter"
|
92
|
-
= scatter_chart @rows, xtitle: @columns[0], ytitle: @columns[1], **chart_options
|
93
|
-
- elsif @only_chart
|
94
|
-
- if @rows.size == 1 && @rows.first.size == 1
|
95
|
-
- v = @rows.first.first
|
96
|
-
- if v.is_a?(String) && v == ""
|
97
|
-
.text-muted empty string
|
98
|
-
- else
|
99
|
-
%p{style: "font-size: 160px;"}= blazer_format_value(@columns.first, v)
|
100
|
-
- else
|
101
|
-
- @no_chart = true
|
54
|
+
map.setZoom(5)._onResize();
|
55
|
+
- elsif @no_chart
|
56
|
+
:javascript
|
57
|
+
$('#chart-tab').hide();
|
58
|
+
$('#table-tab').click();
|
59
|
+
|
102
60
|
- unless @only_chart && !@no_chart
|
103
61
|
- header_width = 100 / @columns.size.to_f
|
104
62
|
.results-container
|
@@ -110,7 +68,7 @@
|
|
110
68
|
%code= @rows[0][0]
|
111
69
|
- else
|
112
70
|
%p.text-muted{style: "margin-bottom: 10px; margin-top: 15px"}
|
113
|
-
=
|
71
|
+
= "#{@rows.size} rows" if @rows.size > 1
|
114
72
|
- @checks.select(&:state).each do |check|
|
115
73
|
·
|
116
74
|
%small{:class => "check-state #{check.state.parameterize.gsub("-", "_")}"}= link_to check.state.upcase, edit_check_path(check)
|
@@ -120,8 +78,14 @@
|
|
120
78
|
·
|
121
79
|
\#{link_to "Forecast", query_path(@query, {forecast: "t"}.merge(variable_params))}
|
122
80
|
%span.pull-right
|
123
|
-
- if @rows.size
|
81
|
+
- if (1..preview_rows_number).cover?(@rows.size)
|
124
82
|
= link_to 'Copy to clipboard', '#results-table', class: 'click2CopyTable btn btn-xs btn-info'
|
83
|
+
|
84
|
+
- if @rows.size > preview_rows_number
|
85
|
+
%hr
|
86
|
+
%h4.text-center.text-info
|
87
|
+
%strong Notice: Now we show maximum is #{preview_rows_number} rows for preview
|
88
|
+
%hr
|
125
89
|
.scroll-content
|
126
90
|
%table#results-table.table.results-table
|
127
91
|
%thead
|
@@ -133,7 +97,7 @@
|
|
133
97
|
%div{style: "min-width: #{@min_width_types.include?(i) ? 180 : 60}px;"}
|
134
98
|
= key
|
135
99
|
%tbody
|
136
|
-
- @rows.each do |row|
|
100
|
+
- @rows.first(preview_rows_number).each do |row|
|
137
101
|
%tr
|
138
102
|
- row.each_with_index do |v, i|
|
139
103
|
- k = @columns[i]
|
@@ -151,3 +115,7 @@
|
|
151
115
|
.text-muted= v2
|
152
116
|
- else
|
153
117
|
%p.text-muted.text-center{style: "margin-top: 15px"} No rows
|
118
|
+
|
119
|
+
:javascript
|
120
|
+
$('#main-chart').appendTo('#chart');
|
121
|
+
$('#map').appendTo('#chart');
|
@@ -1,17 +1,19 @@
|
|
1
1
|
- blazer_title @query.name
|
2
|
+
|
2
3
|
.topbar
|
3
4
|
.container
|
4
5
|
.row{:style => "padding-top: 13px;"}
|
5
6
|
.col-sm-8
|
6
7
|
= render partial: "blazer/nav"
|
7
|
-
%
|
8
|
+
%h4{style: "line-height: 34px; display: inline; margin-left: 5px;"}
|
8
9
|
= @query.name
|
9
10
|
.col-sm-4.text-right
|
10
11
|
= link_to "Edit", edit_query_path(@query, variable_params), class: "btn btn-default", disabled: !@query.editable?(blazer_user)
|
11
12
|
= link_to "Fork", new_query_path(variable_params.merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "btn btn-info"
|
12
13
|
- if !@error && @success
|
13
|
-
= button_to "⤓ .csv", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast]), params: {statement: @statement}, class: "btn btn-primary"
|
14
|
-
= button_to "⤓ .xlsx", run_queries_path(query_id: @query.id, format: "xlsx"), params: {statement: @statement}, class: "btn btn-primary"
|
14
|
+
= button_to "⤓ .csv", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast]), params: { statement: @statement, filename: @filename }, class: "btn btn-primary"
|
15
|
+
= button_to "⤓ .xlsx", run_queries_path(query_id: @query.id, format: "xlsx"), params: { statement: @statement, filename: @filename }, class: "btn btn-primary"
|
16
|
+
|
15
17
|
%div{:style => "margin-bottom: 60px;"}
|
16
18
|
- if @sql_errors.any?
|
17
19
|
.alert.alert-danger
|
@@ -20,31 +22,54 @@
|
|
20
22
|
%li= message
|
21
23
|
- if @query.description.present?
|
22
24
|
%p= @query.description
|
25
|
+
|
23
26
|
= render partial: "blazer/variables", locals: {action: query_path(@query)}
|
24
|
-
|
25
|
-
|
26
|
-
-
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
27
|
+
|
28
|
+
%ul.nav.nav-tabs
|
29
|
+
%li#chart-tab.active= link_to 'Chart', '#chart', data: { toggle: :tab }
|
30
|
+
%li= link_to 'Table', '#table', data: { toggle: :tab }, id: 'table-tab'
|
31
|
+
%li= link_to 'Query', '#query', data: { toggle: :tab }
|
32
|
+
- if @query.integration.present?
|
33
|
+
%li= link_to 'Integration', '#integration', data: { toggle: :tab }
|
34
|
+
|
35
|
+
.tab-content
|
36
|
+
#chart.tab-pane.fade.in.active
|
37
|
+
#query.tab-pane.fade
|
38
|
+
%pre#code
|
39
|
+
%code= @statement.gsub("\r", "\n")
|
40
|
+
- if @query.integration.present?
|
41
|
+
#integration.tab-pane.fade
|
42
|
+
= @query.integration
|
43
|
+
#table.tab-pane.fade
|
44
|
+
- if @success
|
45
|
+
#results
|
46
|
+
%p.text-muted Loading...
|
47
|
+
:javascript
|
48
|
+
function showRun(data) {
|
49
|
+
$("#results").html(data);
|
50
|
+
$("#results table").stupidtable().stickyTableHeaders({
|
51
|
+
fixedOffset: 60,
|
52
|
+
});
|
53
|
+
}
|
54
|
+
|
55
|
+
function showError(message) {
|
56
|
+
$("#results").addClass("query-error").html(message);
|
57
|
+
}
|
58
|
+
|
59
|
+
#{blazer_js_var "data", variable_params.merge(statement: @statement, query_id: @query.id, data_source: @query.data_source)}
|
60
|
+
|
61
|
+
runQuery(data, showRun, showError)
|
62
|
+
- unless %w(mongodb).include?(Blazer.data_sources[@query.data_source].adapter)
|
63
|
+
:javascript
|
64
|
+
// do not highlight really long queries
|
65
|
+
// this can lead to performance issues
|
66
|
+
if ($("code").text().length < 10000) {
|
67
|
+
hljs.highlightBlock(document.getElementById("code"));
|
68
|
+
}
|
69
|
+
|
70
|
+
:javascript
|
71
|
+
$('ul.nav.nav-tabs li a').click(function(event) {
|
72
|
+
localStorage.setItem('currentQueryTab', $(event.currentTarget).attr('href'));
|
73
|
+
});
|
74
|
+
var currentQueryTab = localStorage.getItem('currentQueryTab');
|
75
|
+
$("ul.nav.nav-tabs li a[href='" + currentQueryTab + "']").click();
|