rails_mini_profiler 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +47 -35
  3. data/app/adapters/rails_mini_profiler/database_adapter.rb +16 -0
  4. data/app/controllers/rails_mini_profiler/application_controller.rb +9 -6
  5. data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +15 -4
  6. data/app/helpers/rails_mini_profiler/profiled_requests_helper.rb +10 -0
  7. data/app/javascript/js/clipboard_controller.js +9 -2
  8. data/app/javascript/js/filter_controller.js +4 -0
  9. data/app/javascript/stylesheets/components/buttons.scss +59 -0
  10. data/app/javascript/stylesheets/components/{profiled_request_table/profiled_request_table.scss → dropdown.scss} +0 -76
  11. data/app/javascript/stylesheets/components/input.scss +10 -0
  12. data/app/javascript/stylesheets/{navbar.scss → components/navbar.scss} +0 -0
  13. data/app/javascript/stylesheets/components/page_header.scss +7 -0
  14. data/app/javascript/stylesheets/components/{profiled_request_table/placeholder.scss → placeholder.scss} +4 -1
  15. data/app/javascript/stylesheets/components/profiled_request_table.scss +55 -0
  16. data/app/javascript/stylesheets/components/trace.scss +93 -0
  17. data/app/javascript/stylesheets/profiled_requests.scss +3 -67
  18. data/app/javascript/stylesheets/rails-mini-profiler.scss +16 -30
  19. data/app/javascript/stylesheets/traces.scss +44 -76
  20. data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +2 -2
  21. data/app/presenters/rails_mini_profiler/trace_presenter.rb +9 -7
  22. data/app/search/rails_mini_profiler/profiled_request_search.rb +0 -1
  23. data/app/search/rails_mini_profiler/trace_search.rb +27 -0
  24. data/app/views/rails_mini_profiler/profiled_requests/shared/header/_header.erb +1 -2
  25. data/app/views/rails_mini_profiler/profiled_requests/shared/table/_table_head.erb +7 -7
  26. data/app/views/rails_mini_profiler/profiled_requests/{shared → show}/_trace.html.erb +23 -21
  27. data/app/views/rails_mini_profiler/profiled_requests/show/_trace_list.erb +12 -0
  28. data/app/views/rails_mini_profiler/profiled_requests/show/_trace_list_header.erb +87 -0
  29. data/app/views/rails_mini_profiler/profiled_requests/show/_trace_list_placeholder.erb +12 -0
  30. data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +4 -17
  31. data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +1 -0
  32. data/lib/rails_mini_profiler/configuration/user_interface.rb +18 -0
  33. data/lib/rails_mini_profiler/flamegraph_guard.rb +10 -6
  34. data/lib/rails_mini_profiler/middleware.rb +2 -0
  35. data/lib/rails_mini_profiler/user.rb +1 -1
  36. data/lib/rails_mini_profiler/version.rb +1 -1
  37. data/vendor/assets/javascripts/rails-mini-profiler.css +1 -1
  38. data/vendor/assets/javascripts/rails-mini-profiler.js +1 -1
  39. metadata +25 -9
  40. data/app/javascript/stylesheets/components/page_header/page_header.scss +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ee7ad78091b3a10151ce83c08c255e9ccc78c16112a74a89c939876c52146ed
4
- data.tar.gz: 33c09a36420c374b1b40a8cdbaec6a9a5a0ef5822dddc9bb2e6a47902c0ddce3
3
+ metadata.gz: bb1212a4d90c46143193b2173e9e136aa6757a74a6591137cba33169235d175d
4
+ data.tar.gz: f799849a5d978c2c22d39b3fa1f4be6c02541f75b7a2312d98a510a1d69a195b
5
5
  SHA512:
