diff options
| author | Adam Malczewski <[email protected]> | 2026-05-20 15:04:26 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-20 15:04:26 +0900 |
| commit | adc8bd185b54935e7a31aae04da3175b7989927a (patch) | |
| tree | 031fa53009a4708ce0cc15c0e3dcb2f2a73cf2d9 /packages/frontend/src/lib/components/TaskListPanel.svelte | |
| parent | 52af4ca33b1f83b8f863a6267d447944f55e729d (diff) | |
| download | dispatch-adc8bd185b54935e7a31aae04da3175b7989927a.tar.gz dispatch-adc8bd185b54935e7a31aae04da3175b7989927a.zip | |
feat: phase 3 — config, skills, model groups, task list, and sidebar UI
- Config system: TOML-based dispatch.toml with hot-reload via chokidar
- Model/key resolution: tag-based model selection, key fallback chains
- Skills system: directory loader with TOML frontmatter, agent mappings
- Task list tool: add/update/list/get operations with WebSocket events
- API routes: GET /config, /skills, /skills/:name, /models, /models/resolve
- Frontend: sidebar with model status, task list, config viewer, skills browser, permission log
- Sliding sidebar animation using CSS transitions (not Svelte transitions)
Diffstat (limited to 'packages/frontend/src/lib/components/TaskListPanel.svelte')
| -rw-r--r-- | packages/frontend/src/lib/components/TaskListPanel.svelte | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/packages/frontend/src/lib/components/TaskListPanel.svelte b/packages/frontend/src/lib/components/TaskListPanel.svelte new file mode 100644 index 0000000..5f2ffe2 --- /dev/null +++ b/packages/frontend/src/lib/components/TaskListPanel.svelte @@ -0,0 +1,72 @@ +<script lang="ts"> + interface TaskItem { + id: string; + title: string; + description: string; + status: "pending" | "in_progress" | "done" | "blocked"; + } + + const { tasks }: { tasks: TaskItem[] } = $props(); + + const doneCount = $derived(tasks.filter((t) => t.status === "done").length); + const inProgressCount = $derived(tasks.filter((t) => t.status === "in_progress").length); + + function badgeClass(status: TaskItem["status"]): string { + switch (status) { + case "pending": + return "badge badge-ghost badge-xs"; + case "in_progress": + return "badge badge-info badge-xs"; + case "done": + return "badge badge-success badge-xs"; + case "blocked": + return "badge badge-warning badge-xs"; + } + } + + function statusIcon(status: TaskItem["status"]): string { + switch (status) { + case "pending": + return "⏳"; + case "in_progress": + return "▶"; + case "done": + return "✓"; + case "blocked": + return "⚠"; + } + } +</script> + +<div class="flex flex-col gap-2"> + {#if tasks.length === 0} + <p class="text-xs text-base-content/50">No tasks yet.</p> + {:else} + <p class="text-xs text-base-content/60"> + {tasks.length} task{tasks.length !== 1 ? "s" : ""} + ({doneCount} done, {inProgressCount} in progress) + </p> + <ul class="flex flex-col gap-1"> + {#each tasks as task (task.id)} + <li class="flex flex-col gap-0.5 rounded p-1.5 hover:bg-base-200 transition-colors"> + <div class="flex items-center gap-1.5"> + <span class={badgeClass(task.status)}> + {statusIcon(task.status)} + </span> + <span + class="text-sm leading-tight {task.status === 'in_progress' + ? 'font-bold' + : 'font-medium'}" + > + {task.title} + </span> + </div> + {#if task.description} + <p class="text-xs text-base-content/60 line-clamp-2 pl-5">{task.description}</p> + {/if} + <p class="text-xs text-base-content/30 pl-5 font-mono">{task.id}</p> + </li> + {/each} + </ul> + {/if} +</div> |
