rails-profiler 0.25.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 +739 -31
- 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 +10 -0
- data/lib/profiler/collectors/database_collector.rb +1 -1
- data/lib/profiler/collectors/test_collector.rb +75 -0
- data/lib/profiler/configuration.rb +12 -1
- 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 +13 -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 +19 -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 === "console" || 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");
|
|
@@ -1667,6 +2027,13 @@
|
|
|
1667
2027
|
const [consoleOffset, setConsoleOffset] = d2(0);
|
|
1668
2028
|
const [consoleHasMore, setConsoleHasMore] = d2(false);
|
|
1669
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);
|
|
1670
2037
|
const [outboundRequests, setOutboundRequests] = d2([]);
|
|
1671
2038
|
const [loadingHttp, setLoadingHttp] = d2(initialSection() === "http");
|
|
1672
2039
|
const [loadingJobs, setLoadingJobs] = d2(initialSection() === "jobs");
|
|
@@ -1696,6 +2063,9 @@
|
|
|
1696
2063
|
const [jobDuration, setJobDuration] = d2("");
|
|
1697
2064
|
const [consoleSearch, setConsoleSearch] = d2("");
|
|
1698
2065
|
const [consoleStatus, setConsoleStatus] = d2("");
|
|
2066
|
+
const [testSearch, setTestSearch] = d2("");
|
|
2067
|
+
const [testStatus, setTestStatus] = d2("");
|
|
2068
|
+
const [testSort, setTestSort] = d2({ col: null, dir: "asc" });
|
|
1699
2069
|
const [outboundSearch, setOutboundSearch] = d2("");
|
|
1700
2070
|
const [outboundMethod, setOutboundMethod] = d2("");
|
|
1701
2071
|
const [outboundStatus, setOutboundStatus] = d2("");
|
|
@@ -1733,7 +2103,7 @@
|
|
|
1733
2103
|
};
|
|
1734
2104
|
const loadMoreHttp = () => {
|
|
1735
2105
|
setHttpLoadingMore(true);
|
|
1736
|
-
fetch(`${
|
|
2106
|
+
fetch(`${BASE2}/api/profiles?limit=50&offset=${httpOffset}`).then((res) => res.json()).then((data) => {
|
|
1737
2107
|
setProfiles((prev) => [...prev, ...data.profiles]);
|
|
1738
2108
|
setHttpOffset((prev) => prev + data.profiles.length);
|
|
1739
2109
|
setHttpHasMore(data.has_more);
|
|
@@ -1742,7 +2112,7 @@
|
|
|
1742
2112
|
};
|
|
1743
2113
|
const loadMoreJobs = () => {
|
|
1744
2114
|
setJobLoadingMore(true);
|
|
1745
|
-
fetch(`${
|
|
2115
|
+
fetch(`${BASE2}/api/jobs?limit=50&offset=${jobOffset}`).then((res) => res.json()).then((data) => {
|
|
1746
2116
|
setJobs((prev) => [...prev, ...data.profiles]);
|
|
1747
2117
|
setJobOffset((prev) => prev + data.profiles.length);
|
|
1748
2118
|
setJobHasMore(data.has_more);
|
|
@@ -1751,13 +2121,37 @@
|
|
|
1751
2121
|
};
|
|
1752
2122
|
const loadMoreConsole = () => {
|
|
1753
2123
|
setConsoleLoadingMore(true);
|
|
1754
|
-
fetch(`${
|
|
2124
|
+
fetch(`${BASE2}/api/console?limit=50&offset=${consoleOffset}`).then((res) => res.json()).then((data) => {
|
|
1755
2125
|
setConsoles((prev) => [...prev, ...data.profiles]);
|
|
1756
2126
|
setConsoleOffset((prev) => prev + data.profiles.length);
|
|
1757
2127
|
setConsoleHasMore(data.has_more);
|
|
1758
2128
|
setConsoleLoadingMore(false);
|
|
1759
2129
|
}).catch(() => setConsoleLoadingMore(false));
|
|
1760
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
|
+
};
|
|
1761
2155
|
const handleSectionChange = (s3) => {
|
|
1762
2156
|
if (s3 === section) {
|
|
1763
2157
|
refreshSection(s3);
|
|
@@ -1767,7 +2161,11 @@
|
|
|
1767
2161
|
const url = new URL(window.location.href);
|
|
1768
2162
|
url.searchParams.set("section", s3);
|
|
1769
2163
|
history.pushState(null, "", url.toString());
|
|
1770
|
-
|
|
2164
|
+
if (s3 === "tests") {
|
|
2165
|
+
loadTests();
|
|
2166
|
+
} else {
|
|
2167
|
+
refreshSection(s3);
|
|
2168
|
+
}
|
|
1771
2169
|
setHttpSearch("");
|
|
1772
2170
|
setHttpMethod("");
|
|
1773
2171
|
setHttpStatus("");
|
|
@@ -1781,6 +2179,9 @@
|
|
|
1781
2179
|
setConsoleSearch("");
|
|
1782
2180
|
setConsoleStatus("");
|
|
1783
2181
|
setConsoleSort({ col: null, dir: "asc" });
|
|
2182
|
+
setTestSearch("");
|
|
2183
|
+
setTestStatus("");
|
|
2184
|
+
setTestSort({ col: null, dir: "asc" });
|
|
1784
2185
|
setOutboundSearch("");
|
|
1785
2186
|
setOutboundMethod("");
|
|
1786
2187
|
setOutboundStatus("");
|
|
@@ -1792,44 +2193,55 @@
|
|
|
1792
2193
|
});
|
|
1793
2194
|
};
|
|
1794
2195
|
const deleteProfile = (token) => {
|
|
1795
|
-
fetch(`${
|
|
2196
|
+
fetch(`${BASE2}/api/profiles/${token}`, { method: "DELETE" }).then(() => {
|
|
1796
2197
|
setProfiles((prev) => prev.filter((p3) => p3.token !== token));
|
|
1797
2198
|
});
|
|
1798
2199
|
};
|
|
1799
2200
|
const deleteJob = (token) => {
|
|
1800
|
-
fetch(`${
|
|
2201
|
+
fetch(`${BASE2}/api/jobs/${token}`, { method: "DELETE" }).then(() => {
|
|
1801
2202
|
setJobs((prev) => prev.filter((p3) => p3.token !== token));
|
|
1802
2203
|
});
|
|
1803
2204
|
};
|
|
1804
2205
|
const deleteConsole = (token) => {
|
|
1805
|
-
fetch(`${
|
|
2206
|
+
fetch(`${BASE2}/api/console/${token}`, { method: "DELETE" }).then(() => {
|
|
1806
2207
|
setConsoles((prev) => prev.filter((p3) => p3.token !== token));
|
|
1807
2208
|
});
|
|
1808
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
|
+
};
|
|
1809
2215
|
const clearProfiles = () => {
|
|
1810
2216
|
if (!window.confirm("Delete all HTTP profiles?")) return;
|
|
1811
|
-
fetch(`${
|
|
2217
|
+
fetch(`${BASE2}/api/profiles/clear`, { method: "DELETE" }).then(() => {
|
|
1812
2218
|
setProfiles([]);
|
|
1813
2219
|
});
|
|
1814
2220
|
};
|
|
1815
2221
|
const clearJobs = () => {
|
|
1816
2222
|
if (!window.confirm("Delete all job profiles?")) return;
|
|
1817
|
-
fetch(`${
|
|
2223
|
+
fetch(`${BASE2}/api/jobs/clear`, { method: "DELETE" }).then(() => {
|
|
1818
2224
|
setJobs([]);
|
|
1819
2225
|
});
|
|
1820
2226
|
};
|
|
1821
2227
|
const clearConsole = () => {
|
|
1822
2228
|
if (!window.confirm("Delete all console profiles?")) return;
|
|
1823
|
-
fetch(`${
|
|
2229
|
+
fetch(`${BASE2}/api/console/clear`, { method: "DELETE" }).then(() => {
|
|
1824
2230
|
setConsoles([]);
|
|
1825
2231
|
});
|
|
1826
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
|
+
};
|
|
1827
2239
|
const clearAll = () => {
|
|
1828
2240
|
if (!window.confirm("Delete all HTTP, job and console profiles?")) return;
|
|
1829
2241
|
Promise.all([
|
|
1830
|
-
fetch(`${
|
|
1831
|
-
fetch(`${
|
|
1832
|
-
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" })
|
|
1833
2245
|
]).then(() => {
|
|
1834
2246
|
setProfiles([]);
|
|
1835
2247
|
setJobs([]);
|
|
@@ -1839,7 +2251,7 @@
|
|
|
1839
2251
|
const refreshSection = (s3) => {
|
|
1840
2252
|
if (s3 === "http") {
|
|
1841
2253
|
setLoadingHttp(true);
|
|
1842
|
-
fetch(`${
|
|
2254
|
+
fetch(`${BASE2}/api/profiles?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
1843
2255
|
setProfiles(data.profiles);
|
|
1844
2256
|
setHttpOffset(data.profiles.length);
|
|
1845
2257
|
setHttpHasMore(data.has_more);
|
|
@@ -1850,7 +2262,7 @@
|
|
|
1850
2262
|
});
|
|
1851
2263
|
} else if (s3 === "jobs") {
|
|
1852
2264
|
setLoadingJobs(true);
|
|
1853
|
-
fetch(`${
|
|
2265
|
+
fetch(`${BASE2}/api/jobs?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
1854
2266
|
setJobs(data.profiles);
|
|
1855
2267
|
setJobOffset(data.profiles.length);
|
|
1856
2268
|
setJobHasMore(data.has_more);
|
|
@@ -1861,7 +2273,7 @@
|
|
|
1861
2273
|
});
|
|
1862
2274
|
} else if (s3 === "console") {
|
|
1863
2275
|
setLoadingConsole(true);
|
|
1864
|
-
fetch(`${
|
|
2276
|
+
fetch(`${BASE2}/api/console?limit=50&offset=0`).then((res) => res.json()).then((data) => {
|
|
1865
2277
|
setConsoles(data.profiles);
|
|
1866
2278
|
setConsoleOffset(data.profiles.length);
|
|
1867
2279
|
setConsoleHasMore(data.has_more);
|
|
@@ -1870,18 +2282,32 @@
|
|
|
1870
2282
|
setConsoleError("Failed to load console profiles");
|
|
1871
2283
|
setLoadingConsole(false);
|
|
1872
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
|
+
});
|
|
1873
2299
|
} else if (s3 === "outbound") {
|
|
1874
2300
|
setLoadingOutbound(true);
|
|
1875
|
-
fetch(`${
|
|
2301
|
+
fetch(`${BASE2}/api/outbound_http`).then((res) => res.json()).then((data) => {
|
|
1876
2302
|
setOutboundRequests(data);
|
|
1877
2303
|
setLoadingOutbound(false);
|
|
1878
2304
|
}).catch(() => {
|
|
1879
2305
|
setOutboundError("Failed to load outbound HTTP requests");
|
|
1880
2306
|
setLoadingOutbound(false);
|
|
1881
2307
|
});
|
|
1882
|
-
} else {
|
|
2308
|
+
} else if (s3 === "env") {
|
|
1883
2309
|
setLoadingEnv(true);
|
|
1884
|
-
fetch(`${
|
|
2310
|
+
fetch(`${BASE2}/api/env_vars`).then((res) => res.json()).then((data) => {
|
|
1885
2311
|
setEnvData(data);
|
|
1886
2312
|
setLoadingEnv(false);
|
|
1887
2313
|
}).catch(() => {
|
|
@@ -2009,9 +2435,44 @@
|
|
|
2009
2435
|
}
|
|
2010
2436
|
return consoleSort.dir === "asc" ? av - bv : bv - av;
|
|
2011
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;
|
|
2012
2472
|
const httpFiltersActive = !!(httpSearch || httpMethod || httpStatus || httpDuration || httpPreset);
|
|
2013
2473
|
const jobFiltersActive = !!(jobSearch || jobStatus || jobDuration);
|
|
2014
2474
|
const consoleFiltersActive = !!(consoleSearch || consoleStatus);
|
|
2475
|
+
const testFiltersActive = !!(testSearch || testStatus);
|
|
2015
2476
|
const outboundFiltersActive = !!(outboundSearch || outboundMethod || outboundStatus);
|
|
2016
2477
|
const sortIcon = (activeCol, dir, col) => {
|
|
2017
2478
|
if (activeCol !== col) return /* @__PURE__ */ u3("span", { class: "sort-icon sort-icon--idle", children: "\u21C5" });
|
|
@@ -2043,7 +2504,15 @@
|
|
|
2043
2504
|
e3.preventDefault();
|
|
2044
2505
|
handleSectionChange("console");
|
|
2045
2506
|
}, children: "Console" }),
|
|
2507
|
+
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("tests"), onClick: (e3) => {
|
|
2508
|
+
e3.preventDefault();
|
|
2509
|
+
handleSectionChange("tests");
|
|
2510
|
+
}, children: "Tests" }),
|
|
2046
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" }),
|
|
2047
2516
|
/* @__PURE__ */ u3("a", { href: "#", class: tabClass("outbound"), onClick: (e3) => {
|
|
2048
2517
|
e3.preventDefault();
|
|
2049
2518
|
handleSectionChange("outbound");
|
|
@@ -2143,7 +2612,7 @@
|
|
|
2143
2612
|
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2144
2613
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: methodClass(p3.method), children: p3.method }) }),
|
|
2145
2614
|
/* @__PURE__ */ u3("td", { children: [
|
|
2146
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2615
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, children: p3.path }),
|
|
2147
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" })
|
|
2148
2617
|
] }),
|
|
2149
2618
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: durationClass(p3.duration), children: [
|
|
@@ -2224,7 +2693,7 @@
|
|
|
2224
2693
|
return /* @__PURE__ */ u3("tr", { children: [
|
|
2225
2694
|
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2226
2695
|
/* @__PURE__ */ u3("td", { children: [
|
|
2227
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2696
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${p3.token}`, children: p3.path }),
|
|
2228
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" })
|
|
2229
2698
|
] }),
|
|
2230
2699
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--mono", children: jobData?.queue || "-" }) }),
|
|
@@ -2302,7 +2771,7 @@
|
|
|
2302
2771
|
return /* @__PURE__ */ u3("tr", { children: [
|
|
2303
2772
|
/* @__PURE__ */ u3("td", { children: formatTime(p3.started_at) }),
|
|
2304
2773
|
/* @__PURE__ */ u3("td", { children: [
|
|
2305
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
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 }),
|
|
2306
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" })
|
|
2307
2776
|
] }),
|
|
2308
2777
|
/* @__PURE__ */ u3("td", { children: /* @__PURE__ */ u3("span", { class: durationClass(p3.duration), children: [
|
|
@@ -2318,6 +2787,90 @@
|
|
|
2318
2787
|
] }),
|
|
2319
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" }) })
|
|
2320
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, {}),
|
|
2321
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: [
|
|
2322
2875
|
/* @__PURE__ */ u3("div", { class: "profiler-empty__title", children: "No outbound HTTP requests found" }),
|
|
2323
2876
|
/* @__PURE__ */ u3("p", { class: "profiler-empty__description", children: "Make requests to external services to see outbound HTTP data" })
|
|
@@ -2370,7 +2923,7 @@
|
|
|
2370
2923
|
/* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:2px", children: [
|
|
2371
2924
|
formatTime(req.profile_started_at),
|
|
2372
2925
|
" \xB7 Profile: ",
|
|
2373
|
-
/* @__PURE__ */ u3("a", { href: `${
|
|
2926
|
+
/* @__PURE__ */ u3("a", { href: `${BASE2}/profiles/${req.profile_token}`, children: [
|
|
2374
2927
|
req.profile_token.substring(0, 8),
|
|
2375
2928
|
"\u2026"
|
|
2376
2929
|
] })
|
|
@@ -4386,8 +4939,8 @@
|
|
|
4386
4939
|
const verbs = ["ALL", ...Array.from(new Set(routes.map((r3) => r3.verb))).sort()];
|
|
4387
4940
|
const filtered = routes.filter((route) => {
|
|
4388
4941
|
const matchesVerb = verbFilter === "ALL" || route.verb === verbFilter;
|
|
4389
|
-
const
|
|
4390
|
-
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);
|
|
4391
4944
|
return matchesVerb && matchesText;
|
|
4392
4945
|
});
|
|
4393
4946
|
return /* @__PURE__ */ u3(k, { children: [
|
|
@@ -5186,6 +5739,155 @@
|
|
|
5186
5739
|
] });
|
|
5187
5740
|
}
|
|
5188
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
|
+
|
|
5189
5891
|
// app/assets/typescript/profiler/timeline.ts
|
|
5190
5892
|
function initTimeline(container) {
|
|
5191
5893
|
console.log("Initializing profiler timeline");
|
|
@@ -5449,12 +6151,18 @@ Duration: ${event.duration.toFixed(2)}ms`;
|
|
|
5449
6151
|
J(/* @__PURE__ */ u3(JobProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
5450
6152
|
} else if (profile.profile_type === "console") {
|
|
5451
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);
|
|
5452
6156
|
} else {
|
|
5453
6157
|
J(/* @__PURE__ */ u3(ProfileDashboard, { profile, initialTab: tab, embedded }), showEl);
|
|
5454
6158
|
}
|
|
5455
6159
|
}
|
|
5456
6160
|
}
|
|
5457
|
-
|
|
6161
|
+
const testRunnerEl = document.getElementById("profiler-test-runner");
|
|
6162
|
+
if (testRunnerEl) {
|
|
6163
|
+
J(/* @__PURE__ */ u3(TestRunnerPage, {}), testRunnerEl);
|
|
6164
|
+
}
|
|
6165
|
+
if (!indexEl && !showEl && !testRunnerEl) {
|
|
5458
6166
|
const header = document.querySelector(".header, .profiler-detail");
|
|
5459
6167
|
if (header) {
|
|
5460
6168
|
const toggle = createThemeToggle();
|