dial 0.5.2 → 0.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6cd83bb50a207183202f0f0f9775d060446a352cf88382252fdfc00c4dbb4de6
4
- data.tar.gz: a84109907f3884386ce2122ba5173c33ebc8da6e1c900bb94439389a274887b7
3
+ metadata.gz: d3b2e0414c826c6c8e7237a5b1033b102ee9079491e1d2863db6ffb961a3fda2
4
+ data.tar.gz: 859585a4e0bcf37eb6c36c2f71e1d16cad9e351c4435cc91981c9254704d21bd
5
5
  SHA512:
6
- metadata.gz: b1e2a82ea64022c1dcf83f5fc5ae7cdfc3f53794552c9752f4d39f4f490bfcbc25bb3b1632b211ba08c4e4af7c1dd22483c037d06cf2b59dcda44b9d36c92bd7
7
- data.tar.gz: 27075354578df3d541fdacb9704959c097a4cd2a128653b8e67b57424b64d934e5c50e1f335a33111012ba2f87b381048cde8ac4d12961dce86cea4059edf54d
6
+ metadata.gz: dd66117fe0e8c2fcfac7dacb5348cda5eee119e8f199ead4a5161a5af024e52c50f52765dcdcb0804fcbbd53c061d4f9073287322d0146300f7508d82c9c6823
7
+ data.tar.gz: 6bad07093895c0e2c4d09fd53afecce8d344f189d07eb576d29202ba308009f67eff06a1263ac8d27c2587ca3d3c46f650ffafc499761d56d3f2a092d396d402
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.0] - 2025-10-23
4
+
5
+ - Stop suffixing mounted routes with 'dial/'
6
+ - Add keyboard shortcut to toggle panel visibility
7
+
3
8
  ## [0.5.2] - 2025-10-04
4
9
 
5
10
  - Preserve existing prosopite custom loggers
data/README.md CHANGED
@@ -32,7 +32,7 @@ bundle install
32
32
 
33
33
  ```ruby
34
34
  # this will mount the engine at /dial
35
- mount Dial::Engine, at: "/"
35
+ mount Dial::Engine, at: "/dial"
36
36
  ```
37
37
 
38
38
  4. (Optional) Configure the gem in an initializer:
@@ -66,6 +66,7 @@ Option | Description | Default
66
66
  `storage` | Storage adapter class for profile data. | `Dial::Storage::FileAdapter`
67
67
  `storage_options` | Options hash passed to storage adapter. | `{ ttl: 3600 }`
68
68
  `content_security_policy_nonce` | Sets the content security policy nonce to use when inserting Dial's script. Can be a string, or a Proc which receives `env` and response `headers` as arguments and returns the nonce string. | Rails generated nonce or `nil`
69
+ `toggle_shortcut_keys` | Array of keys for keyboard shortcut to toggle panel visibility. | `["Alt", "Shift", "D"]`
69
70
  `vernier_interval` | Sets the `interval` option for vernier. | `200`
70
71
  `vernier_allocation_interval` | Sets the `allocation_interval` option for vernier. | `2_000`
71
72
  `prosopite_ignore_queries` | Sets the `ignore_queries` option for prosopite. | `[/schema_migrations/i]`
@@ -18,6 +18,7 @@ module Dial
18
18
  storage: Storage::FileAdapter,
19
19
  storage_options: { ttl: STORAGE_TTL },
20
20
  content_security_policy_nonce: -> env, _headers { env[NONCE] || EMPTY_NONCE },
21
+ toggle_shortcut_keys: TOGGLE_SHORTCUT_KEYS,
21
22
  vernier_interval: VERNIER_INTERVAL,
22
23
  vernier_allocation_interval: VERNIER_ALLOCATION_INTERVAL,
23
24
  prosopite_ignore_queries: PROSOPITE_IGNORE_QUERIES,
@@ -21,6 +21,7 @@ module Dial
21
21
  SAMPLING_PERCENTAGE_PROD = 1
22
22
  STORAGE_TTL = 60 * 60
23
23
  EMPTY_NONCE = ""
24
+ TOGGLE_SHORTCUT_KEYS = ["Alt", "Shift", "D"].freeze
24
25
 
