Blur gallery images by default, sync progress UI, and add chat/monitor tests
- Blur NSFW media gallery images until hover/reveal - Surface chat sync progress in the dashboard header - Extend chat service, cache, and monitor with delta-media handling - Add tests for chat cooldown, delta media, and monitor flows Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
633bb0ec04
commit
2260388dc8
15 files changed
+675
-41
No files matched your search
@@ -32,13 +32,20 @@ export function createConversationsRouter(ctx: WebContext): Router {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Pull in any new activity from the homeserver before we read the cache,
|
||||
// so a stale "waiting for them to reply" view picks up the reply they
|
||||
// already sent. Cheap (~one /sync call) and queued behind any in-flight sync.
|
||||
try {
|
||||
await ctx.services.chat.refreshTopChats();
|
||||
} catch (err) {
|
||||
ctx.logger.warn('Pre-open delta sync failed:', err);
|
||||
// If a sync is already in flight (e.g. a Full sync the user kicked off
|
||||
// from the dashboard), don't queue *another* delta + lazy-load behind it
|
||||
// — that's what makes the modal sit on "Loading…" for minutes. Render
|
||||
// from cache and let the frontend show a "sync in progress" banner; the
|
||||
// user can reopen once it's done.
|
||||
const syncStatus = ctx.services.chat.getSyncStatus();
|
||||
const syncInFlight = syncStatus.syncing;
|
||||
|
||||
if (!syncInFlight) {
|
||||
try {
|
||||
await ctx.services.chat.refreshTopChats();
|
||||
} catch (err) {
|
||||
ctx.logger.warn('Pre-open delta sync failed:', err);
|
||||
}
|
||||
}
|
||||
const conversation = await findConversation(decodeURIComponent(req.params.id));
|
||||
if (!conversation) {
|
||||
@@ -53,7 +60,9 @@ export function createConversationsRouter(ctx: WebContext): Router {
|
||||
? conversation.messages[conversation.messages.length - 1].timestamp
|
||||
: 0;
|
||||
const hasNewerActivity = (conversation.lastMessageTime ?? 0) > cachedLastTs;
|
||||
if (!conversation.messages || conversation.messages.length === 0 || hasNewerActivity) {
|
||||
const needsLazyLoad =
|
||||
!conversation.messages || conversation.messages.length === 0 || hasNewerActivity;
|
||||
if (needsLazyLoad && !syncInFlight) {
|
||||
try {
|
||||
await ctx.services.chat.loadConversationDetails(conversation);
|
||||
await ctx.services.chat.saveCacheExternal();
|
||||
@@ -88,7 +97,17 @@ export function createConversationsRouter(ctx: WebContext): Router {
|
||||
ctx.logger.warn(`Failed to look up triggering post for ${conversation.username}:`, err);
|
||||
}
|
||||
|
||||
res.json({ ...conversation, triggeringPost });
|
||||
res.json({
|
||||
...conversation,
|
||||
triggeringPost,
|
||||
syncInProgress: syncInFlight
|
||||
? {
|
||||
kind: syncStatus.syncingKind,
|
||||
progress: syncStatus.progress,
|
||||
staleMessages: needsLazyLoad,
|
||||
}
|
||||
: null,
|
||||
});
|
||||
} catch (error) {
|
||||
ctx.logger.error('Failed to fetch conversation:', error);
|
||||
res.status(500).json({ error: String(error) });
|
||||
|
||||
Reference in new issue
Block a user