From 7cf751a3a5578c089c30dd368d58c9abf6404505 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 3 Jun 2026 00:14:55 -0400 Subject: [PATCH] fix: CI Prettier, P1-6 poll button, P1-11 stale knock state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- LOTUS_TODO.md | 26 ++++++++++----------- src/app/components/room-intro/RoomIntro.tsx | 7 +++++- src/app/features/room/RoomInput.tsx | 13 +++++++++++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/LOTUS_TODO.md b/LOTUS_TODO.md index 536f5e959..0be6840ae 100644 --- a/LOTUS_TODO.md +++ b/LOTUS_TODO.md @@ -57,7 +57,7 @@ Status: `[ ]` pending · `[~]` in progress · `[x]` completed | 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 | | 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 | ### 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 | | 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 | -| `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 | | `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` | @@ -211,9 +211,9 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help - "Homeserver admin: @jared:matrix.lotusguild.org" - Link to support page if present Cache the response in component state; no repeated fetches. - **Where:** `src/app/features/settings/` Help/About panel. - **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`. + **Where:** `src/app/features/settings/` Help/About panel. + **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`. --- @@ -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` - Slightly different background color (use `color.Warning` or neutral surface) - 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'`). - **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). + **Where:** `src/app/features/room/RoomViewHeader.tsx` (badge), `src/app/features/room/RoomInput.tsx` (hide composer when `room.getType() === 'm.server_notice'`). + **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). --- @@ -302,10 +302,10 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help 1. Composer correctly wraps text in `` in `formatted_body` 2. Timeline renderer displays spoiler as blurred/hidden text with a "Reveal" click 3. Mobile touch works for reveal - 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. - **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. + 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. + **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. --- @@ -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." > **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. -**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"). --- diff --git a/src/app/components/room-intro/RoomIntro.tsx b/src/app/components/room-intro/RoomIntro.tsx index 7887822cb..b509c3d78 100644 --- a/src/app/components/room-intro/RoomIntro.tsx +++ b/src/app/components/room-intro/RoomIntro.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import FocusTrap from 'focus-trap-react'; import { Avatar, @@ -46,6 +46,11 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) => const [knocked, setKnocked] = useState(false); const [knockError, setKnockError] = useState(); + useEffect(() => { + setKnocked(false); + setKnockError(undefined); + }, [room.roomId]); + const createEvent = getStateEvent(room, StateEvent.RoomCreate); const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId)); const name = useLocalRoomName(room); diff --git a/src/app/features/room/RoomInput.tsx b/src/app/features/room/RoomInput.tsx index a035209b9..142945555 100644 --- a/src/app/features/room/RoomInput.tsx +++ b/src/app/features/room/RoomInput.tsx @@ -121,6 +121,7 @@ import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag'; import { usePowerLevelTags } from '../../hooks/usePowerLevelTags'; import { useComposingCheck } from '../../hooks/useComposingCheck'; import { VoiceMessageRecorder } from '../../components/VoiceMessageRecorder'; +import { PollCreator } from './PollCreator'; const GifPicker = React.lazy(() => import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })), @@ -154,6 +155,7 @@ export const RoomInput = forwardRef( useEffect(() => { setCharCount(0); }, [roomId]); + const [pollOpen, setPollOpen] = useState(false); const alive = useAlive(); const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId)); @@ -952,6 +954,16 @@ export const RoomInput = forwardRef( )} + setPollOpen(true)} + aria-label="Create poll" + variant="SurfaceVariant" + size="300" + radii="300" + title="Create poll" + > + + { @@ -995,6 +1007,7 @@ export const RoomInput = forwardRef( ) } /> + {pollOpen && setPollOpen(false)} />} ); },