diff --git a/src/web/public/session-ui.js b/src/web/public/session-ui.js index a5036056..e8e84dc3 100644 --- a/src/web/public/session-ui.js +++ b/src/web/public/session-ui.js @@ -2936,6 +2936,7 @@ Object.assign(CodemanApp.prototype, { // A rename still in flight is the user's last word, not the name the // server has yet to replace: start from it, and compare against it below. const shownName = this._inlineRenamePending?.get(sessionId) ?? session.name; + const renameInFlight = shownName !== session.name; const parsed = parseSessionPrefix(shownName); const originalContent = tabName.textContent; const originalChildren = [...tabName.childNodes].map((node) => node.cloneNode(true)); @@ -3017,7 +3018,10 @@ Object.assign(CodemanApp.prototype, { const suffix = input.value.trim(); const fullName = parsed ? parsed.prefix + (suffix ? ': ' + suffix : '') : suffix; - if (fullName === shownName) restoreOriginalChildren(); + // An unchanged confirm puts the old label back, unless the editor opened + // over a rename in flight: that label was repainted from the server's + // older name, so show the in-flight name rather than make it look lost. + if (fullName === shownName && !renameInFlight) restoreOriginalChildren(); else tabName.textContent = fullName || originalContent; // Skip the API call if the session vanished between focus and blur. The diff --git a/test/inline-rename.test.ts b/test/inline-rename.test.ts index e851f310..aa8c7c17 100644 --- a/test/inline-rename.test.ts +++ b/test/inline-rename.test.ts @@ -828,6 +828,26 @@ describe('Inline rename write ordering', () => { ).toBe(false); }); + it('shows the in-flight name when a reopened editor is confirmed unchanged, before the PUT lands', async () => { + await mount('shown', 'Old'); + await commit('shown', 'First'); + // Reopen while the PUT for "First" is held, then confirm it untouched. The + // label must read "First" now, not the "Old" the cancelled editor + // repainted from app.sessions. + await page.evaluate(() => + (window as unknown as { app: { startInlineRename: (id: string) => void } }).app.startInlineRename('shown') + ); + await commit('shown', null); + const label = await page.evaluate( + () => (document.querySelector('.tab-name[data-session-id="shown"]') as HTMLElement).textContent + ); + expect((await state('shown')).bodies).toEqual(['First']); + expect(label).toBe('First'); + await answer(0, 'First'); + await restoreFetch(); + expect(await state('shown')).toEqual({ bodies: ['First'], mapName: 'First', renameActive: false }); + }); + it('reports a failed write even after its editor is gone', async () => { await mount('fail-late', 'Old'); await page.evaluate(() => {