25
26
  VERNIER_INTERVAL = 200
26
27
  VERNIER_ALLOCATION_INTERVAL = 2_000
@@ -3,41 +3,39 @@
3
3
  require "uri"
4
4
 
5
5
  Dial::Engine.routes.draw do
6
- scope path: "/dial", as: "dial" do
7
- get "profile", to: lambda { |env|
8
- query_params = URI.decode_www_form(env[::Rack::QUERY_STRING]).to_h
9
- profile_key = query_params["key"]
10
- unless profile_key && profile_key.match?(/\A[0-9a-f-]+_vernier\z/i)
11
- return [
12
- 400,
13
- { "Content-Type" => "text/plain" },
14
- ["Bad Request"]
15
- ]
16
- end
6
+ get "/profile", to: lambda { |env|
7
+ query_params = URI.decode_www_form(env[::Rack::QUERY_STRING]).to_h
8
+ profile_key = query_params["key"]
9
+ unless profile_key && profile_key.match?(/\A[0-9a-f-]+_vernier\z/i)
10
+ return [
11
+ 400,
12
+ { "Content-Type" => "text/plain" },
13
+ ["Bad Request"]
14
+ ]
15
+ end
17
16
 
18
- profile_storage_key = Dial::Storage.profile_storage_key profile_key
19
- begin
20
- content = Dial::Storage.fetch profile_storage_key
21
- if content
22
- [
23
- 200,
24
- { "Content-Type" => "application/json", "Access-Control-Allow-Origin" => Dial::VERNIER_VIEWER_URL },
25
- [content]
26
- ]
27
- else
28
- [
29
- 404,
30
- { "Content-Type" => "text/plain" },
31
- ["Not Found"]
32
- ]
33
- end
34
- rescue
17
+ profile_storage_key = Dial::Storage.profile_storage_key profile_key
18
+ begin
19
+ content = Dial::Storage.fetch profile_storage_key
20
+ if content
21
+ [
22
+ 200,
23
+ { "Content-Type" => "application/json", "Access-Control-Allow-Origin" => Dial::VERNIER_VIEWER_URL },
24
+ [content]
25
+ ]
26
+ else
35
27
  [
36
- 500,
28
+ 404,
37
29
  { "Content-Type" => "text/plain" },
38
- ["Internal Server Error"]
30
+ ["Not Found"]
39
31
  ]
40
32
  end
41
- }
42
- end
33
+ rescue
34
+ [
35
+ 500,
36
+ { "Content-Type" => "text/plain" },
37
+ ["Internal Server Error"]
38
+ ]
39
+ end
40
+ }
43
41
  end
@@ -71,6 +71,8 @@ module Dial
71
71
  </div>
72
72
  </div>
73
73
 
74
+ <div id="dial-hidden-indicator">Dial</div>
75
+
74
76
  <script nonce="#{configured_nonce env, headers}">
75
77
  #{script}
76
78
  </script>
@@ -149,19 +151,80 @@ module Dial
149
151
  color: black;
150
152
  }
151
153
  }
154
+
155
+ #dial-hidden-indicator {
156
+ all: initial;
157
+ position: fixed;
158
+ bottom: 0.5rem;
159
+ right: 0.5rem;
160
+ z-index: 9999;
161
+ background-color: white;
162
+ color: black;
163
+ padding: 0.25rem 0.5rem;
164
+ border-radius: 0.25rem;
165
+ font-size: 0.75rem;
166
+ cursor: pointer;
167
+ display: none;
168
+ box-shadow: -0.2rem -0.2rem 0.4rem rgba(0, 0, 0, 0.5);
169
+ }
152
170
  CSS
153
171
  end
154
172
 
155
173
  def script
174
+ shortcut_keys = Dial._configuration.toggle_shortcut_keys
175
+
156
176
  <<~JS
177
+ var dialPanel = document.getElementById("dial");
157
178
  var dialPreview = document.getElementById("dial-preview");
158
179
  var dialDetails = document.getElementById("dial-details");
