Skip to content

Commit 1fa956f

Browse files
committed
Merge remote-tracking branch 'origin/main' into trace-proposal
# Conflicts: # trackio/frontend/src/App.svelte
2 parents 7e58229 + 32c05c5 commit 1fa956f

4 files changed

Lines changed: 421 additions & 13 deletions

File tree

.changeset/strong-taxis-fail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trackio": patch
3+
---
4+
5+
feat:Restore sidebar share and embed snippets, and fix query parameter regression
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from urllib.parse import urlencode, urlparse, urlunparse
2+
3+
from playwright.sync_api import expect, sync_playwright
4+
5+
import trackio
6+
7+
8+
def _url_with_query(base_url: str, params: dict[str, str]) -> str:
9+
parsed = urlparse(base_url)
10+
path = parsed.path if parsed.path else "/"
11+
query = urlencode(params)
12+
return urlunparse((parsed.scheme, parsed.netloc, path, "", query, ""))
13+
14+
15+
def test_share_view_query_params_apply(temp_dir):
16+
project = "test_share_qp"
17+
run_ids_by_name: dict[str, list[str]] = {}
18+
for name in ("run-alpha", "run-beta", "run-alpha"):
19+
run = trackio.init(project=project, name=name)
20+
run_ids_by_name.setdefault(name, []).append(run.id)
21+
for _ in range(3):
22+
trackio.log(metrics={"loss": 0.1, "accuracy": 0.9})
23+
trackio.finish()
24+
25+
alpha_ids = run_ids_by_name["run-alpha"]
26+
assert len(alpha_ids) == 2
27+
28+
app, _, _, full_url = trackio.show(
29+
project=project, block_thread=False, open_browser=False
30+
)
31+
32+
try:
33+
with sync_playwright() as p:
34+
browser = p.chromium.launch()
35+
page = browser.new_page()
36+
page.set_default_timeout(15000)
37+
38+
primary = _url_with_query(
39+
full_url,
40+
{
41+
"project": project,
42+
"run_ids": alpha_ids[0],
43+
"metric_filter": "^loss$",
44+
"sidebar": "hidden",
45+
"navbar": "hidden",
46+
"accordion": "hidden",
47+
},
48+
)
49+
page.goto(primary)
50+
page.wait_for_load_state("networkidle")
51+
52+
expect(page.locator(".navbar")).to_have_count(0)
53+
expect(page.locator(".sidebar")).to_have_count(0)
54+
expect(page.locator(".accordion")).to_have_count(0)
55+
56+
expect(page.locator(".metrics-page")).to_be_visible()
57+
expect(page.locator(".vega-embed")).to_have_count(1)
58+
expect(page.locator(".metrics-page .legend-dot")).to_have_count(1)
59+
60+
duplicate = _url_with_query(
61+
full_url,
62+
{
63+
"project": project,
64+
"run_ids": ",".join(alpha_ids),
65+
"metric_filter": "^loss$",
66+
"sidebar": "hidden",
67+
"navbar": "hidden",
68+
"accordion": "hidden",
69+
},
70+
)
71+
page.goto(duplicate)
72+
page.wait_for_load_state("networkidle")
73+
74+
expect(page.locator(".metrics-page")).to_be_visible()
75+
expect(page.locator(".vega-embed")).to_have_count(1)
76+
expect(page.locator(".metrics-page .legend-dot")).to_have_count(2)
77+
78+
legacy = _url_with_query(
79+
full_url,
80+
{
81+
"project": project,
82+
"runs": "run-beta",
83+
"metrics": "loss",
84+
"sidebar": "hidden",
85+
"navbar": "hidden",
86+
"accordion": "hidden",
87+
},
88+
)
89+
page.goto(legacy)
90+
page.wait_for_load_state("networkidle")
91+
92+
expect(page.locator(".navbar")).to_have_count(0)
93+
expect(page.locator(".vega-embed")).to_have_count(1)
94+
expect(page.locator(".metrics-page .legend-dot")).to_have_count(1)
95+
96+
browser.close()
97+
finally:
98+
trackio.delete_project(project, force=True)
99+
app.close()

