sql-jarvis 2.0.1 → 2.0.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -1
- data/LICENSE.txt +1 -1
- data/README.md +153 -52
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.svg +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff2 +0 -0
- data/app/assets/images/blazer/favicon.png +0 -0
- data/app/assets/javascripts/blazer/Chart.js +4195 -3884
- data/app/assets/javascripts/blazer/Sortable.js +1493 -1097
- data/app/assets/javascripts/blazer/ace/ace.js +21294 -4
- data/app/assets/javascripts/blazer/ace/ext-language_tools.js +1991 -3
- data/app/assets/javascripts/blazer/ace/mode-sql.js +110 -1
- data/app/assets/javascripts/blazer/ace/snippets/sql.js +40 -1
- data/app/assets/javascripts/blazer/ace/snippets/text.js +14 -1
- data/app/assets/javascripts/blazer/ace/theme-twilight.js +116 -1
- data/app/assets/javascripts/blazer/application.js +4 -3
- data/app/assets/javascripts/blazer/bootstrap.js +623 -612
- data/app/assets/javascripts/blazer/chartkick.js +1769 -1248
- data/app/assets/javascripts/blazer/daterangepicker.js +263 -115
- data/app/assets/javascripts/blazer/highlight.min.js +3 -0
- data/app/assets/javascripts/blazer/{jquery_ujs.js → jquery-ujs.js} +161 -75
- data/app/assets/javascripts/blazer/jquery.js +9506 -9450
- data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +321 -259
- data/app/assets/javascripts/blazer/moment-timezone-with-data.js +1212 -0
- data/app/assets/javascripts/blazer/queries.js +1 -1
- data/app/assets/javascripts/blazer/routes.js +3 -0
- data/app/assets/javascripts/blazer/selectize.js +3828 -3604
- data/app/assets/javascripts/blazer/stupidtable.js +255 -88
- data/app/assets/javascripts/blazer/vue.js +8015 -4583
- data/app/assets/stylesheets/blazer/application.css +41 -5
- data/app/assets/stylesheets/blazer/bootstrap.css.erb +879 -325
- data/app/assets/stylesheets/blazer/daterangepicker.css +269 -0
- data/app/assets/stylesheets/blazer/selectize.default.css +26 -10
- data/app/controllers/blazer/base_controller.rb +7 -0
- data/app/controllers/blazer/checks_controller.rb +1 -1
- data/app/controllers/blazer/dashboards_controller.rb +0 -4
- data/app/controllers/blazer/queries_controller.rb +20 -12
- data/app/helpers/blazer/base_helper.rb +1 -1
- data/app/mailers/blazer/slack_notifier.rb +76 -0
- data/app/models/blazer/check.rb +9 -0
- data/app/views/blazer/_nav.html.erb +0 -1
- data/app/views/blazer/_variables.html.erb +41 -19
- data/app/views/blazer/checks/_form.html.erb +16 -8
- data/app/views/blazer/checks/edit.html.erb +2 -0
- data/app/views/blazer/checks/index.html.erb +33 -4
- data/app/views/blazer/checks/new.html.erb +2 -0
- data/app/views/blazer/dashboards/_form.html.erb +4 -4
- data/app/views/blazer/dashboards/edit.html.erb +2 -0
- data/app/views/blazer/dashboards/new.html.erb +2 -0
- data/app/views/blazer/dashboards/show.html.erb +7 -3
- data/app/views/blazer/queries/_form.html.erb +11 -6
- data/app/views/blazer/queries/docs.html.erb +131 -0
- data/app/views/blazer/queries/home.html.erb +12 -3
- data/app/views/blazer/queries/run.html.erb +36 -6
- data/app/views/blazer/queries/schema.html.erb +46 -8
- data/app/views/blazer/queries/show.html.erb +4 -4
- data/app/views/layouts/blazer/application.html.erb +3 -3
- data/config/routes.rb +5 -1
- data/lib/blazer.rb +32 -13
- data/lib/blazer/adapters/athena_adapter.rb +1 -1
- data/lib/blazer/adapters/elasticsearch_adapter.rb +14 -17
- data/lib/blazer/adapters/mongodb_adapter.rb +1 -1
- data/lib/blazer/adapters/sql_adapter.rb +7 -1
- data/lib/blazer/engine.rb +4 -0
- data/lib/blazer/result.rb +62 -29
- data/lib/blazer/run_statement_job.rb +6 -9
- data/lib/blazer/version.rb +1 -1
- data/lib/generators/blazer/templates/config.yml.tt +13 -2
- data/lib/generators/blazer/templates/install.rb.tt +1 -0
- data/lib/tasks/blazer.rake +1 -0
- metadata +33 -37
- data/.gitattributes +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -7
- data/.gitignore +0 -14
- data/Gemfile +0 -7
- data/Rakefile +0 -1
- data/app/assets/javascripts/blazer/highlight.pack.js +0 -1
- data/app/assets/javascripts/blazer/moment-timezone.js +0 -1007
- data/app/assets/stylesheets/blazer/daterangepicker-bs3.css +0 -375
- data/blazer.gemspec +0 -30
|
@@ -12,7 +12,7 @@ module Blazer
|
|
|
12
12
|
BLAZER_IMAGE_EXT = %w[png jpg jpeg gif]
|
|
13
13
|
|
|
14
14
|
def blazer_format_value(key, value)
|
|
15
|
-
if value.is_a?(
|
|
15
|
+
if value.is_a?(Numeric) && !key.to_s.end_with?("id") && !key.to_s.start_with?("id")
|
|
16
16
|
number_with_delimiter(value)
|
|
17
17
|
elsif value =~ BLAZER_URL_REGEX
|
|
18
18
|
# see if image or link
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
|
|
3
|
+
module Blazer
|
|
4
|
+
class SlackNotifier
|
|
5
|
+
def self.state_change(check, state, state_was, rows_count, error, check_type)
|
|
6
|
+
check.split_slack_channels.each do |channel|
|
|
7
|
+
text =
|
|
8
|
+
if error
|
|
9
|
+
error
|
|
10
|
+
elsif rows_count > 0 && check_type == "bad_data"
|
|
11
|
+
pluralize(rows_count, "row")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
payload = {
|
|
15
|
+
channel: channel,
|
|
16
|
+
attachments: [
|
|
17
|
+
{
|
|
18
|
+
title: escape("Check #{state.titleize}: #{check.query.name}"),
|
|
19
|
+
title_link: query_url(check.query_id),
|
|
20
|
+
text: escape(text),
|
|
21
|
+
color: state == "passing" ? "good" : "danger"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
post(Blazer.slack_webhook_url, payload)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.failing_checks(channel, checks)
|
|
31
|
+
text =
|
|
32
|
+
checks.map do |check|
|
|
33
|
+
"<#{query_url(check.query_id)}|#{escape(check.query.name)}> #{escape(check.state)}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
payload = {
|
|
37
|
+
channel: channel,
|
|
38
|
+
attachments: [
|
|
39
|
+
{
|
|
40
|
+
title: escape("#{pluralize(checks.size, "Check")} Failing"),
|
|
41
|
+
text: text.join("\n"),
|
|
42
|
+
color: "warning"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
post(Blazer.slack_webhook_url, payload)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# https://api.slack.com/docs/message-formatting#how_to_escape_characters
|
|
51
|
+
# - Replace the ampersand, &, with &
|
|
52
|
+
# - Replace the less-than sign, < with <
|
|
53
|
+
# - Replace the greater-than sign, > with >
|
|
54
|
+
# That's it. Don't HTML entity-encode the entire message.
|
|
55
|
+
def self.escape(str)
|
|
56
|
+
str.gsub("&", "&").gsub("<", "<").gsub(">", ">") if str
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.pluralize(*args)
|
|
60
|
+
ActionController::Base.helpers.pluralize(*args)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.query_url(id)
|
|
64
|
+
Blazer::Engine.routes.url_helpers.query_url(id, ActionMailer::Base.default_url_options)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.post(url, payload)
|
|
68
|
+
uri = URI.parse(url)
|
|
69
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
70
|
+
http.use_ssl = true
|
|
71
|
+
http.open_timeout = 3
|
|
72
|
+
http.read_timeout = 5
|
|
73
|
+
http.post(uri.request_uri, payload.to_json)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/app/models/blazer/check.rb
CHANGED
|
@@ -14,6 +14,14 @@ module Blazer
|
|
|
14
14
|
emails.to_s.downcase.split(",").map(&:strip)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def split_slack_channels
|
|
18
|
+
if Blazer.slack?
|
|
19
|
+
slack_channels.to_s.downcase.split(",").map(&:strip)
|
|
20
|
+
else
|
|
21
|
+
[]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
def update_state(result)
|
|
18
26
|
check_type =
|
|
19
27
|
if respond_to?(:check_type)
|
|
@@ -61,6 +69,7 @@ module Blazer
|
|
|
61
69
|
# do not notify on creation, except when not passing
|
|
62
70
|
if (state_was != "new" || state != "passing") && state != state_was && emails.present?
|
|
63
71
|
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_now
|
|
72
|
+
Blazer::SlackNotifier.state_change(self, state, state_was, result.rows.size, message, check_type)
|
|
64
73
|
end
|
|
65
74
|
save! if changed?
|
|
66
75
|
end
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
<span class="sr-only">Toggle Dropdown</span>
|
|
6
6
|
</button>
|
|
7
7
|
<ul class="dropdown-menu">
|
|
8
|
-
<li><%= link_to "Dashboards", dashboards_path %></li>
|
|
9
8
|
<li><%= link_to "Checks", checks_path %></li>
|
|
10
9
|
<li role="separator" class="divider"></li>
|
|
11
10
|
<li><%= link_to "New Query", new_query_path %></li>
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
<% if @bind_vars.any? %>
|
|
2
|
-
<
|
|
2
|
+
<script>
|
|
3
|
+
<%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
|
|
4
|
+
var now = moment.tz(timeZone)
|
|
5
|
+
var format = "YYYY-MM-DD"
|
|
6
|
+
|
|
7
|
+
function toDate(time) {
|
|
8
|
+
return moment.tz(time.format(format), timeZone)
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
11
|
+
<form id="bind" method="get" action="<%= action %>" class="form-inline" style="margin-bottom: 15px;">
|
|
3
12
|
<% date_vars = ["start_time", "end_time"] %>
|
|
4
13
|
<% if (date_vars - @bind_vars).empty? %>
|
|
5
14
|
<% @bind_vars = @bind_vars - date_vars %>
|
|
@@ -16,18 +25,39 @@
|
|
|
16
25
|
create: true
|
|
17
26
|
});
|
|
18
27
|
</script>
|
|
28
|
+
<% elsif var.end_with?("_at") || var == "start_time" || var == "end_time" %>
|
|
29
|
+
<%= hidden_field_tag var, params[var] %>
|
|
30
|
+
|
|
31
|
+
<div class="selectize-control single" style="width: 200px;">
|
|
32
|
+
<div id="<%= var %>-select" class="selectize-input" style="display: inline-block;">
|
|
33
|
+
<span>Select a date</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<script>
|
|
38
|
+
(function() {
|
|
39
|
+
var input = $("#<%= var %>")
|
|
40
|
+
var datePicker = $("#<%= var %>-select")
|
|
41
|
+
datePicker.daterangepicker({
|
|
42
|
+
singleDatePicker: true,
|
|
43
|
+
locale: {format: format},
|
|
44
|
+
autoUpdateInput: false,
|
|
45
|
+
startDate: input.val().length > 0 ? moment.tz(input.val(), timeZone) : now
|
|
46
|
+
})
|
|
47
|
+
// hack to start with empty date
|
|
48
|
+
datePicker.on("apply.daterangepicker", function(ev, picker) {
|
|
49
|
+
datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
|
|
50
|
+
input.val(toDate(picker.startDate).utc().format())
|
|
51
|
+
submitIfCompleted($("#<%= var %>").closest("form"))
|
|
52
|
+
})
|
|
53
|
+
if (input.val().length > 0) {
|
|
54
|
+
var picker = datePicker.data("daterangepicker")
|
|
55
|
+
datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
|
|
56
|
+
}
|
|
57
|
+
})()
|
|
58
|
+
</script>
|
|
19
59
|
<% else %>
|
|
20
60
|
<%= text_field_tag var, params[var], style: "width: 120px; margin-right: 20px;", autofocus: i == 0 && !var.end_with?("_at") && !params[var], class: "form-control" %>
|
|
21
|
-
<% if var.end_with?("_at") %>
|
|
22
|
-
<script>
|
|
23
|
-
$("#<%= var %>").daterangepicker({singleDatePicker: true, locale: {format: "YYYY-MM-DD"}, autoUpdateInput: false});
|
|
24
|
-
// hack to start with empty date
|
|
25
|
-
$("#<%= var %>").on("apply.daterangepicker", function(ev, picker) {
|
|
26
|
-
$(this).val(picker.startDate.format("YYYY-MM-DD"));
|
|
27
|
-
$(this).change();
|
|
28
|
-
});
|
|
29
|
-
</script>
|
|
30
|
-
<% end %>
|
|
31
61
|
<% end %>
|
|
32
62
|
<% end %>
|
|
33
63
|
|
|
@@ -44,18 +74,10 @@
|
|
|
44
74
|
</div>
|
|
45
75
|
|
|
46
76
|
<script>
|
|
47
|
-
<%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
|
|
48
|
-
var format = "YYYY-MM-DD"
|
|
49
|
-
var now = moment.tz(timeZone)
|
|
50
|
-
|
|
51
77
|
function dateStr(daysAgo) {
|
|
52
78
|
return now.clone().subtract(daysAgo || 0, "days").format(format)
|
|
53
79
|
}
|
|
54
80
|
|
|
55
|
-
function toDate(time) {
|
|
56
|
-
return moment.tz(time.format(format), timeZone)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
81
|
function setTimeInputs(start, end) {
|
|
60
82
|
$("#start_time").val(toDate(start).utc().format())
|
|
61
83
|
$("#end_time").val(toDate(end).endOf("day").utc().format())
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<%= form_for @check, html: {class: "small-form"} do |f| %>
|
|
2
|
+
<% unless @check.respond_to?(:check_type) || @check.respond_to?(:invert) %>
|
|
3
|
+
<p class="text-muted">Checks are designed to identify bad data. A check fails if there are any results.</p>
|
|
4
|
+
<% end %>
|
|
4
5
|
|
|
5
|
-
<% if @check.errors.any? %>
|
|
6
|
-
|
|
7
|
-
<% end %>
|
|
6
|
+
<% if @check.errors.any? %>
|
|
7
|
+
<div class="alert alert-danger"><%= @check.errors.full_messages.first %></div>
|
|
8
|
+
<% end %>
|
|
8
9
|
|
|
9
|
-
<%= form_for @check do |f| %>
|
|
10
10
|
<div class="form-group">
|
|
11
11
|
<%= f.label :query_id, "Query" %>
|
|
12
12
|
<div class="hide">
|
|
@@ -60,7 +60,15 @@
|
|
|
60
60
|
<%= f.label :emails %>
|
|
61
61
|
<%= f.text_field :emails, placeholder: "Optional, comma separated", class: "form-control" %>
|
|
62
62
|
</div>
|
|
63
|
-
|
|
63
|
+
|
|
64
|
+
<% if Blazer.slack? %>
|
|
65
|
+
<div class="form-group">
|
|
66
|
+
<%= f.label :slack_channels %>
|
|
67
|
+
<%= f.text_field :slack_channels, placeholder: "Optional, comma separated", class: "form-control" %>
|
|
68
|
+
</div>
|
|
69
|
+
<% end %>
|
|
70
|
+
|
|
71
|
+
<p class="text-muted">Emails <%= Blazer.slack? ? "and Slack notifications " : nil %>are sent when a check starts failing, and when it starts passing again.
|
|
64
72
|
<p>
|
|
65
73
|
<% if @check.persisted? %>
|
|
66
74
|
<%= link_to "Delete", check_path(@check), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
<% blazer_title "Checks" %>
|
|
2
2
|
|
|
3
|
-
<
|
|
4
|
-
|
|
3
|
+
<div id="header">
|
|
4
|
+
<div class="pull-right" style="line-height: 34px;">
|
|
5
|
+
<div class="btn-group">
|
|
6
|
+
<%= link_to "New Check", new_check_path, class: "btn btn-info" %>
|
|
7
|
+
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
8
|
+
<span class="caret"></span>
|
|
9
|
+
<span class="sr-only">Toggle Dropdown</span>
|
|
10
|
+
</button>
|
|
11
|
+
<ul class="dropdown-menu">
|
|
12
|
+
<li><%= link_to "Home", root_path %></li>
|
|
13
|
+
<li role="separator" class="divider"></li>
|
|
14
|
+
<li><%= link_to "New Query", new_query_path %></li>
|
|
15
|
+
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
|
16
|
+
</ul>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
5
19
|
|
|
6
|
-
<
|
|
20
|
+
<input id="search" type="text" placeholder="Start typing a query or state" style="width: 300px; display: inline-block;" class="search form-control" />
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<table id="checks" class="table">
|
|
7
24
|
<thead>
|
|
8
25
|
<tr>
|
|
9
26
|
<th>Query</th>
|
|
10
27
|
<th style="width: 10%;">State</th>
|
|
11
28
|
<th style="width: 10%;">Run</th>
|
|
12
|
-
<th style="width: 20%;">
|
|
29
|
+
<th style="width: 20%;">Notify</th>
|
|
13
30
|
<th style="width: 15%;"></th>
|
|
14
31
|
</tr>
|
|
15
32
|
</thead>
|
|
@@ -28,6 +45,9 @@
|
|
|
28
45
|
<% check.split_emails.each do |email| %>
|
|
29
46
|
<li><%= email %></li>
|
|
30
47
|
<% end %>
|
|
48
|
+
<% check.split_slack_channels.each do |channel| %>
|
|
49
|
+
<li><%= channel %></li>
|
|
50
|
+
<% end %>
|
|
31
51
|
</ul>
|
|
32
52
|
</td>
|
|
33
53
|
<td style="text-align: right; padding: 1px;">
|
|
@@ -38,3 +58,12 @@
|
|
|
38
58
|
<% end %>
|
|
39
59
|
</tbody>
|
|
40
60
|
</table>
|
|
61
|
+
|
|
62
|
+
<script>
|
|
63
|
+
$("#search").on("keyup", function() {
|
|
64
|
+
var value = $(this).val().toLowerCase()
|
|
65
|
+
$("#checks tbody tr").filter( function() {
|
|
66
|
+
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
|
67
|
+
})
|
|
68
|
+
}).focus()
|
|
69
|
+
</script>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<%= form_for @dashboard, url: (@dashboard.persisted? ? dashboard_path(@dashboard, variable_params) : dashboards_path(variable_params)), html: {id: "app", class: "small-form"} do |f| %>
|
|
2
|
+
<% if @dashboard.errors.any? %>
|
|
3
|
+
<div class="alert alert-danger"><%= @dashboard.errors.full_messages.first %></div>
|
|
4
|
+
<% end %>
|
|
4
5
|
|
|
5
|
-
<%= form_for @dashboard, url: (@dashboard.persisted? ? dashboard_path(@dashboard, variable_params) : dashboards_path(variable_params)), html: {id: "app"} do |f| %>
|
|
6
6
|
<div class="form-group">
|
|
7
7
|
<%= f.label :name %>
|
|
8
8
|
<%= f.text_field :name, class: "form-control" %>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<div class="row" style="padding-top: 13px;">
|
|
6
6
|
<div class="col-sm-9">
|
|
7
7
|
<%= render partial: "blazer/nav" %>
|
|
8
|
-
<h3 style="
|
|
8
|
+
<h3 style="line-height: 34px; display: inline; margin-left: 5px;">
|
|
9
9
|
<%= @dashboard.name %>
|
|
10
10
|
</h3>
|
|
11
11
|
</div>
|
|
@@ -25,7 +25,11 @@
|
|
|
25
25
|
</p>
|
|
26
26
|
<% end %>
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
<% if @bind_vars.any? %>
|
|
29
|
+
<%= render partial: "blazer/variables", locals: {action: dashboard_path(@dashboard)} %>
|
|
30
|
+
<% else %>
|
|
31
|
+
<div style="padding-bottom: 15px;"></div>
|
|
32
|
+
<% end %>
|
|
29
33
|
|
|
30
34
|
<% @queries.each_with_index do |query, i| %>
|
|
31
35
|
<div class="chart-container">
|
|
@@ -35,7 +39,7 @@
|
|
|
35
39
|
</div>
|
|
36
40
|
</div>
|
|
37
41
|
<script>
|
|
38
|
-
<%= blazer_js_var "data", {statement: query.statement, query_id: query.id, only_chart: true} %>
|
|
42
|
+
<%= blazer_js_var "data", {statement: query.statement, query_id: query.id, data_source: query.data_source, only_chart: true} %>
|
|
39
43
|
|
|
40
44
|
runQuery(data, function (data) {
|
|
41
45
|
$("#chart-<%= i %>").html(data)
|
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
<div id="editor" :style="{ height: editorHeight }"><%= @query.statement %></div>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
|
-
<div class="form-group text-right">
|
|
16
|
-
<div class="pull-left" style="margin-top:
|
|
15
|
+
<div class="form-group text-right" style="margin-bottom: 8px;">
|
|
16
|
+
<div class="pull-left" style="margin-top: 8px;">
|
|
17
17
|
<%= link_to "Back", :back %>
|
|
18
|
+
<a :href="docsPath" target="_blank" style="margin-left: 40px;">Docs</a>
|
|
19
|
+
<a :href="schemaPath" target="_blank" style="margin-left: 40px;">Schema</a>
|
|
18
20
|
</div>
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
<%= 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
23
|
<div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;">
|
|
22
24
|
<select id="table_names" style="width: 240px;" placeholder="Preview table"></select>
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
<%= f.collection_select :assignee_ids, @assignees, :first, :last, {}, { placeholder: "Assignees", style: "height: 80px;", class: "form-control", multiple: true } %>
|
|
41
43
|
</div>
|
|
42
44
|
<%- end -%>
|
|
43
|
-
<div class="text-right">
|
|
45
|
+
<div class="form-group text-right">
|
|
44
46
|
<%= f.submit "For Enter Press", class: "hide" %>
|
|
45
47
|
<% if @query.persisted? %>
|
|
46
48
|
<%= link_to "Delete", query_path(@query), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
|
|
@@ -55,7 +57,7 @@
|
|
|
55
57
|
<% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
|
|
56
58
|
<% words << pluralize(checks_count, "check") if checks_count > 0 %>
|
|
57
59
|
<% if words.any? %>
|
|
58
|
-
<div class="alert alert-info" style="margin-
|
|
60
|
+
<div class="alert alert-info" style="margin-bottom: 0;">
|
|
59
61
|
Part of <%= words.to_sentence %>. Be careful when editing.
|
|
60
62
|
</div>
|
|
61
63
|
<% end %>
|
|
@@ -85,8 +87,11 @@
|
|
|
85
87
|
editorHeight: "180px"
|
|
86
88
|
},
|
|
87
89
|
computed: {
|
|
88
|
-
|
|
90
|
+
schemaPath: function() {
|
|
89
91
|
return Routes.schema_queries_path({data_source: this.dataSource})
|
|
92
|
+
},
|
|
93
|
+
docsPath: function() {
|
|
94
|
+
return Routes.docs_queries_path({data_source: this.dataSource})
|
|
90
95
|
}
|
|
91
96
|
},
|
|
92
97
|
methods: {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<% blazer_title "Docs: #{@data_source.name}" %>
|
|
2
|
+
|
|
3
|
+
<h1>Docs: <%= @data_source.name %></h1>
|
|
4
|
+
|
|
5
|
+
<hr />
|
|
6
|
+
|
|
7
|
+
<h2>Smart Variables</h2>
|
|
8
|
+
|
|
9
|
+
<% if @smart_variables.any? %>
|
|
10
|
+
<p>Use these variable names to get a dropdown of values.</p>
|
|
11
|
+
|
|
12
|
+
<table class="table" style="max-width: 500px;">
|
|
13
|
+
<thead>
|
|
14
|
+
<tr>
|
|
15
|
+
<th>Variable</th>
|
|
16
|
+
</tr>
|
|
17
|
+
</thead>
|
|
18
|
+
<tbody>
|
|
19
|
+
<% @smart_variables.each do |k, _| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<td><code>{<%= k %>}</code></td>
|
|
22
|
+
</tr>
|
|
23
|
+
<% end %>
|
|
24
|
+
</tbody>
|
|
25
|
+
</table>
|
|
26
|
+
|
|
27
|
+
<p>Use <code>{start_time}</code> and <code>{end_time}</code> for a date range selector. End a variable name with <code>_at</code> for a date selector.</p>
|
|
28
|
+
<% else %>
|
|
29
|
+
<p>None set - add them in <code>config/blazer.yml</code>.</p>
|
|
30
|
+
<% end %>
|
|
31
|
+
|
|
32
|
+
<h2>Linked Columns</h2>
|
|
33
|
+
|
|
34
|
+
<% if @linked_columns.any? %>
|
|
35
|
+
<p>Use these column names to link results to other pages.</p>
|
|
36
|
+
|
|
37
|
+
<table class="table" style="max-width: 500px;">
|
|
38
|
+
<thead>
|
|
39
|
+
<tr>
|
|
40
|
+
<th style="width: 20%;">Name</th>
|
|
41
|
+
<th>URL</th>
|
|
42
|
+
</tr>
|
|
43
|
+
</thead>
|
|
44
|
+
<tbody>
|
|
45
|
+
<% @linked_columns.each do |k, v| %>
|
|
46
|
+
<tr>
|
|
47
|
+
<td><%= k %></td>
|
|
48
|
+
<td><%= v %></td>
|
|
49
|
+
</tr>
|
|
50
|
+
<% end %>
|
|
51
|
+
</tbody>
|
|
52
|
+
</table>
|
|
53
|
+
|
|
54
|
+
<p>Values that match the format of a URL will be linked automatically.</p>
|
|
55
|
+
<% else %>
|
|
56
|
+
<p>None set - add them in <code>config/blazer.yml</code>.</p>
|
|
57
|
+
<% end %>
|
|
58
|
+
|
|
59
|
+
<h2>Smart Columns</h2>
|
|
60
|
+
|
|
61
|
+
<% if @smart_columns.any? %>
|
|
62
|
+
<p>Use these column names to show additional data.</p>
|
|
63
|
+
|
|
64
|
+
<table class="table" style="max-width: 500px;">
|
|
65
|
+
<thead>
|
|
66
|
+
<tr>
|
|
67
|
+
<th>Name</th>
|
|
68
|
+
</tr>
|
|
69
|
+
</thead>
|
|
70
|
+
<tbody>
|
|
71
|
+
<% @smart_columns.each do |k, _| %>
|
|
72
|
+
<tr>
|
|
73
|
+
<td><%= k %></td>
|
|
74
|
+
</tr>
|
|
75
|
+
<% end %>
|
|
76
|
+
</tbody>
|
|
77
|
+
</table>
|
|
78
|
+
<% else %>
|
|
79
|
+
<p>None set - add them in <code>config/blazer.yml</code>.</p>
|
|
80
|
+
<% end %>
|
|
81
|
+
|
|
82
|
+
<h2>Charts</h2>
|
|
83
|
+
|
|
84
|
+
<p>Use specific combinations of column types to generate charts.</p>
|
|
85
|
+
|
|
86
|
+
<table class="table" style="max-width: 500px;">
|
|
87
|
+
<thead>
|
|
88
|
+
<tr>
|
|
89
|
+
<th style="width: 20%;">Chart</th>
|
|
90
|
+
<th>Column Types</th>
|
|
91
|
+
</tr>
|
|
92
|
+
</thead>
|
|
93
|
+
<tbody>
|
|
94
|
+
<tr>
|
|
95
|
+
<td>Line</td>
|
|
96
|
+
<td>2+ columns - timestamp, numeric(s)</td>
|
|
97
|
+
</tr>
|
|
98
|
+
<tr>
|
|
99
|
+
<td>Line</td>
|
|
100
|
+
<td>3 columns - timestamp, string, numeric</td>
|
|
101
|
+
</tr>
|
|
102
|
+
<tr>
|
|
103
|
+
<td>Column</td>
|
|
104
|
+
<td>2+ columns - string, numeric(s)</td>
|
|
105
|
+
</tr>
|
|
106
|
+
<tr>
|
|
107
|
+
<td>Column</td>
|
|
108
|
+
<td>3 columns - string, string, numeric</td>
|
|
109
|
+
</tr>
|
|
110
|
+
<tr>
|
|
111
|
+
<td>Scatter</td>
|
|
112
|
+
<td>2 columns - both numeric</td>
|
|
113
|
+
</tr>
|
|
114
|
+
<tr>
|
|
115
|
+
<td>Pie</td>
|
|
116
|
+
<td>2 columns - string, numeric - and last column named <code>pie</code></td>
|
|
117
|
+
</tr>
|
|
118
|
+
<tr>
|
|
119
|
+
<td>Map</td>
|
|
120
|
+
<td>
|
|
121
|
+
Named <code>latitude</code> and <code>longitude</code>, or <code>lat</code> and <code>lon</code>, or <code>lat</code> and <code>lng</code>
|
|
122
|
+
<% if !blazer_maps? %>
|
|
123
|
+
<br />
|
|
124
|
+
<strong>Needs configured</strong>
|
|
125
|
+
<% end %>
|
|
126
|
+
</td>
|
|
127
|
+
</tr>
|
|
128
|
+
</tbody>
|
|
129
|
+
</table>
|
|
130
|
+
|
|
131
|
+
<p>Use the column name <code>target</code> to draw a line for goals.</p>
|