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">
  // The workshop's boards, the most recently changed first.
  //
  // Picking one opens it — as a preview, replaced by the next board picked
  // until it is kept — and makes it the board the workshop is looking at.
  import { onMount } from "svelte";
  import { Badge, EmptyState, IconButton, List, ListItem, Notice, Panel, Spinner } from "@wsb/uikit/components";
  import { keyed } from "@wsb/uikit/handles";
  import { boards } from "../../stores/boards.svelte.js";
  import { context } from "../../stores/context.svelte.js";
  import { workbench } from "../../stores/workbench.svelte.js";
  import { formatRelativeTime } from "../../utils/format.js";

  onMount(() => {
    void boards.load();
  });

  function pick(owner: string, number: number) {
    workbench.openBoard(owner, number, { transient: true });
    void context.showBoard(owner, number);
  }
</script>

{#snippet actions()}
  <IconButton handle="workshop.boards.refresh" icon="refresh" label="Read the boards again" busy={boards.refreshing} onpress={() => void boards.refresh()} />
  <IconButton handle="workshop.boards.open" icon="open-external" label="Open every board" onpress={() => workbench.openBoards()} />
{/snippet}

<Panel title="Boards" handle="workshop.boards" {actions}>
  {#if boards.error}
    <Notice tone="danger" title="The boards could not be read" detail={boards.error} />
  {/if}
  {#if boards.noToken}
    <Notice tone="warning" title="No GitHub token" detail="The boards are read from GitHub; give wsb a token in Settings." />
  {:else if boards.loading && boards.byActivity.length === 0}
    <Spinner label="Reading the boards" />
  {:else if boards.byActivity.length === 0}
    <EmptyState icon="boards" title="No boards" detail="A board appears here once a project names it in its settings." />
  {:else}
    <List ariaLabel="Boards">
      {#each boards.byActivity as { board, activity } (board.id)}
        {@const used = boards.projectsUsing(board)}
        {#snippet meta()}
          {#if used.length > 0}<Badge label={String(used.length)} title={`Worked from by ${used.join(", ")}`} />{/if}
        {/snippet}
        <ListItem
          handle={keyed("workshop.board", `${board.owner}/${board.number}`)}
          title={board.title}
          detail={activity.newest_change ? `${board.owner}/${board.number} · ${formatRelativeTime(activity.newest_change)}` : `${board.owner}/${board.number}`}
          icon="board"
          selected={context.board?.owner === board.owner && context.board?.number === board.number}
          {meta}
          onpress={() => pick(board.owner, board.number)}
        />
      {/each}
    </List>
  {/if}
</Panel>