wsb-daemon 0.275.7622

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
<script lang="ts">
  // Every project in the workshop and the worktrees of each, and the
  // worktrees outside every project.
  //
  // Picking a worktree makes it the context: the right sidebar works in it.
  // Picking a project opens its page. The rows say only what tells worktrees
  // apart at a glance — the branch and whether there are changes — and the
  // detail lives on the project's page.
  import { onMount } from "svelte";
  import { Badge, EmptyState, IconButton, Notice, Panel, Tree, TreeItem } from "@wsb/uikit/components";
  import { keyed } from "@wsb/uikit/handles";
  import type { Worktree } from "../../api/types/levels.js";
  import { context } from "../../stores/context.svelte.js";
  import { levels } from "../../stores/levels.svelte.js";
  import { workbench } from "../../stores/workbench.svelte.js";

  let folded = $state<Record<string, boolean>>({});

  onMount(() => {
    void levels.ensureLoaded();
  });

  function detailOf(worktree: Worktree): string {
    if (levels.opening === worktree.id) return "opening…";
    const branch = worktree.branch ?? "detached";
    return worktree.dirty > 0 ? `${branch} · ${worktree.dirty} changed` : branch;
  }
</script>

{#snippet actions()}
  <IconButton handle="workshop.projects.refresh" icon="refresh" label="Read the projects again" busy={levels.loading} onpress={() => void levels.load()} />
  <IconButton handle="workshop.projects.open" icon="open-external" label="Open every project" onpress={() => workbench.openProjects()} />
{/snippet}

{#snippet worktreeRow(worktree: Worktree, depth: number)}
  <TreeItem
    handle={keyed("workshop.worktree", worktree.id)}
    label={worktree.name}
    {depth}
    icon="worktree"
    detail={detailOf(worktree)}
    current={context.worktree === worktree.id}
    onpress={() => void context.enter(worktree.id)}
  />
{/snippet}

<Panel title="Projects" handle="workshop.projects" {actions}>
  {#if levels.error}
    <Notice tone="danger" title="The projects could not be read" detail={levels.error} />
  {/if}
  {#if levels.openFailure}
    <Notice tone="danger" title={`${levels.openFailure.worktree} could not be opened`} detail={levels.openFailure.message} />
  {/if}
  {#if levels.loaded && levels.projects.length === 0 && levels.standalone.length === 0}
    <EmptyState icon="projects" title="No projects" detail="Clone a project into the workshop to see it here." />
  {:else}
    <Tree ariaLabel="Projects">
      {#each levels.projects as project (project.name)}
        {@const open = !(folded[project.name] ?? false)}
        {#snippet count()}<Badge label={String(project.worktrees.length)} title={`${project.worktrees.length} worktrees`} />{/snippet}
        <TreeItem
          handle={keyed("workshop.project", project.name)}
          label={project.name}
          depth={0}
          icon="project"
          expanded={open}
          current={context.project === project.name}
          meta={count}
          ontoggle={(expanded) => { folded = { ...folded, [project.name]: !expanded }; }}
          onpress={() => workbench.openProject(project.name, { transient: true })}
        />
        {#if open}
          {#each project.worktrees as worktree (worktree.id)}
            {@render worktreeRow(worktree, 1)}
          {/each}
        {/if}
      {/each}
      {#each levels.standalone as worktree (worktree.id)}
        {@render worktreeRow(worktree, 0)}
      {/each}
    </Tree>
  {/if}
</Panel>