fix(tui): show discord attachment details

This commit is contained in:
Vincent Koc 2026-05-03 16:02:55 -07:00
parent 475d8cecea
commit 37d632f2ba
No known key found for this signature in database
5 changed files with 67 additions and 37 deletions

View File

@ -32,6 +32,7 @@ All notable changes to `discrawl` will be documented in this file.
- Label direct-message TUI panes as direct messages instead of raw `@me` guild rows, keeping DM channel/person context readable.
- Inherit shared crawlkit TUI improvements for newest-first startup, count-header sorting, selected-message-first chat detail panes, and gitcrawl-style metadata labels.
- Surface Discord attachment filenames and extracted text in TUI detail panes instead of only showing `attachments=true`.
## 0.6.3 - 2026-05-01

View File

@ -229,28 +229,33 @@ func TestWiretapImportsDesktopDirectMessages(t *testing.T) {
func TestDiscordTUIRowsIncludePaneMetadata(t *testing.T) {
rows := discordTUIRows([]store.MessageRow{{
MessageID: "m1",
GuildID: "@me",
GuildName: "Discord Direct Messages",
ChannelID: "c1",
ChannelName: "Vincent K",
AuthorID: "u1",
AuthorName: "Peter",
Content: "hello from desktop",
DisplayContent: "hello from Vincent",
CreatedAt: time.Date(2026, 5, 2, 12, 0, 0, 0, time.UTC),
ReplyToMessage: "m0",
HasAttachments: true,
Pinned: true,
MessageID: "m1",
GuildID: "@me",
GuildName: "Discord Direct Messages",
ChannelID: "c1",
ChannelName: "Vincent K",
AuthorID: "u1",
AuthorName: "Peter",
Content: "hello from desktop",
DisplayContent: "hello from Vincent",
CreatedAt: time.Date(2026, 5, 2, 12, 0, 0, 0, time.UTC),
ReplyToMessage: "m0",
HasAttachments: true,
AttachmentNames: "trace.txt",
AttachmentText: "stack trace line one",
Pinned: true,
}})
require.Len(t, rows, 1)
require.Equal(t, "hello from Vincent", rows[0].Title)
require.Equal(t, "hello from Vincent", rows[0].Detail)
require.Contains(t, rows[0].Detail, "hello from Vincent")
require.Contains(t, rows[0].Detail, "Attachments")
require.Contains(t, rows[0].Detail, "stack trace line one")
require.Equal(t, "hello from Vincent", rows[0].Text)
require.Equal(t, "Direct messages", rows[0].Scope)
require.Equal(t, "Vincent K", rows[0].Container)
require.Contains(t, rows[0].Tags, "dm")
require.Equal(t, "true", rows[0].Fields["attachments"])
require.Equal(t, "trace.txt", rows[0].Fields["attachment_names"])
require.Equal(t, "true", rows[0].Fields["pinned"])
require.Equal(t, "m0", rows[0].Fields["reply_to"])
require.Equal(t, "@me", rows[0].Fields["guild_id"])

View File

@ -128,8 +128,9 @@ func discordTUIRows(rows []store.MessageRow) []tui.Row {
for _, row := range rows {
content := discordDisplayContent(row)
title := strings.TrimSpace(content)
detail := discordDetailContent(row, content)
if title == "" {
title = row.MessageID
title = firstNonEmpty(strings.TrimSpace(row.AttachmentText), row.MessageID)
}
tags := []string{row.GuildID, row.ChannelID}
if row.GuildID == "@me" {
@ -148,24 +149,39 @@ func discordTUIRows(rows []store.MessageRow) []tui.Row {
Author: discordAuthorLabel(row),
Title: title,
Text: content,
Detail: content,
Detail: detail,
URL: discordMessageURL(row),
CreatedAt: formatTime(row.CreatedAt),
Tags: tags,
Fields: map[string]string{
"attachments": boolString(row.HasAttachments),
"author_id": row.AuthorID,
"channel_id": row.ChannelID,
"guild_id": row.GuildID,
"pinned": boolString(row.Pinned),
"reply_to": row.ReplyToMessage,
"source": row.Source,
"attachment_names": row.AttachmentNames,
"attachments": boolString(row.HasAttachments),
"author_id": row.AuthorID,
"channel_id": row.ChannelID,
"guild_id": row.GuildID,
"pinned": boolString(row.Pinned),
"reply_to": row.ReplyToMessage,
"source": row.Source,
},
})
}
return items
}
func discordDetailContent(row store.MessageRow, content string) string {
var parts []string
if strings.TrimSpace(content) != "" {
parts = append(parts, strings.TrimSpace(content))
}
if strings.TrimSpace(row.AttachmentText) != "" {
parts = append(parts, "Attachments\n"+strings.TrimSpace(row.AttachmentText))
}
if len(parts) == 0 {
return ""
}
return strings.Join(parts, "\n\n")
}
func discordDisplayContent(row store.MessageRow) string {
if content := strings.TrimSpace(row.DisplayContent); content != "" {
return content

View File

@ -92,6 +92,8 @@ func TestAttachmentTextAndMentionsAreQueryable(t *testing.T) {
require.NoError(t, err)
require.Len(t, messages, 1)
require.Contains(t, messages[0].Content, "stack trace")
require.Equal(t, "trace.txt", messages[0].AttachmentNames)
require.Contains(t, messages[0].AttachmentText, "stack trace line one")
mentions, err := s.ListMentions(ctx, MentionListOptions{Target: "Shadow", Limit: 10})
require.NoError(t, err)

View File

@ -35,20 +35,22 @@ type MentionListOptions struct {
}
type MessageRow struct {
MessageID string `json:"message_id"`
GuildID string `json:"guild_id"`
GuildName string `json:"guild_name,omitempty"`
ChannelID string `json:"channel_id"`
ChannelName string `json:"channel_name"`
AuthorID string `json:"author_id"`
AuthorName string `json:"author_name"`
Content string `json:"content"`
DisplayContent string `json:"display_content,omitempty"`
CreatedAt time.Time `json:"created_at"`
ReplyToMessage string `json:"reply_to_message_id,omitempty"`
Source string `json:"source,omitempty"`
HasAttachments bool `json:"has_attachments"`
Pinned bool `json:"pinned"`
MessageID string `json:"message_id"`
GuildID string `json:"guild_id"`
GuildName string `json:"guild_name,omitempty"`
ChannelID string `json:"channel_id"`
ChannelName string `json:"channel_name"`
AuthorID string `json:"author_id"`
AuthorName string `json:"author_name"`
Content string `json:"content"`
DisplayContent string `json:"display_content,omitempty"`
CreatedAt time.Time `json:"created_at"`
ReplyToMessage string `json:"reply_to_message_id,omitempty"`
Source string `json:"source,omitempty"`
HasAttachments bool `json:"has_attachments"`
AttachmentNames string `json:"attachment_names,omitempty"`
AttachmentText string `json:"attachment_text,omitempty"`
Pinned bool `json:"pinned"`
}
func (s *Store) ListMessages(ctx context.Context, opts MessageListOptions) ([]MessageRow, error) {
@ -105,6 +107,8 @@ func (s *Store) ListMessages(ctx context.Context, opts MessageListOptions) ([]Me
coalesce(m.reply_to_message_id, ''),
coalesce(json_extract(m.raw_json, '$.source'), ''),
m.has_attachments,
coalesce((select group_concat(a.filename, ', ') from message_attachments a where a.message_id = m.id), ''),
coalesce((select group_concat(a.text_content, char(10)) from message_attachments a where a.message_id = m.id and trim(a.text_content) <> ''), ''),
m.pinned
from messages m
left join guilds g on g.id = m.guild_id
@ -161,6 +165,8 @@ func (s *Store) ListMessages(ctx context.Context, opts MessageListOptions) ([]Me
&row.ReplyToMessage,
&row.Source,
&hasAttachments,
&row.AttachmentNames,
&row.AttachmentText,
&pinned,
); err != nil {
return nil, err