bnb_blazer 0.8.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +40 -0
- data/Rakefile +15 -4
- data/app/assets/images/bnb_blazer/bnb_intel_logo.png +0 -0
- data/app/assets/images/bnb_blazer/bnb_intel_logo_alt.png +0 -0
- data/app/assets/stylesheets/bnb_blazer/application.scss +147 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +4 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/jobs/application_job.rb +2 -0
- data/app/mailers/application_mailer.rb +4 -0
- data/app/models/application_record.rb +3 -0
- data/app/models/user.rb +2 -0
- data/app/views/blazer/_nav.html.erb +71 -0
- data/app/views/blazer/dashboards/show.html.erb +41 -0
- data/app/views/blazer/queries/home.html.erb +168 -0
- data/app/views/blazer/queries/show.html.erb +65 -0
- data/app/views/bnb_blazer/_footer.html.erb +3 -0
- data/app/views/{layouts/bnb_blazer → bnb_blazer}/_navbar.html.haml +0 -0
- data/app/views/layouts/blazer/application.html.erb +33 -0
- data/config/routes.rb +3 -0
- data/lib/bnb-blazer.rb +1 -0
- data/lib/bnb_blazer/engine.rb +8 -1
- data/lib/bnb_blazer/version.rb +1 -1
- data/lib/bnb_blazer.rb +0 -4
- metadata +38 -10
- data/app/overrides/controllers/blazer/base_controller_override.rb +0 -133
- data/app/views/bnb_blazer/queries/show.html.haml +0 -45
- data/app/views/layouts/bnb_blazer/_footer.html.haml +0 -2
- data/app/views/layouts/bnb_blazer/application.html.haml +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37a304cbb84b480b5cc6e7aff4cc09ae7bccd7fcb69b24779ce82af9fa7dff99
|
4
|
+
data.tar.gz: 7c0074350b120fef42441b6254245798f2bcbf9edc342e76ad3d403356847864
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2550fe50da2290c30a6dfd44c01bf0b68dd14d6aba5fab1c0b8dafd6b9bc690af877ff6c8954aadb5f2af04e51d8b2918f7d418e3c01087c3612c30648d77fa
|
7
|
+
data.tar.gz: e4ad811a0790159ee7d3f426f33f74be31cd5c74c3ae3db5eab2f10494eea641c4a2c1c38812b5b8d4a3f397b50c5b049ff21dddcca7d7cb9e171ea973d5fe0c
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# BnbBlazer
|
2
|
+
|
3
|
+
Welcome to BNB Blazer! This is a gem wrapper for the [Blazer](https://github.com/ankane/blazer) query tool designed specifically for BNB projects. In this directory, you'll find the files you need to edit the behavior/appearance of this gem. Additionally, you can spin up the test app to experiment with the appearance of the tool. Put your Ruby code in the file `lib/bnb_blazer`.
|
4
|
+
|
5
|
+
## PURPOSE
|
6
|
+
|
7
|
+
BNB Blazer helps our clients understand how their apps are performing, and keep an eye on key metrics about their business activities inside the app. In short, it helps our clients understand the superpowers that we build for them, and gives them reportable ways to tell others about the cool shit we built.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
To use this wrapper in conjunction with Blazer, add this block to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem "bnb_blazer"
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle install
|
20
|
+
|
21
|
+
## Development
|
22
|
+
|
23
|
+
This gem comes bundled with a test app to help you test out new display designs with pre-populated blazer queries. To get the environment up and running:
|
24
|
+
|
25
|
+
1. Clone this repo down to your machine
|
26
|
+
2. Make sure you have [Dip](https://github.com/brandnewbox/bnb-dip-defaults) installed and configured
|
27
|
+
3. Run `dip setup`
|
28
|
+
4. In your new `bnb_blazer` directory, run `docker-compose up`
|
29
|
+
5. Navigate to http://localhost:3000/blazer in your browser, and away you go!
|
30
|
+
|
31
|
+
For the work of actually overriding the gem, Rails will load any view that we have defined in the `app/views` (not `spec/dummy/app/views`) folder before looking for them in the blazer gem. So any view that we want to override or restyle you just have to create at the same location as it would be found in the blazer gem. E.g. the homepage view for blazer is found at `app/views/blazer/queries/home.html.erb`, so if we want to override what the homepage looks like in our gem then we create a new view at `app/views/blazer/queries/home.html.erb` and copy the existing HTML from the gem and make modifications as necessary.
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/brandnewbox/bnb_blazer.
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -1,7 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require "bundler/setup"
|
2
|
+
|
3
|
+
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
|
4
|
+
load "rails/tasks/engine.rake"
|
5
|
+
|
6
|
+
load "rails/tasks/statistics.rake"
|
3
7
|
|
4
|
-
require_relative 'config/application'
|
5
8
|
require "bundler/gem_tasks"
|
6
9
|
|
7
|
-
|
10
|
+
require "rake/testtask"
|
11
|
+
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = false
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: :test
|
Binary file
|
Binary file
|
@@ -0,0 +1,147 @@
|
|
1
|
+
body {
|
2
|
+
background-color: #edebeb;
|
3
|
+
font-family: 'Roboto Condensed', sans-serif;
|
4
|
+
|
5
|
+
padding-top: 0;
|
6
|
+
padding-bottom: 0;
|
7
|
+
}
|
8
|
+
|
9
|
+
#footer {
|
10
|
+
margin-top: 2em;
|
11
|
+
width: 100%;
|
12
|
+
}
|
13
|
+
|
14
|
+
#results > * {
|
15
|
+
background-color: #ffffff;
|
16
|
+
padding: 2em;
|
17
|
+
box-shadow: #000000;
|
18
|
+
}
|
19
|
+
|
20
|
+
.results-container {
|
21
|
+
margin-top: 20px;
|
22
|
+
}
|
23
|
+
|
24
|
+
.chart-container {
|
25
|
+
background-color: #f5f5f5;
|
26
|
+
padding-top: 10px;
|
27
|
+
padding-bottom: 10px;
|
28
|
+
}
|
29
|
+
|
30
|
+
.nav-btn {
|
31
|
+
color: #2eb1e6;
|
32
|
+
border-bottom: 2px solid #2eb1e6;
|
33
|
+
|
34
|
+
.btn-link {
|
35
|
+
color: #2eb1e6;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
.topbar {
|
40
|
+
height: auto;
|
41
|
+
|
42
|
+
@media (min-width: 480px) {
|
43
|
+
min-height: 56px;
|
44
|
+
}
|
45
|
+
|
46
|
+
.container-fluid, .row {
|
47
|
+
@media (min-width: 480px) {
|
48
|
+
height: 56px;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
.query-header {
|
53
|
+
display: flex;
|
54
|
+
align-items: center;
|
55
|
+
height: 100%;
|
56
|
+
}
|
57
|
+
|
58
|
+
.query-links {
|
59
|
+
display: flex;
|
60
|
+
justify-content: flex-end;
|
61
|
+
align-items: center;
|
62
|
+
height: 100%;
|
63
|
+
|
64
|
+
.btn-link {
|
65
|
+
color: #40424a;
|
66
|
+
font-size: 1.2em;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
.mobile-nav-wrapper {
|
72
|
+
display: flex;
|
73
|
+
justify-content: space-between;
|
74
|
+
align-items: center;
|
75
|
+
padding: 8px 2px;
|
76
|
+
}
|
77
|
+
|
78
|
+
.sidebar {
|
79
|
+
position: fixed;
|
80
|
+
left: -250px;
|
81
|
+
width: 250px;
|
82
|
+
height: 100%;
|
83
|
+
background: #40424a;
|
84
|
+
transition: all 0.5s ease;
|
85
|
+
z-index: 10000;
|
86
|
+
padding: 0 20px;
|
87
|
+
|
88
|
+
&.show {
|
89
|
+
left: 0;
|
90
|
+
}
|
91
|
+
|
92
|
+
.sidebar-header {
|
93
|
+
display: flex;
|
94
|
+
align-items: center;
|
95
|
+
justify-content: space-between;
|
96
|
+
margin-bottom: 25px;
|
97
|
+
}
|
98
|
+
|
99
|
+
.sidebar-closer {
|
100
|
+
color: #FFF;
|
101
|
+
font-size: 4rem;
|
102
|
+
padding: 0;
|
103
|
+
}
|
104
|
+
|
105
|
+
a {
|
106
|
+
display: block;
|
107
|
+
color: #FFF;
|
108
|
+
padding: 10px 0px;
|
109
|
+
font-size: 2.5rem;
|
110
|
+
font-weight: 300;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
.header-title {
|
115
|
+
margin-bottom: 0;
|
116
|
+
|
117
|
+
padding-top: 1em;
|
118
|
+
padding-bottom: 1em;
|
119
|
+
|
120
|
+
@media (min-width: 480px) {
|
121
|
+
padding-top: 0;
|
122
|
+
padding-bottom: 0;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
#queries {
|
127
|
+
#header {
|
128
|
+
position: fixed;
|
129
|
+
top: 0;
|
130
|
+
left: 0;
|
131
|
+
right: 0;
|
132
|
+
height: 60px;
|
133
|
+
z-index: 1001;
|
134
|
+
border-bottom: solid 1px whitesmoke;
|
135
|
+
background-color: #fff;
|
136
|
+
padding-left: 1em;
|
137
|
+
padding-right: 1em;
|
138
|
+
|
139
|
+
display: flex;
|
140
|
+
align-items: center;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
.card {
|
145
|
+
background: #ffffff;
|
146
|
+
padding: 2em;
|
147
|
+
}
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
<div class="topbar">
|
2
|
+
<div class="container-fluid">
|
3
|
+
<div class="row">
|
4
|
+
<div class="col-sm-12 visible-xs">
|
5
|
+
<div class="mobile-nav-wrapper">
|
6
|
+
<svg viewBox="0 0 100 72" width="40" height="40" fill="#2eb1e6" class="sidebar-toggle">
|
7
|
+
<rect width="100" height="12"></rect>
|
8
|
+
<rect y="30" width="100" height="12"></rect>
|
9
|
+
<rect y="60" width="100" height="12"></rect>
|
10
|
+
</svg>
|
11
|
+
<%= link_to root_path do %>
|
12
|
+
<%= image_tag "bnb_blazer/bnb_intel_logo.png", style: "height: 35px;" %>
|
13
|
+
<% end %>
|
14
|
+
</div>
|
15
|
+
</div>
|
16
|
+
<div class="col-sm-12 col-md-6 query-header hidden-xs">
|
17
|
+
<div class="btn-group nav-btn hidden-xs" style="vertical-align: top; margin-right: 3em;">
|
18
|
+
<%= link_to "Home", root_path, class: "btn btn-link" %>
|
19
|
+
<button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
20
|
+
<span class="caret"></span>
|
21
|
+
<span class="sr-only">Toggle Dropdown</span>
|
22
|
+
</button>
|
23
|
+
<ul class="dropdown-menu">
|
24
|
+
<li><%= link_to "Checks", checks_path %></li>
|
25
|
+
<% if Blazer.uploads? %>
|
26
|
+
<li><%= link_to "Uploads", uploads_path %></li>
|
27
|
+
<% end %>
|
28
|
+
<li role="separator" class="divider"></li>
|
29
|
+
<li><%= link_to "New Query", new_query_path %></li>
|
30
|
+
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
31
|
+
<% check_params = @query ? {query_id: @query.id} : {} %>
|
32
|
+
<li><%= link_to "New Check", new_check_path(check_params) %></li>
|
33
|
+
</ul>
|
34
|
+
</div>
|
35
|
+
<h3 class="header-title">
|
36
|
+
<%= @query&.name %>
|
37
|
+
<%= @dashboard&.name %>
|
38
|
+
</h3>
|
39
|
+
</div>
|
40
|
+
<div class="col-sm-12 col-md-6 query-links hidden-xs">
|
41
|
+
<%= yield %>
|
42
|
+
<div style="display: inline-block;">
|
43
|
+
<%= image_tag "bnb_blazer/bnb_intel_logo.png", style: "height: 24px;" %>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
<div class="sidebar visible-xs">
|
50
|
+
<div class="sidebar-header">
|
51
|
+
<%= image_tag "bnb_blazer/bnb_intel_logo_alt.png", style: "height: 32px;" %>
|
52
|
+
<button type="button" class="sidebar-closer btn btn-link">×</button>
|
53
|
+
</div>
|
54
|
+
<div class="sidebar-body">
|
55
|
+
<%= link_to "Home", root_path %>
|
56
|
+
<%- Blazer::Dashboard.order(:name).each do |dashboard| %>
|
57
|
+
<%= link_to dashboard.name, dashboard_path(dashboard) %>
|
58
|
+
<%- end %>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<script>
|
63
|
+
var sidebarToggleEl = document.querySelector('.sidebar-toggle');
|
64
|
+
sidebarToggleEl.addEventListener("click", function(e) {
|
65
|
+
document.querySelector(".sidebar").classList.toggle("show")
|
66
|
+
});
|
67
|
+
var sidebarCloserEl = document.querySelector('.sidebar-closer');
|
68
|
+
sidebarCloserEl.addEventListener("click", function(e) {
|
69
|
+
document.querySelector(".sidebar").classList.remove("show")
|
70
|
+
});
|
71
|
+
</script>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<% blazer_title @dashboard.name %>
|
2
|
+
|
3
|
+
<% content_for :header do %>
|
4
|
+
<%= render layout: "blazer/nav" do %>
|
5
|
+
<%= link_to "Edit", edit_dashboard_path(@dashboard, variable_params(@dashboard)), class: "btn btn-link" %>
|
6
|
+
<% end %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<div style="margin-bottom: 60px;"></div>
|
10
|
+
|
11
|
+
<% if @data_sources.any? { |ds| ds.cache_mode != "off" } %>
|
12
|
+
<p class="text-muted" style="float: right;">
|
13
|
+
Some queries may be cached
|
14
|
+
<%= link_to "Refresh", refresh_dashboard_path(@dashboard, variable_params(@dashboard)), method: :post %>
|
15
|
+
</p>
|
16
|
+
<% end %>
|
17
|
+
|
18
|
+
<% if @bind_vars.any? %>
|
19
|
+
<%= render partial: "blazer/variables", locals: {action: dashboard_path(@dashboard)} %>
|
20
|
+
<% else %>
|
21
|
+
<div style="padding-bottom: 15px;"></div>
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
<% @queries.each_with_index do |query, i| %>
|
25
|
+
<div class="chart-container">
|
26
|
+
<h4><%= link_to query.friendly_name, query_path(query, variable_params(query)), target: "_blank" %></h4>
|
27
|
+
<div id="chart-<%= i %>" class="chart">
|
28
|
+
<p class="text-muted">Loading...</p>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
<script>
|
32
|
+
<%= blazer_js_var "data", {statement: @statements[i], query_id: query.id, data_source: query.data_source, only_chart: true, cohort_period: params[:cohort_period]} %>
|
33
|
+
|
34
|
+
runQuery(data, function (data) {
|
35
|
+
$("#chart-<%= i %>").html(data)
|
36
|
+
$("#chart-<%= i %> table").stupidtable(stupidtableCustomSettings)
|
37
|
+
}, function (message) {
|
38
|
+
$("#chart-<%= i %>").addClass("query-error").html(message)
|
39
|
+
});
|
40
|
+
</script>
|
41
|
+
<% end %>
|
@@ -0,0 +1,168 @@
|
|
1
|
+
<div id="queries">
|
2
|
+
<div id="header">
|
3
|
+
<div class="" style="line-height: 34px;">
|
4
|
+
<% if blazer_user %>
|
5
|
+
<%= link_to "All", root_path, class: !params[:filter] ? "active" : nil, style: "margin-right: 40px;" %>
|
6
|
+
|
7
|
+
<% if Blazer.audit %>
|
8
|
+
<%= link_to "Viewed", root_path(filter: "viewed"), class: params[:filter] == "viewed" ? "active" : nil, style: "margin-right: 40px;" %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<%= link_to "Mine", root_path(filter: "mine"), class: params[:filter] == "mine" ? "active" : nil, style: "margin-right: 40px;" %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="btn-group nav-btn" style="display: flex;">
|
15
|
+
<%= link_to "New Query", new_query_path, class: "btn btn-link" %>
|
16
|
+
<button type="button" class="btn btn-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
17
|
+
<span class="caret"></span>
|
18
|
+
<span class="sr-only">Toggle Dropdown</span>
|
19
|
+
</button>
|
20
|
+
<ul class="dropdown-menu">
|
21
|
+
<li><%= link_to "Checks", checks_path %></li>
|
22
|
+
<% if Blazer.uploads? %>
|
23
|
+
<li><%= link_to "Uploads", uploads_path %></li>
|
24
|
+
<% end %>
|
25
|
+
<li role="separator" class="divider"></li>
|
26
|
+
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
27
|
+
<li><%= link_to "New Check", new_check_path %></li>
|
28
|
+
</ul>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
<input type="text" v-model="searchTerm" placeholder="Start typing a query, dashboard, or person" style="display: inline-block;" v-focus class="search form-control" />
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="card" style="margin-top: 80px;">
|
35
|
+
<table class="table">
|
36
|
+
<thead>
|
37
|
+
<tr>
|
38
|
+
<th>Name</th>
|
39
|
+
<% if Blazer.user_class %>
|
40
|
+
<th style="width: 20%; text-align: right;">Mastermind</th>
|
41
|
+
<% end%>
|
42
|
+
</tr>
|
43
|
+
</thead>
|
44
|
+
<tbody class="list" v-cloak>
|
45
|
+
<tr v-for="query in visibleItems">
|
46
|
+
<td>
|
47
|
+
<a :href="itemPath(query)" :class="{ dashboard: query.dashboard }">{{ query.name }}</a>
|
48
|
+
<span class="vars">{{ query.vars }}</span>
|
49
|
+
</td>
|
50
|
+
<% if Blazer.user_class %>
|
51
|
+
<td class="creator">{{ query.creator }}</td>
|
52
|
+
<% end %>
|
53
|
+
</tr>
|
54
|
+
</tbody>
|
55
|
+
</table>
|
56
|
+
</div>
|
57
|
+
|
58
|
+
<p v-if="more" class="text-muted">Loading...</p>
|
59
|
+
</div>
|
60
|
+
|
61
|
+
<script>
|
62
|
+
<%= blazer_js_var "dashboards", @dashboards %>
|
63
|
+
<%= blazer_js_var "queries", @queries %>
|
64
|
+
<%= blazer_js_var "more", @more %>
|
65
|
+
|
66
|
+
var prepareSearch = function (list) {
|
67
|
+
var i, q, searchStr
|
68
|
+
for (i = 0; i < list.length; i++) {
|
69
|
+
q = list[i]
|
70
|
+
searchStr = q.name + q.creator
|
71
|
+
if (q.creator === "You") {
|
72
|
+
searchStr += "mine me"
|
73
|
+
}
|
74
|
+
q.searchStr = prepareQuery(searchStr)
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
var prepareQuery = function (str) {
|
79
|
+
return str.toLowerCase()
|
80
|
+
}
|
81
|
+
|
82
|
+
var app = new Vue({
|
83
|
+
el: "#queries",
|
84
|
+
data: {
|
85
|
+
searchTerm: "",
|
86
|
+
more: more,
|
87
|
+
updateCounter: 0
|
88
|
+
},
|
89
|
+
created: function() {
|
90
|
+
this.listItems = dashboards.concat(queries)
|
91
|
+
|
92
|
+
prepareSearch(this.listItems)
|
93
|
+
|
94
|
+
this.queryIds = {}
|
95
|
+
for (i = 0; i < queries.length; i++) {
|
96
|
+
this.queryIds[queries[i].id] = true
|
97
|
+
}
|
98
|
+
|
99
|
+
if (this.more) {
|
100
|
+
var _this = this
|
101
|
+
|
102
|
+
$.getJSON(Routes.queries_path(), function (data) {
|
103
|
+
var i, j, newValues, val, size = 500;
|
104
|
+
|
105
|
+
var newValues = []
|
106
|
+
for (j = 0; j < data.length; j++) {
|
107
|
+
val = data[j]
|
108
|
+
if (val && !_this.queryIds[val.id]) {
|
109
|
+
newValues.push(val)
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
prepareSearch(newValues)
|
114
|
+
|
115
|
+
_this.listItems = _this.listItems.concat(newValues)
|
116
|
+
_this.more = false
|
117
|
+
// hack to get to update
|
118
|
+
_this.updateCounter++
|
119
|
+
})
|
120
|
+
}
|
121
|
+
},
|
122
|
+
computed: {
|
123
|
+
visibleItems: function () {
|
124
|
+
// hack to get to update
|
125
|
+
this.updateCounter
|
126
|
+
|
127
|
+
var pageSize = 200
|
128
|
+
var q, i
|
129
|
+
|
130
|
+
if (this.searchTerm.length > 0) {
|
131
|
+
var term = prepareQuery(this.searchTerm)
|
132
|
+
var items = []
|
133
|
+
var fuzzyItems = []
|
134
|
+
for (i = 0; i < this.listItems.length; i++) {
|
135
|
+
q = this.listItems[i]
|
136
|
+
if (q.searchStr.indexOf(term) !== -1) {
|
137
|
+
items.push(q)
|
138
|
+
if (items.length == pageSize) {
|
139
|
+
break
|
140
|
+
}
|
141
|
+
} else if (fuzzysearch(term, q.searchStr)) {
|
142
|
+
fuzzyItems.push(q)
|
143
|
+
}
|
144
|
+
}
|
145
|
+
return items.concat(fuzzyItems).slice(0, pageSize)
|
146
|
+
} else {
|
147
|
+
return this.listItems.slice(0, pageSize)
|
148
|
+
}
|
149
|
+
}
|
150
|
+
},
|
151
|
+
methods: {
|
152
|
+
itemPath: function (item) {
|
153
|
+
if (item.dashboard) {
|
154
|
+
return Routes.dashboard_path(item.to_param)
|
155
|
+
} else {
|
156
|
+
return Routes.query_path(item.to_param)
|
157
|
+
}
|
158
|
+
}
|
159
|
+
},
|
160
|
+
directives: {
|
161
|
+
focus: {
|
162
|
+
inserted: function (el) {
|
163
|
+
el.focus()
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
})
|
168
|
+
</script>
|
@@ -0,0 +1,65 @@
|
|
1
|
+
<% blazer_title @query.name %>
|
2
|
+
|
3
|
+
<% content_for :header do %>
|
4
|
+
<%= render "blazer/nav" do %>
|
5
|
+
<%= link_to "Edit", edit_query_path(@query, variable_params(@query)), class: "btn btn-link", disabled: !@query.editable?(blazer_user) %>
|
6
|
+
<%= link_to "Fork", new_query_path(variable_params(@query).merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "btn btn-link" %>
|
7
|
+
|
8
|
+
<% if !@error && @success %>
|
9
|
+
<%= button_to "Download", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast], cohort_period: params[:cohort_period]), params: {statement: @statement}, class: "btn btn-link" %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div style="margin-bottom: 60px;"></div>
|
15
|
+
|
16
|
+
<% if @sql_errors.any? %>
|
17
|
+
<div class="alert alert-danger">
|
18
|
+
<ul>
|
19
|
+
<% @sql_errors.each do |message| %>
|
20
|
+
<li><%= message %></li>
|
21
|
+
<% end %>
|
22
|
+
</ul>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% if @query.description.present? %>
|
27
|
+
<p><%= @query.description %></p>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
<%= render partial: "blazer/variables", locals: {action: query_path(@query)} %>
|
31
|
+
|
32
|
+
<%# <pre id="code"><code><%= @statement ></code></pre> %>
|
33
|
+
|
34
|
+
<% if @success %>
|
35
|
+
<div id="results">
|
36
|
+
<p class="text-muted">Loading...</p>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<script>
|
40
|
+
function showRun(data) {
|
41
|
+
$("#results").html(data)
|
42
|
+
$("#results table").stupidtable(stupidtableCustomSettings).stickyTableHeaders({fixedOffset: 60})
|
43
|
+
}
|
44
|
+
|
45
|
+
function showError(message) {
|
46
|
+
$("#results").addClass("query-error").html(message)
|
47
|
+
}
|
48
|
+
|
49
|
+
<% data = variable_params(@query).merge(statement: @statement, query_id: @query.id, data_source: @query.data_source) %>
|
50
|
+
<% data.merge!(forecast: "t") if params[:forecast] %>
|
51
|
+
<%= blazer_js_var "data", data %>
|
52
|
+
|
53
|
+
runQuery(data, showRun, showError)
|
54
|
+
</script>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<% unless %w(mongodb).include?(Blazer.data_sources[@query.data_source].adapter) %>
|
58
|
+
<script>
|
59
|
+
// do not highlight really long queries
|
60
|
+
// this can lead to performance issues
|
61
|
+
if ($("code").text().length < 10000) {
|
62
|
+
hljs.highlightBlock(document.getElementById("code"));
|
63
|
+
}
|
64
|
+
</script>
|
65
|
+
<% end %>
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= blazer_title ? blazer_title : "Blazer" %></title>
|
5
|
+
|
6
|
+
<meta charset="utf-8" />
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
8
|
+
<%= favicon_link_tag "blazer/favicon.png" %>
|
9
|
+
<%= stylesheet_link_tag "blazer/application" %>
|
10
|
+
<%= stylesheet_link_tag "bnb_blazer/application" %>
|
11
|
+
<%= javascript_include_tag "blazer/application" %>
|
12
|
+
<script>
|
13
|
+
<%= blazer_js_var "rootPath", root_path %>
|
14
|
+
</script>
|
15
|
+
<% if blazer_maps? %>
|
16
|
+
<%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css", integrity: "sha384-vxzdEt+wZRPNQbhChjmiaFMLWg86IGuq1NGDehJHsD2mphYkxXll/eSs16WWi6Dq", crossorigin: "anonymous" %>
|
17
|
+
<%= javascript_include_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js", integrity: "sha384-CTBEiDLiZJ8gkAQ3fYGoeiRp81/ecNiBkGz11jXFALOZ6++rbnqmdo6OImkmr1MO", crossorigin: "anonymous" %>
|
18
|
+
<% end %>
|
19
|
+
<%= csrf_meta_tags %>
|
20
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
21
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
22
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap" rel="stylesheet">
|
23
|
+
</head>
|
24
|
+
<body>
|
25
|
+
<%= yield :header %>
|
26
|
+
|
27
|
+
<div class="container">
|
28
|
+
<%= yield %>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<%= render partial: "bnb_blazer/footer" %>
|
32
|
+
</body>
|
33
|
+
</html>
|
data/config/routes.rb
ADDED
data/lib/bnb-blazer.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "./bnb_blazer"
|
data/lib/bnb_blazer/engine.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
+
require "blazer"
|
1
2
|
module BnbBlazer
|
2
|
-
class
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
isolate_namespace BnbBlazer
|
3
5
|
|
6
|
+
initializer "blazer" do |app|
|
7
|
+
app.config.assets.precompile << "bnb_blazer/application.css"
|
8
|
+
app.config.assets.precompile << "bnb_blazer/bnb_intel_logo.png"
|
9
|
+
app.config.assets.precompile << "bnb_blazer/bnb_intel_logo_alt.png"
|
10
|
+
end
|
4
11
|
end
|
5
12
|
end
|
data/lib/bnb_blazer/version.rb
CHANGED
data/lib/bnb_blazer.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bnb_blazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: blazer
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sassc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
27
41
|
description: Customized branding of the Blazer gem for BNB projects
|
28
42
|
email:
|
29
43
|
- pickertjoe@gmail.com
|
@@ -31,8 +45,24 @@ executables: []
|
|
31
45
|
extensions: []
|
32
46
|
extra_rdoc_files: []
|
33
47
|
files:
|
48
|
+
- README.md
|
34
49
|
- Rakefile
|
35
|
-
- app/
|
50
|
+
- app/assets/images/bnb_blazer/bnb_intel_logo.png
|
51
|
+
- app/assets/images/bnb_blazer/bnb_intel_logo_alt.png
|
52
|
+
- app/assets/stylesheets/bnb_blazer/application.scss
|
53
|
+
- app/channels/application_cable/channel.rb
|
54
|
+
- app/channels/application_cable/connection.rb
|
55
|
+
- app/helpers/application_helper.rb
|
56
|
+
- app/jobs/application_job.rb
|
57
|
+
- app/mailers/application_mailer.rb
|
58
|
+
- app/models/application_record.rb
|
59
|
+
- app/models/user.rb
|
60
|
+
- app/views/blazer/_nav.html.erb
|
61
|
+
- app/views/blazer/dashboards/show.html.erb
|
62
|
+
- app/views/blazer/queries/home.html.erb
|
63
|
+
- app/views/blazer/queries/show.html.erb
|
64
|
+
- app/views/bnb_blazer/_footer.html.erb
|
65
|
+
- app/views/bnb_blazer/_navbar.html.haml
|
36
66
|
- app/views/bnb_blazer/_variables.html.haml
|
37
67
|
- app/views/bnb_blazer/checks/_form.html.haml
|
38
68
|
- app/views/bnb_blazer/checks/edit.html.haml
|
@@ -47,10 +77,9 @@ files:
|
|
47
77
|
- app/views/bnb_blazer/queries/home.html.haml
|
48
78
|
- app/views/bnb_blazer/queries/new.html.haml
|
49
79
|
- app/views/bnb_blazer/queries/run.html.haml
|
50
|
-
- app/views/
|
51
|
-
-
|
52
|
-
-
|
53
|
-
- app/views/layouts/bnb_blazer/application.html.haml
|
80
|
+
- app/views/layouts/blazer/application.html.erb
|
81
|
+
- config/routes.rb
|
82
|
+
- lib/bnb-blazer.rb
|
54
83
|
- lib/bnb_blazer.rb
|
55
84
|
- lib/bnb_blazer/engine.rb
|
56
85
|
- lib/bnb_blazer/version.rb
|
@@ -75,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
104
|
- !ruby/object:Gem::Version
|
76
105
|
version: '0'
|
77
106
|
requirements: []
|
78
|
-
|
79
|
-
rubygems_version: 2.7.8
|
107
|
+
rubygems_version: 3.1.2
|
80
108
|
signing_key:
|
81
109
|
specification_version: 4
|
82
110
|
summary: Customized branding of the Blazer gem for BNB projects
|
@@ -1,133 +0,0 @@
|
|
1
|
-
Blazer::BaseController.class_eval do
|
2
|
-
# skip filters
|
3
|
-
filters = _process_action_callbacks.map(&:filter) - [:activate_authlogic]
|
4
|
-
skip_before_action(*filters, raise: false)
|
5
|
-
skip_after_action(*filters, raise: false)
|
6
|
-
skip_around_action(*filters, raise: false)
|
7
|
-
|
8
|
-
clear_helpers
|
9
|
-
|
10
|
-
protect_from_forgery with: :exception
|
11
|
-
|
12
|
-
if ENV["BLAZER_PASSWORD"]
|
13
|
-
http_basic_authenticate_with name: ENV["BLAZER_USERNAME"], password: ENV["BLAZER_PASSWORD"]
|
14
|
-
end
|
15
|
-
|
16
|
-
if Blazer.settings["before_action"]
|
17
|
-
raise Blazer::Error, "The docs for protecting Blazer with a custom before_action had an incorrect example from August 2017 to June 2018. The example method had a boolean return value. However, you must render or redirect if a user is unauthorized rather than return a falsy value. Double check that your before_action works correctly for unauthorized users (if it worked when added, there should be no issue). Then, change before_action to before_action_method in config/blazer.yml."
|
18
|
-
end
|
19
|
-
|
20
|
-
if Blazer.before_action
|
21
|
-
before_action Blazer.before_action.to_sym
|
22
|
-
end
|
23
|
-
|
24
|
-
if Blazer.override_csp
|
25
|
-
after_action do
|
26
|
-
response.headers['Content-Security-Policy'] = "default-src 'self' https: 'unsafe-inline' 'unsafe-eval' data:"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
layout "bnb_blazer/application"
|
31
|
-
append_view_path(["views/blazer", "views/bnb_blazer", "views/blazer"])
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def process_vars(statement, data_source)
|
36
|
-
(@bind_vars ||= []).concat(Blazer.extract_vars(statement)).uniq!
|
37
|
-
@bind_vars.each do |var|
|
38
|
-
params[var] ||= Blazer.data_sources[data_source].variable_defaults[var]
|
39
|
-
end
|
40
|
-
@success = @bind_vars.all? { |v| params[v] }
|
41
|
-
|
42
|
-
if @success
|
43
|
-
@bind_vars.each do |var|
|
44
|
-
value = params[var].presence
|
45
|
-
if value
|
46
|
-
if ["start_time", "end_time"].include?(var)
|
47
|
-
value = value.to_s.gsub(" ", "+") # fix for Quip bug
|
48
|
-
end
|
49
|
-
|
50
|
-
if var.end_with?("_at")
|
51
|
-
begin
|
52
|
-
value = Blazer.time_zone.parse(value)
|
53
|
-
rescue
|
54
|
-
# do nothing
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
if value =~ /\A\d+\z/
|
59
|
-
value = value.to_i
|
60
|
-
elsif value =~ /\A\d+\.\d+\z/
|
61
|
-
value = value.to_f
|
62
|
-
end
|
63
|
-
end
|
64
|
-
value = Blazer.transform_variable.call(var, value) if Blazer.transform_variable
|
65
|
-
statement.gsub!("{#{var}}", ActiveRecord::Base.connection.quote(value))
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def add_cohort_analysis_vars
|
71
|
-
@bind_vars << "cohort_period" unless @bind_vars.include?("cohort_period")
|
72
|
-
@smart_vars["cohort_period"] = ["day", "week", "month"]
|
73
|
-
params[:cohort_period] ||= "week"
|
74
|
-
end
|
75
|
-
|
76
|
-
def parse_smart_variables(var, data_source)
|
77
|
-
smart_var_data_source =
|
78
|
-
([data_source] + Array(data_source.settings["inherit_smart_settings"]).map { |ds| Blazer.data_sources[ds] }).find { |ds| ds.smart_variables[var] }
|
79
|
-
|
80
|
-
if smart_var_data_source
|
81
|
-
query = smart_var_data_source.smart_variables[var]
|
82
|
-
|
83
|
-
if query.is_a? Hash
|
84
|
-
smart_var = query.map { |k,v| [v, k] }
|
85
|
-
elsif query.is_a? Array
|
86
|
-
smart_var = query.map { |v| [v, v] }
|
87
|
-
elsif query
|
88
|
-
result = smart_var_data_source.run_statement(query)
|
89
|
-
smart_var = result.rows.map { |v| v.reverse }
|
90
|
-
error = result.error if result.error
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
[smart_var, error]
|
95
|
-
end
|
96
|
-
|
97
|
-
# don't pass to url helpers
|
98
|
-
#
|
99
|
-
# some are dangerous when passed as symbols
|
100
|
-
# root_url({host: "evilsite.com"})
|
101
|
-
#
|
102
|
-
# certain ones (like host) only affect *_url and not *_path
|
103
|
-
#
|
104
|
-
# when permitted parameters are passed in Rails 6,
|
105
|
-
# they appear to be added as GET parameters
|
106
|
-
# root_url(params.permit(:host))
|
107
|
-
UNPERMITTED_KEYS = [:controller, :action, :id, :host, :query, :dashboard, :query_id, :query_ids, :table_names, :authenticity_token, :utf8, :_method, :commit, :statement, :data_source, :name, :fork_query_id, :blazer, :run_id, :script_name, :original_script_name]
|
108
|
-
|
109
|
-
# remove unpermitted keys from both params and permitted keys for better sleep
|
110
|
-
def variable_params(resource)
|
111
|
-
permitted_keys = resource.variables - UNPERMITTED_KEYS.map(&:to_s)
|
112
|
-
params.except(*UNPERMITTED_KEYS).slice(*permitted_keys).permit!
|
113
|
-
end
|
114
|
-
helper_method :variable_params
|
115
|
-
|
116
|
-
def blazer_user
|
117
|
-
send(Blazer.user_method) if Blazer.user_method && respond_to?(Blazer.user_method, true)
|
118
|
-
end
|
119
|
-
helper_method :blazer_user
|
120
|
-
|
121
|
-
def render_errors(resource)
|
122
|
-
@errors = resource.errors
|
123
|
-
action = resource.persisted? ? :edit : :new
|
124
|
-
render action, status: :unprocessable_entity
|
125
|
-
end
|
126
|
-
|
127
|
-
# do not inherit from ApplicationController - #120
|
128
|
-
def default_url_options
|
129
|
-
{}
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
- blazer_title @query.name
|
2
|
-
%nav.navbar.navbar-default.navbar-fixed-top
|
3
|
-
.container
|
4
|
-
= render layout: "layouts/bnb_blazer/navbar" do
|
5
|
-
%li= link_to "Edit", edit_query_path(@query, variable_params(@query)), class: "text-muted font-weight-bold px-1", disabled: !@query.editable?(blazer_user)
|
6
|
-
%li= link_to "Fork", new_query_path(variable_params(@query).merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "text-muted font-weight-bold px-1"
|
7
|
-
- if !@error && @success
|
8
|
-
%li= link_to "Download", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast], cohort_period: params[:cohort_period]), params: {statement: @statement}, class: "text-muted font-weight-bold px-1"
|
9
|
-
|
10
|
-
#blazer-content
|
11
|
-
%div{:style => "margin-bottom: 70px;"}
|
12
|
-
- if @sql_errors.any?
|
13
|
-
.alert.alert-danger
|
14
|
-
%ul
|
15
|
-
- @sql_errors.each do |message|
|
16
|
-
%li= message
|
17
|
-
%h3.text-center=@query.name
|
18
|
-
- if @query.description.present?
|
19
|
-
%p= @query.description
|
20
|
-
= render partial: "bnb_blazer/variables", locals: {action: query_path(@query)}
|
21
|
-
%pre#code
|
22
|
-
%code= @statement
|
23
|
-
- if @success
|
24
|
-
#results
|
25
|
-
%p.text-muted.text-uppercase Loading...
|
26
|
-
:javascript
|
27
|
-
function showRun(data) {
|
28
|
-
$("#results").html(data)
|
29
|
-
$("#results table").stupidtable(stupidtableCustomSettings).stickyTableHeaders({fixedOffset: 60})
|
30
|
-
}
|
31
|
-
|
32
|
-
function showError(message) {
|
33
|
-
$("#results").addClass("query-error").html(message)
|
34
|
-
}
|
35
|
-
|
36
|
-
#{blazer_js_var "data", variable_params(@query).merge(statement: @statement, query_id: @query.id, data_source: @query.data_source)}
|
37
|
-
|
38
|
-
runQuery(data, showRun, showError)
|
39
|
-
- unless %w(mongodb).include?(Blazer.data_sources[@query.data_source].adapter)
|
40
|
-
:javascript
|
41
|
-
// do not highlight really long queries
|
42
|
-
// this can lead to performance issues
|
43
|
-
if ($("code").text().length < 10000) {
|
44
|
-
hljs.highlightBlock(document.getElementById("code"));
|
45
|
-
}
|
@@ -1,21 +0,0 @@
|
|
1
|
-
!!!
|
2
|
-
%html
|
3
|
-
%head
|
4
|
-
%meta{ content: "width=device-width, initial-scale=1.0", name:"viewport" }
|
5
|
-
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
|
6
|
-
%title= blazer_title ? blazer_title : "Blazer"
|
7
|
-
%meta{:charset => "utf-8"}/
|
8
|
-
= favicon_link_tag "blazer/favicon.png"
|
9
|
-
= stylesheet_link_tag "blazer/application"
|
10
|
-
= stylesheet_link_tag "application"
|
11
|
-
= javascript_include_tag "blazer/application"
|
12
|
-
:javascript
|
13
|
-
#{blazer_js_var "rootPath", root_path}
|
14
|
-
- if blazer_maps?
|
15
|
-
= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css", integrity: "sha384-vxzdEt+wZRPNQbhChjmiaFMLWg86IGuq1NGDehJHsD2mphYkxXll/eSs16WWi6Dq", crossorigin: "anonymous"
|
16
|
-
= javascript_include_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js", integrity: "sha384-CTBEiDLiZJ8gkAQ3fYGoeiRp81/ecNiBkGz11jXFALOZ6++rbnqmdo6OImkmr1MO", crossorigin: "anonymous"
|
17
|
-
= csrf_meta_tags
|
18
|
-
%body
|
19
|
-
.container.blazer-content
|
20
|
-
= yield
|
21
|
-
= render "layouts/blazer/footer"
|