6
- metadata.gz: a40ccbdbfd8a40b8b9eba3ba9a1f29436bd25f645640112ad0cda3426a7b4c3c4b8fe174569c304c3a8dbe3cc1c1987d5b6bee4b2c4a52309cd0e273879f437e
7
- data.tar.gz: 7f7527d2d8fd2e898951a36ecfb0e413cf1264b1dc495a637e4cd1a802ab690df754ae3c39d5d626e37c931120430c0f8a58a78262c5672b0f27edf7c2262ae3
6
+ metadata.gz: ae143e874778e4af9560e5b6521003c5d4933ec86ffe5900a56c57b93791a3d0faa3ac18294cecccac12048dc35c38a70aa7a53ffa91b12d2025a89c0acc0384
7
+ data.tar.gz: f2a8ca075571593f1cce9d1b59910ea5aac8f95a06c277298be9e0e93be5dcd1b013fbaefbef22bf173f6e2db40fed29068cfda44d422aa372cdde30818ec9cf
data/README.md CHANGED
@@ -63,8 +63,6 @@ route:
63
63
  ```ruby
64
64
  # routes.rb
65
65
  Rails.application.routes.draw do
66
- ...
67
-
68
66
  mount RailsMiniProfiler::Engine => '/rails_mini_profiler'
69
67
  end
70
68
  ```
@@ -76,18 +74,18 @@ top right that is injected into your pages.
76
74
 
77
75
  ![overview](docs/images/overview.png)
78
76
 
79
- Requests to your application will be profiled automatically. You can view all stored requests by navigating to `yourapp/rails_mini_profiler/profiled_requests`.
77
+ Requests to your application will be profiled automatically. You can view and search all stored requests by navigating to `yourapp/rails_mini_profiler/profiled_requests`.
80
78
 
81
79
  ### Request Details
82
80
 
83
81
  <p align="center">
84
82
  <img alt="Light" src="docs/images/trace.png" width="45%">
85
83
  &nbsp; &nbsp; &nbsp; &nbsp;
86
- <img alt="Dark" src="docs/images/sequel.png" width="45%">
84
+ <img alt="Dark" src="docs/images/trace-details.png" width="45%">
87
85
  </p>
88
86
 
89
87
  This view shows you how your requests spend their time. How much of it is spent in the DB, how much in rendering views?
90
- By clicking on individual traces you can find out detailed information.
88
+ May can filter and clicking on individual traces to gain deeper insights and see detailed information.
91
89
 
92
90
  ### Flamegraphs
93
91
 
@@ -114,15 +112,8 @@ Rails Mini Profiler provides a wide array of configuration options. You can find
114
112
  | `skip_paths` | `[]` | An array of request paths that should not be profiled. Regex allowed. |
