Merge pull request #27 from jolavillette/fix/chatroom-invites-for-121

Room invitations: allow declining, and stop reading a field they do not carry
This commit is contained in:
defnax 2026-08-27 20:01:36 +02:00 committed by GitHub
commit de06c5fcae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 80 additions and 6 deletions

View File

@ -1178,6 +1178,10 @@ const ChatRoomJoinView = () => {
if (!room) return null;
const lobbyHexId = rs.idToHex(room.lobby_id);
const isInvitation = ChatRoomsModel.invitationIds.has(lobbyHexId);
// ChatLobbyInvite has no total_number_of_peers -- the field only exists
// on the records the nearby-lobby list returns -- so an invited room
// would always claim it has nobody in it.
const participantCount = room.total_number_of_peers || 0;
const privacy = getLobbyPrivacyInfo(room);
@ -1194,13 +1198,13 @@ const ChatRoomJoinView = () => {
m('.info-label', 'Security'),
m('.info-value', privacy.security),
m('.info-label', 'Participants'),
m('.info-value', participantCount + ' users'),
m('.info-value', isInvitation ? 'Unknown until you join' : participantCount + ' users'),
]),
]),
m('.detail-section', [
m('h3', 'Join Room'),
m('h3', isInvitation ? 'Invitation' : 'Join Room'),
m('p.join-description', 'Select an identity to join this chat room:'),
ChatRoomsModel.joiningLobbyId === lobbyHexId &&
m('p.join-description', [m('i.fas.fa-spinner.fa-spin'), ' Joining…']),
@ -1230,6 +1234,17 @@ const ChatRoomJoinView = () => {
)
)
),
// Without this an invitation can only be accepted: it stays in the
// room list and keeps the Chat badge lit, since invitationCount()
// feeds it and nothing else ever clears the entry.
isInvitation && m(
'button.chat-invite-decline',
{
disabled: ChatRoomsModel.joiningLobbyId === lobbyHexId,
onclick: () => ChatRoomsModel.declineInvitation(lobbyHexId),
},
[m('i.fas.fa-times'), ' Decline invitation']
),
]),
]);
},

View File

@ -428,6 +428,35 @@ const ChatRoomsModel = {
// RsChatLobbyEventCode::CHAT_LOBBY_INVITE_RECEIVED
if (event && Number(event.mEventCode) === 4) this.loadPendingInvitations();
},
// An invitation that is neither accepted nor refused keeps the Chat badge
// lit for good: it is counted by invitationCount() and nothing else clears
// it. denyLobbyInvite() is what the core offers for that.
declineInvitation(lobbyId) {
return rs.rsJsonApiRequest(
'/rsChats/denyLobbyInvite',
{ id: { xstr64: lobbyId } },
(data, success) => {
if (!success || !data || !data.retval) {
this.joinError = 'RetroShare could not decline this invitation.';
m.redraw();
return;
}
this.invitationIds.delete(lobbyId);
// The room came from the invitation, not from the nearby list, so it
// has to go with it -- otherwise it stays as a room with no
// participants that cannot be joined.
this.allRooms = this.allRooms.filter(
(room) => rs.idToHex(room.lobby_id) !== lobbyId
);
if (ChatHubState.selectedRoomId === lobbyId) {
ChatHubState.selectedRoomId = null;
ChatHubState.mobilePane = 'list';
}
this.joinError = '';
m.redraw();
}
);
},
acceptInvitation(lobbyId, identity) {
this.joiningLobbyId = lobbyId;
this.joinError = '';
@ -957,7 +986,8 @@ const ChatLobbyModel = {
const flags = Number(room.lobby_flags || 0);
if ((flags & 0x10) !== 0) {
ChatRoomsModel.joinError = 'This room requires a signed identity. Select a PGP-linked identity.';
} else if (Number(room.total_number_of_peers || 0) === 0) {
} else if (!ChatRoomsModel.invitationIds.has(lobbyId)
&& Number(room.total_number_of_peers || 0) === 0) {
ChatRoomsModel.joinError = 'This room is no longer being advertised by an online participant. Try again when someone in the room is online.';
ChatRoomsModel.loadPublicRooms();
} else {

View File

@ -137,7 +137,7 @@ const navbar = () => {
? 'Connected to RetroShare Core'
: 'Connection Lost',
}),
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v154'),
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v158'),
m('i.fas.fa-sync-alt.refresh-icon', {
style: { cursor: 'pointer', fontSize: '0.8em' },
onclick: () => window.location.reload(true),
@ -260,7 +260,7 @@ const MobileStatus = () => {
m('small', statusbar.formatBytes(state.totalOut)),
]),
]),
m('.mobile-status-sheet__version', 'WebUI v154'),
m('.mobile-status-sheet__version', 'WebUI v158'),
])),
];
},

View File

@ -798,6 +798,35 @@ textarea.chatMsg {
gap: 0.75rem;
}
// Refusing is the secondary action next to the identity cards that accept:
// outlined rather than filled, and full width on a phone like the other
// buttons of these panels.
.chat-invite-decline {
display: inline-flex;
align-items: center;
gap: .5rem;
margin-top: 1rem;
padding: .5rem 1rem;
border: 1px solid #fca5a5;
border-radius: .5rem;
background: #fff;
color: #b91c1c;
font-weight: 600;
cursor: pointer;
&:hover { background: #fef2f2; }
&:disabled {
opacity: .5;
cursor: not-allowed;
}
@media (max-width: 700px) {
width: 100%;
justify-content: center;
}
}
.identity-card {
display: flex;
align-items: center;

File diff suppressed because one or more lines are too long