From 3ef65d7c7453fb6b5a9bdeb99ba462d1bd079c5d Mon Sep 17 00:00:00 2001 From: Codeman maintainer Date: Fri, 6 Nov 2026 04:02:11 +0100 Subject: [PATCH] fix: let the path picker's error status wrap (release review) The cases-folder refusal grew to 143 characters, and the status line is one line with an ellipsis and no title, so at 513px on desktop it ended at "or make the case with Ad..." and lost the instruction. .path-picker-status.error now wraps: 2 lines on desktop, 4 on a phone, measured clear in Chromium at both, and it covers the picker's other refusals too. Tests: a pin on that rule (fails without the fix), and the option check now reads each picker's whole options object instead of a fixed 400 characters, which stopped short of the container-workdir picker's 829. Retitled to say what it checks: Create New has the flag too. Co-Authored-By: Claude Opus 5.5 --- src/web/public/styles.css | 2 ++ test/path-picker-new-folder.test.ts | 34 +++++++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/web/public/styles.css b/src/web/public/styles.css index 19631492..9cb4a7d7 100644 --- a/src/web/public/styles.css +++ b/src/web/public/styles.css @@ -15977,8 +15977,10 @@ body.touch-device.cjk-input-visible .main { white-space: nowrap; } +/* An ordinary status fits one line; a refusal may not, and it must be readable whole. */ .path-picker-status.error { color: var(--danger, #ef4444); + white-space: normal; } .path-picker-list { diff --git a/test/path-picker-new-folder.test.ts b/test/path-picker-new-folder.test.ts index 3f13f3bf..03436d0d 100644 --- a/test/path-picker-new-folder.test.ts +++ b/test/path-picker-new-folder.test.ts @@ -14,6 +14,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; const PUBLIC = resolve(import.meta.dirname, '../src/web/public'); const accessoryJs = readFileSync(resolve(PUBLIC, 'keyboard-accessory.js'), 'utf8'); const sessionUiJs = readFileSync(resolve(PUBLIC, 'session-ui.js'), 'utf8'); +const stylesCss = readFileSync(resolve(PUBLIC, 'styles.css'), 'utf8'); const dom = new JSDOM('', { url: 'https://localhost/' }); const jsdomWindow = dom.window as unknown as Window & typeof globalThis; @@ -166,22 +167,31 @@ describe('PathPicker New folder', () => { expect(doc.querySelector('.path-picker-overlay')).not.toBeNull(); }); + // A picker's whole options object: a fixed window stops short of the container picker's long one. + const pickerOptions = (name: string) => { + const start = sessionUiJs.indexOf(`${name}() {`); + expect(start, name).toBeGreaterThan(-1); + const open = sessionUiJs.indexOf('PathPicker.open', start); + expect(open, name).toBeGreaterThan(start); + const end = sessionUiJs.indexOf('\n });', open); + expect(end, name).toBeGreaterThan(open); + return sessionUiJs.slice(open, end); + }; + it("is on for Create New's custom folder picker too", () => { - const start = sessionUiJs.indexOf('openNewCasePathPicker() {'); - expect(sessionUiJs.slice(start, sessionUiJs.indexOf('PathPicker.open', start) + 400)).toContain( - 'allowNewFolder: true' - ); + expect(pickerOptions('openNewCasePathPicker')).toContain('allowNewFolder: true'); }); - it('is on for Link Existing and off for the other session-ui pickers', () => { - const block = (name: string) => { - const start = sessionUiJs.indexOf(`${name}() {`); - expect(start, name).toBeGreaterThan(-1); - return sessionUiJs.slice(start, sessionUiJs.indexOf('PathPicker.open', start) + 400); - }; - expect(block('openLinkCasePathPicker')).toContain('allowNewFolder: true'); + it('is on for Link Existing and off for the Clone and Docker pickers', () => { + expect(pickerOptions('openLinkCasePathPicker')).toContain('allowNewFolder: true'); for (const other of ['openDockerWorkspacePathPicker', 'openDockerWorkdirPicker', 'openCloneCasePathPicker']) { - expect(block(other), other).not.toContain('allowNewFolder'); + expect(pickerOptions(other), other).not.toContain('allowNewFolder'); } }); + + it('lets an error wrap: the status line has no other way to show the rest of a long refusal', () => { + const start = stylesCss.indexOf('.path-picker-status.error {'); + expect(start).toBeGreaterThan(-1); + expect(stylesCss.slice(start, stylesCss.indexOf('}', start))).toContain('white-space: normal'); + }); });