From f902d0374cba45a185c51d419283276ee28863bc Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Wed, 13 Aug 2025 19:16:34 -0400 Subject: [PATCH] ssb: Start to break out private messages by conversation. #125 --- apps/ssb.json | 2 +- apps/ssb/tf-app.js | 33 ++++++++++++++++++++++++++++++++- apps/ssb/tf-tab-news-feed.js | 26 ++++++++++++++++++++++++++ apps/ssb/tf-tab-news.js | 28 ++++++++++++++++++++++------ apps/ssb/tf-user.js | 8 ++++++-- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/apps/ssb.json b/apps/ssb.json index 0f3468e79..8808de71e 100644 --- a/apps/ssb.json +++ b/apps/ssb.json @@ -1,5 +1,5 @@ { "type": "tildefriends-app", "emoji": "πŸ¦€", - "previous": "&TTGzyovmfKozjELCGPBFLLEXQcpfaArOMmqzemvz9J8=.sha256" + "previous": "&lFyDLIdToivp5zCqHBCRRBs3ESnWoKRi9JQJEkuclQ4=.sha256" } diff --git a/apps/ssb/tf-app.js b/apps/ssb/tf-app.js index d40866c5a..7b08d5687 100644 --- a/apps/ssb/tf-app.js +++ b/apps/ssb/tf-app.js @@ -22,6 +22,7 @@ class TfElement extends LitElement { guest: {type: Boolean}, url: {type: String}, private_messages: {type: Array}, + grouped_private_messages: {type: Object}, recent_reactions: {type: Array}, is_administrator: {type: Boolean}, stay_connected: {type: Boolean}, @@ -366,6 +367,32 @@ class TfElement extends LitElement { return result; } + async group_private_messages(messages) { + let groups = {}; + let result = await this.decrypt( + await tfrpc.rpc.query( + ` + SELECT messages.id, author, timestamp, json(content) AS content + FROM messages + JOIN json_each(?) AS ids + WHERE messages.id = ids.value + ORDER BY timestamp DESC + `, + [JSON.stringify(messages)] + ) + ); + for (let message of result) { + let key = JSON.stringify( + message?.decrypted?.recps?.filter((x) => x != this.whoami)?.sort() + ); + if (!groups[key]) { + groups[key] = []; + } + groups[key].push(message); + } + return groups; + } + async load_channels_latest(following) { let start_time = new Date(); let latest_private = this.get_latest_private(following); @@ -438,12 +465,15 @@ class TfElement extends LitElement { console.log('channels took', (new Date() - start_time) / 1000.0); let self = this; start_time = new Date(); - latest_private.then(function (latest) { + latest_private.then(async function (latest) { self.channels_latest = Object.assign({}, self.channels_latest, { 'πŸ”': latest[0], }); console.log('private took', (new Date() - start_time) / 1000.0); self.private_messages = latest[1]; + self.grouped_private_messages = await self.group_private_messages( + latest[1] + ); }); } @@ -630,6 +660,7 @@ class TfElement extends LitElement { @loadmessages=${this.reset_progress} .connections=${this.connections} .private_messages=${this.private_messages} + .grouped_private_messages=${this.grouped_private_messages} .recent_reactions=${this.recent_reactions} ?is_administrator=${this.is_administrator} ?stay_connected=${this.stay_connected} diff --git a/apps/ssb/tf-tab-news-feed.js b/apps/ssb/tf-tab-news-feed.js index ba8c1c0a3..5bc3f5903 100644 --- a/apps/ssb/tf-tab-news-feed.js +++ b/apps/ssb/tf-tab-news-feed.js @@ -18,6 +18,7 @@ class TfTabNewsFeedElement extends LitElement { time_range: {type: Array}, time_loading: {type: Array}, private_messages: {type: Array}, + grouped_private_messages: {type: Object}, recent_reactions: {type: Array}, }; } @@ -227,6 +228,31 @@ class TfTabNewsFeedElement extends LitElement { ] ); result = (await this.decrypt(result)).filter((x) => x.decrypted); + } else if (this.hash.startsWith('#πŸ”')) { + let ids = this.hash.substring('#πŸ”'.length).split(','); + console.log(this.grouped_private_messages); + result = await tfrpc.rpc.query( + ` + SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature + FROM messages + JOIN json_each(?1) AS private_messages ON messages.id = private_messages.value + WHERE + (?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND + json(messages.content) LIKE '"%' + ORDER BY messages.rowid DESC LIMIT ?4 + `, + [ + JSON.stringify( + this.grouped_private_messages?.[JSON.stringify(ids)]?.map( + (x) => x.id + ) ?? [] + ), + start_time, + end_time, + k_max_results, + ] + ); + result = (await this.decrypt(result)).filter((x) => x.decrypted); } else if (this.hash == '#πŸ‘') { result = await tfrpc.rpc.query( ` diff --git a/apps/ssb/tf-tab-news.js b/apps/ssb/tf-tab-news.js index 87b095e18..efd156a02 100644 --- a/apps/ssb/tf-tab-news.js +++ b/apps/ssb/tf-tab-news.js @@ -24,6 +24,7 @@ class TfTabNewsElement extends LitElement { channels_latest: {type: Object}, connections: {type: Array}, private_messages: {type: Array}, + grouped_private_messages: {type: Object}, recent_reactions: {type: Array}, peer_exchange: {type: Boolean}, is_administrator: {type: Boolean}, @@ -257,12 +258,26 @@ class TfTabNewsElement extends LitElement { style=${this.hash == '#πŸ‘' ? 'font-weight: bold' : undefined} >${this.unread_status('πŸ‘')}πŸ‘votes - ${this.unread_status('πŸ”')}πŸ”private + ${Object.keys(this?.grouped_private_messages ?? [])?.map( + (key) => html` + ${(key != '[]' ? JSON.parse(key) : [this.whoami]).map( + (id) => html` + + ` + )} + ` + )} ${Object.keys(this.drafts) .sort() .map( @@ -434,6 +449,7 @@ class TfTabNewsElement extends LitElement { .channels_unread=${this.channels_unread} .channels_latest=${this.channels_latest} .private_messages=${this.private_messages} + .grouped_private_messages=${this.grouped_private_messages} .recent_reactions=${this.recent_reactions} > diff --git a/apps/ssb/tf-user.js b/apps/ssb/tf-user.js index d0b4b3fba..c586eabb4 100644 --- a/apps/ssb/tf-user.js +++ b/apps/ssb/tf-user.js @@ -9,6 +9,7 @@ class TfUserElement extends LitElement { fallback_name: {type: String}, icon_only: {type: Boolean}, users: {type: Object}, + nolink: {type: Boolean}, }; } @@ -37,7 +38,9 @@ class TfUserElement extends LitElement { let name_string = name ?? this.fallback_name ?? this.id; name = this.icon_only ? undefined - : html`${name_string}`; + : !this.nolink + ? html`${name_string}` + : html`${name_string}`; if (user) { let image_link = user.image; @@ -56,7 +59,8 @@ class TfUserElement extends LitElement { } } return html`
${image} ${name}
`;