rails-profiler 0.24.0 → 0.26.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/app/assets/builds/profiler.css +24 -0
- data/app/assets/builds/profiler.js +994 -26
- data/app/controllers/profiler/api/console_controller.rb +46 -0
- data/app/controllers/profiler/api/profiles_controller.rb +1 -1
- data/app/controllers/profiler/api/test_runner_controller.rb +115 -0
- data/app/controllers/profiler/api/tests_controller.rb +46 -0
- data/app/controllers/profiler/test_runner_controller.rb +11 -0
- data/app/views/profiler/test_runner/index.html.erb +1 -0
- data/config/routes.rb +13 -0
- data/lib/profiler/collectors/console_collector.rb +57 -0
- data/lib/profiler/collectors/database_collector.rb +1 -1
- data/lib/profiler/collectors/test_collector.rb +75 -0
- data/lib/profiler/configuration.rb +14 -1
- data/lib/profiler/console_profiler.rb +102 -0
- data/lib/profiler/instrumentation/irb_instrumentation.rb +21 -0
- data/lib/profiler/mcp/resources/failing_tests.rb +40 -0
- data/lib/profiler/mcp/resources/slow_tests.rb +45 -0
- data/lib/profiler/mcp/server.rb +77 -6
- data/lib/profiler/mcp/tools/get_test_profile_detail.rb +126 -0
- data/lib/profiler/mcp/tools/query_test_profiles.rb +109 -0
- data/lib/profiler/mcp/tools/run_tests.rb +112 -0
- data/lib/profiler/railtie.rb +21 -1
- data/lib/profiler/test_helpers/minitest_support.rb +39 -0
- data/lib/profiler/test_helpers/reporter.rb +121 -0
- data/lib/profiler/test_helpers/rspec_support.rb +33 -0
- data/lib/profiler/test_profiler.rb +140 -0
- data/lib/profiler/test_runner/discovery.rb +57 -0
- data/lib/profiler/test_runner/run_store.rb +120 -0
- data/lib/profiler/test_runner/runner.rb +106 -0
- data/lib/profiler/version.rb +1 -1
- metadata +23 -2
|
@@ -323,6 +323,11 @@
|
|
|
323
323
|
var u4 = p2(t2++, 7);
|
|
324
324
|
return C2(u4.__H, r3) && (u4.__ = n2(), u4.__H = r3, u4.__h = n2), u4.__;
|
|
325
325
|
}
|
|
326
|
+
function q2(n2, t3) {
|
|
327
|
+
return o2 = 8, T2(function() {
|
|
328
|
+
return n2;
|
|
329
|
+
}, t3);
|
|
330
|
+
}
|
|
326
331
|
function j2() {
|
|
327
332
|
for (var n2; n2 = f2.shift(); ) {
|
|
328
333
|
var t3 = n2.__H;
|
|
@@ -1274,10 +1279,10 @@
|
|
|
1274
1279
|
const overrideCount = Object.keys(overrides).length;
|
|
1275
1280
|
const allEntries = Object.entries(variables);
|
|
1276
1281
|
const filteredEntries = T2(() => {
|
|
1277
|
-
const
|
|
1278
|
-
if (!
|
|
1282
|
+
const q3 = search.toLowerCase().trim();
|
|
1283
|
+
if (!q3) return allEntries;
|
|
1279
1284
|
return allEntries.filter(
|
|
1280
|
-
([k3, v3]) => k3.toLowerCase().includes(
|
|
1285
|
+
([k3, v3]) => k3.toLowerCase().includes(q3) || v3.toLowerCase().includes(q3)
|
|
1281
1286
|
);
|
|
1282
1287
|
}, [variables, search]);
|
|
1283
1288
|
const groups = T2(() => {
|
|
@@ -1605,8 +1610,363 @@
|
|
|
1605
1610
|
] });
|
|
1606
1611
|
}
|
|
1607
1612
|
|
|
1608
|
-
// app/assets/typescript/profiler/components/
|
|
1613
|
+
// app/assets/typescript/profiler/components/test-runner/TestFileTree.tsx
|
|
1614
|
+
function TestFileTree({ tree, selected, onToggleFile, onToggleDir }) {
|
|
1615
|
+
const [collapsed, setCollapsed] = d2(/* @__PURE__ */ new Set());
|
|
1616
|
+
const toggleCollapse = (dir) => {
|
|
1617
|
+
setCollapsed((prev) => {
|
|
1618
|
+
const next = new Set(prev);
|
|
1619
|
+
next.has(dir) ? next.delete(dir) : next.add(dir);
|
|
1620
|
+
return next;
|
|
1621
|
+
});
|
|
1622
|
+
};
|
|
1623
|
+
const dirSelected = (paths) => {
|
|
1624
|
+
const count = paths.filter((p3) => selected.has(p3)).length;
|
|
1625
|
+
if (count === 0) return "none";
|
|
1626
|
+
if (count === paths.length) return "all";
|
|
1627
|
+
return "partial";
|
|
1628
|
+
};
|
|
1629
|
+
return /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--mono", style: "overflow-y: auto; height: 100%", children: tree.map(({ directory, files }) => {
|
|
1630
|
+
const paths = files.map((f4) => f4.path);
|
|
1631
|
+
const sel = dirSelected(paths);
|
|
1632
|
+
const isCollapsed = collapsed.has(directory);
|
|
1633
|
+
return /* @__PURE__ */ u3("div", { style: "margin-bottom: 4px", children: [
|
|
1634
|
+
/* @__PURE__ */ u3(
|
|
1635
|
+
"div",
|
|
1636
|
+
{
|
|
1637
|
+
style: "display: flex; align-items: center; gap: 6px; padding: 3px 6px; cursor: pointer; border-radius: 4px; background: var(--profiler-bg-secondary, rgba(255,255,255,0.05))",
|
|
1638
|
+
onClick: () => toggleCollapse(directory),
|
|
1639
|
+
children: [
|
|
1640
|
+
/* @__PURE__ */ u3(
|
|
1641
|
+
"input",
|
|
1642
|
+
{
|
|
1643
|
+
type: "checkbox",
|
|
1644
|
+
checked: sel === "all",
|
|
1645
|
+
ref: (el) => {
|
|
1646
|
+
if (el) el.indeterminate = sel === "partial";
|
|
1647
|
+
},
|
|
1648
|
+
onClick: (e3) => {
|
|
1649
|
+
e3.stopPropagation();
|
|
1650
|
+
onToggleDir(directory, paths);
|
|
1651
|
+
},
|
|
1652
|
+
style: "cursor: pointer; flex-shrink: 0"
|
|
1653
|
+
}
|
|
1654
|
+
),
|
|
1655
|
+
/* @__PURE__ */ u3("span", { style: "color: var(--profiler-text-muted, #888); flex-shrink: 0", children: isCollapsed ? "\u25B6" : "\u25BC" }),
|
|
1656
|
+
/* @__PURE__ */ u3("span", { style: "color: var(--profiler-accent, #06b6d4); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap", title: directory, children: [
|
|
1657
|
+
directory,
|
|
1658
|
+
"/"
|
|
1659
|
+
] }),
|
|
1660
|
+
/* @__PURE__ */ u3("span", { style: "color: var(--profiler-text-muted, #888); margin-left: auto; flex-shrink: 0", children: [
|
|
1661
|
+
"(",
|
|
1662
|
+
files.length,
|
|
1663
|
+
")"
|
|
1664
|
+
] })
|
|
1665
|
+
]
|
|
1666
|
+
}
|
|
1667
|
+
),
|
|
1668
|
+
!isCollapsed && files.map((file) => /* @__PURE__ */ u3(
|
|
1669
|
+
"div",
|
|
1670
|
+
{
|
|
1671
|
+
style: "display: flex; align-items: center; gap: 6px; padding: 2px 6px 2px 24px; cursor: pointer; border-radius: 4px",
|
|
1672
|
+
onClick: () => onToggleFile(file.path),
|
|
1673
|
+
children: [
|
|
1674
|
+
/* @__PURE__ */ u3(
|
|
1675
|
+
"input",
|
|
1676
|
+
{
|
|
1677
|
+
type: "checkbox",
|
|
1678
|
+
checked: selected.has(file.path),
|
|
1679
|
+
onClick: (e3) => {
|
|
1680
|
+
e3.stopPropagation();
|
|
1681
|
+
onToggleFile(file.path);
|
|
1682
|
+
},
|
|
1683
|
+
style: "cursor: pointer; flex-shrink: 0"
|
|
1684
|
+
}
|
|
1685
|
+
),
|
|
1686
|
+
/* @__PURE__ */ u3("span", { style: "overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--profiler-text, #e2e8f0)", title: file.path, children: file.name })
|
|
1687
|
+
]
|
|
1688
|
+
},
|
|
1689
|
+
file.path
|
|
1690
|
+
))
|
|
1691
|
+
] }, directory);
|
|
1692
|
+
}) });
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// app/assets/typescript/profiler/components/test-runner/RunOutput.tsx
|
|
1696
|
+
function statusColor(status) {
|
|
1697
|
+
if (status === "passed") return "var(--profiler-success, #10b981)";
|
|
1698
|
+
if (status === "failed") return "var(--profiler-error, #ef4444)";
|
|
1699
|
+
if (status === "running") return "var(--profiler-accent, #06b6d4)";
|
|
1700
|
+
if (status === "killed" || status === "error") return "var(--profiler-warning, #f59e0b)";
|
|
1701
|
+
return "var(--profiler-text-muted, #888)";
|
|
1702
|
+
}
|
|
1703
|
+
function statusLabel(status) {
|
|
1704
|
+
const map = {
|
|
1705
|
+
pending: "\u23F3 Pending",
|
|
1706
|
+
running: "\u25CF Running\u2026",
|
|
1707
|
+
passed: "\u2713 Passed",
|
|
1708
|
+
failed: "\u2717 Failed",
|
|
1709
|
+
killed: "\u25A0 Killed",
|
|
1710
|
+
error: "\u26A0 Error"
|
|
1711
|
+
};
|
|
1712
|
+
return map[status] || status;
|
|
1713
|
+
}
|
|
1714
|
+
function parseAnsi(raw) {
|
|
1715
|
+
const ANSI_STYLES = {
|
|
1716
|
+
"0": "",
|
|
1717
|
+
"1": "font-weight:bold",
|
|
1718
|
+
"31": "color:var(--ansi-red)",
|
|
1719
|
+
"32": "color:var(--ansi-green)",
|
|
1720
|
+
"33": "color:var(--ansi-yellow)",
|
|
1721
|
+
"34": "color:var(--ansi-blue)",
|
|
1722
|
+
"35": "color:var(--ansi-purple)",
|
|
1723
|
+
"36": "color:var(--ansi-cyan)"
|
|
1724
|
+
};
|
|
1725
|
+
const spans = [];
|
|
1726
|
+
let currentStyle = "";
|
|
1727
|
+
const parts = raw.split(/(\x1b\[[0-9;]*m)/);
|
|
1728
|
+
for (const part of parts) {
|
|
1729
|
+
if (part.startsWith("\x1B[") && part.endsWith("m")) {
|
|
1730
|
+
const codes = part.slice(2, -1).split(";");
|
|
1731
|
+
if (codes.includes("0")) {
|
|
1732
|
+
currentStyle = "";
|
|
1733
|
+
} else {
|
|
1734
|
+
const styles = codes.map((c3) => ANSI_STYLES[c3] ?? "").filter(Boolean);
|
|
1735
|
+
currentStyle = [...currentStyle ? [currentStyle] : [], ...styles].join(";");
|
|
1736
|
+
}
|
|
1737
|
+
} else if (part.length > 0) {
|
|
1738
|
+
spans.push({ text: part, style: currentStyle });
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
return spans;
|
|
1742
|
+
}
|
|
1743
|
+
function AnsiOutput({ text }) {
|
|
1744
|
+
const spans = parseAnsi(text);
|
|
1745
|
+
if (spans.length === 0) {
|
|
1746
|
+
return /* @__PURE__ */ u3("span", { style: "color:var(--profiler-text-muted)", children: "No output yet\u2026" });
|
|
1747
|
+
}
|
|
1748
|
+
return /* @__PURE__ */ u3(k, { children: spans.map(
|
|
1749
|
+
(s3, i3) => s3.style ? /* @__PURE__ */ u3("span", { style: s3.style, children: s3.text }, i3) : /* @__PURE__ */ u3("span", { children: s3.text }, i3)
|
|
1750
|
+
) });
|
|
1751
|
+
}
|
|
1752
|
+
function RunOutput({ run }) {
|
|
1753
|
+
const outputRef = A2(null);
|
|
1754
|
+
y2(() => {
|
|
1755
|
+
if (outputRef.current && run?.status === "running") {
|
|
1756
|
+
outputRef.current.scrollTop = outputRef.current.scrollHeight;
|
|
1757
|
+
}
|
|
1758
|
+
}, [run?.output]);
|
|
1759
|
+
if (!run) {
|
|
1760
|
+
return /* @__PURE__ */ u3("div", { class: "profiler-empty", style: "height: 100%; display: flex; align-items: center; justify-content: center", children: /* @__PURE__ */ u3("div", { children: [
|
|
1761
|
+
/* @__PURE__ */ u3("div", { class: "profiler-empty__title", style: "font-size: 1.1rem", children: "Select files and click Run" }),
|
|
1762
|
+
/* @__PURE__ */ u3("p", { class: "profiler-empty__description", children: "Test output will appear here in real time" })
|
|
1763
|
+
] }) });
|
|
1764
|
+
}
|
|
1765
|
+
return /* @__PURE__ */ u3("div", { style: "display: flex; flex-direction: column; height: 100%; gap: 12px", children: [
|
|
1766
|
+
/* @__PURE__ */ u3("div", { style: "display: flex; align-items: center; gap: 12px; flex-shrink: 0", children: [
|
|
1767
|
+
/* @__PURE__ */ u3("span", { style: `font-weight: 600; color: ${statusColor(run.status)}`, children: statusLabel(run.status) }),
|
|
1768
|
+
run.duration != null && /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--muted", children: [
|
|
1769
|
+
(run.duration / 1e3).toFixed(1),
|
|
1770
|
+
"s"
|
|
1771
|
+
] }),
|
|
1772
|
+
(run.status === "passed" || run.status === "failed") && /* @__PURE__ */ u3("a", { href: "/_profiler?section=tests", class: "profiler-text--xs", style: "color: var(--profiler-accent, #06b6d4); margin-left: auto", children: "View in Profiler \u2192" })
|
|
1773
|
+
] }),
|
|
1774
|
+
/* @__PURE__ */ u3(
|
|
1775
|
+
"pre",
|
|
1776
|
+
{
|
|
1777
|
+
ref: outputRef,
|
|
1778
|
+
style: "flex: 1; overflow-y: auto; background: var(--profiler-terminal-bg); color: var(--profiler-terminal-text); padding: 14px 16px; border-radius: 6px; font-family: var(--profiler-font-mono); font-size: 12px; line-height: 1.65; margin: 0; white-space: pre-wrap; word-break: break-all; border: 1px solid var(--profiler-border)",
|
|
1779
|
+
children: /* @__PURE__ */ u3(AnsiOutput, { text: run.output || "" })
|
|
1780
|
+
}
|
|
1781
|
+
),
|
|
1782
|
+
run.files.length > 0 && /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "flex-shrink: 0", children: [
|
|
1783
|
+
run.files.length,
|
|
1784
|
+
" file",
|
|
1785
|
+
run.files.length !== 1 ? "s" : "",
|
|
1786
|
+
" \xB7 ",
|
|
1787
|
+
run.framework
|
|
1788
|
+
] })
|
|
1789
|
+
] });
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
// app/assets/typescript/profiler/components/test-runner/TestRunnerContent.tsx
|
|
1609
1793
|
var BASE = "/_profiler";
|
|
1794
|
+
function TestRunnerContent() {
|
|
1795
|
+
const [framework, setFramework] = d2("");
|
|
1796
|
+
const [frameworks, setFrameworks] = d2([]);
|
|
1797
|
+
const [tree, setTree] = d2([]);
|
|
1798
|
+
const [selected, setSelected] = d2(/* @__PURE__ */ new Set());
|
|
1799
|
+
const [loading, setLoading] = d2(true);
|
|
1800
|
+
const [currentRun, setCurrentRun] = d2(null);
|
|
1801
|
+
const [isRunning, setIsRunning] = d2(false);
|
|
1802
|
+
const [error, setError] = d2(null);
|
|
1803
|
+
const loadFiles = q2((fw) => {
|
|
1804
|
+
setLoading(true);
|
|
1805
|
+
fetch(`${BASE}/api/test_runner/files?framework=${fw}`).then((r3) => r3.json()).then((data) => {
|
|
1806
|
+
setFrameworks(data.frameworks || []);
|
|
1807
|
+
setTree(data.tree || []);
|
|
1808
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
1809
|
+
setLoading(false);
|
|
1810
|
+
}).catch(() => {
|
|
1811
|
+
setError("Failed to load test files");
|
|
1812
|
+
setLoading(false);
|
|
1813
|
+
});
|
|
1814
|
+
}, []);
|
|
1815
|
+
y2(() => {
|
|
1816
|
+
fetch(`${BASE}/api/test_runner/files`).then((r3) => r3.json()).then((data) => {
|
|
1817
|
+
const fws = (data.frameworks || []).map(String);
|
|
1818
|
+
setFrameworks(fws);
|
|
1819
|
+
const defaultFw = fws[0] || "minitest";
|
|
1820
|
+
setFramework(defaultFw);
|
|
1821
|
+
return fetch(`${BASE}/api/test_runner/files?framework=${defaultFw}`);
|
|
1822
|
+
}).then((r3) => r3.json()).then((data) => {
|
|
1823
|
+
setTree(data.tree || []);
|
|
1824
|
+
setLoading(false);
|
|
1825
|
+
}).catch(() => {
|
|
1826
|
+
setError("Failed to load test files");
|
|
1827
|
+
setLoading(false);
|
|
1828
|
+
});
|
|
1829
|
+
}, []);
|
|
1830
|
+
y2(() => {
|
|
1831
|
+
if (!currentRun || !isRunning) return;
|
|
1832
|
+
if (["passed", "failed", "killed", "error"].includes(currentRun.status)) {
|
|
1833
|
+
setIsRunning(false);
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
const es = new EventSource(`${BASE}/api/test_runner/runs/${currentRun.id}/stream`);
|
|
1837
|
+
es.addEventListener("output", (e3) => {
|
|
1838
|
+
try {
|
|
1839
|
+
const data = JSON.parse(e3.data);
|
|
1840
|
+
setCurrentRun((prev) => prev ? { ...prev, output: (prev.output || "") + data.chunk } : prev);
|
|
1841
|
+
} catch {
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
es.addEventListener("done", (e3) => {
|
|
1845
|
+
try {
|
|
1846
|
+
const data = JSON.parse(e3.data);
|
|
1847
|
+
setCurrentRun((prev) => prev ? { ...prev, status: data.status } : prev);
|
|
1848
|
+
} catch {
|
|
1849
|
+
}
|
|
1850
|
+
setIsRunning(false);
|
|
1851
|
+
es.close();
|
|
1852
|
+
});
|
|
1853
|
+
es.onerror = () => {
|
|
1854
|
+
es.close();
|
|
1855
|
+
fetch(`${BASE}/api/test_runner/runs/${currentRun.id}`).then((r3) => r3.json()).then((data) => {
|
|
1856
|
+
setCurrentRun(data);
|
|
1857
|
+
setIsRunning(false);
|
|
1858
|
+
}).catch(() => setIsRunning(false));
|
|
1859
|
+
};
|
|
1860
|
+
return () => es.close();
|
|
1861
|
+
}, [currentRun?.id, isRunning]);
|
|
1862
|
+
const handleFrameworkChange = (fw) => {
|
|
1863
|
+
setFramework(fw);
|
|
1864
|
+
loadFiles(fw);
|
|
1865
|
+
};
|
|
1866
|
+
const toggleFile = (path) => {
|
|
1867
|
+
setSelected((prev) => {
|
|
1868
|
+
const next = new Set(prev);
|
|
1869
|
+
next.has(path) ? next.delete(path) : next.add(path);
|
|
1870
|
+
return next;
|
|
1871
|
+
});
|
|
1872
|
+
};
|
|
1873
|
+
const toggleDir = (_dir, paths) => {
|
|
1874
|
+
setSelected((prev) => {
|
|
1875
|
+
const next = new Set(prev);
|
|
1876
|
+
const allSelected = paths.every((p3) => next.has(p3));
|
|
1877
|
+
if (allSelected) {
|
|
1878
|
+
paths.forEach((p3) => next.delete(p3));
|
|
1879
|
+
} else {
|
|
1880
|
+
paths.forEach((p3) => next.add(p3));
|
|
1881
|
+
}
|
|
1882
|
+
return next;
|
|
1883
|
+
});
|
|
1884
|
+
};
|
|
1885
|
+
const selectAll = () => {
|
|
1886
|
+
const all = tree.flatMap((d3) => d3.files.map((f4) => f4.path));
|
|
1887
|
+
setSelected(new Set(all));
|
|
1888
|
+
};
|
|
1889
|
+
const selectNone = () => setSelected(/* @__PURE__ */ new Set());
|
|
1890
|
+
const runTests = () => {
|
|
1891
|
+
if (selected.size === 0 || isRunning) return;
|
|
1892
|
+
setError(null);
|
|
1893
|
+
fetch(`${BASE}/api/test_runner/runs`, {
|
|
1894
|
+
method: "POST",
|
|
1895
|
+
headers: { "Content-Type": "application/json" },
|
|
1896
|
+
body: JSON.stringify({ files: Array.from(selected), framework })
|
|
1897
|
+
}).then((r3) => r3.json()).then((data) => {
|
|
1898
|
+
setCurrentRun(data);
|
|
1899
|
+
setIsRunning(true);
|
|
1900
|
+
}).catch(() => setError("Failed to start test run"));
|
|
1901
|
+
};
|
|
1902
|
+
const stopRun = () => {
|
|
1903
|
+
if (!currentRun) return;
|
|
1904
|
+
fetch(`${BASE}/api/test_runner/runs/${currentRun.id}`, { method: "DELETE" }).then(() => {
|
|
1905
|
+
setIsRunning(false);
|
|
1906
|
+
setCurrentRun((prev) => prev ? { ...prev, status: "killed" } : prev);
|
|
1907
|
+
}).catch(() => {
|
|
1908
|
+
});
|
|
1909
|
+
};
|
|
1910
|
+
const totalFiles = tree.reduce((n2, d3) => n2 + d3.files.length, 0);
|
|
1911
|
+
return /* @__PURE__ */ u3("div", { children: [
|
|
1912
|
+
error && /* @__PURE__ */ u3("div", { style: "color: var(--profiler-error, #ef4444); background: rgba(239,68,68,0.1); border: 1px solid var(--profiler-error, #ef4444); border-radius: 4px; padding: 8px 12px; margin-bottom: 12px; font-size: 13px", children: error }),
|
|
1913
|
+
/* @__PURE__ */ u3("div", { class: "profiler-action-bar profiler-mb-3", children: [
|
|
1914
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", children: frameworks.length > 0 && frameworks.map((fw) => /* @__PURE__ */ u3(
|
|
1915
|
+
"button",
|
|
1916
|
+
{
|
|
1917
|
+
class: `profiler-preset-btn${framework === fw ? " profiler-preset-btn--active" : ""}`,
|
|
1918
|
+
onClick: () => handleFrameworkChange(fw),
|
|
1919
|
+
disabled: isRunning,
|
|
1920
|
+
children: fw === "rspec" ? "RSpec" : "Minitest"
|
|
1921
|
+
},
|
|
1922
|
+
fw
|
|
1923
|
+
)) }),
|
|
1924
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", style: "margin-left: auto", children: [
|
|
1925
|
+
/* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--muted", children: [
|
|
1926
|
+
selected.size,
|
|
1927
|
+
" / ",
|
|
1928
|
+
totalFiles,
|
|
1929
|
+
" selected"
|
|
1930
|
+
] }),
|
|
1931
|
+
/* @__PURE__ */ u3("button", { class: "btn btn-secondary btn-sm", onClick: selectAll, disabled: isRunning || loading, children: "All" }),
|
|
1932
|
+
/* @__PURE__ */ u3("button", { class: "btn btn-secondary btn-sm", onClick: selectNone, disabled: isRunning, children: "None" }),
|
|
1933
|
+
isRunning ? /* @__PURE__ */ u3("button", { class: "btn btn-danger btn-sm", onClick: stopRun, children: "\u25A0 Stop" }) : /* @__PURE__ */ u3(
|
|
1934
|
+
"button",
|
|
1935
|
+
{
|
|
1936
|
+
class: "btn btn-sm",
|
|
1937
|
+
style: "background: var(--profiler-accent, #06b6d4); color: #000; font-weight: 600",
|
|
1938
|
+
onClick: runTests,
|
|
1939
|
+
disabled: selected.size === 0,
|
|
1940
|
+
children: [
|
|
1941
|
+
"\u25B6 Run Selected (",
|
|
1942
|
+
selected.size,
|
|
1943
|
+
")"
|
|
1944
|
+
]
|
|
1945
|
+
}
|
|
1946
|
+
)
|
|
1947
|
+
] })
|
|
1948
|
+
] }),
|
|
1949
|
+
/* @__PURE__ */ u3("div", { style: "display: grid; grid-template-columns: 260px 1fr; height: 460px; border: 1px solid var(--profiler-border, rgba(255,255,255,0.1)); border-radius: 6px; overflow: hidden", children: [
|
|
1950
|
+
/* @__PURE__ */ u3("div", { style: "border-right: 1px solid var(--profiler-border, rgba(255,255,255,0.1)); overflow-y: auto; padding: 8px", children: loading ? /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "padding: 8px", children: "Loading files\u2026" }) : tree.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "padding: 8px", children: [
|
|
1951
|
+
"No ",
|
|
1952
|
+
framework,
|
|
1953
|
+
" test files found"
|
|
1954
|
+
] }) : /* @__PURE__ */ u3(
|
|
1955
|
+
TestFileTree,
|
|
1956
|
+
{
|
|
1957
|
+
tree,
|
|
1958
|
+
selected,
|
|
1959
|
+
onToggleFile: toggleFile,
|
|
1960
|
+
onToggleDir: toggleDir
|
|
1961
|
+
}
|
|
1962
|
+
) }),
|
|
1963
|
+
/* @__PURE__ */ u3("div", { style: "overflow: hidden; display: flex; flex-direction: column", children: /* @__PURE__ */ u3(RunOutput, { run: currentRun }) })
|
|
1964
|
+
] })
|
|
1965
|
+
] });
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
// app/assets/typescript/profiler/components/ProfileList.tsx
|
|
1969
|
+
var BASE2 = "/_profiler";
|
|
1610
1970
|
function TableSkeleton({ cols, rows = 6 }) {
|
|
1611
1971
|
return /* @__PURE__ */ u3("div", { children: Array.from({ length: rows }).map((_2, i3) => /* @__PURE__ */ u3("div", { class: "profiler-skeleton__row", children: cols.map((size, j3) => /* @__PURE__ */ u3("div", { class: `profiler-skeleton__cell profiler-skeleton__cell--${size}` }, j3)) }, i3)) });
|
|
1612
1972
|
}
|
|
@@ -1644,7 +2004,7 @@
|
|
|
1644
2004
|
const params = new URLSearchParams(window.location.search);
|
|
1645
2005
|
const initialSection = () => {
|
|
1646
2006
|
const s3 = params.get("section");
|
|
1647
|
-
return s3 === "http" || s3 === "jobs" || s3 === "outbound" || s3 === "env" ? s3 : "http";
|
|
2007
|
+
return s3 === "http" || s3 === "jobs" || s3 === "console" || s3 === "tests" || s3 === "runner" || s3 === "outbound" || s3 === "env" ? s3 : "http";
|
|
1648
2008
|
};
|
|
1649
2009
|
const initialSort = () => {
|
|
1650
2010
|
const col = params.get("sort");
|
|
@@ -1663,12 +2023,25 @@
|
|
|
1663
2023
|
const [jobOffset, setJobOffset] = d2(0);
|
|
1664
2024
|
const [jobHasMore, setJobHasMore] = d2(false);
|
|
1665
2025
|
const [jobLoadingMore, setJobLoadingMore] = d2(false);
|
|
2026
|
+
const [consoles, setConsoles] = d2([]);
|
|
2027
|
+
const [consoleOffset, setConsoleOffset] = d2(0);
|
|
2028
|
+
const [consoleHasMore, setConsoleHasMore] = d2(false);
|
|
2029
|
+
const [consoleLoadingMore, setConsoleLoadingMore] = d2(false);
|
|
2030
|
+
const [tests, setTests] = d2([]);
|
|
2031
|
+
const [testOffset, setTestOffset] = d2(0);
|
|
2032
|
+
const [testHasMore, setTestHasMore] = d2(false);
|
|
2033
|
+
const [testLoadingMore, setTestLoadingMore] = d2(false);
|
|
2034
|
+
const [loadingTests, setLoadingTests] = d2(initialSection() === "tests");
|
|
2035
|
+
const [testsLoaded, setTestsLoaded] = d2(false);
|
|
2036
|
+
const [testsError, setTestsError] = d2(null);
|
|
1666
2037
|
const [outboundRequests, setOutboundRequests] = d2([]);
|
|
1667
2038
|
const [loadingHttp, setLoadingHttp] = d2(initialSection() === "http");
|
|
1668
2039
|
const [loadingJobs, setLoadingJobs] = d2(initialSection() === "jobs");
|
|
2040
|
+
const [loadingConsole, setLoadingConsole] = d2(initialSection() === "console");
|
|
1669
2041
|
const [loadingOutbound, setLoadingOutbound] = d2(initialSection() === "outbound");
|
|
1670
2042
|
const [error, setError] = d2(null);
|
|
1671
2043
|
const [jobsError, setJobsError] = d2(null);
|
|
2044
|
+
const [consoleError, setConsoleError] = d2(null);
|
|
1672
2045
|
const [outboundError, setOutboundError] = d2(null);
|
|
1673
2046
|
const [envData, setEnvData] = d2(void 0);
|
|
1674
2047
|
const [loadingEnv, setLoadingEnv] = d2(initialSection() === "env");
|
|
@@ -1684,9 +2057,15 @@
|
|
|
1684
2057
|
});
|
|
1685
2058
|
const [httpSort, setHttpSort] = d2(initialSort);
|
|
1686
2059
|
const [jobSort, setJobSort] = d2({ col: null, dir: "asc" });
|
|
2060
|
+
const [consoleSort, setConsoleSort] = d2({ col: null, dir: "asc" });
|
|
1687
2061
|
const [jobSearch, setJobSearch] = d2("");
|
|
1688
2062
|
const [jobStatus, setJobStatus] = d2("");
|
|
1689
2063
|
const [jobDuration, setJobDuration] = d2("");
|
|
2064
|
+
const [consoleSearch, setConsoleSearch] = d2("");
|
|
2065
|
+
const [consoleStatus, setConsoleStatus] = d2("");
|
|
2066
|
+
const [testSearch, setTestSearch] = d2("");
|
|
2067
|
+
const [testStatus, setTestStatus] = d2("");
|
|
2068
|
+
const [testSort, setTestSort] = d2({ col: null, dir: "asc" });
|
|
1690
2069
|
const [outboundSearch, setOutboundSearch] = d2("");
|
|
1691
2070
|
const [outboundMethod, setOutboundMethod] = d2("");
|
|
1692
2071
|
const [outboundStatus, setOutboundStatus] = d2("");
|
|
@@ -1724,7 +2103,7 @@
|
|
|
1724
2103
|
};
|
|
1725
2104
|
const loadMoreHttp = () => {
|
|
1726
2105
|
setHttpLoadingMore(true);
|
|
1727
|
-
fetch(`${
|
|
2106
|
+
fetch(`${BASE2}/api/profiles?limit=50&offset=${httpOffset}`).then((res) => res.json()).then((data) => {
|
|
1728
2107
|
setProfiles((prev) => [...prev, ...data.profiles]);
|
|
1729
2108
|
setHttpOffset((prev) => prev + data.profiles.length);
|
|
1730
2109
|
setHttpHasMore(data.has_more);
|
|
@@ -1733,13 +2112,46 @@
|
|
|
1733
2112
|
};
|
|
1734
2113
|
const loadMoreJobs = () => {
|
|
1735
2114
|
setJobLoadingMore(true);
|
|
1736
|
-
fetch(`${
|
|
2115
|
+
fetch(`${BASE2}/api/jobs?limit=50&offset=${jobOffset}`).then((res) => res.json()).then((data) => {
|
|
1737
2116
|
setJobs((prev) => [...prev, ...data.profiles]);
|
|
1738
2117
|
setJobOffset((prev) => prev + data.profiles.length);
|
|
1739
2118
|
setJobHasMore(data.has_more);
|
|
1740
2119
|
setJobLoadingMore(false);
|
|
1741
2120
|
}).catch(() => setJobLoadingMore(false));
|
|
1742
2121
|
};
|
|
2122
|
+
const loadMoreConsole = () => {
|
|
2123
|
+
setConsoleLoadingMore(true);
|
|
2124
|
+
fetch(`${BASE2}/api/console?limit=50&offset=${consoleOffset}`).then((res) => res.json()).then((data) => {
|
|
2125
|
+
setConsoles((prev) => [...prev, ...data.profiles]);
|
|
2126
|
+
setConsoleOffset((prev) => prev + data.profiles.length);
|
|
2127
|
+
setConsoleHasMore(data.has_more);
|
|
2128
|
+
setConsoleLoadingMore(false);
|
|
2129
|
+
}).catch(() => setConsoleLoadingMore(false));
|
|
2130
|
+
};
|
|
2131
|
+
const loadTests = () => {
|
|
2132
|
+
if (testsLoaded) return;
|
|
2133
|
+
setLoadingTests(true);
|
|
2134
|
+
fetch(`${BASE2}/api/tests?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
2135
|
+
setTests(data.profiles);
|
|
2136
|
+
setTestOffset(data.profiles.length);
|
|
2137
|
+
setTestHasMore(data.has_more);
|
|
2138
|
+
setLoadingTests(false);
|
|
2139
|
+
setTestsLoaded(true);
|
|
2140
|
+
}).catch(() => {
|
|
2141
|
+
setTestsError("Failed to load test profiles");
|
|
2142
|
+
setLoadingTests(false);
|
|
2143
|
+
setTestsLoaded(true);
|
|
2144
|
+
});
|
|
2145
|
+
};
|
|
2146
|
+
const loadMoreTests = () => {
|
|
2147
|
+
setTestLoadingMore(true);
|
|
2148
|
+
fetch(`${BASE2}/api/tests?limit=50&offset=${testOffset}`).then((res) => res.json()).then((data) => {
|
|
2149
|
+
setTests((prev) => [...prev, ...data.profiles]);
|
|
2150
|
+
setTestOffset((prev) => prev + data.profiles.length);
|
|
2151
|
+
setTestHasMore(data.has_more);
|
|
2152
|
+
setTestLoadingMore(false);
|
|
2153
|
+
}).catch(() => setTestLoadingMore(false));
|
|
2154
|
+
};
|
|
1743
2155
|
const handleSectionChange = (s3) => {
|
|
1744
2156
|
if (s3 === section) {
|
|
1745
2157
|
refreshSection(s3);
|
|
@@ -1749,7 +2161,11 @@
|
|
|
1749
2161
|
const url = new URL(window.location.href);
|
|
1750
2162
|
url.searchParams.set("section", s3);
|
|
1751
2163
|
history.pushState(null, "", url.toString());
|
|
1752
|
-
|
|
2164
|
+
if (s3 === "tests") {
|
|
2165
|
+
loadTests();
|
|
2166
|
+
} else {
|
|
2167
|
+
refreshSection(s3);
|
|
2168
|
+
}
|
|
1753
2169
|
setHttpSearch("");
|
|
1754
2170
|
setHttpMethod("");
|
|
1755
2171
|
setHttpStatus("");
|
|
@@ -1760,6 +2176,12 @@
|
|
|
1760
2176
|
setJobStatus("");
|
|
1761
2177
|
setJobDuration("");
|
|
1762
2178
|
setJobSort({ col: null, dir: "asc" });
|
|
2179
|
+
setConsoleSearch("");
|
|
2180
|
+
setConsoleStatus("");
|
|
2181
|
+
setConsoleSort({ col: null, dir: "asc" });
|
|
2182
|
+
setTestSearch("");
|
|
2183
|
+
setTestStatus("");
|
|
2184
|
+
setTestSort({ col: null, dir: "asc" });
|
|
1763
2185
|
setOutboundSearch("");
|
|
1764
2186
|
setOutboundMethod("");
|
|
1765
2187
|
setOutboundStatus("");
|
|
@@ -1771,41 +2193,65 @@
|
|
|
1771
2193
|
});
|
|
1772
2194
|
};
|
|
1773
2195
|
const deleteProfile = (token) => {
|
|
1774
|
-
fetch(`${
|
|
2196
|
+
fetch(`${BASE2}/api/profiles/${token}`, { method: "DELETE" }).then(() => {
|
|
1775
2197
|
setProfiles((prev) => prev.filter((p3) => p3.token !== token));
|
|
1776
2198
|
});
|
|
1777
2199
|
};
|
|
1778
2200
|
const deleteJob = (token) => {
|
|
1779
|
-
fetch(`${
|
|
2201
|
+
fetch(`${BASE2}/api/jobs/${token}`, { method: "DELETE" }).then(() => {
|
|
1780
2202
|
setJobs((prev) => prev.filter((p3) => p3.token !== token));
|
|
1781
2203
|
});
|
|
1782
2204
|
};
|
|
2205
|
+
const deleteConsole = (token) => {
|
|
2206
|
+
fetch(`${BASE2}/api/console/${token}`, { method: "DELETE" }).then(() => {
|
|
2207
|
+
setConsoles((prev) => prev.filter((p3) => p3.token !== token));
|
|
2208
|
+
});
|
|
2209
|
+
};
|
|
2210
|
+
const deleteTest = (token) => {
|
|
2211
|
+
fetch(`${BASE2}/api/tests/${token}`, { method: "DELETE" }).then(() => {
|
|
2212
|
+
setTests((prev) => prev.filter((p3) => p3.token !== token));
|
|
2213
|
+
});
|
|
2214
|
+
};
|
|
1783
2215
|
const clearProfiles = () => {
|
|
1784
2216
|
if (!window.confirm("Delete all HTTP profiles?")) return;
|
|
1785
|
-
fetch(`${
|
|
2217
|
+
fetch(`${BASE2}/api/profiles/clear`, { method: "DELETE" }).then(() => {
|
|
1786
2218
|
setProfiles([]);
|
|
1787
2219
|
});
|
|
1788
2220
|
};
|
|
1789
2221
|
const clearJobs = () => {
|
|
1790
2222
|
if (!window.confirm("Delete all job profiles?")) return;
|
|
1791
|
-
fetch(`${
|
|
2223
|
+
fetch(`${BASE2}/api/jobs/clear`, { method: "DELETE" }).then(() => {
|
|
1792
2224
|
setJobs([]);
|
|
1793
2225
|
});
|
|
1794
2226
|
};
|
|
2227
|
+
const clearConsole = () => {
|
|
2228
|
+
if (!window.confirm("Delete all console profiles?")) return;
|
|
2229
|
+
fetch(`${BASE2}/api/console/clear`, { method: "DELETE" }).then(() => {
|
|
2230
|
+
setConsoles([]);
|
|
2231
|
+
});
|
|
2232
|
+
};
|
|
2233
|
+
const clearTests = () => {
|
|
2234
|
+
if (!window.confirm("Delete all test profiles?")) return;
|
|
2235
|
+
fetch(`${BASE2}/api/tests/clear`, { method: "DELETE" }).then(() => {
|
|
2236
|
+
setTests([]);
|
|
2237
|
+
});
|
|
2238
|
+
};
|
|
1795
2239
|
const clearAll = () => {
|
|
1796
|
-
if (!window.confirm("Delete all HTTP and
|
|
2240
|
+
if (!window.confirm("Delete all HTTP, job and console profiles?")) return;
|
|
1797
2241
|
Promise.all([
|
|
1798
|
-
fetch(`${
|
|
1799
|
-
fetch(`${
|
|
2242
|
+
fetch(`${BASE2}/api/profiles/clear`, { method: "DELETE" }),
|
|
2243
|
+
fetch(`${BASE2}/api/jobs/clear`, { method: "DELETE" }),
|
|
2244
|
+
fetch(`${BASE2}/api/console/clear`, { method: "DELETE" })
|
|
1800
2245
|
]).then(() => {
|
|
1801
2246
|
setProfiles([]);
|
|
1802
2247
|
setJobs([]);
|
|
2248
|
+
setConsoles([]);
|
|
1803
2249
|
});
|
|
1804
2250
|
};
|
|
1805
2251
|
const refreshSection = (s3) => {
|
|
1806
2252
|
if (s3 === "http") {
|
|
1807
2253
|
setLoadingHttp(true);
|
|
1808
|
-
fetch(`${
|
|
2254
|
+
fetch(`${BASE2}/api/profiles?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
1809
2255
|
setProfiles(data.profiles);
|
|
1810
2256
|
setHttpOffset(data.profiles.length);
|
|
1811
2257
|
setHttpHasMore(data.has_more);
|
|
@@ -1816,7 +2262,7 @@
|
|
|
1816
2262
|
});
|
|
1817
2263
|
} else if (s3 === "jobs") {
|
|
1818
2264
|
setLoadingJobs(true);
|
|
1819
|
-
fetch(`${
|
|
2265
|
+
fetch(`${BASE2}/api/jobs?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
1820
2266
|
setJobs(data.profiles);
|
|
1821
2267
|
setJobOffset(data.profiles.length);
|
|
1822
2268
|
setJobHasMore(data.has_more);
|
|
@@ -1825,18 +2271,43 @@
|
|
|
1825
2271
|
setJobsError("Failed to load job profiles");
|
|
1826
2272
|
setLoadingJobs(false);
|
|
1827
2273
|
});
|
|
2274
|
+
} else if (s3 === "console") {
|
|
2275
|
+
setLoadingConsole(true);
|
|
2276
|
+
fetch(`${BASE2}/api/console?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
2277
|
+
setConsoles(data.profiles);
|
|
2278
|
+
setConsoleOffset(data.profiles.length);
|
|
2279
|
+
setConsoleHasMore(data.has_more);
|
|
2280
|
+
setLoadingConsole(false);
|
|
2281
|
+
}).catch(() => {
|
|
2282
|
+
setConsoleError("Failed to load console profiles");
|
|
2283
|
+
setLoadingConsole(false);
|
|
2284
|
+
});
|
|
2285
|
+
} else if (s3 === "tests") {
|
|
2286
|
+
setLoadingTests(true);
|
|
2287
|
+
setTestsLoaded(false);
|
|
2288
|
+
fetch(`${BASE2}/api/tests?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
2289
|
+
setTests(data.profiles);
|
|
2290
|
+
setTestOffset(data.profiles.length);
|
|
2291
|
+
setTestHasMore(data.has_more);
|
|
2292
|
+
setLoadingTests(false);
|
|
2293
|
+
setTestsLoaded(true);
|
|
2294
|
+
}).catch(() => {
|
|
2295
|
+
setTestsError("Failed to load test profiles");
|
|
2296
|
+
setLoadingTests(false);
|
|
2297
|
+
setTestsLoaded(true);
|
|
2298
|
+
});
|
|
1828
2299
|
} else if (s3 === "outbound") {
|
|
1829
2300
|
setLoadingOutbound(true);
|
|
1830
|
-
fetch(`${
|
|
2301
|
+
fetch(`${BASE2}/api/outbound_http`).then((res) => res.json()).then((data) => {
|
|
1831
2302
|
setOutboundRequests(data);
|
|
1832
2303
|
setLoadingOutbound(false);
|
|
1833
2304
|
}).catch(() => {
|
|
1834
2305
|
setOutboundError("Failed to load outbound HTTP requests");
|
|
1835
2306
|
setLoadingOutbound(false);
|
|
1836
2307
|
});
|
|
1837
|
-
} else {
|
|
2308
|
+
} else if (s3 === "env") {
|
|
1838
2309
|
setLoadingEnv(true);
|
|
1839
|
-
fetch(`${
|
|
2310
|
+
fetch(`${BASE2}/api/env_vars`).then((res) => res.json()).then((data) => {
|
|
1840
2311
|
setEnvData(data);
|
|
1841
2312
|
setLoadingEnv(false);
|
|
1842
2313
|
}).catch(() => {
|
|
@@ -1846,6 +2317,11 @@
|
|
|
1846
2317
|
}
|
|
1847
2318
|
};
|
|
1848
2319
|
const refresh = () => refreshSection(section);
|
|
2320
|
+
const toggleConsoleSort = (col) => {
|
|
2321
|
+
setConsoleSort(
|
|
2322
|
+
(prev) => prev.col === col ? { col, dir: prev.dir === "asc" ? "desc" : "asc" } : { col, dir: "asc" }
|
|
2323
|
+
);
|
|
2324
|
+
};
|
|
1849
2325
|
const tabClass = (s3) => `tab${section === s3 ? " active" : ""}`;
|
|
1850
2326
|
const filteredProfiles = profiles.filter((p3) => {
|
|
1851
2327
|
if (httpSearch && !p3.path.toLowerCase().includes(httpSearch.toLowerCase())) return false;
|
|
@@ -1933,8 +2409,70 @@
|
|
|
1933
2409
|
}
|
|
1934
2410
|
return true;
|
|
1935
2411
|
});
|
|
2412
|
+
const filteredConsoles = consoles.filter((p3) => {
|
|
2413
|
+
if (consoleSearch && !p3.path.toLowerCase().includes(consoleSearch.toLowerCase())) return false;
|
|
2414
|
+
if (consoleStatus === "error" && p3.status !== 500) return false;
|
|
2415
|
+
if (consoleStatus === "ok" && p3.status === 500) return false;
|
|
2416
|
+
return true;
|
|
2417
|
+
});
|
|
2418
|
+
const sortedConsoles = consoleSort.col ? [...filteredConsoles].sort((a3, b) => {
|
|
2419
|
+
if (consoleSort.col === "date") {
|
|
2420
|
+
const diff = new Date(a3.started_at).getTime() - new Date(b.started_at).getTime();
|
|
2421
|
+
return consoleSort.dir === "asc" ? diff : -diff;
|
|
2422
|
+
}
|
|
2423
|
+
let av, bv;
|
|
2424
|
+
switch (consoleSort.col) {
|
|
2425
|
+
case "duration":
|
|
2426
|
+
av = a3.duration;
|
|
2427
|
+
bv = b.duration;
|
|
2428
|
+
break;
|
|
2429
|
+
case "status":
|
|
2430
|
+
av = a3.status;
|
|
2431
|
+
bv = b.status;
|
|
2432
|
+
break;
|
|
2433
|
+
default:
|
|
2434
|
+
return 0;
|
|
2435
|
+
}
|
|
2436
|
+
return consoleSort.dir === "asc" ? av - bv : bv - av;
|
|
2437
|
+
}) : filteredConsoles;
|
|
2438
|
+
const filteredTests = tests.filter((p3) => {
|
|
2439
|
+
if (testSearch) {
|
|
2440
|
+
const testData = p3.collectors_data?.test;
|
|
2441
|
+
const name = (testData?.test_name || p3.path).toLowerCase();
|
|
2442
|
+
if (!name.includes(testSearch.toLowerCase())) return false;
|
|
2443
|
+
}
|
|
2444
|
+
if (testStatus === "failed" && p3.status !== 500) return false;
|
|
2445
|
+
if (testStatus === "passed" && p3.status === 500) return false;
|
|
2446
|
+
if (testStatus === "pending") {
|
|
2447
|
+
const testData = p3.collectors_data?.test;
|
|
2448
|
+
if (testData?.status !== "pending") return false;
|
|
2449
|
+
}
|
|
2450
|
+
return true;
|
|
2451
|
+
});
|
|
2452
|
+
const sortedTests = testSort.col ? [...filteredTests].sort((a3, b) => {
|
|
2453
|
+
let av, bv;
|
|
2454
|
+
if (testSort.col === "date") {
|
|
2455
|
+
const diff = new Date(a3.started_at).getTime() - new Date(b.started_at).getTime();
|
|
2456
|
+
return testSort.dir === "asc" ? diff : -diff;
|
|
2457
|
+
}
|
|
2458
|
+
switch (testSort.col) {
|
|
2459
|
+
case "duration":
|
|
2460
|
+
av = a3.duration;
|
|
2461
|
+
bv = b.duration;
|
|
2462
|
+
break;
|
|
2463
|
+
case "status":
|
|
2464
|
+
av = a3.status;
|
|
2465
|
+
bv = b.status;
|
|
2466
|
+
break;
|
|
2467
|
+
default:
|
|
2468
|
+
return 0;
|
|
2469
|
+
}
|
|
2470
|
+
return testSort.dir === "asc" ? av - bv : bv - av;
|
|
2471
|
+
}) : filteredTests;
|
|
1936
2472
|
const httpFiltersActive = !!(httpSearch || httpMethod || httpStatus || httpDuration || httpPreset);
|
|
1937
2473
|
const jobFiltersActive = !!(jobSearch || jobStatus || jobDuration);
|
|
2474
|
+
const consoleFiltersActive = !!(consoleSearch || consoleStatus);
|
|
2475
|
+
const testFiltersActive = !!(testSearch || testStatus);
|
|
1938
2476
|
const outboundFiltersActive = !!(outboundSearch || outboundMethod || outboundStatus);
|
|
1939
2477
|
const sortIcon = (activeCol, dir, col) => {
|
|
1940
2478
|
if (activeCol !== col) return /* @__PURE__ */ u3("span", { class: "sort-icon sort-icon--idle", children: "\u21C5" });
|
|
@@ -1962,7 +2500,19 @@
|
|
|
1962
2500
|
e3.preventDefault();
|
|
1963
2501
|
handleSectionChange("jobs");
|
|
1964
2502
|
}, children: "Background Jobs" }),
|
|
2503
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("console"), onClick: (e3) => {
|
|
2504
|
+
e3.preventDefault();
|
|
2505
|
+
handleSectionChange("console");
|
|
2506
|
+
}, children: "Console" }),
|
|
2507
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("tests"), onClick: (e3) => {
|
|
2508
|
+
e3.preventDefault();
|
|
2509
|
+
handleSectionChange("tests");
|
|
2510
|
+
}, children: "Tests" }),
|
|
1965
2511
|
/* @__PURE__ */ u3("div", { style: "flex: 1" }),
|
|
2512
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("runner"), onClick: (e3) => {
|
|
2513
|
+
e3.preventDefault();
|
|
2514
|
+
handleSectionChange("runner");
|
|
2515
|
+
}, children: "Test Runner" }),
|
|
1966
2516
|
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("outbound"), onClick: (e3) => {
|
|
1967
2517
|
e3.preventDefault();
|
|
1968
2518
|
handleSectionChange("outbound");
|
|
@@ -2062,7 +2612,7 @@
|
|
|
2062
2612
|
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2063
2613
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: methodClass(p3.method), children: p3.method }) }),
|
|
2064
2614
|
/* @__PURE__ */ u3("td", { children: [
|
|
2065
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2615
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, children: p3.path }),
|
|
2066
2616
|
p3.gem_version && p3.gem_version !== currentVersion && /* @__PURE__ */ u3("span", { class: "profiler-version-warn", title: `Captur\xE9 avec v${p3.gem_version} (actuel : v${currentVersion})`, children: "\u26A0\uFE0F" })
|
|
2067
2617
|
] }),
|
|
2068
2618
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: durationClass(p3.duration), children: [
|
|
@@ -2143,7 +2693,7 @@
|
|
|
2143
2693
|
return /* @__PURE__ */ u3("tr", { children: [
|
|
2144
2694
|
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2145
2695
|
/* @__PURE__ */ u3("td", { children: [
|
|
2146
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2696
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, children: p3.path }),
|
|
2147
2697
|
p3.gem_version && p3.gem_version !== currentVersion && /* @__PURE__ */ u3("span", { class: "profiler-version-warn", title: `Captur\xE9 avec v${p3.gem_version} (actuel : v${currentVersion})`, children: "\u26A0\uFE0F" })
|
|
2148
2698
|
] }),
|
|
2149
2699
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--mono", children: jobData?.queue || "-" }) }),
|
|
@@ -2160,6 +2710,167 @@
|
|
|
2160
2710
|
] }),
|
|
2161
2711
|
jobHasMore && !jobFiltersActive && /* @__PURE__ */ u3("div", { class: "profiler-load-more", children: /* @__PURE__ */ u3("button", { class: "btn btn-secondary", onClick: loadMoreJobs, disabled: jobLoadingMore, children: jobLoadingMore ? "Loading\u2026" : "Load more" }) })
|
|
2162
2712
|
] })),
|
|
2713
|
+
section === "console" && (loadingConsole ? /* @__PURE__ */ u3(TableSkeleton, { cols: ["sm", "flex", "sm", "sm", "xs", "sm"] }) : consoleError ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: /* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: consoleError }) }) : consoles.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: [
|
|
2714
|
+
/* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No console profiles found" }),
|
|
2715
|
+
/* @__PURE__ */ u3("p", { class: "profiler-empty__description", children: [
|
|
2716
|
+
"Run expressions in ",
|
|
2717
|
+
/* @__PURE__ */ u3("code", { children: "rails console" }),
|
|
2718
|
+
" to see profiling data"
|
|
2719
|
+
] })
|
|
2720
|
+
] }) : /* @__PURE__ */ u3(k, { children: [
|
|
2721
|
+
/* @__PURE__ */ u3("div", { class: "profiler-action-bar profiler-mb-3", children: [
|
|
2722
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", children: [
|
|
2723
|
+
/* @__PURE__ */ u3(
|
|
2724
|
+
"input",
|
|
2725
|
+
{
|
|
2726
|
+
type: "text",
|
|
2727
|
+
class: "profiler-filter-input",
|
|
2728
|
+
placeholder: "Search expression\u2026",
|
|
2729
|
+
value: consoleSearch,
|
|
2730
|
+
onInput: (e3) => setConsoleSearch(e3.target.value)
|
|
2731
|
+
}
|
|
2732
|
+
),
|
|
2733
|
+
/* @__PURE__ */ u3("select", { class: "profiler-filter-select", value: consoleStatus, onChange: (e3) => setConsoleStatus(e3.target.value), children: [
|
|
2734
|
+
/* @__PURE__ */ u3("option", { value: "", children: "All Statuses" }),
|
|
2735
|
+
/* @__PURE__ */ u3("option", { value: "ok", children: "OK" }),
|
|
2736
|
+
/* @__PURE__ */ u3("option", { value: "error", children: "Error" })
|
|
2737
|
+
] })
|
|
2738
|
+
] }),
|
|
2739
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", children: [
|
|
2740
|
+
consoleFiltersActive && /* @__PURE__ */ u3("span", { class: "profiler-filter-count", children: [
|
|
2741
|
+
filteredConsoles.length,
|
|
2742
|
+
" / ",
|
|
2743
|
+
consoles.length
|
|
2744
|
+
] }),
|
|
2745
|
+
/* @__PURE__ */ u3("button", { class: `btn-refresh${loadingConsole ? " btn-refresh--spinning" : ""}`, onClick: refresh, disabled: loadingConsole, title: "Refresh", children: "\u21BA" }),
|
|
2746
|
+
/* @__PURE__ */ u3("button", { class: "btn btn-danger btn-sm", onClick: clearConsole, title: "Delete console profiles", children: "Clear" }),
|
|
2747
|
+
/* @__PURE__ */ u3("button", { class: "btn btn-danger btn-sm", onClick: clearAll, title: "Delete all profiles", children: "Clear All" })
|
|
2748
|
+
] })
|
|
2749
|
+
] }),
|
|
2750
|
+
filteredConsoles.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: /* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No results match filters" }) }) : /* @__PURE__ */ u3("table", { children: [
|
|
2751
|
+
/* @__PURE__ */ u3("thead", { children: /* @__PURE__ */ u3("tr", { children: [
|
|
2752
|
+
/* @__PURE__ */ u3("th", { class: `sortable${consoleSort.col === "date" ? " sortable--active" : ""}`, onClick: () => toggleConsoleSort("date"), children: [
|
|
2753
|
+
"Time ",
|
|
2754
|
+
sortIcon(consoleSort.col, consoleSort.dir, "date")
|
|
2755
|
+
] }),
|
|
2756
|
+
/* @__PURE__ */ u3("th", { children: "Expression" }),
|
|
2757
|
+
/* @__PURE__ */ u3("th", { class: `sortable${consoleSort.col === "duration" ? " sortable--active" : ""}`, onClick: () => toggleConsoleSort("duration"), children: [
|
|
2758
|
+
"Duration ",
|
|
2759
|
+
sortIcon(consoleSort.col, consoleSort.dir, "duration")
|
|
2760
|
+
] }),
|
|
2761
|
+
/* @__PURE__ */ u3("th", { children: "SQL" }),
|
|
2762
|
+
/* @__PURE__ */ u3("th", { class: `sortable${consoleSort.col === "status" ? " sortable--active" : ""}`, onClick: () => toggleConsoleSort("status"), children: [
|
|
2763
|
+
"Status ",
|
|
2764
|
+
sortIcon(consoleSort.col, consoleSort.dir, "status")
|
|
2765
|
+
] }),
|
|
2766
|
+
/* @__PURE__ */ u3("th", { children: "Token" }),
|
|
2767
|
+
/* @__PURE__ */ u3("th", {})
|
|
2768
|
+
] }) }),
|
|
2769
|
+
/* @__PURE__ */ u3("tbody", { children: sortedConsoles.map((p3) => {
|
|
2770
|
+
const isError = p3.status === 500;
|
|
2771
|
+
return /* @__PURE__ */ u3("tr", { children: [
|
|
2772
|
+
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2773
|
+
/* @__PURE__ */ u3("td", { children: [
|
|
2774
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, class: "profiler-text--mono", style: "font-size:0.85em;", children: p3.path.length > 60 ? p3.path.slice(0, 60) + "\u2026" : p3.path }),
|
|
2775
|
+
p3.gem_version && p3.gem_version !== currentVersion && /* @__PURE__ */ u3("span", { class: "profiler-version-warn", title: `Captur\xE9 avec v${p3.gem_version} (actuel : v${currentVersion})`, children: "\u26A0\uFE0F" })
|
|
2776
|
+
] }),
|
|
2777
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: durationClass(p3.duration), children: [
|
|
2778
|
+
p3.duration.toFixed(2),
|
|
2779
|
+
" ms"
|
|
2780
|
+
] }) }),
|
|
2781
|
+
/* @__PURE__ */ u3("td", { children: p3.collectors_data?.database?.total_queries ?? "\u2014" }),
|
|
2782
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: isError ? "badge-error" : "badge-success", children: isError ? "\u2717 Error" : "\u2713 OK" }) }),
|
|
2783
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--xs profiler-text--mono profiler-text--muted", children: /* @__PURE__ */ u3("button", { class: "token-copy", onClick: () => copyToken(p3.token), title: "Copy full token", children: copiedToken === p3.token ? "\u2713" : p3.token.substring(0, 8) + "\u2026" }) }),
|
|
2784
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("button", { class: "btn-row-delete", onClick: () => deleteConsole(p3.token), title: "Delete", children: "\xD7" }) })
|
|
2785
|
+
] }, p3.token);
|
|
2786
|
+
}) })
|
|
2787
|
+
] }),
|
|
2788
|
+
consoleHasMore && !consoleFiltersActive && /* @__PURE__ */ u3("div", { class: "profiler-load-more", children: /* @__PURE__ */ u3("button", { class: "btn btn-secondary", onClick: loadMoreConsole, disabled: consoleLoadingMore, children: consoleLoadingMore ? "Loading\u2026" : "Load more" }) })
|
|
2789
|
+
] })),
|
|
2790
|
+
section === "tests" && (loadingTests ? /* @__PURE__ */ u3(TableSkeleton, { cols: ["sm", "flex", "md", "sm", "xs", "sm"] }) : testsError ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: /* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: testsError }) }) : tests.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: [
|
|
2791
|
+
/* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No test profiles found" }),
|
|
2792
|
+
/* @__PURE__ */ u3("p", { class: "profiler-empty__description", children: [
|
|
2793
|
+
"Add ",
|
|
2794
|
+
/* @__PURE__ */ u3("code", { children: "Profiler::TestHelpers::RSpecSupport.install(config)" }),
|
|
2795
|
+
" to your spec_helper.rb and run your tests. Or use the ",
|
|
2796
|
+
/* @__PURE__ */ u3("a", { href: "#", style: "color:var(--profiler-accent,#06b6d4)", onClick: (e3) => {
|
|
2797
|
+
e3.preventDefault();
|
|
2798
|
+
handleSectionChange("runner");
|
|
2799
|
+
}, children: "Test Runner" }),
|
|
2800
|
+
" tab to run tests from here."
|
|
2801
|
+
] })
|
|
2802
|
+
] }) : /* @__PURE__ */ u3(k, { children: [
|
|
2803
|
+
/* @__PURE__ */ u3("div", { class: "profiler-action-bar profiler-mb-3", children: [
|
|
2804
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", children: [
|
|
2805
|
+
/* @__PURE__ */ u3(
|
|
2806
|
+
"input",
|
|
2807
|
+
{
|
|
2808
|
+
type: "text",
|
|
2809
|
+
class: "profiler-filter-input",
|
|
2810
|
+
placeholder: "Search test name\u2026",
|
|
2811
|
+
value: testSearch,
|
|
2812
|
+
onInput: (e3) => setTestSearch(e3.target.value)
|
|
2813
|
+
}
|
|
2814
|
+
),
|
|
2815
|
+
/* @__PURE__ */ u3("select", { class: "profiler-filter-select", value: testStatus, onChange: (e3) => setTestStatus(e3.target.value), children: [
|
|
2816
|
+
/* @__PURE__ */ u3("option", { value: "", children: "All Statuses" }),
|
|
2817
|
+
/* @__PURE__ */ u3("option", { value: "passed", children: "Passed" }),
|
|
2818
|
+
/* @__PURE__ */ u3("option", { value: "failed", children: "Failed" }),
|
|
2819
|
+
/* @__PURE__ */ u3("option", { value: "pending", children: "Pending" })
|
|
2820
|
+
] })
|
|
2821
|
+
] }),
|
|
2822
|
+
/* @__PURE__ */ u3("div", { class: "profiler-filter-group", children: [
|
|
2823
|
+
testFiltersActive && /* @__PURE__ */ u3("span", { class: "profiler-filter-count", children: [
|
|
2824
|
+
filteredTests.length,
|
|
2825
|
+
" / ",
|
|
2826
|
+
tests.length
|
|
2827
|
+
] }),
|
|
2828
|
+
/* @__PURE__ */ u3("button", { class: `btn-refresh${loadingTests ? " btn-refresh--spinning" : ""}`, onClick: refresh, disabled: loadingTests, title: "Refresh", children: "\u21BA" }),
|
|
2829
|
+
/* @__PURE__ */ u3("button", { class: "btn btn-danger btn-sm", onClick: clearTests, title: "Delete test profiles", children: "Clear All" })
|
|
2830
|
+
] })
|
|
2831
|
+
] }),
|
|
2832
|
+
filteredTests.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: /* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No results match filters" }) }) : /* @__PURE__ */ u3("table", { children: [
|
|
2833
|
+
/* @__PURE__ */ u3("thead", { children: /* @__PURE__ */ u3("tr", { children: [
|
|
2834
|
+
/* @__PURE__ */ u3("th", { class: `sortable${testSort.col === "date" ? " sortable--active" : ""}`, onClick: () => setTestSort((prev) => ({ col: "date", dir: prev.col === "date" && prev.dir === "asc" ? "desc" : "asc" })), children: [
|
|
2835
|
+
"Time ",
|
|
2836
|
+
sortIcon(testSort.col, testSort.dir, "date")
|
|
2837
|
+
] }),
|
|
2838
|
+
/* @__PURE__ */ u3("th", { children: "Test Name" }),
|
|
2839
|
+
/* @__PURE__ */ u3("th", { children: "File" }),
|
|
2840
|
+
/* @__PURE__ */ u3("th", { class: `sortable${testSort.col === "duration" ? " sortable--active" : ""}`, onClick: () => setTestSort((prev) => ({ col: "duration", dir: prev.col === "duration" && prev.dir === "asc" ? "desc" : "asc" })), children: [
|
|
2841
|
+
"Duration ",
|
|
2842
|
+
sortIcon(testSort.col, testSort.dir, "duration")
|
|
2843
|
+
] }),
|
|
2844
|
+
/* @__PURE__ */ u3("th", { children: "Queries" }),
|
|
2845
|
+
/* @__PURE__ */ u3("th", { class: `sortable${testSort.col === "status" ? " sortable--active" : ""}`, onClick: () => setTestSort((prev) => ({ col: "status", dir: prev.col === "status" && prev.dir === "asc" ? "desc" : "asc" })), children: [
|
|
2846
|
+
"Status ",
|
|
2847
|
+
sortIcon(testSort.col, testSort.dir, "status")
|
|
2848
|
+
] }),
|
|
2849
|
+
/* @__PURE__ */ u3("th", { children: "Token" }),
|
|
2850
|
+
/* @__PURE__ */ u3("th", {})
|
|
2851
|
+
] }) }),
|
|
2852
|
+
/* @__PURE__ */ u3("tbody", { children: sortedTests.map((p3) => {
|
|
2853
|
+
const testData = p3.collectors_data?.test;
|
|
2854
|
+
const isFailed = p3.status === 500;
|
|
2855
|
+
const status = testData?.status || (isFailed ? "failed" : "passed");
|
|
2856
|
+
return /* @__PURE__ */ u3("tr", { children: [
|
|
2857
|
+
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2858
|
+
/* @__PURE__ */ u3("td", { style: "max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap", children: /* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, title: testData?.test_name || p3.path, children: testData?.test_name || p3.path }) }),
|
|
2859
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--xs profiler-text--mono profiler-text--muted", children: testData?.test_file || "-" }),
|
|
2860
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: durationClass(p3.duration), children: [
|
|
2861
|
+
p3.duration.toFixed(2),
|
|
2862
|
+
" ms"
|
|
2863
|
+
] }) }),
|
|
2864
|
+
/* @__PURE__ */ u3("td", { children: p3.collectors_data?.database?.total_queries ?? "\u2014" }),
|
|
2865
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: status === "failed" ? "badge-error" : status === "pending" ? "badge-warning" : "badge-success", children: status === "failed" ? "\u2717 Failed" : status === "pending" ? "\u23F8 Pending" : "\u2713 Passed" }) }),
|
|
2866
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--xs profiler-text--mono profiler-text--muted", children: /* @__PURE__ */ u3("button", { class: "token-copy", onClick: () => copyToken(p3.token), title: "Copy full token", children: copiedToken === p3.token ? "\u2713" : p3.token.substring(0, 8) + "\u2026" }) }),
|
|
2867
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("button", { class: "btn-row-delete", onClick: () => deleteTest(p3.token), title: "Delete", children: "\xD7" }) })
|
|
2868
|
+
] }, p3.token);
|
|
2869
|
+
}) })
|
|
2870
|
+
] }),
|
|
2871
|
+
testHasMore && !testFiltersActive && /* @__PURE__ */ u3("div", { class: "profiler-load-more", children: /* @__PURE__ */ u3("button", { class: "btn btn-secondary", onClick: loadMoreTests, disabled: testLoadingMore, children: testLoadingMore ? "Loading\u2026" : "Load more" }) })
|
|
2872
|
+
] })),
|
|
2873
|
+
section === "runner" && /* @__PURE__ */ u3(TestRunnerContent, {}),
|
|
2163
2874
|
section === "outbound" && (loadingOutbound ? /* @__PURE__ */ u3(TableSkeleton, { cols: ["sm", "xs", "flex", "sm", "xs"], rows: 4 }) : outboundError ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: /* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: outboundError }) }) : outboundRequests.length === 0 ? /* @__PURE__ */ u3("div", { class: "profiler-empty", children: [
|
|
2164
2875
|
/* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No outbound HTTP requests found" }),
|
|
2165
2876
|
/* @__PURE__ */ u3("p", { class: "profiler-empty__description", children: "Make requests to external services to see outbound HTTP data" })
|
|
@@ -2212,7 +2923,7 @@
|
|
|
2212
2923
|
/* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:2px", children: [
|
|
2213
2924
|
formatTime(req.profile_started_at),
|
|
2214
2925
|
" \xB7 Profile: ",
|
|
2215
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2926
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${req.profile_token}`, children: [
|
|
2216
2927
|
req.profile_token.substring(0, 8),
|
|
2217
2928
|
"\u2026"
|
|
2218
2929
|
] })
|
|
@@ -4228,8 +4939,8 @@
|
|
|
4228
4939
|
const verbs = ["ALL", ...Array.from(new Set(routes.map((r3) => r3.verb))).sort()];
|
|
4229
4940
|
const filtered = routes.filter((route) => {
|
|
4230
4941
|
const matchesVerb = verbFilter === "ALL" || route.verb === verbFilter;
|
|
4231
|
-
const
|
|
4232
|
-
const matchesText = !
|
|
4942
|
+
const q3 = filter.toLowerCase();
|
|
4943
|
+
const matchesText = !q3 || (route.pattern ?? "").toLowerCase().includes(q3) || (route.name ?? "").toLowerCase().includes(q3) || (route.controller_action ?? "").toLowerCase().includes(q3);
|
|
4233
4944
|
return matchesVerb && matchesText;
|
|
4234
4945
|
});
|
|
4235
4946
|
return /* @__PURE__ */ u3(k, { children: [
|
|
@@ -4928,6 +5639,255 @@
|
|
|
4928
5639
|
] });
|
|
4929
5640
|
}
|
|
4930
5641
|
|
|
5642
|
+
// app/assets/typescript/profiler/components/dashboard/tabs/ConsoleTab.tsx
|
|
5643
|
+
function ConsoleTab({ data }) {
|
|
5644
|
+
return /* @__PURE__ */ u3("div", { class: "profiler-p-4", children: [
|
|
5645
|
+
/* @__PURE__ */ u3("div", { class: "profiler-mb-6", children: [
|
|
5646
|
+
/* @__PURE__ */ u3("h3", { class: "profiler-section-title profiler-mb-2", children: "Expression" }),
|
|
5647
|
+
/* @__PURE__ */ u3("pre", { class: "profiler-code-block profiler-code-block--full", children: data.expression })
|
|
5648
|
+
] }),
|
|
5649
|
+
data.return_value !== void 0 && /* @__PURE__ */ u3("div", { children: [
|
|
5650
|
+
/* @__PURE__ */ u3("h3", { class: "profiler-section-title profiler-mb-2", children: "Return value" }),
|
|
5651
|
+
/* @__PURE__ */ u3("pre", { class: "profiler-code-block profiler-code-block--full", children: data.return_value })
|
|
5652
|
+
] })
|
|
5653
|
+
] });
|
|
5654
|
+
}
|
|
5655
|
+
|
|
5656
|
+
// app/assets/typescript/profiler/components/dashboard/ConsoleProfileDashboard.tsx
|
|
5657
|
+
function ConsoleProfileDashboard({ profile, initialTab, embedded }) {
|
|
5658
|
+
const cd = profile.collectors_data || {};
|
|
5659
|
+
const hasHttp = cd["http"]?.total_requests > 0;
|
|
5660
|
+
const hasDumps = (cd["dump"]?.count ?? 0) > 0;
|
|
5661
|
+
const hasLogs = (cd["logs"]?.total ?? 0) > 0;
|
|
5662
|
+
const hasException = !!cd["exception"]?.exception_class;
|
|
5663
|
+
const consoleData = cd["console"];
|
|
5664
|
+
const validTabs = ["console", "database", "cache", "http", "dump", "logs", "exception", "env", "timeline"];
|
|
5665
|
+
const defaultTab = validTabs.includes(initialTab) ? initialTab : "console";
|
|
5666
|
+
const [activeTab, setActiveTab] = d2(hasException ? "exception" : defaultTab);
|
|
5667
|
+
const isFailed = profile.status === 500;
|
|
5668
|
+
const handleTabClick = (tab) => (e3) => {
|
|
5669
|
+
e3.preventDefault();
|
|
5670
|
+
setActiveTab(tab);
|
|
5671
|
+
const url = new URL(window.location.href);
|
|
5672
|
+
url.searchParams.set("tab", tab);
|
|
5673
|
+
history.pushState(null, "", url.toString());
|
|
5674
|
+
};
|
|
5675
|
+
const tabClass = (key) => `tab${activeTab === key ? " active" : ""}`;
|
|
5676
|
+
return /* @__PURE__ */ u3("div", { class: "container", children: [
|
|
5677
|
+
/* @__PURE__ */ u3("div", { class: "header", children: [
|
|
5678
|
+
/* @__PURE__ */ u3("h1", { children: /* @__PURE__ */ u3("a", { href: "/_profiler?section=console", children: [
|
|
5679
|
+
/* @__PURE__ */ u3("span", { class: "h1-emoji", children: ">_" }),
|
|
5680
|
+
" Console Profile"
|
|
5681
|
+
] }) }),
|
|
5682
|
+
/* @__PURE__ */ u3("p", { style: "font-family: monospace; word-break: break-all", children: profile.path }),
|
|
5683
|
+
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-4 profiler-mt-2", children: [
|
|
5684
|
+
/* @__PURE__ */ u3("span", { children: [
|
|
5685
|
+
"Duration: ",
|
|
5686
|
+
/* @__PURE__ */ u3("strong", { children: [
|
|
5687
|
+
profile.duration.toFixed(2),
|
|
5688
|
+
" ms"
|
|
5689
|
+
] })
|
|
5690
|
+
] }),
|
|
5691
|
+
/* @__PURE__ */ u3("span", { children: [
|
|
5692
|
+
"Status: ",
|
|
5693
|
+
/* @__PURE__ */ u3("strong", { children: /* @__PURE__ */ u3("span", { class: `badge-${isFailed ? "error" : "success"}`, children: isFailed ? "Error" : "OK" }) })
|
|
5694
|
+
] }),
|
|
5695
|
+
profile.memory != null && /* @__PURE__ */ u3("span", { children: [
|
|
5696
|
+
"Memory: ",
|
|
5697
|
+
/* @__PURE__ */ u3("strong", { children: [
|
|
5698
|
+
(profile.memory / 1024 / 1024).toFixed(2),
|
|
5699
|
+
" MB"
|
|
5700
|
+
] })
|
|
5701
|
+
] }),
|
|
5702
|
+
profile.gem_version && /* @__PURE__ */ u3("span", { class: "profiler-version-badge", children: [
|
|
5703
|
+
"v",
|
|
5704
|
+
profile.gem_version
|
|
5705
|
+
] })
|
|
5706
|
+
] }),
|
|
5707
|
+
profile.gem_version && profile.gem_version !== getGemVersion() && /* @__PURE__ */ u3("div", { class: "profiler-version-mismatch", children: [
|
|
5708
|
+
"\u26A0\uFE0F Profil captur\xE9 avec la version ",
|
|
5709
|
+
/* @__PURE__ */ u3("strong", { children: profile.gem_version }),
|
|
5710
|
+
" \u2014 version actuelle : ",
|
|
5711
|
+
/* @__PURE__ */ u3("strong", { children: getGemVersion() })
|
|
5712
|
+
] })
|
|
5713
|
+
] }),
|
|
5714
|
+
/* @__PURE__ */ u3("div", { class: "profiler-panel", children: [
|
|
5715
|
+
/* @__PURE__ */ u3("div", { class: "tabs", children: [
|
|
5716
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("console"), onClick: handleTabClick("console"), children: "Console" }),
|
|
5717
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("database"), onClick: handleTabClick("database"), children: "Database" }),
|
|
5718
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("cache"), onClick: handleTabClick("cache"), children: "Cache" }),
|
|
5719
|
+
hasHttp && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("http"), onClick: handleTabClick("http"), children: "HTTP" }),
|
|
5720
|
+
hasDumps && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("dump"), onClick: handleTabClick("dump"), children: "Dumps" }),
|
|
5721
|
+
hasLogs && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("logs"), onClick: handleTabClick("logs"), children: "Logs" }),
|
|
5722
|
+
hasException && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("exception"), onClick: handleTabClick("exception"), children: "Exception" }),
|
|
5723
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("env"), onClick: handleTabClick("env"), children: "Env" }),
|
|
5724
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("timeline"), onClick: handleTabClick("timeline"), children: "Timeline" })
|
|
5725
|
+
] }),
|
|
5726
|
+
/* @__PURE__ */ u3("div", { class: "profiler-p-0 tab-content active", children: [
|
|
5727
|
+
activeTab === "console" && consoleData && /* @__PURE__ */ u3(ConsoleTab, { data: consoleData }),
|
|
5728
|
+
activeTab === "database" && /* @__PURE__ */ u3(DatabaseTab, { dbData: cd["database"], token: profile.token }),
|
|
5729
|
+
activeTab === "cache" && /* @__PURE__ */ u3(CacheTab, { cacheData: cd["cache"] }),
|
|
5730
|
+
activeTab === "http" && hasHttp && /* @__PURE__ */ u3(HttpTab, { httpData: cd["http"] }),
|
|
5731
|
+
activeTab === "dump" && hasDumps && /* @__PURE__ */ u3(DumpsTab, { dumpData: cd["dump"] }),
|
|
5732
|
+
activeTab === "logs" && hasLogs && /* @__PURE__ */ u3(LogsTab, { logData: cd["logs"] }),
|
|
5733
|
+
activeTab === "exception" && hasException && /* @__PURE__ */ u3(ExceptionTab, { exceptionData: cd["exception"] }),
|
|
5734
|
+
activeTab === "env" && /* @__PURE__ */ u3(EnvTab, { envData: cd["env"], readOnly: true }),
|
|
5735
|
+
activeTab === "timeline" && /* @__PURE__ */ u3(FlameGraphTab, { flamegraphData: cd["flamegraph"], perfData: cd["performance"], functionProfileData: cd["function_profile"] })
|
|
5736
|
+
] })
|
|
5737
|
+
] }),
|
|
5738
|
+
!embedded && /* @__PURE__ */ u3("div", { class: "profiler-mt-6", children: /* @__PURE__ */ u3("a", { href: "/_profiler", style: "color: var(--profiler-accent);", children: "\u2190 Back to profiles" }) })
|
|
5739
|
+
] });
|
|
5740
|
+
}
|
|
5741
|
+
|
|
5742
|
+
// app/assets/typescript/profiler/components/dashboard/tabs/TestTab.tsx
|
|
5743
|
+
function statusBadge2(status) {
|
|
5744
|
+
if (status === "passed") return /* @__PURE__ */ u3("span", { class: "badge-success", children: "\u2713 Passed" });
|
|
5745
|
+
if (status === "failed") return /* @__PURE__ */ u3("span", { class: "badge-error", children: "\u2717 Failed" });
|
|
5746
|
+
if (status === "pending") return /* @__PURE__ */ u3("span", { class: "badge-warning", children: "\u23F8 Pending" });
|
|
5747
|
+
return /* @__PURE__ */ u3("span", { class: "badge-default", children: status });
|
|
5748
|
+
}
|
|
5749
|
+
function TestTab({ testData }) {
|
|
5750
|
+
return /* @__PURE__ */ u3("div", { children: /* @__PURE__ */ u3("table", { class: "profiler-detail-table", children: /* @__PURE__ */ u3("tbody", { children: [
|
|
5751
|
+
/* @__PURE__ */ u3("tr", { children: [
|
|
5752
|
+
/* @__PURE__ */ u3("th", { children: "Test Name" }),
|
|
5753
|
+
/* @__PURE__ */ u3("td", { style: "word-break: break-word", children: testData.test_name })
|
|
5754
|
+
] }),
|
|
5755
|
+
/* @__PURE__ */ u3("tr", { children: [
|
|
5756
|
+
/* @__PURE__ */ u3("th", { children: "Status" }),
|
|
5757
|
+
/* @__PURE__ */ u3("td", { children: statusBadge2(testData.status) })
|
|
5758
|
+
] }),
|
|
5759
|
+
/* @__PURE__ */ u3("tr", { children: [
|
|
5760
|
+
/* @__PURE__ */ u3("th", { children: "File" }),
|
|
5761
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: [
|
|
5762
|
+
testData.test_file,
|
|
5763
|
+
":",
|
|
5764
|
+
testData.test_line
|
|
5765
|
+
] })
|
|
5766
|
+
] }),
|
|
5767
|
+
/* @__PURE__ */ u3("tr", { children: [
|
|
5768
|
+
/* @__PURE__ */ u3("th", { children: "Framework" }),
|
|
5769
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: testData.framework })
|
|
5770
|
+
] }),
|
|
5771
|
+
testData.assertions != null && /* @__PURE__ */ u3("tr", { children: [
|
|
5772
|
+
/* @__PURE__ */ u3("th", { children: "Assertions" }),
|
|
5773
|
+
/* @__PURE__ */ u3("td", { children: testData.assertions })
|
|
5774
|
+
] }),
|
|
5775
|
+
testData.skip_reason && /* @__PURE__ */ u3("tr", { children: [
|
|
5776
|
+
/* @__PURE__ */ u3("th", { children: "Skip reason" }),
|
|
5777
|
+
/* @__PURE__ */ u3("td", { class: "profiler-text--xs profiler-text--muted", children: testData.skip_reason })
|
|
5778
|
+
] }),
|
|
5779
|
+
testData.exception_message && /* @__PURE__ */ u3("tr", { children: [
|
|
5780
|
+
/* @__PURE__ */ u3("th", { children: "Exception" }),
|
|
5781
|
+
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("pre", { class: "profiler-text--xs", style: "white-space: pre-wrap; color: var(--profiler-error, #ef4444)", children: testData.exception_message }) })
|
|
5782
|
+
] })
|
|
5783
|
+
] }) }) });
|
|
5784
|
+
}
|
|
5785
|
+
|
|
5786
|
+
// app/assets/typescript/profiler/components/dashboard/TestProfileDashboard.tsx
|
|
5787
|
+
function TestProfileDashboard({ profile, initialTab, embedded }) {
|
|
5788
|
+
const cd = profile.collectors_data || {};
|
|
5789
|
+
const hasDumps = (cd["dump"]?.count ?? 0) > 0;
|
|
5790
|
+
const hasLogs = (cd["logs"]?.total ?? 0) > 0;
|
|
5791
|
+
const hasException = !!cd["exception"]?.exception_class;
|
|
5792
|
+
const testData = cd["test"];
|
|
5793
|
+
const validTabs = ["test", "database", "cache", "dump", "logs", "exception", "env", "timeline"];
|
|
5794
|
+
const defaultTab = validTabs.includes(initialTab) ? initialTab : "test";
|
|
5795
|
+
const [activeTab, setActiveTab] = d2(hasException ? "exception" : defaultTab);
|
|
5796
|
+
const isFailed = profile.status === 500;
|
|
5797
|
+
const testStatus = testData?.status || (isFailed ? "failed" : "passed");
|
|
5798
|
+
const handleTabClick = (tab) => (e3) => {
|
|
5799
|
+
e3.preventDefault();
|
|
5800
|
+
setActiveTab(tab);
|
|
5801
|
+
const url = new URL(window.location.href);
|
|
5802
|
+
url.searchParams.set("tab", tab);
|
|
5803
|
+
history.pushState(null, "", url.toString());
|
|
5804
|
+
};
|
|
5805
|
+
const tabClass = (key) => `tab${activeTab === key ? " active" : ""}`;
|
|
5806
|
+
return /* @__PURE__ */ u3("div", { class: "container", children: [
|
|
5807
|
+
/* @__PURE__ */ u3("div", { class: "header", children: [
|
|
5808
|
+
/* @__PURE__ */ u3("h1", { children: /* @__PURE__ */ u3("a", { href: "/_profiler?section=tests", children: [
|
|
5809
|
+
/* @__PURE__ */ u3("span", { class: "h1-emoji", children: "\u{1F9EA}" }),
|
|
5810
|
+
" Test Profile"
|
|
5811
|
+
] }) }),
|
|
5812
|
+
/* @__PURE__ */ u3("p", { style: "word-break: break-word", children: testData?.test_name || profile.path }),
|
|
5813
|
+
/* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-4 profiler-mt-2", children: [
|
|
5814
|
+
/* @__PURE__ */ u3("span", { children: [
|
|
5815
|
+
"Duration: ",
|
|
5816
|
+
/* @__PURE__ */ u3("strong", { children: [
|
|
5817
|
+
profile.duration.toFixed(2),
|
|
5818
|
+
" ms"
|
|
5819
|
+
] })
|
|
5820
|
+
] }),
|
|
5821
|
+
/* @__PURE__ */ u3("span", { children: [
|
|
5822
|
+
"Status: ",
|
|
5823
|
+
/* @__PURE__ */ u3("strong", { children: /* @__PURE__ */ u3("span", { class: `badge-${isFailed ? "error" : testStatus === "pending" ? "warning" : "success"}`, children: testStatus === "failed" ? "\u2717 Failed" : testStatus === "pending" ? "\u23F8 Pending" : "\u2713 Passed" }) })
|
|
5824
|
+
] }),
|
|
5825
|
+
profile.memory != null && /* @__PURE__ */ u3("span", { children: [
|
|
5826
|
+
"Memory: ",
|
|
5827
|
+
/* @__PURE__ */ u3("strong", { children: [
|
|
5828
|
+
(profile.memory / 1024 / 1024).toFixed(2),
|
|
5829
|
+
" MB"
|
|
5830
|
+
] })
|
|
5831
|
+
] })
|
|
5832
|
+
] }),
|
|
5833
|
+
testData?.test_file && /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted profiler-mt-2", children: [
|
|
5834
|
+
/* @__PURE__ */ u3("span", { class: "profiler-text--mono", children: [
|
|
5835
|
+
testData.test_file,
|
|
5836
|
+
":",
|
|
5837
|
+
testData.test_line
|
|
5838
|
+
] }),
|
|
5839
|
+
/* @__PURE__ */ u3("span", { style: "margin-left: 8px", children: [
|
|
5840
|
+
"\xB7 ",
|
|
5841
|
+
testData.framework
|
|
5842
|
+
] })
|
|
5843
|
+
] })
|
|
5844
|
+
] }),
|
|
5845
|
+
/* @__PURE__ */ u3("div", { class: "profiler-panel profiler-mb-6", children: [
|
|
5846
|
+
/* @__PURE__ */ u3("div", { class: "tabs", children: [
|
|
5847
|
+
hasException && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("exception"), onClick: handleTabClick("exception"), style: "color:var(--profiler-error,#ef4444);", children: "\u{1F4A5} Exception" }),
|
|
5848
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("test"), onClick: handleTabClick("test"), children: "Test" }),
|
|
5849
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("database"), onClick: handleTabClick("database"), children: "Database" }),
|
|
5850
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("cache"), onClick: handleTabClick("cache"), children: "Cache" }),
|
|
5851
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("timeline"), onClick: handleTabClick("timeline"), children: "Timeline" }),
|
|
5852
|
+
hasDumps && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("dump"), onClick: handleTabClick("dump"), children: [
|
|
5853
|
+
"Dumps (",
|
|
5854
|
+
cd["dump"].count,
|
|
5855
|
+
")"
|
|
5856
|
+
] }),
|
|
5857
|
+
hasLogs && /* @__PURE__ */ u3("a", { href: "#", class: tabClass("logs"), onClick: handleTabClick("logs"), children: "Logs" }),
|
|
5858
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("env"), onClick: handleTabClick("env"), children: "Env" })
|
|
5859
|
+
] }),
|
|
5860
|
+
/* @__PURE__ */ u3("div", { class: "profiler-p-4 tab-content active", children: [
|
|
5861
|
+
activeTab === "test" && testData && /* @__PURE__ */ u3(TestTab, { testData }),
|
|
5862
|
+
activeTab === "database" && /* @__PURE__ */ u3(DatabaseTab, { dbData: cd["database"], token: profile.token }),
|
|
5863
|
+
activeTab === "cache" && /* @__PURE__ */ u3(CacheTab, { data: cd["cache"] }),
|
|
5864
|
+
activeTab === "timeline" && /* @__PURE__ */ u3(FlameGraphTab, { data: cd["flamegraph"] }),
|
|
5865
|
+
activeTab === "dump" && hasDumps && /* @__PURE__ */ u3(DumpsTab, { data: cd["dump"] }),
|
|
5866
|
+
activeTab === "logs" && hasLogs && /* @__PURE__ */ u3(LogsTab, { data: cd["logs"] }),
|
|
5867
|
+
activeTab === "exception" && hasException && /* @__PURE__ */ u3(ExceptionTab, { data: cd["exception"] }),
|
|
5868
|
+
activeTab === "env" && /* @__PURE__ */ u3(EnvTab, { envData: cd["env"] })
|
|
5869
|
+
] })
|
|
5870
|
+
] })
|
|
5871
|
+
] });
|
|
5872
|
+
}
|
|
5873
|
+
|
|
5874
|
+
// app/assets/typescript/profiler/components/test-runner/TestRunnerPage.tsx
|
|
5875
|
+
var BASE3 = "/_profiler";
|
|
5876
|
+
function TestRunnerPage() {
|
|
5877
|
+
return /* @__PURE__ */ u3("div", { class: "container", children: [
|
|
5878
|
+
/* @__PURE__ */ u3("div", { class: "header", children: [
|
|
5879
|
+
/* @__PURE__ */ u3("h1", { children: [
|
|
5880
|
+
/* @__PURE__ */ u3("a", { href: BASE3, children: /* @__PURE__ */ u3("span", { class: "h1-emoji", children: "\u{1F50D}" }) }),
|
|
5881
|
+
" ",
|
|
5882
|
+
/* @__PURE__ */ u3("span", { class: "h1-emoji", children: "\u{1F9EA}" }),
|
|
5883
|
+
" Test Runner"
|
|
5884
|
+
] }),
|
|
5885
|
+
/* @__PURE__ */ u3("p", { children: "Run tests from the profiler and capture a performance profile for each test." })
|
|
5886
|
+
] }),
|
|
5887
|
+
/* @__PURE__ */ u3("div", { class: "profiler-panel profiler-mb-6", children: /* @__PURE__ */ u3("div", { class: "profiler-p-4", children: /* @__PURE__ */ u3(TestRunnerContent, {}) }) })
|
|
5888
|
+
] });
|
|
5889
|
+
}
|
|
5890
|
+
|
|
4931
5891
|
// app/assets/typescript/profiler/timeline.ts
|
|
4932
5892
|
function initTimeline(container) {
|
|
4933
5893
|
console.log("Initializing profiler timeline");
|
|
@@ -5189,12 +6149,20 @@ Duration: ${event.duration.toFixed(2)}ms`;
|
|
|
5189
6149
|
const embedded = showEl.dataset.embedded === "true";
|
|
5190
6150
|
if (profile.profile_type === "job") {
|
|
5191
6151
|
J(/* @__PURE__ */ u3(JobProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
6152
|
+
} else if (profile.profile_type === "console") {
|
|
6153
|
+
J(/* @__PURE__ */ u3(ConsoleProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
6154
|
+
} else if (profile.profile_type === "test") {
|
|
6155
|
+
J(/* @__PURE__ */ u3(TestProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
5192
6156
|
} else {
|
|
5193
6157
|
J(/* @__PURE__ */ u3(ProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
5194
6158
|
}
|
|
5195
6159
|
}
|
|
5196
6160
|
}
|
|
5197
|
-
|
|
6161
|
+
const testRunnerEl = document.getElementById("profiler-test-runner");
|
|
6162
|
+
if (testRunnerEl) {
|
|
6163
|
+
J(/* @__PURE__ */ u3(TestRunnerPage, {}), testRunnerEl);
|
|
6164
|
+
}
|
|
6165
|
+
if (!indexEl && !showEl && !testRunnerEl) {
|
|
5198
6166
|
const header = document.querySelector(".header, .profiler-detail");
|
|
5199
6167
|
if (header) {
|
|
5200
6168
|
const toggle = createThemeToggle();
|