115
113
  | `storage` | `Storage.new` | Storage configuration. See [Storage](#Storage). |
116
114
  | `ui` | `UserInterface.new` | UI configuration. See [UI](#UI). |
117
- | `user_provider` | `Rack::Request.new(env).ip` | How to identify users. See [Users](#Users) |
118
-
119
- ### Request Configuration
115
+ | `user_provider` | `Rack::Request.new(env).ip` | How to identify users. See [Authorization](#Authorization) |
120
116
 
121
- You may override the configuration by sending request parameters. The following parameters are available:
122
-
123
- | Name | Description |
124
- | ---------------- | ------------------------------------------------------------------------------------------- |
125
- | `rmp_flamegraph` | Overrides `flamegraph_enabled` If set to `true` will redirect to the flamegraph immediatly. |
126
117
 
127
118
  ### Storage
128
119
 
@@ -140,7 +131,7 @@ Rails Mini Profiler does not offer an automatic way to clean up old profiling in
140
131
 
141
132
  ```ruby
142
133
  # Clockwork
143
- every(1.month, 'purge rails mini profiler' do
134
+ every(1.month, 'purge rails mini profiler') do
144
135
  ProfiledRequestCleanupJob.perform_later
145
136
  end
146
137
 
@@ -158,25 +149,33 @@ end
158
149
 
159
150
  Rails Mini Profiler allows you to configure various UI features.
160
151
 
161
- | Name | Default | Description |
162
- |---------------------|--------------|-------------------------------------------------------------------------------------------------|
163
- | `badge_enabled` | `true` | Should the hedgehog 🦔 badge be injected into pages? |
164
- | `badge_position` | `'top-left'` | Where to display the badge. Options are `'top-left', 'top-right', 'bottom-left, 'bottom-right'` |
165
- | `page_size` | `25` | The page size for lists shown in the UI. |
166
- | `webpacker_enabled` | `true` | Use Webpacker if available? Disable to fall back to the asset pipeline.
152
+ | Name | Default | Description |
153
+ |---------------------|---------------------------|-------------------------------------------------------------------------------------------------|
154
+ | `badge_enabled` | `true` | Should the hedgehog 🦔 badge be injected into pages? |
155
+ | `badge_position` | `'top-left'` | Where to display the badge. Options are `'top-left', 'top-right', 'bottom-left, 'bottom-right'` |
156
+ | `base_controller` | `ApplicationController` | Which controller UI controllers should inherit from. |
157
+ | `page_size` | `25` | The page size for lists shown in the UI. |
158
+ | `webpacker_enabled` | `true` | Use Webpacker if available? Disable to fall back to the asset pipeline. |
167
159
 
160
+ ### Request Configuration
168
161
 
169
- ### Users
162
+ You may override static configuration on a per-request by attaching request parameters. For example, `https://myapp.com/api/mydata?rmp_flamegraph=false`
170
163
 
171
- Profiling information is segregated by user ID. That means users cannot see each other's profiled requests.
164
+ | Name | Description |
165
+ | ---------------- | ------------------------------------------------------------------------------------------- |
166
+ | `rmp_flamegraph` | Overrides `flamegraph_enabled` If set to `true` will redirect to the flamegraph immediately. |
167
+
168
+ ### Authorization
172
169
 
173
- Per default, individual users are identified by their IP address. You may change this by setting a custom user provider:
170
+ Profiling information is segregated by user ID. That means users cannot see each other's profiled requests. Per default, individual users are identified by their IP adress.
171
+
172
+ You may change this by setting a custom user provider:
174
173
 
175
174
  ```ruby
176
175
  config.user_provider = proc { |env| Rack::Request.new(env).ip }
177
176
  ```
178
177
 
179
- You may also explicitly set the user from the application itself:
178
+ You may also explicitly set the user by modifying your application controller (or the controller you have configured as UI base controller):
180
179
 
181
180
  ```ruby
182
181
  class ApplicationController < ActionController::Base
@@ -186,15 +185,18 @@ class ApplicationController < ActionController::Base
186
185
  end
187
186
  ```
188
187
 
189
- Note that you **must** set the current user when running Rails Mini Profiler in production. No profiles will be saved otherwise.
188
+ `ApplicationController` is used as the default base class for UI controllers. To change it, you may use `configuration.ui.base_controller`.
190
189
 
191
190
  ### Profiling in Production
192
191
 
193
192
  Rails Mini Profiler is not intended for performance reporting. There are other tools for that ( [Skylight](https://www.skylight.io/),
194
- [New Relic](https://newrelic.com/), [DataDog](https://www.datadoghq.com/)...).
193
+ [New Relic](https://newrelic.com/), [DataDog](https://www.datadoghq.com/)...). But you can still use RMP in production to profile specific requests.
194
+
195
+ Per default, *no requests will be profiled* in production, and the Rails Mini Profiler UI will be inaccessible.
196
+
197
+ #### Enabling Profiling
195
198
 
196
- However, you can still use it in production to profile specific requests. Since profiling impacts performance, it is recommended
197
- that you limit which requests are being profiled:
199
+ Since profiling impacts performance, it is recommended that you limit which requests are being profiled:
198
200
 
199
201
  ```ruby
200
202
  RailsMiniProfiler.configure do |config|
@@ -202,7 +204,17 @@ RailsMiniProfiler.configure do |config|
202
204
  end
203
205
  ```
204
206
 
205
- Only requests by explicitly set users will be stored. To configure how individual users are identified see [Users](#Users)
207
+ #### Authorizing Users
208
+
209
+ You must explicitly authorize profiling for users, as well as authenticate them to the UI:
210
+
211
+ ```ruby
212
+ class ApplicationController < ActionController::Base
213
+ before_action do
214
+ RailsMiniProfiler::User.authorize(current_user.id) # Requests by this user will now be profiled, and they get access to the UI
215
+ end
216
+ end
217
+ ```
206
218
 
207
219
  ## Why Rails Mini Profiler?
208
220
 
@@ -212,13 +224,13 @@ Improving the performance of any application is a 3-step process. You have to an
212
224
  2. Why is it slow?
213
225
  3. Did my solution fix the slowness?
214
226
 
215
- I'm a huge fan of [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler), and AMP tools such as [Skylight](https://www.skylight.io/) or [Scout APM](https://scoutapm.com), and each of these tools has its place.
227
+ I'm a huge fan of [rack-mini-profiler](https://github.com/MiniProfiler/rack-mini-profiler), and APM tools such as [Skylight](https://www.skylight.io/) or [Scout APM](https://scoutapm.com). Each of these tools has its own areas where it succeeds.
216
228
 
217
- APM tools are excellent for profiling your app in production - aka. they show you what is slow - and offer _some_ hints as to what causes the slowdown. `rack-mini-profiler` can do some sampling in production, but excels at providing detailed insight into _why_ something is slow, using Flamegraphs and detailed query information.
229
+ APM tools are excellent for profiling your app in production - aka. they show you what is slow - and offer _some_ hints as to what causes the slowdown. `rack-mini-profiler` can do some sampling in production, but excels at providing detailed insight into _why_ something is slow by providing Flamegraphs and detailed query information.
218
230
 
219
231
  Rails Mini Profiler improves upon `rack-mini-profiler` in the latter regard. It is a developer tool, rather than a monitoring tool, and sets a big focus on developer experience. Simply put, it aims to be the best tool available to help you figure out _why_ specific requests are slow.
220
232
 
221
- As such, compared to `rack-mini-profiler`, it does not support non-Rails apps (e.g. Sinatra) or production sampling, but provides a much better user experience and better supports API-only applications.
233
+ As such, compared to `rack-mini-profiler`, it does not support non-Rails apps (e.g. Sinatra) or production sampling, but provides a much better user experience and better support for API-only applications.
222
234
 
223
235
  ## Troubleshooting
224
236
 
@@ -243,13 +255,13 @@ rails db:migrate
243
255
 
244
256
  Rails Mini Profiler supports API-only apps, but you have to make some small adjustments to use it. At the top of `application.rb` add [Sprockets](https://github.com/rails/sprockets-rails):
245
257
 
246
- ```
258
+ ```ruby
247
259
  require "sprockets/railtie"
248
260
  ```
249
261
 
250
262
  Then, modify `application.rb`:
251
263
 
252
- ```
264
+ ```ruby
253
265
  module ApiOnly
254
266
  class Application < Rails::Application
255
267
 
@@ -259,7 +271,7 @@ module ApiOnly
259
271
  end
260
272
  ```
261
273
 
262
- **Note: Sprockets and flash are currently required for some of Rails Mini Profiler's UI features. These modifications may no longer be needed in the future.
274
+ **Note**: Sprockets and flash are currently required for some of Rails Mini Profiler's UI features. These modifications may no longer be needed in the future.
263
275
 
264
276
  ### No Flamegraphs are being recored?
265
277
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ class DatabaseAdapter
5
+ class << self
6
+ def cast_to_text(column)
7
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
8
+ # Cast json field to text to have access to the LIKE operator
9
+ "#{column}::text"
10
+ else
11
+ column
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsMiniProfiler
4
- class ApplicationController < ActionController::Base
5
- include Pagy::Backend
6
-
4
+ class ApplicationController < RailsMiniProfiler.configuration.ui.base_controller
7
5
  rescue_from ActiveRecord::RecordNotFound, with: ->(error) { handle(error, 404) }
8
6
 
9
- before_action :check_current_user
7
+ before_action :check_rmp_user
10
8
 
11
9
  protected
12
10
 
@@ -26,8 +24,13 @@ module RailsMiniProfiler
26
24
  end
27
25
  end
28
26
 
29
- def check_current_user
30
- redirect_back(fallback_location: root_path) unless User.get(request.env).present?
27
+ def check_rmp_user
28
+ user = User.get(request.env).present?
29
+ redirect_back(fallback_location: fallback_location) unless user
30
+ end
31
+
32
+ def fallback_location
33
+ defined?(main_app.root_path) ? main_app.root_path : '/'
31
34
  end
32
35
  end
33
36
  end
@@ -4,6 +4,8 @@ require_dependency 'rails_mini_profiler/application_controller'
4
4
 
5
5
  module RailsMiniProfiler
6
6
  class ProfiledRequestsController < ApplicationController
7
+ include Pagy::Backend
8
+
7
9
  before_action :set_profiled_request, only: %i[show destroy]
8
10
 
9
11
  def index
@@ -14,11 +16,16 @@ module RailsMiniProfiler
14
16
  end
15
17
 
16
18
  def show
17
- @traces = @profiled_request.traces
18
- @traces = @traces.where("#{payload_column} LIKE ?", "%#{params[:search]}%") if params[:search]
19
- @traces = @traces
19
+ search = TraceSearch.new(show_params, scope: @profiled_request.traces)
20
+ context = {
21
+ start: @profiled_request.start,
22
+ finish: @profiled_request.finish,
23
+ total_duration: @profiled_request.duration,
24
+ total_allocations: @profiled_request.allocations
25
+ }
26
+ @traces = search.results
20
27
  .order(:start)
21
- .map { |trace| present(trace, profiled_request: @profiled_request) }
28
+ .map { |trace| present(trace, context: context) }
22
29
  @profiled_request = present(@profiled_request)
23
30
  end
24
31
 
@@ -40,6 +47,10 @@ module RailsMiniProfiler
40
47
 
41
48
  private
42
49
 
50
+ def show_params
51
+ params.permit(:id, :payload, :duration, :allocations, name: [])
52
+ end
53
+
43
54
  def index_params
44
55
  params.permit(:path, :duration, id: [], method: [], media_type: [], status: [])
45
56
  end
@@ -12,5 +12,15 @@ module RailsMiniProfiler
12
12
  def formatted_allocations(allocations)
13
13
  number_to_human(allocations, units: { unit: '', thousand: 'k', million: 'M', billion: 'B', trillion: 'T' })
14
14
  end
15
+
16
+ def trace_display_name(name)
17
+ {
18
+ 'sql.active_record': 'ActiveRecord Query',
19
+ 'instantiation.active_record': 'ActiveRecord Instantiation',
20
+ 'render_template.action_view': 'Render View',
21
+ 'render_partial.action_view': 'Render Partial',
22
+ 'process_action.action_controller': 'Controller'
23
+ }[name.to_sym]
24
+ end
15
25
  end
16
26
  end
@@ -36,11 +36,18 @@ export default class extends Controller {
36
36
  }
37
37
 
38
38
  const copiedClass = this.data.get("copiedClass");
39
- console.log(copiedClass);
40
- this.buttonTarget.classList.add(copiedClass);
39
+ if (copiedClass) {
40
+ this.buttonTarget.classList.add(copiedClass);
41
+ }
42
+ const copiedMessage = this.data.get("copiedMessage");
43
+ const content = this.buttonTarget.innerHTML;
44
+ if (copiedMessage) {
45
+ this.buttonTarget.innerHTML = copiedMessage;
46
+ }
41
47
 
42
48
  this.timeout = setTimeout(() => {
43
49
  this.buttonTarget.classList.remove(copiedClass);
50
+ this.buttonTarget.innerHTML = content;
44
51
  }, this.successDuration);
45
52
  }
46
53
  }
@@ -7,6 +7,10 @@ export default class extends Controller {
7
7
  location.href = `${window.location.pathname}?${this.params}`;
8
8
  }
9
9
 
10
+ reset() {
11
+ location.href = `${window.location.pathname}`;
12
+ }
13
+
10
14
  post() {
11
15
  const token = document.head.querySelector(
12
16
  'meta[name="csrf-token"]'
@@ -0,0 +1,59 @@
1
+ button,
2
+ .button {
3
+ display: inline-block;
4
+ padding: 0.5em 0.5em;
5
+ border: none;
6
+ border-radius: 5px;
7
+ cursor: pointer;
8
+ font-size: 1rem;
9
+ text-align: center;
10
+ text-decoration: none;
11
+
12
+ &:disabled {
13
+ background: var(--grey-200);
14
+ cursor: not-allowed;
15
+ }
16
+ }
17
+
18
+ .btn-red {
19
+ background: var(--red-500);
20
+ color: white;
21
+ font-weight: 600;
22
+ outline: none;
23
+
24
+ &:hover {
25
+ background: var(--red-600);
26
+ }
27
+ }
28
+
29
+ .btn-grey {
30
+ background: var(--grey-200);
31
+
32
+ &:hover {
33
+ background: var(--grey-100);
34
+ }
35
+ }
36
+
37
+ .btn-white {
38
+ border: 1px solid var(--grey-200);
39
+ background: white;
40
+
41
+ &:hover {
42
+ background: var(--grey-100);
43
+ }
44
+ }
45
+
46
+ button:hover {
47
+ box-shadow: 0 0.25rem 0.25rem 0 var(--grey-50);
48
+ }
49
+
50
+ button.none {
51
+ padding: 0;
52
+ border: none;
53
+ background: none;
54
+ outline: none;
55
+
56
+ &:hover {
57
+ box-shadow: none;
58
+ }
59
+ }
@@ -1,54 +1,3 @@
1
- .table {
2
- width: 100%;
3
- border: hidden 1px var(--border-color);
4
-
5
- /* Hack to get table row borders, see https://stackoverflow.com/a/2586780/2553104 */
6
- border-collapse: collapse;
7
- border-radius: 5px;
8
- box-shadow: 0 0 0 1px var(--border-color);
9
- table-layout: fixed;
10
- }
11
-
12
- .table th,
13
- .table td {
14
- padding: 0.5rem 1rem;
15
- }
16
-
17
- .table thead tr {
18
- border: hidden 1px var(--border-color);
19
- box-shadow: 0 0 0 1px var(--border-color);
20
- color: var(--grey-400);
21
- }
22
-
23
- .table tr:nth-child(even) {
24
- background: var(--grey-50);
25
- }
26
-
27
- .table thead th {
28
- font-weight: 400;
29
- }
30
-
31
- .table-filter-icon {
32
- width: 14px;
33
- margin-left: 0.5rem;
34
- }
35
-
36
- .table tbody tr:not(.no-row) {
37
- border: solid 1px var(--border-color);
38
- color: var(--grey-700);
39
- cursor: pointer;
40
- }
41
-
42
- .table tbody tr:not(.no-row):hover {
43
- background: var(--grey-100);
44
- }
45
-
46
- .request-checkbox {
47
- z-index: 1;
48
- width: 1rem;
49
- height: 1rem;
50
- }
51
-
52
1
  .dropdown-body {
53
2
  padding: 0.33rem 0.5rem;
54
3
  }
@@ -152,28 +101,3 @@
152
101
  background: var(--red-600);
153
102
  }
154
103
  }
155
-
156
- .dropdown-search-button {
157
- display: inline-block;
158
- padding: 0.5em 0.5em;
159
- border: none;
160
- background: var(--red-500);
161
- border-radius: 5px;
162
- color: white;
163
- cursor: pointer;
164
- font-size: 1rem;
165
- font-weight: 600;
166
- text-align: center;
167
- text-decoration: none;
168
-
169
- &:hover {
170
- background: var(--red-600);
171
- }
172
- }
173
-
174
- .request-path {
175
- overflow: hidden;
176
- max-width: 280px;
177
- text-overflow: ellipsis;
178
- white-space: nowrap;
179
- }
@@ -0,0 +1,10 @@
1
+ input[type=submit] {
2
+ display: inline-block;
3
+ padding: 0.5em 0.5em;
4
+ border: none;
5
+ border-radius: 5px;
6
+ cursor: pointer;
7
+ font-size: 1rem;
8
+ text-align: center;
9
+ text-decoration: none;
10
+ }
@@ -0,0 +1,7 @@
1
+ .page-header {
2
+ padding: 2.5rem 0 2.5rem;
3
+ }
4
+
5
+ .page-header h1 {
6
+ font-size: 28px;
7
+ }
@@ -1,4 +1,3 @@
1
-
2
1
  .placeholder {
3
2
  display: flex;
4
3
  width: 100%;
@@ -20,6 +19,10 @@
20
19
  text-align: center;
21
20
  }
22
21
 
22
+ .placeholder-text h2 {
23
+ padding-bottom: 1rem;
24
+ }
25
+
23
26
  .placeholder-link {
24
27
  color: var(--grey-400);
25
28
 
@@ -0,0 +1,55 @@
1
+ .table {
2
+ width: 100%;
3
+ border: hidden 1px var(--border-color);
4
+
5
+ /* Hack to get table row borders, see https://stackoverflow.com/a/2586780/2553104 */
6
+ border-collapse: collapse;
7
+ border-radius: 5px;
8
+ box-shadow: 0 0 0 1px var(--border-color);
9
+ table-layout: fixed;
10
+ }
11
+
12
+ .table th,
13
+ .table td {
14
+ padding: 0.5rem 1rem;
15
+ }
16
+
17
+ .table thead tr {
18
+ color: var(--grey-500);
19
+ }
20
+
21
+ .table tr:nth-child(even) {
22
+ background: var(--grey-50);
23
+ }
24
+
25
+ .table thead th {
26
+ font-weight: 400;
27
+ }
28
+
29
+ .table-filter-icon {
30
+ width: 14px;
31
+ margin-left: 0.5rem;
32
+ }
33
+
34
+ .table tbody tr:not(.no-row) {
35
+ border: solid 1px var(--border-color);
36
+ color: var(--grey-700);
37
+ cursor: pointer;
38
+ }
39
+
40
+ .table tbody tr:not(.no-row):hover {
41
+ background: var(--grey-100);
42
+ }
43
+
44
+ .request-checkbox {
45
+ z-index: 1;
46
+ width: 1rem;
47
+ height: 1rem;
48
+ }
49
+
50
+ .request-path {
51
+ overflow: hidden;
52
+ max-width: 280px;
53
+ text-overflow: ellipsis;
54
+ white-space: nowrap;
55
+ }
@@ -0,0 +1,93 @@
1
+ .trace {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: flex-start;
5
+ padding: 0.25em 0;
6
+ list-style: none;
7
+ }
8
+
9
+ .trace:nth-child(odd) {
10
+ background: var(--grey-100);
11
+ }
12
+
13
+ .trace .trace-bar {
14
+ position: relative;
15
+ height: 16px;
16
+ padding: 0;
17
+ margin: 0;
18
+ background: linear-gradient(to top right, var(--grey-500), var(--grey-400));
19
+ cursor: pointer;
20
+ }
21
+
22
+ .instantiation-trace .trace-bar {
23
+ background: linear-gradient(to top right, var(--green-400), var(--green-300));
24
+ }
25
+
26
+ .sequel-trace .trace-bar {
27
+ background: linear-gradient(to top right, var(--green-500), var(--green-400));
28
+ }
29
+
30
+ .controller-trace .trace-bar {
31
+ background: linear-gradient(to top right, var(--yellow-500), var(--yellow-400));
32
+ }
33
+
34
+ .render-template-trace .trace-bar,
35
+ .render-partial-trace .trace-bar {
36
+ background: linear-gradient(to top right, var(--blue-500), var(--blue-400));
37
+ }
38
+
39
+ .trace-name {
40
+ overflow: hidden;
41
+ box-sizing: border-box;
42
+ padding: 0 0.5em;
43
+ margin: 0;
44
+ color: var(--grey-400);
45
+ font-size: 14px;
46
+ text-align: right;
47
+ text-overflow: ellipsis;
48
+ }
49
+
50
+ .trace-payload {
51
+ margin: 0;
52
+ }
53
+
54
+ .sequel-trace-query {
55
+ overflow: auto;
56
+ max-height: 100px;
57
+ padding: 1em 1em;
58
+ background: var(--grey-100);
59
+ white-space: pre-wrap;
60
+ }
61
+
62
+ .sequel-trace-binds {
63
+ overflow: auto;
64
+ max-height: 100px;
65
+ padding: 0.5em 1em;
66
+ margin: 0 0 1em 0;
67
+ background: var(--grey-50);
68
+ font-size: 12px;
69
+ white-space: pre-wrap;
70
+ }
71
+
72
+ .backtrace {
73
+ display: flex;
74
+ flex-direction: row;
75
+ align-items: center;
76
+ justify-content: space-between;
77
+ padding: 0.5em;
78
+ background: var(--grey-100);
79
+ }
80
+
81
+ .backtrace button {
82
+ overflow: auto;
83
+ height: 20px;
84
+ padding: 0;
85
+ margin: 0;
86
+ background: none;
87
+ color: var(--grey-500);
88
+ }
89
+
90
+ .backtrace button svg {
91
+ width: 20px;
92
+ height: 20px;
93
+ }