feat(chat): rich shared-media view, status selector, drag-drop upload + fixes
Chat / shared media:
- Media/Docs/Links: clean underline tabs (green active), audio & video now
classified as Media and rendered as tiles (download + headphone/play +
duration) instead of broken-image glyphs; image thumbnails -> lightbox
- Drag-and-drop a file/video/image onto a conversation to send it
- Fix: removed #chatPanel{position:relative} override that collapsed the
conversation pane (messages spilled into a clipped right-edge strip)
- "Media, links & docs" row cleaned up (no folder/placeholder icon); media
popup keeps the back arrow, drops the redundant close button
Presence / status:
- Single current-status row with an arrow that expands Available/Away/On leave
- On leave = circle with minus, In a call = solid red indicators
- Fix: selected-status tick now follows the chosen option
Icons: added headphones + play; bumped icons.js cache-bust to v4
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+16
-1
@@ -41,6 +41,7 @@ const users = {
|
||||
setPassword: (id, hash, salt) => db.prepare('UPDATE users SET pw_hash=?, pw_salt=? WHERE id=?').run(hash, salt, id),
|
||||
setActive: (id, active) => db.prepare('UPDATE users SET active=? WHERE id=?').run(active ? 1 : 0, id),
|
||||
setAvatar: (id, url) => db.prepare('UPDATE users SET avatar_url=? WHERE id=?').run(url || null, id),
|
||||
setStatus: (id, status) => db.prepare('UPDATE users SET status=? WHERE id=?').run(status, id),
|
||||
remove: (id) => db.prepare('DELETE FROM users WHERE id=?').run(id),
|
||||
};
|
||||
|
||||
@@ -141,6 +142,13 @@ const messages = {
|
||||
byAttachment: (attachmentId) => db.prepare('SELECT * FROM messages WHERE attachment_id=? LIMIT 1').get(attachmentId),
|
||||
setPoll: (messageId, pollId) => db.prepare('UPDATE messages SET poll_id=? WHERE id=?').run(pollId, messageId),
|
||||
markDelivered: (id) => db.prepare('UPDATE messages SET delivered_at=? WHERE id=? AND delivered_at IS NULL').run(now(), id),
|
||||
// Delete-for-everyone: clear the content but keep the row (renders as a placeholder).
|
||||
markDeleted: (id) => db.prepare("UPDATE messages SET deleted=1, body='', attachment_id=NULL, poll_id=NULL WHERE id=?").run(id),
|
||||
// Shared media/files in a conversation (group) or DM — newest first.
|
||||
attachmentsForConversation: (teamId, conversationId) => db.prepare(`SELECT a.id, a.name, a.mime, a.size, m.created_at FROM messages m JOIN attachments a ON a.id=m.attachment_id WHERE m.team_id=? AND m.conversation_id=? AND m.deleted=0 ORDER BY m.created_at DESC`).all(teamId, conversationId),
|
||||
attachmentsForDm: (teamId, a, b) => db.prepare(`SELECT at.id, at.name, at.mime, at.size, m.created_at FROM messages m JOIN attachments at ON at.id=m.attachment_id WHERE m.team_id=? AND m.conversation_id IS NULL AND ((m.sender_id=? AND m.recipient_id=?) OR (m.sender_id=? AND m.recipient_id=?)) AND m.deleted=0 ORDER BY m.created_at DESC`).all(teamId, a, b, b, a),
|
||||
linksForConversation: (teamId, conversationId) => db.prepare("SELECT body, created_at FROM messages WHERE team_id=? AND conversation_id=? AND deleted=0 AND body LIKE '%http%' ORDER BY created_at DESC").all(teamId, conversationId),
|
||||
linksForDm: (teamId, a, b) => db.prepare("SELECT body, created_at FROM messages WHERE team_id=? AND conversation_id IS NULL AND ((sender_id=? AND recipient_id=?) OR (sender_id=? AND recipient_id=?)) AND deleted=0 AND body LIKE '%http%' ORDER BY created_at DESC").all(teamId, a, b, b, a),
|
||||
// Full 1:1 (DM) thread between two users (both directions), oldest first.
|
||||
thread: (teamId, a, b, limit = 300) =>
|
||||
db.prepare(`SELECT * FROM messages WHERE team_id=? AND conversation_id IS NULL
|
||||
@@ -275,4 +283,11 @@ const pushSubs = {
|
||||
removeByEndpoint: (endpoint) => db.prepare('DELETE FROM push_subscriptions WHERE endpoint=?').run(endpoint),
|
||||
};
|
||||
|
||||
module.exports = { teams, users, authSessions, machines, audit, sessionsLog, refreshTokens, apiKeys, webhooks, messages, reactions, attachments, conversations, scheduledMeetings, recordings, polls, pollVotes, pushSubs };
|
||||
const favorites = {
|
||||
set: (userId, target, on) => on
|
||||
? db.prepare('INSERT OR IGNORE INTO favorites (user_id,target,created_at) VALUES (?,?,?)').run(userId, target, now())
|
||||
: db.prepare('DELETE FROM favorites WHERE user_id=? AND target=?').run(userId, target),
|
||||
forUser: (userId) => db.prepare('SELECT target FROM favorites WHERE user_id=?').all(userId).map((r) => r.target),
|
||||
};
|
||||
|
||||
module.exports = { teams, users, authSessions, machines, audit, sessionsLog, refreshTokens, apiKeys, webhooks, messages, reactions, attachments, conversations, scheduledMeetings, recordings, polls, pollVotes, pushSubs, favorites };
|
||||
|
||||
Reference in New Issue
Block a user