180
+ var dialHiddenIndicator = document.getElementById("dial-hidden-indicator");
181
+
182
+ function getDialHiddenState() {
183
+ var stored = localStorage.getItem("dial_panel_hidden");
184
+ if (!stored) return false;
185
+
186
+ try {
187
+ var data = JSON.parse(stored);
188
+ var expiresAt = new Date(data.expiresAt);
189
+ if (new Date() > expiresAt) {
190
+ localStorage.removeItem("dial_panel_hidden");
191
+ return false;
192
+ }
193
+ return data.hidden;
194
+ } catch (e) {
195
+ localStorage.removeItem("dial_panel_hidden");
196
+ return false;
197
+ }
198
+ }
199
+
200
+ function setDialHiddenState(hidden) {
201
+ var expiresAt = new Date();
202
+ expiresAt.setTime(expiresAt.getTime() + (24 * 60 * 60 * 1000));
203
+ localStorage.setItem("dial_panel_hidden", JSON.stringify({
204
+ hidden: hidden,
205
+ expiresAt: expiresAt.toISOString()
206
+ }));
207
+ }
208
+
209
+ function toggleDialPanel() {
210
+ var isHidden = dialPanel.style.display === "none";
211
+ dialPanel.style.display = isHidden ? "flex" : "none";
212
+ dialHiddenIndicator.style.display = isHidden ? "none" : "block";
213
+ setDialHiddenState(!isHidden);
214
+ }
215
+
216
+ if (getDialHiddenState()) {
217
+ dialPanel.style.display = "none";
218
+ dialHiddenIndicator.style.display = "block";
219
+ }
159
220
 
160
221
  dialPreview.addEventListener("click", () => {
161
222
  var isCollapsed = ["", "none"].includes(dialDetails.style.display);
162
223
  dialDetails.style.display = isCollapsed ? "block" : "none";
163
224
  });
164
225
 
226
+ dialHiddenIndicator.addEventListener("click", toggleDialPanel);
227
+
165
228
  document.addEventListener("click", (event) => {
166
229
  if (!dialPreview.contains(event.target) && !dialDetails.contains(event.target)) {
167
230
  dialDetails.style.display = "none";
@@ -172,6 +235,26 @@ module Dial
172
235
  });
173
236
  }
174
237
  });
238
+
239
+ document.addEventListener("keydown", (event) => {
240
+ var keys = #{shortcut_keys.to_json};
241
+ var expectedKey = keys[keys.length - 1].toLowerCase();
242
+ var keyPressed = event.code.toLowerCase() === "key" + expectedKey || event.key.toLowerCase() === expectedKey;
243
+ var modifiersMatch = true;
244
+
245
+ for (var i = 0; i < keys.length - 1; i++) {
246
+ var modifier = keys[i].toLowerCase();
247
+ if (modifier === "alt" && !event.altKey) modifiersMatch = false;
248
+ if (modifier === "ctrl" && !event.ctrlKey) modifiersMatch = false;
249
+ if (modifier === "shift" && !event.shiftKey) modifiersMatch = false;
250
+ if (modifier === "meta" && !event.metaKey) modifiersMatch = false;
251
+ }
252
+
253
+ if (keyPressed && modifiersMatch) {
254
+ event.preventDefault();
255
+ toggleDialPanel();
256
+ }
257
+ });
175
258
  JS
176
259
  end
177
260
 
@@ -192,7 +275,7 @@ module Dial
192
275
  def formatted_profile_output env, profile_key
193
276
  url_base = ::Rails.application.routes.url_helpers.dial_url host: env[::Rack::HTTP_HOST]
194
277
  prefix = "/" unless url_base.end_with? "/"
195
- profile_out_url = URI.encode_www_form_component url_base + "#{prefix}dial/profile?key=#{profile_key}"
278
+ profile_out_url = URI.encode_www_form_component url_base + "#{prefix}profile?key=#{profile_key}"
196
279
 
197
280
  "<a href='https://vernier.prof/from-url/#{profile_out_url}' target='_blank'>View profile</a>"
198
281
  end
data/lib/dial/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dial
4
- VERSION = "0.5.2"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dial
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
@@ -143,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  requirements: []
146
- rubygems_version: 3.7.2
146
+ rubygems_version: 4.0.0.dev
147
147
  specification_version: 4
148
148
  summary: A modern profiler for your Rails application
149
149
  test_files: []