diff --git a/src/web/public/session-ui.js b/src/web/public/session-ui.js index 388fcadc..bfc20f1f 100644 --- a/src/web/public/session-ui.js +++ b/src/web/public/session-ui.js @@ -4298,7 +4298,7 @@ Object.assign(CodemanApp.prototype, { openCloneCasePathPicker() { const input = document.getElementById('cloneCasePath'); PathPicker.open({ - title: 'Choose the parent folder for the clone', + title: 'Choose the folder to clone inside', initialPath: input.value.trim(), directoriesOnly: true, allowNewFolder: true, @@ -4408,10 +4408,8 @@ Object.assign(CodemanApp.prototype, { // The server's suggestion wins over the local guess (it is the same function // the case name is validated against), but never over a name the user typed. const nameInput = document.getElementById('cloneCaseName'); - if (nameInput && !this._cloneNameEdited && parse.suggestedName) { - nameInput.value = parse.suggestedName; - this.updateCloneCasePathPreview(); - } + if (nameInput && !this._cloneNameEdited && parse.suggestedName) nameInput.value = parse.suggestedName; + this.updateCloneCasePathPreview(); const where = parse.owner ? `${parse.provider} ${parse.owner}/${parse.repo}` : `${parse.provider} ${parse.repo}`; if (data.gitAvailable === false) { @@ -4466,7 +4464,7 @@ Object.assign(CodemanApp.prototype, { const customFolder = !!document.getElementById('cloneCustomPathToggle')?.checked; if (customFolder && !(document.getElementById('cloneCasePath')?.value || '').trim()) { - this.showToast('Choose the parent folder for the clone', 'error'); + this.showToast('Choose the folder to clone inside', 'error'); return; } diff --git a/src/web/routes/case-routes.ts b/src/web/routes/case-routes.ts index db756e11..23bbc62c 100644 --- a/src/web/routes/case-routes.ts +++ b/src/web/routes/case-routes.ts @@ -758,7 +758,7 @@ export function registerCaseRoutes( ? ApiErrorCode.ALREADY_EXISTS : ApiErrorCode.INVALID_INPUT, prepared.code === 'EXISTS' - ? `${customPath} already has files in it. Pick an empty folder, or a folder that does not exist yet.` + ? `${customPath} already has files in it. The clone target must be empty or not exist yet.` : prepared.reason ); } diff --git a/test/clone-custom-folder-ui.test.ts b/test/clone-custom-folder-ui.test.ts index a7bdbd38..b0b4eeba 100644 --- a/test/clone-custom-folder-ui.test.ts +++ b/test/clone-custom-folder-ui.test.ts @@ -123,7 +123,7 @@ describe('Clone Repo custom folder', () => { allowNewFolder: boolean; onSelect(p: string): void; }; - expect(options.title).toBe('Choose the parent folder for the clone'); + expect(options.title).toBe('Choose the folder to clone inside'); expect(options.directoriesOnly).toBe(true); // A parent that does not exist yet is refused, so the picker has to be able to make it. expect(options.allowNewFolder).toBe(true); @@ -140,7 +140,7 @@ describe('Clone Repo custom folder', () => { app.showToast = vi.fn(); (doc.getElementById('cloneCustomPathToggle') as HTMLInputElement).checked = true; await app.cloneCase(); - expect(app.showToast).toHaveBeenCalledWith('Choose the parent folder for the clone', 'error'); + expect(app.showToast).toHaveBeenCalledWith('Choose the folder to clone inside', 'error'); expect(fetchMock).not.toHaveBeenCalled(); }); @@ -159,4 +159,30 @@ describe('Clone Repo custom folder', () => { expect(app.showToast).toHaveBeenCalledWith('Please enter a case name', 'error'); expect(fetchMock).not.toHaveBeenCalled(); }); + + it('refreshes the preview when the preflight replaces the case name', () => { + const { app, doc, set } = bootClone(); + set('cloneRepoUrl', 'https://github.com/opticon454/bifrost?tab=readme-ov-file'); + set('cloneCaseName', 'bifrost-tab-readme-ov-file'); + set('cloneCasePath', '/mnt/projects'); + app.updateCloneCasePathPreview(); + expect(doc.getElementById('cloneCasePathPreview')?.textContent).toBe( + 'Will clone into: /mnt/projects/bifrost-tab-readme-ov-file' + ); + app._applyClonePreflight({ gitAvailable: true, parse: { cloneable: true, suggestedName: 'bifrost' } }, ''); + expect((doc.getElementById('cloneCaseName') as HTMLInputElement).value).toBe('bifrost'); + expect(doc.getElementById('cloneCasePathPreview')?.textContent).toBe('Will clone into: /mnt/projects/bifrost'); + }); + + it('previews the name taken from the URL as it is typed', () => { + const { app, doc, set, win } = bootClone(); + app.isCliAvailable = () => true; // lives in settings-ui.js, which this test does not load + set('cloneCaseName', ''); + set('cloneCasePath', '/mnt/projects'); + set('cloneRepoUrl', 'https://github.com/opticon454/bifrost'); + app.onCloneUrlInput(); + win.clearTimeout(app._clonePreflightTimer); + expect((doc.getElementById('cloneCaseName') as HTMLInputElement).value).toBe('bifrost'); + expect(doc.getElementById('cloneCasePathPreview')?.textContent).toBe('Will clone into: /mnt/projects/bifrost'); + }); });