webui v149: selecting a contact in People opened a distant chat tunnel

The right pane keeps its last tab in State.activeTab, and that state is global
rather than per contact. So the list item handler ends on "if the chat tab is
the one showing, connect" -- which is never true on a fresh page, and always
true afterwards. Once a conversation has been opened, every later click in the
contact list requests a GXS tunnel toward whoever was just selected: a network
action the other side sees, from a click that only meant "show me this profile".

Selecting somebody now shows their profile, and the tunnel waits for the Chat
Conversation tab. The three places that do mean it -- the tab itself, the Start
Chat button, the Chats list and its context menu -- are untouched.

The mirror case was broken the other way round. "Start private chat" from a chat
room calls setSelectedId(id, 'chat'), which preselects the chat tab on a page
that is not mounted yet; nothing ever opened the tunnel there, so the pane sat
on its Connecting spinner for good. That intent is explicit, so it is now
remembered and honoured once the own identities are loaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
jolavillette 2026-08-18 09:03:23 +02:00
parent ee3836cfab
commit 6f2b72c3f1
4 changed files with 25 additions and 6 deletions

View File

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

View File

@ -41,7 +41,19 @@ const PeopleLayout = () => {
m.redraw();
});
loadGxsIdentities();
loadOwnGxsIds().then(() => preloadAllChatHistory());
loadOwnGxsIds().then(() => {
preloadAllChatHistory();
// "Start private chat" from a chat room routes here with the chat tab
// preselected, but nothing ever opened the tunnel: the pane sat on its
// Connecting spinner for good. That intent is explicit, so it is
// honoured -- once the own identities needed to open a tunnel are in.
if (State.pendingChatOpen && State.pendingChatOpen === State.selectedId) {
State.pendingChatOpen = null;
initializeDistantChat();
} else {
State.pendingChatOpen = null;
}
});
stopWatchingOwnIds = peopleUtil.watchOwnIds((ids) => {
State.ownGxsIds = ids || [];
if (!peopleUtil.isUsableIdentityId(State.selectedId)) {
@ -184,6 +196,7 @@ PeopleLayout.setSelectedId = (id, activeTab = 'details', showCompose = false) =>
State.activeFilter = filter;
State.selectedId = id;
State.activeTab = activeTab;
State.pendingChatOpen = activeTab === 'chat' ? id : null;
State.mobilePane = 'detail';
if (showCompose) {
State.showMailCompose = true;

View File

@ -281,9 +281,14 @@ const PeopleSidebar = () => {
State.chatPid = null;
State.chatMessages = [];
stopStatusPolling();
if (State.activeTab === 'chat') {
initializeDistantChat();
}
// Selecting somebody is not asking to talk to them.
// The chat tab is sticky, so inheriting it here meant
// that once a conversation had been opened, every
// later click in the list silently requested a GXS
// tunnel toward the contact -- an action the peer
// sees. Show the profile; the tunnel waits for the
// Chat Conversation tab.
State.activeTab = 'details';
}
m.redraw();
},

View File

@ -28,6 +28,7 @@ const State = {
historySearchQuery: '',
fullHistoryMessages: [],
isHistoryLoading: false,
pendingChatOpen: null, // gxsId a chat was explicitly asked for from another page
};
function getDistantChatSession(gxsId) {