|
4 | 4 | import { getProjectSummary, getRunSummary, deleteRun, renameRun } from "../lib/api.js"; |
5 | 5 | import { navigateTo, setQueryParam } from "../lib/router.js"; |
6 | 6 | import { buildColorMap } from "../lib/stores.js"; |
| 7 | + import { filterMetricsByRegex } from "../lib/dataProcessing.js"; |
7 | 8 |
|
8 | 9 | let { |
9 | 10 | project = null, |
10 | 11 | runs = [], |
| 12 | + filterText = "", |
11 | 13 | onRunsChanged = null, |
12 | 14 | runMutationAllowed = true, |
13 | 15 | } = $props(); |
|
21 | 23 | let renamingIndex = $state(-1); |
22 | 24 | let renameValue = $state(""); |
23 | 25 | let renameInput = $state(null); |
24 | | - let filterText = $state(""); |
25 | 26 |
|
26 | | - let filteredRuns = $derived( |
27 | | - filterText |
28 | | - ? runsData.filter((r) => r.name.toLowerCase().includes(filterText.toLowerCase())) |
29 | | - : runsData, |
30 | | - ); |
| 27 | + let filteredRuns = $derived.by(() => { |
| 28 | + if (!filterText || !filterText.trim()) return runsData; |
| 29 | + const matches = new Set(filterMetricsByRegex(runsData.map((r) => r.name), filterText)); |
| 30 | + return runsData.filter((r) => matches.has(r.name)); |
| 31 | + }); |
31 | 32 |
|
32 | 33 | async function loadRuns() { |
33 | 34 | if (!project) { |
|
117 | 118 | <p>Refresh this page or wait for the dashboard to poll; new runs appear in the table with step counts.</p> |
118 | 119 | </div> |
119 | 120 | {:else} |
120 | | - <div class="filter-section"> |
121 | | - <input |
122 | | - type="text" |
123 | | - class="filter-input" |
124 | | - aria-label="Filter runs" |
125 | | - placeholder="Filter runs..." |
126 | | - bind:value={filterText} |
127 | | - /> |
128 | | - {#if filterText} |
| 121 | + {#if filterText} |
| 122 | + <div class="filter-count-row"> |
129 | 123 | <span class="filter-count">{filteredRuns.length} of {runsData.length} runs</span> |
130 | | - {/if} |
131 | | - </div> |
| 124 | + </div> |
| 125 | + {/if} |
132 | 126 | <table class="runs-table"> |
133 | 127 | <thead> |
134 | 128 | <tr> |
|
238 | 232 | background: none; |
239 | 233 | padding: 0; |
240 | 234 | } |
241 | | - .filter-section { |
242 | | - display: flex; |
243 | | - align-items: center; |
244 | | - gap: 12px; |
245 | | - margin-bottom: 16px; |
246 | | - } |
247 | | - .filter-input { |
248 | | - flex: 1; |
249 | | - max-width: 400px; |
250 | | - padding: 8px 12px; |
251 | | - border: 1px solid var(--border-color-primary, #e5e7eb); |
252 | | - border-radius: var(--radius-sm, 4px); |
253 | | - font-size: var(--text-md, 14px); |
254 | | - background: var(--background-fill-primary, white); |
255 | | - color: var(--body-text-color, #1f2937); |
256 | | - } |
257 | | - .filter-input:focus { |
258 | | - outline: none; |
259 | | - border-color: var(--color-accent, #f97316); |
| 235 | + .filter-count-row { |
| 236 | + margin-bottom: 12px; |
260 | 237 | } |
261 | 238 | .filter-count { |
262 | 239 | font-size: var(--text-sm, 12px); |
|
0 commit comments