ssb: Start to break out private messages by conversation. #125

This commit is contained in:
2025-08-13 19:16:34 -04:00
parent b5f0a0c4f7
commit f902d0374c
5 changed files with 87 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🦀", "emoji": "🦀",
"previous": "&TTGzyovmfKozjELCGPBFLLEXQcpfaArOMmqzemvz9J8=.sha256" "previous": "&lFyDLIdToivp5zCqHBCRRBs3ESnWoKRi9JQJEkuclQ4=.sha256"
} }

View File

@@ -22,6 +22,7 @@ class TfElement extends LitElement {
guest: {type: Boolean}, guest: {type: Boolean},
url: {type: String}, url: {type: String},
private_messages: {type: Array}, private_messages: {type: Array},
grouped_private_messages: {type: Object},
recent_reactions: {type: Array}, recent_reactions: {type: Array},
is_administrator: {type: Boolean}, is_administrator: {type: Boolean},
stay_connected: {type: Boolean}, stay_connected: {type: Boolean},
@@ -366,6 +367,32 @@ class TfElement extends LitElement {
return result; 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) { async load_channels_latest(following) {
let start_time = new Date(); let start_time = new Date();
let latest_private = this.get_latest_private(following); 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); console.log('channels took', (new Date() - start_time) / 1000.0);
let self = this; let self = this;
start_time = new Date(); start_time = new Date();
latest_private.then(function (latest) { latest_private.then(async function (latest) {
self.channels_latest = Object.assign({}, self.channels_latest, { self.channels_latest = Object.assign({}, self.channels_latest, {
'🔐': latest[0], '🔐': latest[0],
}); });
console.log('private took', (new Date() - start_time) / 1000.0); console.log('private took', (new Date() - start_time) / 1000.0);
self.private_messages = latest[1]; 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} @loadmessages=${this.reset_progress}
.connections=${this.connections} .connections=${this.connections}
.private_messages=${this.private_messages} .private_messages=${this.private_messages}
.grouped_private_messages=${this.grouped_private_messages}
.recent_reactions=${this.recent_reactions} .recent_reactions=${this.recent_reactions}
?is_administrator=${this.is_administrator} ?is_administrator=${this.is_administrator}
?stay_connected=${this.stay_connected} ?stay_connected=${this.stay_connected}

View File

@@ -18,6 +18,7 @@ class TfTabNewsFeedElement extends LitElement {
time_range: {type: Array}, time_range: {type: Array},
time_loading: {type: Array}, time_loading: {type: Array},
private_messages: {type: Array}, private_messages: {type: Array},
grouped_private_messages: {type: Object},
recent_reactions: {type: Array}, recent_reactions: {type: Array},
}; };
} }
@@ -227,6 +228,31 @@ class TfTabNewsFeedElement extends LitElement {
] ]
); );
result = (await this.decrypt(result)).filter((x) => x.decrypted); 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 == '#👍') { } else if (this.hash == '#👍') {
result = await tfrpc.rpc.query( result = await tfrpc.rpc.query(
` `

View File

@@ -24,6 +24,7 @@ class TfTabNewsElement extends LitElement {
channels_latest: {type: Object}, channels_latest: {type: Object},
connections: {type: Array}, connections: {type: Array},
private_messages: {type: Array}, private_messages: {type: Array},
grouped_private_messages: {type: Object},
recent_reactions: {type: Array}, recent_reactions: {type: Array},
peer_exchange: {type: Boolean}, peer_exchange: {type: Boolean},
is_administrator: {type: Boolean}, is_administrator: {type: Boolean},
@@ -257,12 +258,26 @@ class TfTabNewsElement extends LitElement {
style=${this.hash == '#👍' ? 'font-weight: bold' : undefined} style=${this.hash == '#👍' ? 'font-weight: bold' : undefined}
>${this.unread_status('👍')}👍votes</a >${this.unread_status('👍')}👍votes</a
> >
<a ${Object.keys(this?.grouped_private_messages ?? [])?.map(
href="#🔐" (key) => html`
class="w3-bar-item w3-button" <a
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined} href=${'#🔐' + JSON.parse(key).join(',')}
>${this.unread_status('🔐')}🔐private</a class="w3-bar-item w3-button"
> style=${this.hash == '#🔐' + JSON.parse(key).join(',')
? 'font-weight: bold'
: undefined}
>${(key != '[]' ? JSON.parse(key) : [this.whoami]).map(
(id) => html`
<tf-user
id=${id}
nolink="true"
.users=${this.users}
></tf-user>
`
)}</a
>
`
)}
${Object.keys(this.drafts) ${Object.keys(this.drafts)
.sort() .sort()
.map( .map(
@@ -434,6 +449,7 @@ class TfTabNewsElement extends LitElement {
.channels_unread=${this.channels_unread} .channels_unread=${this.channels_unread}
.channels_latest=${this.channels_latest} .channels_latest=${this.channels_latest}
.private_messages=${this.private_messages} .private_messages=${this.private_messages}
.grouped_private_messages=${this.grouped_private_messages}
.recent_reactions=${this.recent_reactions} .recent_reactions=${this.recent_reactions}
></tf-tab-news-feed> ></tf-tab-news-feed>
</div> </div>

View File

@@ -9,6 +9,7 @@ class TfUserElement extends LitElement {
fallback_name: {type: String}, fallback_name: {type: String},
icon_only: {type: Boolean}, icon_only: {type: Boolean},
users: {type: Object}, users: {type: Object},
nolink: {type: Boolean},
}; };
} }
@@ -37,7 +38,9 @@ class TfUserElement extends LitElement {
let name_string = name ?? this.fallback_name ?? this.id; let name_string = name ?? this.fallback_name ?? this.id;
name = this.icon_only name = this.icon_only
? undefined ? undefined
: html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`; : !this.nolink
? html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`
: html`<span>${name_string}</span>`;
if (user) { if (user) {
let image_link = user.image; let image_link = user.image;
@@ -56,7 +59,8 @@ class TfUserElement extends LitElement {
} }
} }
return html` <div return html` <div
style="display: inline-block; vertical-align: middle; font-weight: bold; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis" style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' +
(this.nolink ? '' : '; font-weight: bold')}
> >
${image} ${name} ${image} ${name}
</div>`; </div>`;