rails-profiler 0.32.3 → 0.33.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 +4 -4
- data/CHANGELOG.md +32 -0
- data/app/assets/builds/profiler-toolbar.js +21 -4
- data/app/assets/builds/profiler.js +5 -0
- data/lib/profiler/collectors/ajax_collector.rb +22 -1
- data/lib/profiler/mcp/tools/get_profile_ajax.rb +1 -0
- data/lib/profiler/models/profile.rb +1 -1
- data/lib/profiler/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4dc81c1f51aaa36f9a01703962763e6526c95ea44a86aec0f6580a46c6239bfe
|
|
4
|
+
data.tar.gz: 1555289065c0d81d6267b21ddb9d3ae2c2c0716e1290f33e30df30590ff4b8c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 967050b5160cb75653481fd86444696cb81fa84c46aa7faa34064a3c281c0acaa5ec08d4029a8b1aca2525da8ffb5d0033b934025d885a8b53e969faca151293
|
|
7
|
+
data.tar.gz: e63d49ccaf002fb7b4911920fc3e279597451fa276d669f557fde971e13e2855cbc347cc16bf254ff2d995b14ba0c18454e929910326a41d0104ee83db49c327
|
data/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,38 @@ every commit of every tag interval is accounted for one way or the other.
|
|
|
19
19
|
|
|
20
20
|
## [Unreleased]
|
|
21
21
|
|
|
22
|
+
## [0.33.0] - 2026-10-14
|
|
23
|
+
|
|
24
|
+
<!-- stamped -->
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **AJAX:** Requests made by Turbo (Hotwire) for a `<turbo-frame>`, and requests answered with
|
|
29
|
+
Turbo Stream actions, carry a `FRAME` or `STREAM` badge in the AJAX panel of the toolbar and in
|
|
30
|
+
the AJAX tab of the dashboard. The AJAX data of a page in the API gives each request a `turbo`
|
|
31
|
+
field: `frame`, `stream` or `null`. The MCP tool `get_profile_ajax` gives the same kind on a
|
|
32
|
+
`Turbo` line of each Turbo request, and none for a plain fetch. The Request tab of a frame
|
|
33
|
+
request shows its `Turbo-Frame` header.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **AJAX:** A Turbo Drive visit is no longer listed as an AJAX request of the page it leaves,
|
|
38
|
+
and neither is a link Turbo prefetches on hover: they are the next page, with their own
|
|
39
|
+
profile. The requests a page reached by a Drive visit makes are linked to that page instead of
|
|
40
|
+
to the first page of the session.
|
|
41
|
+
- **Toolbar:** After a Turbo Drive visit, the toolbar of the previous page is taken down: it no
|
|
42
|
+
longer keeps checking for updates of the previous profile, and `Alt+P` toggles the toolbar
|
|
43
|
+
once instead of once per page visited.
|
|
44
|
+
|
|
45
|
+
### Limitations
|
|
46
|
+
|
|
47
|
+
- **Toolbar:** A Turbo 8 page refresh with morphing (`turbo_refreshes_with method: :morph`, or
|
|
48
|
+
a `broadcasts_refreshes` model) is not handled: it empties the toolbar, which keeps checking
|
|
49
|
+
for updates of the profile of the page as first loaded, and the requests made after it stay
|
|
50
|
+
linked to that profile. This predates this release and is left for a later one.
|
|
51
|
+
- **Toolbar:** After going back in the browser history, two toolbar containers are left in the
|
|
52
|
+
page, only one of them visible. This predates this release too.
|
|
53
|
+
|
|
22
54
|
## [0.32.3] - 2026-10-14
|
|
23
55
|
|
|
24
56
|
<!-- stamped -->
|
|
@@ -3356,6 +3356,10 @@
|
|
|
3356
3356
|
};
|
|
3357
3357
|
return map[method] || "";
|
|
3358
3358
|
}
|
|
3359
|
+
var TURBO_TITLES = {
|
|
3360
|
+
frame: "Turbo Frame request",
|
|
3361
|
+
stream: "Turbo Stream response"
|
|
3362
|
+
};
|
|
3359
3363
|
function AjaxPanel({ ajaxData }) {
|
|
3360
3364
|
return /* @__PURE__ */ u3(k, { children: [
|
|
3361
3365
|
/* @__PURE__ */ u3("div", { class: "profiler-toolbar-panel-header", children: [
|
|
@@ -3373,6 +3377,7 @@
|
|
|
3373
3377
|
return /* @__PURE__ */ u3("div", { class: `profiler-ajax-card ${statusCls}`, children: /* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: [
|
|
3374
3378
|
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", children: [
|
|
3375
3379
|
/* @__PURE__ */ u3("span", { class: `badge ${methodBadgeClass(req.method)}`, children: req.method }),
|
|
3380
|
+
req.turbo && /* @__PURE__ */ u3("span", { class: "badge badge-default", title: TURBO_TITLES[req.turbo], children: req.turbo.toUpperCase() }),
|
|
3376
3381
|
/* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--truncate", children: req.path })
|
|
3377
3382
|
] }),
|
|
3378
3383
|
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", children: [
|
|
@@ -4367,14 +4372,26 @@
|
|
|
4367
4372
|
if (!el || !toggleEl) return;
|
|
4368
4373
|
const token = el.dataset.token;
|
|
4369
4374
|
if (!token) return;
|
|
4375
|
+
window.__PROFILER_TOOLBAR_TEARDOWN__?.();
|
|
4376
|
+
const listeners = new AbortController();
|
|
4377
|
+
const { signal } = listeners;
|
|
4378
|
+
const teardown = () => {
|
|
4379
|
+
listeners.abort();
|
|
4380
|
+
J(null, el);
|
|
4381
|
+
if (window.__PROFILER_TOOLBAR_TEARDOWN__ === teardown) delete window.__PROFILER_TOOLBAR_TEARDOWN__;
|
|
4382
|
+
};
|
|
4383
|
+
window.__PROFILER_TOOLBAR_TEARDOWN__ = teardown;
|
|
4384
|
+
document.addEventListener("turbo:load", () => {
|
|
4385
|
+
if (!el.isConnected) teardown();
|
|
4386
|
+
}, { signal });
|
|
4370
4387
|
const themeEls = [el, toggleEl];
|
|
4371
4388
|
applyTheme(themeEls);
|
|
4372
4389
|
window.addEventListener("storage", (e3) => {
|
|
4373
4390
|
if (e3.key === "profiler-theme") applyTheme(themeEls);
|
|
4374
|
-
});
|
|
4391
|
+
}, { signal });
|
|
4375
4392
|
window.addEventListener("profiler:theme-change", ((e3) => {
|
|
4376
4393
|
if (e3.detail?.theme) themeEls.forEach((elem) => elem.setAttribute("data-theme", e3.detail.theme));
|
|
4377
|
-
}));
|
|
4394
|
+
}), { signal });
|
|
4378
4395
|
let isCollapsed = localStorage.getItem("profiler-toolbar-collapsed") === "true";
|
|
4379
4396
|
toggleEl.dataset.collapsed = String(isCollapsed);
|
|
4380
4397
|
if (isCollapsed && !el.style.transform) {
|
|
@@ -4406,13 +4423,13 @@
|
|
|
4406
4423
|
}, ANIM_MS + 50);
|
|
4407
4424
|
}
|
|
4408
4425
|
}
|
|
4409
|
-
toggleEl.addEventListener("click", toggleCollapse);
|
|
4426
|
+
toggleEl.addEventListener("click", toggleCollapse, { signal });
|
|
4410
4427
|
document.addEventListener("keydown", (e3) => {
|
|
4411
4428
|
if (e3.altKey && e3.key === "p") {
|
|
4412
4429
|
e3.preventDefault();
|
|
4413
4430
|
toggleCollapse();
|
|
4414
4431
|
}
|
|
4415
|
-
});
|
|
4432
|
+
}, { signal });
|
|
4416
4433
|
J(
|
|
4417
4434
|
/* @__PURE__ */ u3(QueryClientProvider, { client: toolbarQueryClient, children: /* @__PURE__ */ u3(ToolbarMount, { token }) }),
|
|
4418
4435
|
el
|
|
@@ -8173,6 +8173,10 @@
|
|
|
8173
8173
|
}
|
|
8174
8174
|
|
|
8175
8175
|
// app/assets/typescript/profiler/components/dashboard/tabs/AjaxTab.tsx
|
|
8176
|
+
var TURBO_TITLES = {
|
|
8177
|
+
frame: "Turbo Frame request",
|
|
8178
|
+
stream: "Turbo Stream response"
|
|
8179
|
+
};
|
|
8176
8180
|
function AjaxTab({ ajaxData }) {
|
|
8177
8181
|
if (!ajaxData?.requests?.length) {
|
|
8178
8182
|
return /* @__PURE__ */ u3("div", { class: "profiler-empty", children: [
|
|
@@ -8225,6 +8229,7 @@
|
|
|
8225
8229
|
/* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: [
|
|
8226
8230
|
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-3", children: [
|
|
8227
8231
|
/* @__PURE__ */ u3("span", { class: `profiler-ajax-card__method badge-${methodBadge(req.method)}`, children: req.method }),
|
|
8232
|
+
req.turbo && /* @__PURE__ */ u3("span", { class: "badge-default", title: TURBO_TITLES[req.turbo], children: req.turbo.toUpperCase() }),
|
|
8228
8233
|
/* @__PURE__ */ u3("strong", { class: "profiler-ajax-card__path", children: req.path })
|
|
8229
8234
|
] }),
|
|
8230
8235
|
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", children: [
|
|
@@ -105,9 +105,30 @@ module Profiler
|
|
|
105
105
|
"method" => profile.method,
|
|
106
106
|
"status" => profile.status,
|
|
107
107
|
"duration" => profile.duration,
|
|
108
|
-
"started_at" => profile.started_at&.iso8601
|
|
108
|
+
"started_at" => profile.started_at&.iso8601,
|
|
109
|
+
"turbo" => turbo_kind(profile)
|
|
109
110
|
}
|
|
110
111
|
end
|
|
112
|
+
|
|
113
|
+
TURBO_STREAM_MIME = "text/vnd.turbo-stream.html"
|
|
114
|
+
|
|
115
|
+
# "frame" for a request a <turbo-frame> made (Turbo sends its id in Turbo-Frame), "stream"
|
|
116
|
+
# for one answered with Turbo Stream actions, nil for any other fetch or XHR.
|
|
117
|
+
def turbo_kind(profile)
|
|
118
|
+
return "frame" if header_value(profile.headers, "Turbo-Frame").to_s != ""
|
|
119
|
+
return "stream" if header_value(profile.response_headers, "Content-Type").to_s.start_with?(TURBO_STREAM_MIME)
|
|
120
|
+
|
|
121
|
+
nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Header names keep the case they were saved with: Content-Type from Rack 2, content-type
|
|
125
|
+
# from Rack 3.
|
|
126
|
+
def header_value(headers, name)
|
|
127
|
+
return nil unless headers.respond_to?(:each)
|
|
128
|
+
|
|
129
|
+
headers.each { |key, value| return value if key.to_s.casecmp?(name) }
|
|
130
|
+
nil
|
|
131
|
+
end
|
|
111
132
|
end
|
|
112
133
|
end
|
|
113
134
|
end
|
|
@@ -61,6 +61,7 @@ module Profiler
|
|
|
61
61
|
lines << "- **Path:** #{req['path']}"
|
|
62
62
|
lines << "- **Status:** #{req['status']}"
|
|
63
63
|
lines << "- **Duration:** #{req['duration'].round(2)} ms"
|
|
64
|
+
lines << "- **Turbo:** #{req['turbo']}" if req['turbo']
|
|
64
65
|
lines << "- **Token:** #{req['token']}" if req['token']
|
|
65
66
|
lines << "- **Started At:** #{req['started_at']}" if req['started_at']
|
|
66
67
|
end
|
|
@@ -346,7 +346,7 @@ module Profiler
|
|
|
346
346
|
Accept Accept-Charset Accept-Encoding Accept-Language
|
|
347
347
|
Authorization Cache-Control Connection Content-Length Content-Type
|
|
348
348
|
Cookie Host If-Modified-Since If-None-Match Origin
|
|
349
|
-
Referer User-Agent
|
|
349
|
+
Referer User-Agent Turbo-Frame
|
|
350
350
|
].freeze
|
|
351
351
|
|
|
352
352
|
def extract_headers(env)
|
data/lib/profiler/version.rb
CHANGED