Skip to content

Commit 7ba8831

Browse files
committed
Restore sidebar share and embed snippets.
Bring back the old "share this view" and iframe embed snippets in the refactored Svelte sidebar by generating share URLs from current project, metric filter, selected runs, and header visibility. Made-with: Cursor
1 parent 65a6897 commit 7ba8831

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

trackio/frontend/src/App.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@
355355
{metricColumns}
356356
{availableSystemDevices}
357357
bind:selectedSystemDevices
358+
{spaceId}
358359
{logoUrls}
359360
{darkMode}
360361
/>

trackio/frontend/src/components/Sidebar.svelte

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
mutationAuth = "local",
3333
readOnlySource = null,
3434
projectLocked = false,
35+
spaceId = null,
3536
logoUrls = { light: "/static/trackio/trackio_logo_type_light_transparent.png", dark: "/static/trackio/trackio_logo_type_dark_transparent.png" },
3637
darkMode = false,
3738
} = $props();
@@ -80,6 +81,7 @@
8081
let filteredRunIds = $derived(filteredRuns.map((r) => r.id ?? r.name));
8182
8283
let latestOnly = $state(false);
84+
let shareTab = $state("share");
8385
8486
function toggleLatestOnly() {
8587
latestOnly = !latestOnly;
@@ -108,6 +110,60 @@
108110
selectedSystemDevices = [...selectedSystemDevices, device];
109111
}
110112
}
113+
114+
function buildSpaceHost(spaceIdValue) {
115+
if (!spaceIdValue || !spaceIdValue.includes("/")) return "";
116+
const [namespace, name] = spaceIdValue.split("/", 2);
117+
if (!namespace || !name) return "";
118+
return `${namespace}-${name}.hf.space`;
119+
}
120+
121+
function selectedRunNamesFromIds(selectedIds, allRuns) {
122+
const byId = new Map(allRuns.map((run) => [run.id ?? run.name, run.name]));
123+
return selectedIds.map((id) => byId.get(id)).filter(Boolean);
124+
}
125+
126+
let shareUrl = $derived.by(() => {
127+
const host = buildSpaceHost(spaceId);
128+
if (!host || !selectedProject) return "";
129+
const params = new URLSearchParams();
130+
params.set("project", selectedProject);
131+
if (metricFilter?.trim()) {
132+
params.set("metrics", metricFilter.trim());
133+
}
134+
const runNames = selectedRunNamesFromIds(selectedRuns, runs);
135+
if (runNames.length) {
136+
params.set("runs", runNames.join(","));
137+
}
138+
if (!showHeaders) {
139+
params.set("accordion", "hidden");
140+
}
141+
params.set("sidebar", "hidden");
142+
params.set("navbar", "hidden");
143+
return `https://${host}?${params.toString()}`;
144+
});
145+
146+
let embedCode = $derived.by(() => {
147+
if (!shareUrl) return "";
148+
return `<iframe src="${shareUrl}" style="width:1600px; height:500px; border:0;"></iframe>`;
149+
});
150+
151+
async function copyText(value) {
152+
if (!value) return;
153+
try {
154+
await navigator.clipboard.writeText(value);
155+
} catch {
156+
const textarea = document.createElement("textarea");
157+
textarea.value = value;
158+
textarea.style.position = "fixed";
159+
textarea.style.opacity = "0";
160+
document.body.appendChild(textarea);
161+
textarea.focus();
162+
textarea.select();
163+
document.execCommand("copy");
164+
document.body.removeChild(textarea);
165+
}
166+
}
111167
</script>
112168
113169
<div class="sidebar" class:collapsed={!open}>
@@ -149,6 +205,48 @@
149205
</div>
150206
151207
{#if variant === "full"}
208+
{#if spaceId}
209+
<div class="section">
210+
<div class="share-tabs">
211+
<button
212+
class="share-tab-btn"
213+
class:active={shareTab === "share"}
214+
onclick={() => { shareTab = "share"; }}
215+
>
216+
Share
217+
</button>
218+
<button
219+
class="share-tab-btn"
220+
class:active={shareTab === "embed"}
221+
onclick={() => { shareTab = "embed"; }}
222+
>
223+
Embed
224+
</button>
225+
</div>
226+
{#if shareTab === "share"}
227+
<div class="share-field">
228+
<span class="section-label">Share this view</span>
229+
<div class="share-input-row">
230+
<input type="text" value={shareUrl} readonly />
231+
<button class="copy-btn" onclick={() => copyText(shareUrl)}>
232+
Copy
233+
</button>
234+
</div>
235+
</div>
236+
{:else}
237+
<div class="share-field">
238+
<span class="section-label">Embed this view</span>
239+
<div class="share-input-row">
240+
<textarea readonly rows="2" value={embedCode}></textarea>
241+
<button class="copy-btn" onclick={() => copyText(embedCode)}>
242+
Copy
243+
</button>
244+
</div>
245+
</div>
246+
{/if}
247+
</div>
248+
{/if}
249+
152250
<div class="section">
153251
<div class="runs-header">
154252
<label class="select-all-label">
@@ -467,6 +565,57 @@
467565
margin-top: 2px;
468566
margin-bottom: 18px;
469567
}
568+
.share-tabs {
569+
display: flex;
570+
gap: 6px;
571+
margin-bottom: 8px;
572+
}
573+
.share-tab-btn {
574+
border: 1px solid var(--border-color-primary, #e5e7eb);
575+
border-radius: var(--radius-md, 6px);
576+
padding: 4px 8px;
577+
font-size: 12px;
578+
color: var(--body-text-color-subdued, #6b7280);
579+
background: var(--background-fill-primary, white);
580+
cursor: pointer;
581+
}
582+
.share-tab-btn.active {
583+
color: var(--body-text-color, #1f2937);
584+
background: var(--background-fill-secondary, #f9fafb);
585+
}
586+
.share-field {
587+
display: flex;
588+
flex-direction: column;
589+
gap: 6px;
590+
}
591+
.share-input-row {
592+
display: flex;
593+
gap: 6px;
594+
align-items: stretch;
595+
}
596+
.share-input-row input,
597+
.share-input-row textarea {
598+
width: 100%;
599+
min-width: 0;
600+
border: 1px solid var(--border-color-primary, #e5e7eb);
601+
border-radius: var(--radius-md, 6px);
602+
padding: 6px 8px;
603+
font-size: 12px;
604+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
605+
color: var(--body-text-color, #1f2937);
606+
background: var(--background-fill-secondary, #f9fafb);
607+
resize: vertical;
608+
}
609+
.copy-btn {
610+
border: 1px solid var(--border-color-primary, #e5e7eb);
611+
border-radius: var(--radius-md, 6px);
612+
padding: 6px 10px;
613+
font-size: 12px;
614+
color: var(--body-text-color, #1f2937);
615+
background: var(--background-fill-primary, white);
616+
cursor: pointer;
617+
flex-shrink: 0;
618+
}
470619
.section-label {
471620
font-size: 13px;
472621
font-weight: 500;

0 commit comments

Comments
 (0)