fix(tui): show discord attachment details
This commit is contained in:
parent
01b1053809
commit
9e822ad7d7
@ -30,6 +30,7 @@
|
||||
|
||||
- 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
|
||||
|
||||
|
||||
@ -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"])
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user