From 55c3678906fb662621aebfefdb73af3000f6830a Mon Sep 17 00:00:00 2001 From: Benson Wong Date: Sun, 28 Jun 2026 02:27:05 +0000 Subject: [PATCH] ui: extract shared ActivityTable and split ModelDetail into components - Add ActivityTable component consolidating column customization, table rendering, pagination, and capture dialog previously duplicated between Activity.svelte and ModelDetail.svelte - Split ModelDetail tabs into ModelActivityTab, ModelLogsTab, and ModelDetailsTab components under components/model/ - Reduce Activity.svelte and ModelDetail.svelte to thin shells - ModelDetail tabs now reuse ActivityTable instead of duplicating column management, formatting, and capture logic --- ui-svelte/src/components/ActivityTable.svelte | 461 ++++++++++++++++ .../components/model/ModelActivityTab.svelte | 24 + .../components/model/ModelDetailsTab.svelte | 44 ++ .../src/components/model/ModelLogsTab.svelte | 26 + ui-svelte/src/routes/Activity.svelte | 378 +------------ ui-svelte/src/routes/ModelDetail.svelte | 505 +----------------- 6 files changed, 582 insertions(+), 856 deletions(-) create mode 100644 ui-svelte/src/components/ActivityTable.svelte create mode 100644 ui-svelte/src/components/model/ModelActivityTab.svelte create mode 100644 ui-svelte/src/components/model/ModelDetailsTab.svelte create mode 100644 ui-svelte/src/components/model/ModelLogsTab.svelte diff --git a/ui-svelte/src/components/ActivityTable.svelte b/ui-svelte/src/components/ActivityTable.svelte new file mode 100644 index 00000000..8e98a2e7 --- /dev/null +++ b/ui-svelte/src/components/ActivityTable.svelte @@ -0,0 +1,461 @@ + + + + +
+ {#if title} + + {title} + ({metrics.length}) + + {/if} +
+
+ {#if showPagination} + Per page + pageSizeStore.set(Number(v))} + > + {$pageSizeStore} + + {#each [5, 10, 25, 50] as size (size)} + {size} + {/each} + + + {/if} +
+
+ + {#if columnsMenuOpen} +
+ + {#each orderedColumns as col (col.key)} + {@const key = col.key} +
handleDragOver(e, key)} + ondrop={(e) => handleDrop(e, key)} + > + handleDragStart(e, key)} + ondragend={handleDragEnd} + > + + + +
+ {/each} +
+ {/if} +
+
+
+
+ + + + + {#each activeVisibleColumns as key (key)} + + {/each} + + + + {#if displayMetrics.length === 0} + + + + {:else} + {#each displayMetrics as metric (metric.id)} + + {#each activeVisibleColumns as key (key)} + + {/each} + + {/each} + {/if} + +
+ {#if key === "cached"} + Cached + {:else if key === "prompt"} + Prompt + {:else if key === "drafted"} + Drafted + {:else} + {columnLabelMap[key] ?? key} + {/if} +
+ {emptyMessage} +
+ {#if key === "id"} + {metric.id + 1} + {:else if key === "time"} + {formatRelativeTime(metric.timestamp)} + {:else if key === "model"} + {metric.model} + {:else if key === "req_path"} + {metric.req_path || "-"} + {:else if key === "resp_status_code"} + {#if metric.error_msg} + + {metric.resp_status_code || "-"} + + {:else} + {metric.resp_status_code || "-"} + {/if} + {:else if key === "resp_content_type"} + {metric.resp_content_type || "-"} + {:else if key === "cached"} + {metric.tokens.cache_tokens > 0 ? metric.tokens.cache_tokens.toLocaleString() : "-"} + {:else if key === "prompt"} + {metric.tokens.input_tokens.toLocaleString()} + {:else if key === "generated"} + {metric.tokens.output_tokens.toLocaleString()} + {:else if key === "drafted"} + {formatDrafted(metric.tokens.draft_tokens, metric.tokens.draft_acc_tokens)} + {:else if key === "prompt_speed"} + {formatSpeed(metric.tokens.prompt_per_second)} + {:else if key === "gen_speed"} + {formatSpeed(metric.tokens.tokens_per_second)} + {:else if key === "duration"} + {formatDuration(metric.duration_ms)} + {:else if key === "capture"} + {#if metric.has_capture} + + {:else} + - + {/if} + {:else if key === "meta"} + {#if Object.keys(metric.metadata || {}).length > 0} + + ... + + {:else} + - + {/if} + {:else} + - + {/if} +
+ + {#if showPagination && metrics.length > 0} +
+ + Page {page + 1} of {totalPages} · {metrics.length} total + +
+ + + + +
+
+ {/if} +
+
+ + diff --git a/ui-svelte/src/components/model/ModelActivityTab.svelte b/ui-svelte/src/components/model/ModelActivityTab.svelte new file mode 100644 index 00000000..0f921f8e --- /dev/null +++ b/ui-svelte/src/components/model/ModelActivityTab.svelte @@ -0,0 +1,24 @@ + + + diff --git a/ui-svelte/src/components/model/ModelDetailsTab.svelte b/ui-svelte/src/components/model/ModelDetailsTab.svelte new file mode 100644 index 00000000..3c3c4064 --- /dev/null +++ b/ui-svelte/src/components/model/ModelDetailsTab.svelte @@ -0,0 +1,44 @@ + + + + + Capabilities + + + {#if capabilities.length === 0} + No capabilities reported. + {:else} +
+ {#each capabilities as [key] (key)} + + {capabilityLabels[key] ?? key} + + {/each} +
+ {/if} +
+
diff --git a/ui-svelte/src/components/model/ModelLogsTab.svelte b/ui-svelte/src/components/model/ModelLogsTab.svelte new file mode 100644 index 00000000..e231d849 --- /dev/null +++ b/ui-svelte/src/components/model/ModelLogsTab.svelte @@ -0,0 +1,26 @@ + + +
+ +
diff --git a/ui-svelte/src/routes/Activity.svelte b/ui-svelte/src/routes/Activity.svelte index 787ad249..b264cac1 100644 --- a/ui-svelte/src/routes/Activity.svelte +++ b/ui-svelte/src/routes/Activity.svelte @@ -1,220 +1,9 @@
@@ -222,160 +11,11 @@
- -
-
- - {#if columnsMenuOpen} -
- - {#each orderedColumns as col (col.key)} - {@const key = col.key} -
handleDragOver(e, key)} - ondrop={(e) => handleDrop(e, key)} - > - handleDragStart(e, key)} - ondragend={handleDragEnd} - > - - - -
- {/each} -
- {/if} -
-
- - - - - {#each activeVisibleColumns as key (key)} - - {/each} - - - - {#if sortedMetrics.length === 0} - - - - {:else} - {#each sortedMetrics as metric (metric.id)} - - {#each activeVisibleColumns as key (key)} - - {/each} - - {/each} - {/if} - -
- {#if key === "cached"} - Cached - {:else if key === "prompt"} - Prompt - {:else if key === "drafted"} - Drafted - {:else} - {columnLabelMap[key] ?? key} - {/if} -
- No activity recorded -
- {#if key === "id"} - {metric.id + 1} - {:else if key === "time"} - {formatRelativeTime(metric.timestamp)} - {:else if key === "model"} - {metric.model} - {:else if key === "req_path"} - {metric.req_path || "-"} - {:else if key === "resp_status_code"} - {#if metric.error_msg} - - {metric.resp_status_code || "-"} - - {:else} - {metric.resp_status_code || "-"} - {/if} - {:else if key === "resp_content_type"} - {metric.resp_content_type || "-"} - {:else if key === "cached"} - {metric.tokens.cache_tokens > 0 ? metric.tokens.cache_tokens.toLocaleString() : "-"} - {:else if key === "prompt"} - {metric.tokens.input_tokens.toLocaleString()} - {:else if key === "generated"} - {metric.tokens.output_tokens.toLocaleString()} - {:else if key === "drafted"} - {formatDrafted(metric.tokens.draft_tokens, metric.tokens.draft_acc_tokens)} - {:else if key === "prompt_speed"} - {formatSpeed(metric.tokens.prompt_per_second)} - {:else if key === "gen_speed"} - {formatSpeed(metric.tokens.tokens_per_second)} - {:else if key === "duration"} - {formatDuration(metric.duration_ms)} - {:else if key === "capture"} - {#if metric.has_capture} - - {:else} - - - {/if} - {:else if key === "meta"} - {#if Object.keys(metric.metadata || {}).length > 0} - - ... - - {:else} - - - {/if} - {:else} - - - {/if} -
-
+ - - diff --git a/ui-svelte/src/routes/ModelDetail.svelte b/ui-svelte/src/routes/ModelDetail.svelte index efdb4d61..27d0525f 100644 --- a/ui-svelte/src/routes/ModelDetail.svelte +++ b/ui-svelte/src/routes/ModelDetail.svelte @@ -1,265 +1,18 @@
@@ -302,7 +62,7 @@

Model “{modelId}” not found.

Back to Playground - {:else} + {:else}
@@ -359,247 +119,18 @@ - - - - Recent Activity - ({modelMetrics.length}) - -
- Per page - pageSizeStore.set(Number(v))} - > - {$pageSizeStore} - - {#each [5, 10, 25, 50] as size (size)} - {size} - {/each} - - -
-
- - {#if columnsMenuOpen} -
- - {#each orderedColumns as col (col.key)} - {@const key = col.key} -
handleDragOver(e, key)} - ondrop={(e) => handleDrop(e, key)} - > - handleDragStart(e, key)} - ondragend={handleDragEnd} - > - - - -
- {/each} -
- {/if} -
-
-
-
- - - - - {#each activeVisibleColumns as key (key)} - - {/each} - - - - {#if pageMetrics.length === 0} - - - - {:else} - {#each pageMetrics as metric (metric.id)} - - {#each activeVisibleColumns as key (key)} - - {/each} - - {/each} - {/if} - -
- {#if key === "cached"} - Cached - {:else if key === "prompt"} - Prompt - {:else if key === "drafted"} - Drafted - {:else} - {columnLabelMap[key] ?? key} - {/if} -
- No activity recorded for this model -
- {#if key === "id"} - {metric.id + 1} - {:else if key === "time"} - {formatRelativeTime(metric.timestamp)} - {:else if key === "req_path"} - {metric.req_path || "-"} - {:else if key === "resp_status_code"} - {#if metric.error_msg} - - {metric.resp_status_code || "-"} - - {:else} - {metric.resp_status_code || "-"} - {/if} - {:else if key === "resp_content_type"} - {metric.resp_content_type || "-"} - {:else if key === "cached"} - {metric.tokens.cache_tokens > 0 ? metric.tokens.cache_tokens.toLocaleString() : "-"} - {:else if key === "prompt"} - {metric.tokens.input_tokens.toLocaleString()} - {:else if key === "generated"} - {metric.tokens.output_tokens.toLocaleString()} - {:else if key === "drafted"} - {formatDrafted(metric.tokens.draft_tokens, metric.tokens.draft_acc_tokens)} - {:else if key === "prompt_speed"} - {formatSpeed(metric.tokens.prompt_per_second)} - {:else if key === "gen_speed"} - {formatSpeed(metric.tokens.tokens_per_second)} - {:else if key === "duration"} - {formatDuration(metric.duration_ms)} - {:else if key === "capture"} - {#if metric.has_capture} - - {:else} - - - {/if} - {:else if key === "meta"} - {#if Object.keys(metric.metadata || {}).length > 0} - - ... - - {:else} - - - {/if} - {:else} - - - {/if} -
- - {#if modelMetrics.length > 0} -
- - Page {page + 1} of {totalPages} · {modelMetrics.length} total - -
- - - - -
-
- {/if} -
-
+
- - + + - - - Capabilities - - - {#if capabilities.length === 0} - No capabilities reported. - {:else} -
- {#each capabilities as [key] (key)} - - {capabilityLabels[key] ?? key} - - {/each} -
- {/if} -
-
+
{/if}
- -