diff --git a/.changeset/fix-footnote-long-url-wrapping.md b/.changeset/fix-footnote-long-url-wrapping.md new file mode 100644 index 00000000000..be56cf2eaeb --- /dev/null +++ b/.changeset/fix-footnote-long-url-wrapping.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli-kit': patch +--- + +Render banner/alert footnote URLs on a single contiguous line so long links are no longer broken by hard newlines and remain copy-pasteable when terminal hyperlinks are unsupported diff --git a/packages/cli-kit/src/private/node/ui/components/Alert.test.tsx b/packages/cli-kit/src/private/node/ui/components/Alert.test.tsx index d956487745a..56ea8c2ef3e 100644 --- a/packages/cli-kit/src/private/node/ui/components/Alert.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/Alert.test.tsx @@ -165,14 +165,14 @@ describe('Alert', async () => { }) // The footnote block (rendered after the closing `╰`) must list the - // URL. Ink wraps the long URL onto its own line when it exceeds terminal - // width, so we assert the `[1]` anchor and the URL show up *outside* the - // bordered box rather than as a single contiguous `[1] URL` substring. + // URL as a single contiguous `[1] URL` line. The footnote Box is sized to + // the line length so Ink never hard-wraps the URL (which would insert + // newline characters and break copy-paste/clickability); the terminal + // soft-wraps the overflow at display time instead. const closingBorderIndex = frame.indexOf('╰') expect(closingBorderIndex).toBeGreaterThanOrEqual(0) const afterBox = frame.slice(closingBorderIndex) - expect(afterBox).toContain('[1]') - expect(afterBox).toContain(longUrl) + expect(afterBox).toContain(`[1] ${longUrl}`) // And the body must reference the footnote. expect(frame).toContain('docs [1]') }) diff --git a/packages/cli-kit/src/private/node/ui/components/Banner.tsx b/packages/cli-kit/src/private/node/ui/components/Banner.tsx index 948306f9648..8411a5538ef 100644 --- a/packages/cli-kit/src/private/node/ui/components/Banner.tsx +++ b/packages/cli-kit/src/private/node/ui/components/Banner.tsx @@ -32,9 +32,18 @@ const Footnotes = () => { return linkIds.length > 0 ? ( - {linkIds.map((id) => ( - {`[${id}] ${links[id]?.url}`} - ))} + {linkIds.map((id) => { + const line = `[${id}] ${links[id]?.url}` + // Render each footnote on a Box wide enough to fit the whole line so + // Ink doesn't hard-wrap long URLs (which inserts newline characters and + // breaks copy-paste/clickability). The terminal soft-wraps the overflow + // at display time without mutating the underlying text. + return ( + + {line} + + ) + })} ) : null } diff --git a/packages/cli-kit/src/public/node/plugins/multiple-installation-warning.test.ts b/packages/cli-kit/src/public/node/plugins/multiple-installation-warning.test.ts index dddda0afc4a..b5170d2085e 100644 --- a/packages/cli-kit/src/public/node/plugins/multiple-installation-warning.test.ts +++ b/packages/cli-kit/src/public/node/plugins/multiple-installation-warning.test.ts @@ -26,23 +26,22 @@ describe('showMultipleCLIWarningIfNeeded', () => { // Then expect(mockOutput.info()).toMatchInlineSnapshot(` - "╭─ info ───────────────────────────────────────────────────────────────────────╮ - │ │ - │ Two Shopify CLI installations found – using global installation │ - │ │ - │ A global installation (v${CLI_KIT_VERSION}) and a local dependency (v3.70.0) were │ - │ detected. │ - │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ - │ your package.json, unless you want to use different versions across │ - │ multiple apps. │ - │ │ - │ See Shopify CLI documentation. [1] │ - │ │ - ╰──────────────────────────────────────────────────────────────────────────────╯ - [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executab - le-or-local-dependency - " - `) + "╭─ info ───────────────────────────────────────────────────────────────────────╮ + │ │ + │ Two Shopify CLI installations found – using global installation │ + │ │ + │ A global installation (v${CLI_KIT_VERSION}) and a local dependency (v3.70.0) were │ + │ detected. │ + │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ + │ your package.json, unless you want to use different versions across │ + │ multiple apps. │ + │ │ + │ See Shopify CLI documentation. [1] │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────╯ + [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executable-or-local-dependency + " + `) mockOutput.clear() }) @@ -58,23 +57,22 @@ describe('showMultipleCLIWarningIfNeeded', () => { // Then expect(mockOutput.info()).toMatchInlineSnapshot(` - "╭─ info ───────────────────────────────────────────────────────────────────────╮ - │ │ - │ Two Shopify CLI installations found – using local dependency │ - │ │ - │ A global installation (v3.70.0) and a local dependency (v${CLI_KIT_VERSION}) were │ - │ detected. │ - │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ - │ your package.json, unless you want to use different versions across │ - │ multiple apps. │ - │ │ - │ See Shopify CLI documentation. [1] │ - │ │ - ╰──────────────────────────────────────────────────────────────────────────────╯ - [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executab - le-or-local-dependency - " - `) + "╭─ info ───────────────────────────────────────────────────────────────────────╮ + │ │ + │ Two Shopify CLI installations found – using local dependency │ + │ │ + │ A global installation (v3.70.0) and a local dependency (v${CLI_KIT_VERSION}) were │ + │ detected. │ + │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ + │ your package.json, unless you want to use different versions across │ + │ multiple apps. │ + │ │ + │ See Shopify CLI documentation. [1] │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────╯ + [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executable-or-local-dependency + " + `) mockOutput.clear() }) @@ -91,23 +89,22 @@ describe('showMultipleCLIWarningIfNeeded', () => { // Then expect(mockOutput.info()).toMatchInlineSnapshot(` - "╭─ info ───────────────────────────────────────────────────────────────────────╮ - │ │ - │ Two Shopify CLI installations found – using global installation │ - │ │ - │ A global installation (v${CLI_KIT_VERSION}) and a local dependency (v3.70.0) were │ - │ detected. │ - │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ - │ your package.json, unless you want to use different versions across │ - │ multiple apps. │ - │ │ - │ See Shopify CLI documentation. [1] │ - │ │ - ╰──────────────────────────────────────────────────────────────────────────────╯ - [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executab - le-or-local-dependency - " - `) + "╭─ info ───────────────────────────────────────────────────────────────────────╮ + │ │ + │ Two Shopify CLI installations found – using global installation │ + │ │ + │ A global installation (v${CLI_KIT_VERSION}) and a local dependency (v3.70.0) were │ + │ detected. │ + │ We recommend removing the @shopify/cli and @shopify/app dependencies from │ + │ your package.json, unless you want to use different versions across │ + │ multiple apps. │ + │ │ + │ See Shopify CLI documentation. [1] │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────╯ + [1] https://shopify.dev/docs/apps/build/cli-for-apps#switch-to-a-global-executable-or-local-dependency + " + `) }) test('does not show a warning if there is no local dependency', async () => { diff --git a/packages/cli-kit/src/public/node/ui.tsx b/packages/cli-kit/src/public/node/ui.tsx index 4147ee6247d..28e4a1863da 100644 --- a/packages/cli-kit/src/public/node/ui.tsx +++ b/packages/cli-kit/src/public/node/ui.tsx @@ -100,10 +100,7 @@ export type RenderAlertOptions = Omit * │ │ * ╰──────────────────────────────────────────────────────────╯ * [1] https://shopify.dev - * [2] https://www.google.com/search?q=jh56t9l34kpo35tw8s28hn7s - * 9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo - * 35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j - * 69i60.2711j0j7&sourceid=chrome&ie=UTF-8 + * [2] https://www.google.com/search?q=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&rlz=1C1GCEU_enUS832US832&oq=jh56t9l34kpo35tw8s28hn7s9s2xvzla01d8cn6j7yq&aqs=chrome.0.35i39l2j0l4j46j69i60.2711j0j7&sourceid=chrome&ie=UTF-8 * [3] https://shopify.com * */ @@ -134,8 +131,7 @@ export function renderInfo(options: RenderAlertOptions) { * │ • See your deployment and set it live [1] │ * │ │ * ╰──────────────────────────────────────────────────────────╯ - * [1] https://partners.shopify.com/1797046/apps/4523695/deploy - * ments + * [1] https://partners.shopify.com/1797046/apps/4523695/deployments * */ export function renderSuccess(options: RenderAlertOptions) {