Invite into a Matrix room, and stop implying a tick means more than it does
A field rather than a picker, because a Matrix address names a person globally - there is no roster to choose from and nobody to look up first. Offered on every Matrix room rather than gated on permission: the server decides and says so plainly, and guessing here would only hide the action from somebody who could have used it. And the sessions panel now says what verifying actually does. moho does no cross-signing, so a verification is recorded between these two sessions and never published - Element goes on showing the device as unverified. Somebody not told that would reasonably conclude one of the two clients is broken, which is a worse outcome than the missing feature. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+1
-1
Submodule nobilis updated: 78019ca762...1ef66ab532
@@ -6,6 +6,63 @@ import { formatFullTime } from '../lib/util'
|
||||
import type { BufferEntry } from '../state/store'
|
||||
import type { Message } from '../../../shared/wire'
|
||||
|
||||
/**
|
||||
* Asking somebody into a Matrix room.
|
||||
*
|
||||
* A field rather than a picker, because a Matrix address names a person
|
||||
* globally - there is no roster to choose from and nobody to look up first.
|
||||
* Offered on every Matrix room rather than gated on permission: the server
|
||||
* decides, and it says so plainly enough that guessing here would only mean
|
||||
* hiding the action from somebody who could have used it.
|
||||
*/
|
||||
function InviteToRoom({ buffer }: { buffer: BufferEntry }): JSX.Element {
|
||||
const store = useStore()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [who, setWho] = useState('')
|
||||
const [busy, setBusy] = useState(false)
|
||||
|
||||
const invite = (): void => {
|
||||
const userId = who.trim()
|
||||
if (!userId) return
|
||||
setBusy(true)
|
||||
void window.moho
|
||||
.rpc('inviteMatrixMember', { accountId: buffer.accountId, bufferId: buffer.id, userId })
|
||||
.then(() => {
|
||||
store.toast('info', `Invited ${userId}`)
|
||||
setWho('')
|
||||
setOpen(false)
|
||||
})
|
||||
.catch((e: Error) => store.toast('error', e.message))
|
||||
.finally(() => setBusy(false))
|
||||
}
|
||||
|
||||
if (!open) {
|
||||
return <IconButton name="person_add" title="Invite somebody to this room" onClick={() => setOpen(true)} />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="conversation-search">
|
||||
<Icon name="person_add" size={16} />
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
value={who}
|
||||
placeholder="@someone:server"
|
||||
disabled={busy}
|
||||
onChange={(e) => setWho(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
setWho('')
|
||||
setOpen(false)
|
||||
}
|
||||
if (e.key === 'Enter') invite()
|
||||
}}
|
||||
onBlur={() => !who.trim() && setOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* What a channel's restrictions mean, for the ones worth explaining.
|
||||
*
|
||||
@@ -160,6 +217,11 @@ export function ConversationTools({ buffer }: { buffer: BufferEntry }): JSX.Elem
|
||||
the conversation being read rather than on the window. */}
|
||||
{isDiscord && isDm && <AddToConversation buffer={buffer} />}
|
||||
|
||||
{/* The same job on Matrix, where it needs no picker: a Matrix address
|
||||
names somebody whether or not this account has ever met them, so
|
||||
there is no friend list to choose from and nothing to look up. */}
|
||||
{buffer.accountId.startsWith('matrix:') && <InviteToRoom buffer={buffer} />}
|
||||
|
||||
<div className="conversation-search">
|
||||
<Icon name="search" size={16} />
|
||||
<input
|
||||
|
||||
@@ -57,6 +57,16 @@ export function MatrixAccountTools({ account }: { account: Account }): JSX.Eleme
|
||||
<div className="small muted">
|
||||
Your other logged-in devices. Verify one to let encrypted history decrypt across both.
|
||||
</div>
|
||||
{/* Said because the tick is otherwise a promise this cannot keep.
|
||||
moho does no cross-signing, so a verification here is recorded
|
||||
between these two sessions and never published - Element will
|
||||
still show the device as unverified, and somebody who was not
|
||||
told that would reasonably conclude one of the two clients is
|
||||
broken. */}
|
||||
<div className="small muted">
|
||||
Verifying marks a session as trusted <em>in moho</em>. moho does not do cross-signing,
|
||||
so other clients will still show it unverified.
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" className="icon-button" title="Refresh" onClick={refresh}>
|
||||
<Icon name="refresh" size={16} />
|
||||
|
||||
Reference in New Issue
Block a user