fix: CI Prettier, P1-6 poll button, P1-11 stale knock state
CI / Build & Quality Checks (push) Successful in 10m33s

- LOTUS_TODO.md: Prettier formatting (CI gate fix)
- P1-6: Wire PollCreator into RoomInput — poll button (Icons.OrderList)
  opens modal, renders PollCreator when pollOpen is true
- P1-11: Reset knocked + knockError on room.roomId change via useEffect;
  add missing useEffect import to RoomIntro.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 00:14:55 -04:00
parent 82840dc4e2
commit 42422bbe61
3 changed files with 32 additions and 14 deletions
+13 -13
View File
@@ -57,7 +57,7 @@ Status: `[ ]` pending · `[~]` in progress · `[x]` completed
| Image + video spoilers (blur/reveal) | `ImageContent.tsx`, `VideoContent.tsx` | #105 — smooth CSS transition | | Image + video spoilers (blur/reveal) | `ImageContent.tsx`, `VideoContent.tsx` | #105 — smooth CSS transition |
| Report message per event | `Message.tsx:588-709``mx.reportEvent()` | #106 — add category selector | | Report message per event | `Message.tsx:588-709``mx.reportEvent()` | #106 — add category selector |
| Drag-and-drop file upload | `useFileDrop.ts` — works but overlay bug | #73 — fix overlay dismiss | | Drag-and-drop file upload | `useFileDrop.ts` — works but overlay bug | #73 — fix overlay dismiss |
| Typing indicator (animated dots) | `TypingIndicator.tsx`, `TypingIndicator.css.ts` | #108 — TDS orange dots ✅ June 2026 | | Typing indicator (animated dots) | `TypingIndicator.tsx`, `TypingIndicator.css.ts` | #108 — TDS orange dots ✅ June 2026 |
| Pinned messages count badge | Confirmed in upstream header icon | None needed | | Pinned messages count badge | Confirmed in upstream header icon | None needed |
### Upstream Cinny Features Confirmed MISSING (we should build these) ### Upstream Cinny Features Confirmed MISSING (we should build these)
@@ -93,7 +93,7 @@ DM last-message preview, Media gallery, Knock-to-join full UX
| URL preview defaults: `urlPreview: true`, `encUrlPreview: false` | Task #49: DONE — default changed + Warning chip | | URL preview defaults: `urlPreview: true`, `encUrlPreview: false` | Task #49: DONE — default changed + Warning chip |
| Private read receipts: `ReceiptType.ReadPrivate` + `markAsRead()` param exist | Task #34: trivially simple | | Private read receipts: `ReceiptType.ReadPrivate` + `markAsRead()` param exist | Task #34: trivially simple |
| Relations API at `/_matrix/client/v1/` NOT v3 | EditHistoryModal uses raw fetch with explicit v1 path | | Relations API at `/_matrix/client/v1/` NOT v3 | EditHistoryModal uses raw fetch with explicit v1 path |
| `mx.getContent()` returns post-edit content after SDK applies replacements | EditHistoryModal uses `mEvent.event.content` for the "Original" entry | | `mx.getContent()` returns post-edit content after SDK applies replacements | EditHistoryModal uses `mEvent.event.content` for the "Original" entry |
| GIF CSP: `connect-src` on LXC 106 must include `https://*.giphy.com` | Fixed in nginx — live, no deploy needed | | GIF CSP: `connect-src` on LXC 106 must include `https://*.giphy.com` | Fixed in nginx — live, no deploy needed |
| `getLocalRoomNamesContent` is now `export`ed from `useRoomMeta.ts` | Used by `RoomNavItem` to avoid duplicating the parse logic | | `getLocalRoomNamesContent` is now `export`ed from `useRoomMeta.ts` | Used by `RoomNavItem` to avoid duplicating the parse logic |
| Right-click room menu: 6 items in `RoomNavItem.tsx:70-220` | Task #102: add Mute-duration submenu via `PopOut` | | Right-click room menu: 6 items in `RoomNavItem.tsx:70-220` | Task #102: add Mute-duration submenu via `PopOut` |
@@ -211,9 +211,9 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
- "Homeserver admin: @jared:matrix.lotusguild.org" - "Homeserver admin: @jared:matrix.lotusguild.org"
- Link to support page if present - Link to support page if present
Cache the response in component state; no repeated fetches. Cache the response in component state; no repeated fetches.
**Where:** `src/app/features/settings/` Help/About panel. **Where:** `src/app/features/settings/` Help/About panel.
**Complexity:** Low — one fetch, display result. **Complexity:** Low — one fetch, display result.
**COMPLETED June 2026.** Fetches `/.well-known/matrix/support` via `mx.getHomeserverUrl()`. AbortController cleanup. JSON type guard. Loading state. Clickable `matrix_id``matrix.to` link; `email_address``mailto:` link (both rendered when both present). `formatRole()` handles all role strings. **Server-side:** CORS `Access-Control-Allow-Origin: *` added to LXC 139 (NPM) for `/.well-known/matrix/support`. Static JSON response configured: `@jared:matrix.lotusguild.org` (admin), support_page `https://matrix.lotusguild.org`. **COMPLETED June 2026.** Fetches `/.well-known/matrix/support` via `mx.getHomeserverUrl()`. AbortController cleanup. JSON type guard. Loading state. Clickable `matrix_id``matrix.to` link; `email_address``mailto:` link (both rendered when both present). `formatRole()` handles all role strings. **Server-side:** CORS `Access-Control-Allow-Origin: *` added to LXC 139 (NPM) for `/.well-known/matrix/support`. Static JSON response configured: `@jared:matrix.lotusguild.org` (admin), support_page `https://matrix.lotusguild.org`.
--- ---
@@ -226,9 +226,9 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
- A distinct "Server Notice" header badge (server icon + label) in `RoomViewHeader.tsx` - A distinct "Server Notice" header badge (server icon + label) in `RoomViewHeader.tsx`
- Slightly different background color (use `color.Warning` or neutral surface) - Slightly different background color (use `color.Warning` or neutral surface)
- Composer hidden/disabled in server notice rooms (check room type in `RoomInput.tsx`) - Composer hidden/disabled in server notice rooms (check room type in `RoomInput.tsx`)
**Where:** `src/app/features/room/RoomViewHeader.tsx` (badge), `src/app/features/room/RoomInput.tsx` (hide composer when `room.getType() === 'm.server_notice'`). **Where:** `src/app/features/room/RoomViewHeader.tsx` (badge), `src/app/features/room/RoomInput.tsx` (hide composer when `room.getType() === 'm.server_notice'`).
**Complexity:** Low. **Complexity:** Low.
**COMPLETED June 2026.** "Server Notice" `Chip variant="Warning"` in room header with tooltip. Read-only composer replaced by informational `Box` message. Invite, Room Settings, and Report Room menu items hidden for server-notice rooms (both header three-dot menu and sidebar context menu). Distinct `Icons.Warning` icon for server-notice rooms in `getRoomIconSrc()`. Detection via `room.getType() === 'm.server_notice'` (type-based, not name-based). **COMPLETED June 2026.** "Server Notice" `Chip variant="Warning"` in room header with tooltip. Read-only composer replaced by informational `Box` message. Invite, Room Settings, and Report Room menu items hidden for server-notice rooms (both header three-dot menu and sidebar context menu). Distinct `Icons.Warning` icon for server-notice rooms in `getRoomIconSrc()`. Detection via `room.getType() === 'm.server_notice'` (type-based, not name-based).
--- ---
@@ -302,10 +302,10 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
1. Composer correctly wraps text in `<span data-mx-spoiler>` in `formatted_body` 1. Composer correctly wraps text in `<span data-mx-spoiler>` in `formatted_body`
2. Timeline renderer displays spoiler as blurred/hidden text with a "Reveal" click 2. Timeline renderer displays spoiler as blurred/hidden text with a "Reveal" click
3. Mobile touch works for reveal 3. Mobile touch works for reveal
If any step is broken, fix it. If all working correctly, close this task with no changes. If any step is broken, fix it. If all working correctly, close this task with no changes.
**[AUDIT REQUIRED]** — Full code audit of spoiler mark in toolbar → event content → timeline renderer. **[AUDIT REQUIRED]** — Full code audit of spoiler mark in toolbar → event content → timeline renderer.
**Complexity:** Low (audit) — fix complexity TBD. **Complexity:** Low (audit) — fix complexity TBD.
**COMPLETED June 2026 — NO CHANGES NEEDED.** Full audit confirmed: spoiler composing (`data-md` + `data-mx-spoiler` in `markdown/inline/rules.ts:99`), MSC4193 stable property name at `types/matrix/common.ts:5`, rendering in `react-custom-html-parser.tsx:461`, image/video spoiler support in `ImageContent.tsx` and `VideoContent.tsx`. All working correctly. **COMPLETED June 2026 — NO CHANGES NEEDED.** Full audit confirmed: spoiler composing (`data-md` + `data-mx-spoiler` in `markdown/inline/rules.ts:99`), MSC4193 stable property name at `types/matrix/common.ts:5`, rendering in `react-custom-html-parser.tsx:461`, image/video spoiler support in `ImageContent.tsx` and `VideoContent.tsx`. All working correctly.
--- ---
@@ -317,7 +317,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
> "URL previews in encrypted rooms are fetched by your homeserver, which sees the URL but not the message content." > "URL previews in encrypted rooms are fetched by your homeserver, which sees the URL but not the message content."
> **Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`). > **Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`).
> **Complexity:** Very Low — one default value change + one sentence of UI text. > **Complexity:** Very Low — one default value change + one sentence of UI text.
**COMPLETED June 2026.** `encUrlPreview` default → `true`. Encrypted URL preview setting now shows: description text explaining homeserver sees all URLs + `Chip variant="Warning" fill="Soft"` badge "Privacy risk — enabled by default". Plain `urlPreview` setting also got a description. Both labels corrected to "URL Preview" (was "Url Preview"). > **COMPLETED June 2026.** `encUrlPreview` default → `true`. Encrypted URL preview setting now shows: description text explaining homeserver sees all URLs + `Chip variant="Warning" fill="Soft"` badge "Privacy risk — enabled by default". Plain `urlPreview` setting also got a description. Both labels corrected to "URL Preview" (was "Url Preview").
--- ---
+6 -1
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import FocusTrap from 'focus-trap-react'; import FocusTrap from 'focus-trap-react';
import { import {
Avatar, Avatar,
@@ -46,6 +46,11 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
const [knocked, setKnocked] = useState(false); const [knocked, setKnocked] = useState(false);
const [knockError, setKnockError] = useState<string | undefined>(); const [knockError, setKnockError] = useState<string | undefined>();
useEffect(() => {
setKnocked(false);
setKnockError(undefined);
}, [room.roomId]);
const createEvent = getStateEvent(room, StateEvent.RoomCreate); const createEvent = getStateEvent(room, StateEvent.RoomCreate);
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId)); const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
const name = useLocalRoomName(room); const name = useLocalRoomName(room);
+13
View File
@@ -121,6 +121,7 @@ import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag';
import { usePowerLevelTags } from '../../hooks/usePowerLevelTags'; import { usePowerLevelTags } from '../../hooks/usePowerLevelTags';
import { useComposingCheck } from '../../hooks/useComposingCheck'; import { useComposingCheck } from '../../hooks/useComposingCheck';
import { VoiceMessageRecorder } from '../../components/VoiceMessageRecorder'; import { VoiceMessageRecorder } from '../../components/VoiceMessageRecorder';
import { PollCreator } from './PollCreator';
const GifPicker = React.lazy(() => const GifPicker = React.lazy(() =>
import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })), import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })),
@@ -154,6 +155,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
useEffect(() => { useEffect(() => {
setCharCount(0); setCharCount(0);
}, [roomId]); }, [roomId]);
const [pollOpen, setPollOpen] = useState(false);
const alive = useAlive(); const alive = useAlive();
const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId)); const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId));
@@ -952,6 +954,16 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
<Icon src={Icons.SpaceGlobe} size="100" /> <Icon src={Icons.SpaceGlobe} size="100" />
)} )}
</IconButton> </IconButton>
<IconButton
onClick={() => setPollOpen(true)}
aria-label="Create poll"
variant="SurfaceVariant"
size="300"
radii="300"
title="Create poll"
>
<Icon src={Icons.OrderList} size="100" />
</IconButton>
<VoiceMessageRecorder <VoiceMessageRecorder
onSend={handleVoiceSend} onSend={handleVoiceSend}
onError={(err) => { onError={(err) => {
@@ -995,6 +1007,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
) )
} }
/> />
{pollOpen && <PollCreator room={room} roomId={roomId} onClose={() => setPollOpen(false)} />}
</div> </div>
); );
}, },