Compare commits

..
Author SHA1 Message Date
Lotus CIandClaude Opus 5.5 33cc0de97c fix(calls): the call PiP no longer opens on top of the composer (#323)
CI / Build & Quality Checks (pull_request) Successful in 3m22s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 15s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m4s
The first-use PiP position was bottom-right, 72px from the bottom: on
desktop over Send, on phones over Send, Emoji and the message box, so
the first thing you typed or tapped in the text room hit the call.
Default to top-right under the room header instead. A dragged position
is still remembered.

Refs #323

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 20:47:34 -04:00
jared 906a034e26 Merge pull request 'fix(calls): starting a call in a voice channel no longer @room-pings everyone (#295)' (#378) from fix/voice-room-no-room-ping into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 20:38:37 -04:00
jared b855eb505d Merge pull request 'fix(reactions): the reactions row no longer flickers or loses its spacing (#305)' (#377) from fix/reactions-collapse-loop into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 20:07:27 -04:00
jared cc8e7444f6 Merge pull request 'fix(rooms): members can start and join calls in new private rooms (#328)' (#376) from fix/group-call-permission into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 19:54:43 -04:00
Lotus CIandClaude Opus 5.5 d7ea408fd0 chore(call): pin element-call-embedded 0.25.0-lotus.23 (sendNotificationType=none, #295)
CI / Build & Quality Checks (pull_request) Successful in 2m48s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 10s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m7s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 18:42:52 -04:00
Lotus CI d3f01b5116 Merge remote-tracking branch 'origin/lotus' into fix/voice-room-no-room-ping 2026-10-17 18:40:48 -04:00
jared f84c0d6e9e Merge pull request 'fix(dialogs): Enter in Poll, Schedule, Report dialogs no longer discards input (#315)' (#369) from fix/dialog-enter-closes into lotus
CI / Build & Quality Checks (push) Successful in 3m14s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 17s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
2026-10-17 18:35:54 -04:00
Lotus CIandClaude Opus 5.5 a6c7333ea3 fix(rooms): members can start and join calls in new private rooms (#328)
CI / Build & Quality Checks (pull_request) Successful in 2m58s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 14m30s
createRoom granted org.matrix.msc3401.call.member at user level only for
voice rooms. Every other room fell back to Synapse's state_default (50),
so in a private group room (where Lotus shows the call button and rings)
only admins could start a call; members saw "1 Live · Join" and then
"You don't have permission to join!". All new non-space rooms now get
call.member: 0 (spaces keep their own override).

Verified headless through Create Room → Private: before, no call.member
entry (state_default 50); now 0. Existing rooms are unchanged; an admin
can set it in room permissions.

Fixes #328

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-17 18:09:33 -04:00
jared f0b7400d1b Merge branch 'lotus' into fix/dialog-enter-closes
CI / Build & Quality Checks (pull_request) Successful in 3m12s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 14s
CI / Playwright smoke (e2e) (pull_request) Successful in 13m57s
2026-10-17 17:53:08 -04:00
Lotus CIandClaude Opus 5.5 a86947be48 fix(calls): starting a call in a voice channel no longer @room-pings everyone (#295)
CallEmbed asked Element Call to send a call-start notification for every
non-DM call. In persistent voice channels and space rooms it carries an
@room mention: every member got a highlighted ping (and phone push)
whenever a moderator or admin joined first, and other clients showed it
as a missed call. Now only rooms that can ring (isRingableRoom: DMs and
invite-only groups outside a space) get ring/notification; everything
else passes sendNotificationType=none (element-call-embedded 0.25.0-lotus.23).

Verified with a local build of the fork: an admin joining the Voice Lounge
sends none, and Bob gets no new notification (before: +1 highlighted).

Fixes #295

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-16 22:08:22 -04:00
Lotus CIandClaude Opus 5.5 b6f9af3f58 fix(dialogs): Enter in Poll, Schedule, Report dialogs no longer discards input (#315)
CI / Build & Quality Checks (pull_request) Successful in 3m58s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 11s
CI / Playwright smoke (e2e) (pull_request) Failing after 18m27s
Several dialogs are <Box as="form"> with the header ✕ (folds IconButton,
no type attribute, so a submit button) as the form's first button. On
implicit submission, Enter in a text field "clicked" ✕, closing the dialog
and throwing away what was typed (a poll's question and answers, a
schedule, a report reason).

The header close/cancel IconButtons now have type="button": Create Poll,
Schedule Message, Report User, Report Room, Account Data editor, State
Event editor, device verification setup, and the message delete/report
dialogs.

Verified headless: in Create Poll, typing a question and pressing Enter
used to close the dialog; now it stays open with the question kept.

Fixes #315

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-16 21:58:05 -04:00
13 changed files with 51 additions and 20 deletions
+4 -4
View File
@@ -81,7 +81,7 @@
},
"devDependencies": {
"@axe-core/playwright": "4.13.0",
"@lotusguild/element-call-embedded": "0.25.0-lotus.22",
"@lotusguild/element-call-embedded": "0.25.0-lotus.23",
"@playwright/test": "1.63.0",
"@rollup/plugin-inject": "5.0.5",
"@rollup/plugin-wasm": "6.2.2",
@@ -2695,9 +2695,9 @@
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
},
"node_modules/@lotusguild/element-call-embedded": {
"version": "0.25.0-lotus.22",
"resolved": "https://code.lotusguild.org/api/packages/LotusGuild/npm/%40lotusguild%2Felement-call-embedded/-/0.25.0-lotus.22/element-call-embedded-0.25.0-lotus.22.tgz",
"integrity": "sha512-AimDKZA4xUKEEyl2XUFUSUDl03tBKFv88T/3igKyH2VqNSPMGnqcQJC5HXIkHLTWrOmg8kLcJ//FFbqlUZiLcA==",
"version": "0.25.0-lotus.23",
"resolved": "https://code.lotusguild.org/api/packages/LotusGuild/npm/%40lotusguild%2Felement-call-embedded/-/0.25.0-lotus.23/element-call-embedded-0.25.0-lotus.23.tgz",
"integrity": "sha512-vRmcWeJcU0Accyl2x3mqNEzrIe8djE5BekyYbYOSCsMflC98rZgD1mO7KOe7bA1cX7gparRf6sAt1fotHoU+bA==",
"dev": true
},
"node_modules/@matrix-org/matrix-sdk-crypto-wasm": {
+1 -1
View File
@@ -108,7 +108,7 @@
},
"devDependencies": {
"@axe-core/playwright": "4.13.0",
"@lotusguild/element-call-embedded": "0.25.0-lotus.22",
"@lotusguild/element-call-embedded": "0.25.0-lotus.23",
"@playwright/test": "1.63.0",
"@rollup/plugin-inject": "5.0.5",
"@rollup/plugin-wasm": "6.2.2",
+1 -1
View File
@@ -297,7 +297,7 @@ export function AccountDataEditor({
</Chip>
</Box>
<Box shrink="No">
<IconButton onClick={requestClose} variant="Surface" aria-label="Close">
<IconButton type="button" onClick={requestClose} variant="Surface" aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Box>
+7 -2
View File
@@ -89,6 +89,8 @@ import { zIndices } from '../styles/zIndex';
const PIP_MIN_W = 200;
const PIP_MIN_H = 112;
/** Default PiP top: just below the 64px-ish room header. */
const PIP_DEFAULT_TOP = 72;
type Corner = 'se' | 'sw' | 'ne' | 'nw';
@@ -1046,8 +1048,11 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
el.style.left = `${Math.max(0, Math.min(savedPos.left, window.innerWidth - 280))}px`;
el.style.top = `${Math.max(0, Math.min(savedPos.top, window.innerHeight - 158))}px`;
} else {
el.style.left = `${window.innerWidth - 280 - 16}px`;
el.style.top = `${window.innerHeight - 158 - 72}px`;
// [Gitea #323] First use: top-right under the room header, over the
// timeline. Bottom-right sat on the composer (Send / Emoji, and on
// phones the whole message box), so typing landed on the call.
el.style.left = `${Math.max(0, window.innerWidth - 280 - 16)}px`;
el.style.top = `${PIP_DEFAULT_TOP}px`;
}
el.style.width = '280px';
el.style.height = '158px';
@@ -315,7 +315,7 @@ export const DeviceVerificationSetup = forwardRef<HTMLDivElement, DeviceVerifica
Setup Device Verification
</Text>
</Box>
<IconButton size="300" radii="300" onClick={onCancel} aria-label="Cancel">
<IconButton type="button" size="300" radii="300" onClick={onCancel} aria-label="Cancel">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
@@ -361,7 +361,7 @@ export const DeviceVerificationReset = forwardRef<HTMLDivElement, DeviceVerifica
Reset Device Verification
</Text>
</Box>
<IconButton size="300" radii="300" onClick={onCancel} aria-label="Cancel">
<IconButton type="button" size="300" radii="300" onClick={onCancel} aria-label="Cancel">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+5 -2
View File
@@ -139,8 +139,11 @@ export const createRoom = async (mx: MatrixClient, data: CreateRoomData): Promis
data.allowFederation,
data.additionalCreators,
),
power_level_content_override:
data.type === RoomType.Call ? createVoiceRoomPowerLevelsOverride() : undefined,
// [Gitea #328] Every non-space room gets call.member at user level, not just
// voice rooms: the call button is shown in private group rooms too, and with
// Synapse's state_default (50) only admins could start or join a call there
// ("You don't have permission to join!").
power_level_content_override: createVoiceRoomPowerLevelsOverride(),
initial_state: initialState,
};
@@ -275,7 +275,7 @@ export function StateEventEditor({ type, stateKey, requestClose }: StateEventEdi
</Chip>
</Box>
<Box shrink="No">
<IconButton onClick={requestClose} variant="Surface" aria-label="Close">
<IconButton type="button" onClick={requestClose} variant="Surface" aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Box>
+1 -1
View File
@@ -143,7 +143,7 @@ export function PollCreator({ roomId, threadRootId, onClose }: PollCreatorProps)
Create Poll
</Text>
</Box>
<IconButton size="300" radii="300" onClick={onClose} aria-label="Close">
<IconButton type="button" size="300" radii="300" onClick={onClose} aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+1 -1
View File
@@ -118,7 +118,7 @@ export function ReportRoomModal({ roomId, onClose }: ReportRoomModalProps) {
Report Room
</Text>
</Box>
<IconButton size="300" onClick={onClose} radii="300" aria-label="Close">
<IconButton type="button" size="300" onClick={onClose} radii="300" aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+1 -1
View File
@@ -124,7 +124,7 @@ export function ReportUserModal({ userId, onClose }: ReportUserModalProps) {
Report User
</Text>
</Box>
<IconButton size="300" onClick={onClose} radii="300" aria-label="Close">
<IconButton type="button" size="300" onClick={onClose} radii="300" aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
@@ -202,7 +202,7 @@ export function ScheduleMessageModal({
{title}
</Text>
</Box>
<IconButton size="300" radii="300" onClick={onClose} aria-label="Close">
<IconButton type="button" size="300" radii="300" onClick={onClose} aria-label="Close">
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+14 -2
View File
@@ -725,7 +725,13 @@ export const MessageDeleteItem = as<
Delete Message
</Text>
</Box>
<IconButton size="300" onClick={handleClose} radii="300" aria-label="Close">
<IconButton
type="button"
size="300"
onClick={handleClose}
radii="300"
aria-label="Close"
>
<Icon src={Icons.Cross} />
</IconButton>
</Header>
@@ -865,7 +871,13 @@ export const MessageReportItem = as<
Report Message
</Text>
</Box>
<IconButton size="300" onClick={handleClose} radii="300" aria-label="Close">
<IconButton
type="button"
size="300"
onClick={handleClose}
radii="300"
aria-label="Close"
>
<Icon src={Icons.Cross} />
</IconButton>
</Header>
+12 -1
View File
@@ -31,6 +31,7 @@ import { verifyDenoiseAssets } from './denoiseSmokeCheck';
import { canDelegateCapability } from './utils';
import { getCallPageUrl } from './callPageUrl';
import { restrictWidgetMessages } from '../widgetTransport';
import { isRingableRoom } from '../../utils/callRing';
// Maximum time to wait for the embedded Element Call iframe to progress from
// initial load to a ready/joined state. If it hasn't by then, we assume the
@@ -251,8 +252,18 @@ export class CallEmbed {
verifyDenoiseAssets(denoiseModel).catch(() => undefined);
}
// [Gitea #295] Only ask Element Call to notify where a call can ring at all
// (DMs, invite-only groups outside a space). In a voice channel or space
// room the notification carries an @room mention, so every member got a
// highlighted ping (and phone push) whenever a moderator hopped in, and
// other clients showed it as a missed call.
// `none` needs element-call-embedded ≥ 0.25.0-lotus.23 (older builds ignore it).
if (CallEmbed.startingCall(intent)) {
params.append('sendNotificationType', CallEmbed.dmCall(intent) ? 'ring' : 'notification');
let notify = 'none';
if (isRingableRoom(room, CallEmbed.dmCall(intent))) {
notify = CallEmbed.dmCall(intent) ? 'ring' : 'notification';
}
params.append('sendNotificationType', notify);
}
// [Gitea #43] On its own origin when config.json sets elementCallUrl.