Skip to content

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

@daegunjhy

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
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions