# All files / src/components/streams StreamTranscript.tsx

100% Statements 8/8
80% Branches 4/5
100% Functions 3/3
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64

    13x
    13x

    21x
    1x

    20x
    15x

    5x

    13x

     /**
     * StreamTranscript — read-only transcript of an IPC stream room (RFC #1264 Phase 2).
     *
     * Pure presentational: renders an ordered (oldest-first) list of stream messages
     * with sender + timestamp. Fed by the durable transcript (scrollback) merged with
     * the live message feed; the owning page supplies the data and loading state.
     *
     * @module
     */

    import { type JSX } from "react";
    import type { StreamMessageData } from "../../hooks/types.js";
    import styles from "./StreamTranscript.module.scss";

    /** Props for the StreamTranscript component. */
    export interface StreamTranscriptProps {
      /** Messages to render, oldest first. */
      messages: StreamMessageData[];
      /** Whether the transcript is currently loading (scrollback fetch in flight). */
      loading?: boolean;
    }

    /** Format an ISO 8601 timestamp as a short local time. */
    function formatTime(iso: string): string {
      const date = new Date(iso);
      return Number.isNaN(date.getTime()) ? iso : date.toLocaleTimeString();
    }

    /** Read-only, ordered transcript of an IPC stream room's messages. */
    export function StreamTranscript({
      messages,
      loading = false,
    }: StreamTranscriptProps): JSX.Element {
      if (loading) {
        return (
          <div className={styles.state} data-testid="stream-transcript-loading">
            Loading transcript…
          </div>
        );
      }
      if (messages.length === 0) {
        return (
          <div className={styles.state} data-testid="stream-transcript-empty">
            No messages yet.
          </div>
        );
      }
      return (
        <div className={styles.transcript} data-testid="stream-transcript">
          {messages.map((m) => (
            <div key={m.seq} className={styles.message} data-testid="stream-transcript-message">
              <div className={styles.meta}>
                <span className={styles.sender} title={m.senderId}>
                  {m.senderId.slice(0, 12)}
                </span>
                <span className={styles.time}>{formatTime(m.timestamp)}</span>
              </div>
              <div className={styles.content}>{m.content}</div>
            </div>
          ))}
        </div>
      );
    }