|
37 | 37 | let taskRuns = $state<TaskRun[]>([]); |
38 | 38 | let totalCount = $state(0); |
39 | 39 | let expandedId = $state<string | null>(null); |
| 40 | + let hoveredTaskId = $state<string | null>(null); |
40 | 41 | let isReady = $state(false); |
41 | 42 | let isLoading = $state(false); |
42 | 43 | let limit = $state(defaultLimit); |
|
51 | 52 | const toggleExpanded = (runId: string) => { |
52 | 53 | expandedId = expandedId === runId ? null : runId; |
53 | 54 | }; |
| 55 | + const applyTaskNameFilter = (name: string) => { |
| 56 | + selectedTaskName = name; |
| 57 | + if (activeSearch || searchTerm) { |
| 58 | + activeSearch = ""; |
| 59 | + searchTerm = ""; |
| 60 | + updateQuery({ q: null }); |
| 61 | + } |
| 62 | + }; |
| 63 | + const applyTaskIdFilter = (taskId: string) => { |
| 64 | + searchTerm = taskId; |
| 65 | + activeSearch = taskId; |
| 66 | + updateQuery({ q: taskId }); |
| 67 | + }; |
54 | 68 | const handleSearchInput = (event: Event) => { |
55 | 69 | const target = event.currentTarget as HTMLInputElement | null; |
56 | 70 | if (!target) return; |
|
251 | 265 | {#if totalCount === 0} |
252 | 266 | Showing 0 tasks |
253 | 267 | {:else} |
254 | | - Showing 1–{taskRuns.length} of {totalCount} tasks |
| 268 | + Showing 1–{taskRuns.length} of {totalCount} task runs |
255 | 269 | {/if} |
256 | 270 | </span> |
257 | 271 | {#if isLoading} |
|
269 | 283 | <table class="min-w-full border-collapse text-left text-sm"> |
270 | 284 | <thead class="bg-slate-100 text-xs font-semibold uppercase tracking-wide text-slate-600"> |
271 | 285 | <tr> |
272 | | - <th class="px-4 py-3">Task ID</th> |
| 286 | + <th class="px-4 py-3">Task Run</th> |
273 | 287 | <th class="px-4 py-3">Task Name</th> |
274 | 288 | <th class="px-4 py-3">Queue</th> |
275 | 289 | <th class="px-4 py-3">Status</th> |
276 | 290 | <th class="px-4 py-3">Attempt</th> |
277 | | - <th class="px-4 py-3">Run ID</th> |
278 | 291 | <th class="px-4 py-3">Age</th> |
279 | 292 | <th class="px-4 py-3"></th> |
280 | 293 | </tr> |
|
285 | 298 | class="border-t border-black/5 hover:bg-slate-50 hover:cursor-pointer" |
286 | 299 | onclick={() => toggleExpanded(run.runId)} |
287 | 300 | > |
288 | | - <td class="px-4 py-3 font-mono text-xs text-slate-600">{run.id}</td> |
| 301 | + <td class="px-4 py-3"> |
| 302 | + <div class="flex flex-col gap-1"> |
| 303 | + <span class="font-mono text-xs text-slate-700">run: {run.runId}</span> |
| 304 | + <button |
| 305 | + type="button" |
| 306 | + aria-label="Highlight task id" |
| 307 | + class={`w-fit cursor-default text-left font-mono text-[10px] ${ |
| 308 | + hoveredTaskId === run.id |
| 309 | + ? "rounded bg-amber-50 px-1 text-amber-700" |
| 310 | + : "text-slate-500" |
| 311 | + }`} |
| 312 | + onmouseenter={() => { |
| 313 | + hoveredTaskId = run.id; |
| 314 | + }} |
| 315 | + onmouseleave={() => { |
| 316 | + hoveredTaskId = null; |
| 317 | + }} |
| 318 | + > |
| 319 | + task: {run.id} |
| 320 | + </button> |
| 321 | + </div> |
| 322 | + </td> |
289 | 323 | <td class="px-4 py-3 text-slate-800">{run.name}</td> |
290 | 324 | <td class="px-4 py-3 text-slate-600">{run.queue}</td> |
291 | 325 | <td class="px-4 py-3"> |
|
296 | 330 | </span> |
297 | 331 | </td> |
298 | 332 | <td class="px-4 py-3 text-slate-600">{run.attempt}</td> |
299 | | - <td class="px-4 py-3 font-mono text-xs text-slate-600">{run.runId}</td> |
300 | 333 | <td class="px-4 py-3 text-slate-600">{run.age}</td> |
301 | 334 | <td class="px-4 py-3 text-slate-600">{expandedId === run.runId ? "▲" : "▼"}</td> |
302 | 335 | </tr> |
303 | 336 | {#if expandedId === run.runId} |
304 | 337 | <tr class="border-t border-black/10 bg-white"> |
305 | | - <td colspan="8" class="px-4 py-4"> |
| 338 | + <td colspan="7" class="px-4 py-4"> |
306 | 339 | <div class="mt-4"> |
307 | 340 | <div class="flex items-center justify-between"> |
308 | 341 | <h3 class="text-sm font-semibold text-slate-800">Basic Information</h3> |
|
329 | 362 | <div class="flex gap-2"> |
330 | 363 | <dt class="text-slate-500">Task Name:</dt> |
331 | 364 | <dd> |
332 | | - <a href={`/tasks/${run.id}`} class="text-slate-700 hover:underline"> |
| 365 | + <button |
| 366 | + type="button" |
| 367 | + class="cursor-pointer text-left text-slate-700 hover:underline" |
| 368 | + onclick={() => applyTaskNameFilter(run.name)} |
| 369 | + > |
333 | 370 | {run.name} |
334 | | - </a> |
| 371 | + </button> |
335 | 372 | </dd> |
336 | 373 | </div> |
337 | 374 | <div class="flex gap-2"> |
|
341 | 378 | <div class="flex gap-2"> |
342 | 379 | <dt class="text-slate-500">Task ID:</dt> |
343 | 380 | <dd> |
344 | | - <a |
345 | | - href={`/tasks/${run.id}`} |
346 | | - class="rounded bg-blue-50 px-1 py-0.5 font-mono text-xs text-blue-700 hover:underline" |
| 381 | + <button |
| 382 | + type="button" |
| 383 | + class="cursor-pointer rounded bg-blue-50 px-1 py-0.5 text-left font-mono text-xs text-blue-700 hover:underline" |
| 384 | + onclick={() => applyTaskIdFilter(run.id)} |
| 385 | + onmouseenter={() => { |
| 386 | + hoveredTaskId = run.id; |
| 387 | + }} |
| 388 | + onmouseleave={() => { |
| 389 | + hoveredTaskId = null; |
| 390 | + }} |
347 | 391 | > |
348 | 392 | {run.id} |
349 | | - </a> |
| 393 | + </button> |
350 | 394 | </dd> |
351 | 395 | </div> |
352 | 396 | <div class="flex gap-2"> |
|
0 commit comments