summaryrefslogtreecommitdiffhomepage
path: root/src/app/views/MessageQueuePane.svelte
blob: 46b9a22bb5788cb47811e036575f79bb216c79f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<script lang="ts">
  /**
   * The `message-queue` view — pending steering messages, rendered via the
   * generic SurfaceView (dispatches on rendererId, never surface id). The
   * non-empty conditional moved INSIDE the view (decision 4): the tree's leaf
   * always exists; an idle queue renders NOTHING.
   */
  import { SurfaceView } from "../../features/surface-host";
  import { parseMessageQueuePayload } from "../../features/surface-host/logic/message-queue";
  import type { AppViewPorts } from "../view-ports";

  // The message-queue extension's per-conversation surface (steering). Pulled
  // out of the generic Extensions list — pending steering messages are tied to
  // the chat, not the sidebar.
  const MESSAGE_QUEUE_ID = "message-queue";

  let { ports }: { ports: AppViewPorts } = $props();
  const store = $derived(ports.store);

  // The surface spec + whether it currently has pending messages.
  const messageQueueSpec = $derived(store.surface(MESSAGE_QUEUE_ID));
  const hasQueuedMessages = $derived.by(() => {
    const spec = messageQueueSpec;
    if (spec === null) return false;
    const field = spec.fields.find((f) => f.kind === "custom" && f.rendererId === MESSAGE_QUEUE_ID);
    if (field === undefined || field.kind !== "custom") return false;
    const data = parseMessageQueuePayload(field.payload);
    return data !== null && data.messages.length > 0;
  });
</script>

{#if hasQueuedMessages && messageQueueSpec !== null}
  <div class="px-4 pt-2">
    <SurfaceView
      spec={messageQueueSpec}
      onInvoke={(msg) => store.invoke(msg.surfaceId, msg.actionId, msg.payload)}
      onCancelQueuedMessage={(messageId) => store.cancelQueuedMessage(messageId)}
    />
  </div>
{/if}