trackio/frontend/src/App.svelte

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@
3232
import Settings from "./pages/Settings.svelte";
3333
import { initTheme, isDark, onThemeChange } from "./lib/theme.js";
3434
35+
function metricFilterFromLegacyMetricsParam(metricsParam) {
36+
if (!metricsParam) return "";
37+
const trimmed = metricsParam.trim();
38+
const parts = trimmed.split(",").map((s) => s.trim()).filter(Boolean);
39+
if (parts.length === 0) return "";
40+
const isSimpleToken = (p) => /^[\w./-]+$/.test(p);
41+
if (parts.every(isSimpleToken)) {
42+
return parts
43+
.map((p) => {
44+
const esc = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45+
return `^${esc}$`;
46+
})
47+
.join("|");
48+
}
49+
return trimmed;
50+
}
51+
3552
initTheme();
3653
3754
let darkMode = $state(isDark());
@@ -53,6 +70,7 @@
5370
let metricColumns = $state([]);
5471
let sidebarOpen = $state(true);
5572
let sidebarHidden = $state(false);
73+
let navbarHidden = $state(false);
5674
let urlTick = $state(0);
5775
let alerts = $state([]);
5876
let pollTimer = $state(null);
@@ -212,6 +230,11 @@
212230
refreshRuns();
213231
});
214232
233+
$effect(() => {
234+
urlTick;
235+
navbarHidden = getQueryParam("navbar") === "hidden";
236+
});
237+
215238
onMount(() => {
216239
const sidebarParam = getQueryParam("sidebar");
217240
if (sidebarParam === "hidden") {
@@ -230,17 +253,12 @@
230253
if (!Number.isNaN(s)) smoothing = s;
231254
}
232255
233-
const metricsParam = getQueryParam("metrics");
234-
if (metricsParam) {
235-
const parts = metricsParam.split(",").map((s) => s.trim()).filter(Boolean);
236-
if (parts.length) {
237-
metricFilter = parts
238-
.map((p) => {
239-
const esc = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
240-
return `^${esc}$`;
241-
})
242-
.join("|");
243-
}
256+
const metricFilterParam = getQueryParam("metric_filter");
257+
const metricsLegacyParam = getQueryParam("metrics");
258+
if (metricFilterParam) {
259+
metricFilter = metricFilterParam;
260+
} else if (metricsLegacyParam) {
261+
metricFilter = metricFilterFromLegacyMetricsParam(metricsLegacyParam);
244262
}
245263
246264
if (getQueryParam("accordion") === "hidden") {
@@ -286,6 +304,7 @@
286304
}
287305
await refreshProjects();
288306
await refreshRuns();
307+
289308
await refreshAlerts();
290309
} catch (e) {
291310
console.error("Failed to load projects:", e);
@@ -317,6 +336,38 @@
317336
if (projectLocked) applyLockedProject();
318337
});
319338
339+
let urlRunsFromQueryApplied = $state(false);
340+
341+
$effect(() => {
342+
if (urlRunsFromQueryApplied) return;
343+
if (!appBootstrapReady) return;
344+
if (!selectedProject) return;
345+
const runIdsParam = getQueryParam("run_ids");
346+
const runsParam = getQueryParam("runs");
347+
if (!runIdsParam && !runsParam) {
348+
urlRunsFromQueryApplied = true;
349+
return;
350+
}
351+
if (!runs.length) {
352+
urlRunsFromQueryApplied = true;
353+
return;
354+
}
355+
let wanted;
356+
if (runIdsParam) {
357+
const ids = runIdsParam.split(",").map((s) => s.trim()).filter(Boolean);
358+
const validKeys = new Set(runs.map((r) => runKey(r)));
359+
wanted = ids.filter((id) => validKeys.has(id));
360+
} else {
361+
const names = runsParam.split(",").map((s) => s.trim()).filter(Boolean);
362+
const wantedNames = new Set(names);
363+
wanted = runs.filter((r) => wantedNames.has(r.name)).map((r) => runKey(r));
364+
}
365+
if (wanted.length) {
366+
selectedRuns = wanted;
367+
}
368+
urlRunsFromQueryApplied = true;
369+
});
370+
320371
let showSidebar = $derived(
321372
currentPage === "metrics" ||
322373
currentPage === "traces" ||
@@ -361,13 +412,16 @@
361412
bind:selectedSystemDevices
362413
bind:traceModel
363414
{traceModelChoices}
415+
{spaceId}
364416
{logoUrls}
365417
{darkMode}
366418
/>
367419
{/if}
368420
369421
<div class="main">
370-
<Navbar {currentPage} onNavigate={handleNavigate} />
422+
{#if !navbarHidden}
423+
<Navbar {currentPage} onNavigate={handleNavigate} />
424+
{/if}
371425
372426
<div class="page-content">
373427
{#if currentPage === "metrics"}

0 commit comments

Comments
 (0)