summaryrefslogtreecommitdiffhomepage
path: root/src/features/workspaces/ui/WorkspaceCard.svelte
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-28 15:29:55 +0900
committerAdam Malczewski <[email protected]>2026-06-28 15:29:55 +0900
commitded7cc4ebf872556b4ab16bac81c1b551d8e44da (patch)
tree0f5cbed2405f83a819032a551295490b70e31d1d /src/features/workspaces/ui/WorkspaceCard.svelte
parent3899ecef48325014a3bb5d6333a7a3e1fc34296a (diff)
parent60aa5dc48b6af502f88befd7d1517ab52cf6c60f (diff)
downloaddispatch-web-ded7cc4ebf872556b4ab16bac81c1b551d8e44da.tar.gz
dispatch-web-ded7cc4ebf872556b4ab16bac81c1b551d8e44da.zip
Merge branch 'feature/workspace-star' into predev
# Conflicts: # backend-handoff.md # src/features/workspaces/ui/WorkspaceCard.test.ts
Diffstat (limited to 'src/features/workspaces/ui/WorkspaceCard.svelte')
-rw-r--r--src/features/workspaces/ui/WorkspaceCard.svelte45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/features/workspaces/ui/WorkspaceCard.svelte b/src/features/workspaces/ui/WorkspaceCard.svelte
index 1825b7d..6de4109 100644
--- a/src/features/workspaces/ui/WorkspaceCard.svelte
+++ b/src/features/workspaces/ui/WorkspaceCard.svelte
@@ -96,6 +96,28 @@
if (!result.ok) computerError = result.error;
}
+ // ── Star (concurrency priority) ──────────────────────────────────────────────
+ let savingStar = $state(false);
+ let starError = $state<string | null>(null);
+
+ async function toggleStar(): Promise<void> {
+ if (savingStar) return;
+ savingStar = true;
+ starError = null;
+ try {
+ // Optimistic: the store flips `starred` immediately and re-sorts; revert
+ // on error is handled there. We read `ws.starred` for the target value.
+ const result = await store.setStarred(ws.id, !ws.starred);
+ if (!result.ok) starError = result.error;
+ } catch (err) {
+ // A throw (e.g. a rejected effect) — surface it; the store already
+ // reverted the optimistic flip if it got far enough to apply it.
+ starError = err instanceof Error ? err.message : "Star toggle failed";
+ } finally {
+ savingStar = false;
+ }
+ }
+
// ── Delete ─────────────────────────────────────────────────────────────────
let deleting = $state(false);
@@ -143,6 +165,25 @@
>
{/if}
<span class="font-mono text-xs opacity-50">/{ws.id}</span>
+ <button
+ type="button"
+ class="btn btn-ghost btn-xs px-1"
+ disabled={savingStar}
+ aria-pressed={ws.starred}
+ aria-label={ws.starred ? "Unstar workspace" : "Star workspace"}
+ title={ws.starred
+ ? "Starred — its agents get concurrency priority. Click to unstar."
+ : "Star this workspace to give its agents concurrency priority."}
+ onclick={toggleStar}
+ >
+ {#if savingStar}
+ <span class="loading loading-spinner loading-xs"></span>
+ {:else if ws.starred}
+ <span class="text-warning" aria-hidden="true">★</span>
+ {:else}
+ <span class="opacity-40" aria-hidden="true">☆</span>
+ {/if}
+ </button>
<span class="ml-auto text-xs opacity-50">
{ws.conversationCount}
{ws.conversationCount === 1 ? "conversation" : "conversations"}
@@ -168,6 +209,10 @@
<p class="text-xs text-error">{titleError}</p>
{/if}
+ {#if starError}
+ <p class="text-xs text-error">{starError}</p>
+ {/if}
+
<div class="flex items-center gap-2">
<span class="w-8 shrink-0 text-xs opacity-60">cwd</span>
<input