Skip to content

Refactor MessageItem.svelte — extract snippets and apply ExpandableContent #141

Description

@daegunjhy

Problem

MessageItem.svelte (459 lines) has grown into a monolithic component with significant code duplication:

  1. Duplicated header pattern (8x) — Every message type block repeats the same header row structure:

    <div class="flex justify-between items-center text-xs text-gh-text-secondary">
      <span>/* type label */</span>
      <div class="flex items-center gap-2">
        <span>{formatDate(msg.timestamp)}</span>
        {@render splitButton()}
        {@render deleteButton()}
      </div>
    </div>

    This pattern appears in: progress, turnDuration, stopHook, fileSnapshot, slashCommand, localCommand, toolUse, and standard message blocks.

  2. file-history-snapshot renders raw list — When a snapshot has many tracked files (10+), the full <ul> list renders without truncation. Other content types use ExpandableContent for long content, but file snapshots do not.

  3. Inline type assertions — Multiple as unknown as { ... } casts scattered in derived computations (snapshotData, commandData, agentName, customTitle, messageId).

Proposed Changes

Phase 1: Extract messageHeader snippet

  • Create a {#snippet messageHeader(label, icon, timestamp?)} that encapsulates the header row pattern
  • Replace all 8 duplicated header blocks with {@render messageHeader(...)} calls
  • Reduces ~80 lines of duplication

Phase 2: Apply ExpandableContent to file-history-snapshot

  • Wrap the file list in ExpandableContent when snapshotData.files.length > 5
  • Format: one file path per line, preserving click-to-open behavior for expanded state
  • Collapsed state shows first 5 files + "Click to expand (N more files)"

Phase 3: Extract derived computations to utilities

  • Move snapshotData, commandData, toolUseData, thinkingBlocks parsing to $lib/utils/message.ts
  • Replace inline as unknown as casts with typed parser functions
  • Improves testability — parsers can be unit tested independently

Out of Scope

Storybook

  • Update MessageItem.stories.svelte to cover:
    • File snapshot with 1 file (no collapse)
    • File snapshot with 10+ files (collapsed by default)
    • Verify header consistency across all message types

Verification

  • pnpm -F web build passes
  • pnpm -F core test passes (if utils moved)
  • Storybook visual check for all message types
  • Playwright e2e: session viewer renders messages correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions