You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: Bug contains-studio#1 - pinned messages no longer show (edited) label; fix search test parallel flakiness
- Add editedAt field to Message schema (set only on content edit, not pin/unpin)
- Update edit route to set editedAt; fix isEdited derivation to use !!msg.editedAt
- Add editedAt to ApiMessage interface
- Fix Bug contains-studio#4 search test: add random suffix to search term, assert within data-testid="search-results-dropdown"
- Update bugs.md to reflect remaining bugs (contains-studio#7 Files tab, contains-studio#8 Typing indicators)
- All 63 Playwright tests and 207 backend tests pass
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only messages whose **content** was modified should display the `(edited)` badge.
42
42
43
43
### Actual
44
-
Pinning a message triggers a database `UPDATE` which changes `updatedAt`. The frontend compares `updatedAt > createdAt` to decide whether to show `(edited)`, so every pinned message is incorrectly labeled as edited — even if the text was never changed.
44
+
Pinning a message triggers a database `UPDATE` which changes `updatedAt`. The frontend (`src/lib/api.ts:46`) computes `isEdited: msg.updatedAt !== msg.createdAt`, so every pinned message is incorrectly labeled as edited — even if the text was never changed.
45
45
46
46
### Root Cause
47
-
The "(edited)" check does not distinguish between a content edit and a metadata update (e.g. `isPinned` toggle). The backend should either use a separate `editedAt` field for content edits, or the pin operation should preserve the existing `updatedAt`.
48
-
49
-
---
50
-
51
-
## Bug #2 — Emoji reactions stored as shortcodes render as raw text
52
-
53
-
**Severity:** High
54
-
**Feature:** Reactions
55
-
56
-
### Steps to Reproduce
57
-
1. Open any channel that has reactions inserted via the seed script (or the database directly)
58
-
2. Observe the reaction badges under those messages
59
-
60
-
### Expected
61
-
Reactions display as Unicode emoji with a count — e.g. `👍 2`, `🔥 1`, `🎉 1`
62
-
63
-
### Actual
64
-
Reactions display as raw shortcode text — e.g. `+1 2`, `fire 1`, `tada1`, `thinking_gl...`, `confetti_ball`
65
-
66
-
### Note
67
-
Reactions **added via the emoji picker in the UI** display correctly because the picker sends the actual Unicode character. The bug only affects reactions stored as shortcode strings. The frontend renders whatever string is in the database without any shortcode → Unicode conversion.
68
-
69
-
### Root Cause
70
-
The reaction display component has no emoji lookup/mapping step. Any reaction stored as a shortcode (`:fire:`, `+1`, etc.) will render as plain text.
71
-
72
-
---
73
-
74
-
## Bug #3 — `TypeError` in `fetchDirectMessages` spams the console
75
-
76
-
**Severity:** Critical
77
-
**Feature:** Direct Messages
78
-
79
-
### Steps to Reproduce
80
-
1. Log in as any user
81
-
2. Open the browser DevTools console
82
-
3. Wait a few seconds
83
-
84
-
### Expected
85
-
No errors; DMs load silently in the background.
86
-
87
-
### Actual
88
-
Hundreds of repeated errors per minute fill the console:
89
-
90
-
```
91
-
Failed to fetch DMs: TypeError: Cannot read properties of undefined (reading 'id')
92
-
at useChannelStore.ts:13 (Array.map callback)
93
-
at fetchDirectMessages (useChannelStore.ts:12)
94
-
```
95
-
96
-
Additionally, `fetchMessages` is polled against channels the user is **not** a member of, producing a second stream of errors:
97
-
98
-
```
99
-
Failed to fetch messages: ApiError: You must be a member of this channel
100
-
at useMessageStore.ts:57
101
-
```
102
-
103
-
Both errors repeat on every polling interval, flooding the console and wasting CPU.
104
-
105
-
### Root Cause
106
-
-`fetchDirectMessages` maps over an API response that can contain `undefined` entries without a null-guard.
107
-
- The channel polling loop iterates over **all visible channels** rather than only the channels the user has joined, causing 403 responses for private/unjoined channels.
108
-
109
-
---
110
-
111
-
## Bug #4 — Leave channel has no UI entry point
112
-
113
-
**Severity:** High
114
-
**Feature:** Leave Channel
115
-
116
-
### Steps to Reproduce
117
-
1. Log in and join any channel
118
-
2. Try to find a "Leave channel" option in the UI — check the channel header dropdown (`˅`), the `⋮` menu, hover actions, right-click on the channel name, etc.
119
-
120
-
### Expected
121
-
A "Leave channel" option accessible from somewhere in the channel UI.
122
-
123
-
### Actual
124
-
No UI element exists anywhere. The feature is completely missing from the interface.
125
-
126
-
### Note
127
-
The backend endpoint `POST /channels/:id/leave` is fully implemented, and the frontend API wrapper `leaveChannel(id)` exists in `src/lib/api.ts` — but **no component calls it**. The plumbing is there; only the UI trigger is missing.
128
-
129
-
---
130
-
131
-
## Bug #5 — Thread reply input ignores the Enter key
132
-
133
-
**Severity:** Low
134
-
**Feature:** Threads
135
-
136
-
### Steps to Reproduce
137
-
1. Click "N replies" on any message to open the Thread panel
138
-
2. Click the reply input field and type a message
139
-
3. Press Enter
140
-
141
-
### Expected
142
-
The reply is sent (consistent with the main message box, which displays the hint "Enter to send, Shift + Enter for new line").
143
-
144
-
### Actual
145
-
Nothing happens on Enter. The user must click the blue send button manually.
146
-
147
-
### Note
148
-
This is a minor inconsistency between the thread reply input (plain `<input>`) and the main Quill-based rich-text editor. The main editor correctly handles Enter-to-send.
149
-
150
-
---
151
-
152
-
## Bug #6 — File attachment disappears without sending a message
153
-
154
-
**Severity:** High
155
-
**Feature:** File Upload
156
-
157
-
### Steps to Reproduce
158
-
1. In any channel, click the `+` button in the message composer
159
-
2. Select a file — it appears as a badge in the composer (e.g. `qa-test.png ×`)
160
-
3. Click the send button
161
-
162
-
### Expected
163
-
A message containing the file attachment appears in the channel.
164
-
165
-
### Actual
166
-
The file is uploaded to the server (`POST /files` returns `201 Created`) and the attachment badge disappears from the composer, but **no message is ever created**. `POST /channels/:id/messages` is never called after the file upload completes.
167
-
168
-
### Root Cause
169
-
The `handleFileSelect` in `MessageInput.tsx` uploads the file immediately on selection and stores the result in `pendingFiles` state. However, the send action does not appear to include `pendingFiles` in the message payload, so the uploaded file ID is silently discarded on send.
47
+
`api.ts` derives `isEdited` by comparing `updatedAt` vs `createdAt`. The backend should either use a separate `editedAt` field set only on content edits, or the pin operation should preserve the existing `updatedAt`.
170
48
171
49
---
172
50
@@ -186,7 +64,7 @@ A panel or filtered view listing files shared in the channel — similar to how
186
64
Clicking "Files" has no visible effect. The main message view is unchanged and no files panel appears.
187
65
188
66
### Note
189
-
The "Pins" tab works correctly and opens a right-side panel. The "Files" tab appears to be a stub with no implementation behind it.
67
+
The "Pins" tab works correctly and opens a right-side panel. The "Files" tab only sets `activeTab` state in `MessageHeader.tsx`with no `onToggleFiles` prop or panel component behind it.
190
68
191
69
---
192
70
@@ -219,110 +97,15 @@ The feature is 0% implemented on the frontend side.
219
97
220
98
---
221
99
222
-
## Bug #9 — Pinned message has no visual background highlight
223
-
224
-
**Severity:** Low
225
-
**Feature:** Pinned Messages
226
-
227
-
### Steps to Reproduce
228
-
1. Pin any message in a channel
229
-
2. View the message in the channel feed
230
-
231
-
### Expected
232
-
The background of a pinned message row should be a light amber/orange (`#FEF9ED`) to visually distinguish it from regular messages.
233
-
234
-
### Actual
235
-
Pinned messages render with the same white background as all other messages. The only pinned indicator is the small orange pin icon/label, which can be easy to miss.
236
-
237
-
### Root Cause
238
-
`Message.tsx` applies a fixed `hover:bg-[#F8F8F8]` class but never conditionally applies a pinned background. The `message.isPinned` flag is available; it just isn't used for background styling.
239
-
240
-
---
241
-
242
-
## Bug #10 — Video call button in message composer should be removed
243
-
244
-
**Severity:** Low
245
-
**Feature:** Message Input
246
-
247
-
### Steps to Reproduce
248
-
1. Open any channel
249
-
2. Look at the bottom toolbar of the message composer
250
-
251
-
### Expected
252
-
Only controls that have working functionality should appear. Video calls are not supported.
253
-
254
-
### Actual
255
-
A video-camera icon (`Video` from `lucide-react`) is rendered in the composer toolbar. Clicking it does nothing. It creates a misleading affordance.
256
-
257
-
### Root Cause
258
-
`MessageInput.tsx` imports and renders a `<Video>` icon button that has no `onClick` handler and no underlying feature.
259
-
260
-
---
261
-
262
-
## Bug #11 — Reaction emoji glyphs render too small inside the pill
263
-
264
-
**Severity:** Medium
265
-
**Feature:** Reactions
266
-
267
-
### Steps to Reproduce
268
-
1. Add any emoji reaction to a message
269
-
2. Observe the reaction pill/badge
270
-
271
-
### Expected
272
-
The emoji character and its accompanying count number are comfortably legible — at least `16px` for the glyph and consistent sizing for the count.
273
-
274
-
### Actual
275
-
The emoji `<span>` is constrained to a `w-4 h-4` (16 px) box, which clips or compresses many multi-codepoint emoji. The count number is rendered at `text-[12px]`, making the whole badge feel tiny. Both should be visually larger while the oval pill container itself can stay the same proportions.
276
-
277
-
### Root Cause
278
-
In `MessageReactions.tsx`, the emoji span has `w-4 h-4 flex items-center justify-center` with no explicit `font-size`, and the count uses `font-normal` at the container's default `text-[12px]`.
279
-
280
-
---
281
-
282
-
## Bug #12 — Channel star/favorite button has no effect
283
-
284
-
**Severity:** High
285
-
**Feature:** Channel Navigation
286
-
287
-
### Steps to Reproduce
288
-
1. Open any channel
289
-
2. Click the ☆ star icon next to the channel name in the header
290
-
3. Navigate away and back, or look at the sidebar
291
-
292
-
### Expected
293
-
- Clicking the star toggles a "starred/favorited" state for that channel.
294
-
- The star icon fills in (★) to confirm the toggle.
295
-
- A **Starred** section appears at the top of the channel list in the sidebar listing all starred channels.
296
-
- The state persists across navigation (stored in `localStorage` or the backend).
297
-
298
-
### Actual
299
-
Clicking the star does nothing. No visual feedback, no state change, no sidebar section.
300
-
301
-
### Root Cause
302
-
`MessageHeader.tsx` renders the `<Star>` icon button with no `onClick` handler and no state. The channel store has no `isStarred` field and no `toggleStar` action.
303
-
304
-
---
305
-
306
100
## Summary
307
101
308
102
| Severity | Count | Bugs |
309
103
|----------|-------|------|
310
-
| Critical | 1 |#3|
311
-
| High | 5 |#2, #4, #6, #8, #12|
312
-
| Medium | 3 |#1, #7, #11|
313
-
| Low | 3 |#5, #9, #10|
314
-
|**Total**|**12**||
315
-
316
-
### Recommended Fix Priority
317
-
1.**Bug #3** (Critical) — Fix the null-guard crash and the over-broad polling; this generates hundreds of errors per session.
318
-
2.**Bug #8** (High) — Add `typing:start`/`typing:stop` emit in `MessageInput.tsx` and a listener + UI indicator.
319
-
3.**Bug #6** (High) — Ensure `pendingFiles` IDs are included in the `sendMessage` payload.
320
-
4.**Bug #4** (High) — Wire the existing `leaveChannel()` API call to a UI element (e.g. channel header `⋮` menu).
321
-
5.**Bug #12** (High) — Implement star/favorite toggle with a Starred section in the sidebar.
322
-
6.**Bug #2** (High) — Add a shortcode → Unicode emoji mapping in the reaction display component.
323
-
7.**Bug #7** (Medium) — Implement the Files side panel (similar to Pins panel).
324
-
8.**Bug #11** (Medium) — Make reaction emoji glyphs and count numbers larger inside the pill.
325
-
9.**Bug #1** (Medium) — Use a dedicated `editedAt` field (set only on content edits) instead of `updatedAt`.
326
-
10.**Bug #5** (Low) — Add Enter-to-send handling to the thread reply input.
0 commit comments