summaryrefslogtreecommitdiffhomepage
path: root/packages/frontend/src/lib/components/TaskListPanel.svelte
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-20 15:04:26 +0900
committerAdam Malczewski <[email protected]>2026-05-20 15:04:26 +0900
commitadc8bd185b54935e7a31aae04da3175b7989927a (patch)
tree031fa53009a4708ce0cc15c0e3dcb2f2a73cf2d9 /packages/frontend/src/lib/components/TaskListPanel.svelte
parent52af4ca33b1f83b8f863a6267d447944f55e729d (diff)
downloaddispatch-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.svelte72
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>