Skip to content

Commit 2648173

Browse files
Merge pull request #45 from paritytech/fix-link-display-no-osc8
Fix link display in terminals without OSC 8 hyperlink support
2 parents 59eacd8 + 65742ed commit 2648173

4 files changed

Lines changed: 82 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@parity/cdm-cli": patch
3+
---
4+
5+
Fix deploy/install link display in terminals without OSC 8 hyperlink support. Instead of squeezing the full URL into a narrow table column (where it wrapped into an unreadable smear), the cell now keeps the short hash and the full link is printed on its own line below the row.

src/apps/cli/src/lib/components/DeployTable.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Box, Text } from "ink";
33
import type { ContractStatus, PhaseInfo } from "../deploy-pipeline";
44
import {
55
Link,
6+
LinkLine,
7+
hyperlinksSupported,
68
Spinner,
79
ProgressBar,
810
EmptyBar,
@@ -203,7 +205,7 @@ function ContractRow({
203205
addrCell = <Idle />;
204206
}
205207

206-
return (
208+
const row = (
207209
<Box>
208210
<Cell width={COL_CONTRACT}>
209211
<Text bold wrap="truncate">
@@ -217,6 +219,43 @@ function ContractRow({
217219
<Cell width={COL_ADDR}>{addrCell}</Cell>
218220
</Box>
219221
);
222+
223+
if (hyperlinksSupported) return row;
224+
225+
// No OSC 8 support: the phase cells only show short hashes, so surface each
226+
// full link on its own line below the row. Conditions mirror the cell
227+
// rendering above so an inline line appears iff a cell shows a link.
228+
const linkDefs: { label: string; url: string }[] = [];
229+
if (
230+
["registering", "done"].includes(state) &&
231+
s?.deployTxHash &&
232+
s?.deployBlockHash &&
233+
assethubUrl
234+
) {
235+
linkDefs.push({ label: "deploy", url: pjsExplorerUrl(assethubUrl, s.deployBlockHash) });
236+
}
237+
if (["registering", "done"].includes(state) && s?.cid && ipfsGatewayUrl) {
238+
linkDefs.push({ label: "metadata", url: ipfsUrl(ipfsGatewayUrl, s.cid) });
239+
}
240+
if (state === "done" && s?.registerTxHash && s?.registerBlockHash && assethubUrl) {
241+
linkDefs.push({ label: "register", url: pjsExplorerUrl(assethubUrl, s.registerBlockHash) });
242+
}
243+
if (linkDefs.length === 0) return row;
244+
245+
// Deploy and register share one block hash (single batch), so collapse
246+
// duplicate URLs into a single line with a combined label.
247+
const byUrl = new Map<string, string[]>();
248+
for (const { label, url } of linkDefs) {
249+
byUrl.set(url, [...(byUrl.get(url) ?? []), label]);
250+
}
251+
return (
252+
<Box flexDirection="column">
253+
{row}
254+
{[...byUrl].map(([url, labels]) => (
255+
<LinkLine key={url} label={labels.join("/")} url={url} />
256+
))}
257+
</Box>
258+
);
220259
}
221260

222261
export interface DeployTableProps {

src/apps/cli/src/lib/components/InstallTable.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Box, Text } from "ink";
33
import type { InstallStatus } from "../install-pipeline";
44
import {
55
Link,
6+
LinkLine,
7+
hyperlinksSupported,
68
Spinner,
79
Cell,
810
Idle,
@@ -70,7 +72,7 @@ function InstallRow({
7072
addrCell = <Idle />;
7173
}
7274

73-
return (
75+
const row = (
7476
<Box>
7577
<Cell width={COL_CONTRACT}>
7678
<Text bold wrap="truncate">
@@ -82,6 +84,17 @@ function InstallRow({
8284
<Cell width={COL_ADDR}>{addrCell}</Cell>
8385
</Box>
8486
);
87+
88+
// When OSC 8 hyperlinks aren't available, the metadata cell only shows the
89+
// short CID hash; surface the full link on its own line below the row.
90+
const hasLink = state === "done" && s?.metadataCid && ipfsGatewayUrl;
91+
if (hyperlinksSupported || !hasLink) return row;
92+
return (
93+
<Box flexDirection="column">
94+
{row}
95+
<LinkLine url={ipfsUrl(ipfsGatewayUrl!, s!.metadataCid!)} />
96+
</Box>
97+
);
8598
}
8699

87100
export interface InstallTableProps {

src/apps/cli/src/lib/components/shared.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import React from "react";
22
import { Box, Text } from "ink";
33
import supportsHyperlinks from "supports-hyperlinks";
44

5+
/** Whether the terminal supports OSC 8 embedded hyperlinks. */
6+
export const hyperlinksSupported = supportsHyperlinks.stdout;
7+
58
/** Terminal hyperlink using OSC 8 escape sequence */
69
export function Link({ url, children }: { url: string; children: React.ReactNode }) {
7-
if (supportsHyperlinks.stdout) {
10+
if (hyperlinksSupported) {
811
return (
912
<Text>
1013
{`\x1b]8;;${url}\x07`}
@@ -13,7 +16,25 @@ export function Link({ url, children }: { url: string; children: React.ReactNode
1316
</Text>
1417
);
1518
}
16-
return <Text>{url}</Text>;
19+
// No OSC 8 support: render only the short anchor text in the cell so the
20+
// table stays aligned. The full URL is surfaced separately on its own line
21+
// via <LinkLine>. Rendering the full URL here would squeeze it into a
22+
// narrow column and wrap it into an unreadable smear (issue #44).
23+
return <Text>{children}</Text>;
24+
}
25+
26+
/**
27+
* A full link printed on its own line, used as a fallback when the terminal
28+
* lacks OSC 8 hyperlink support. The URL is rendered outside the table grid so
29+
* it stays on a single line instead of being squeezed into a column.
30+
*/
31+
export function LinkLine({ label, url }: { label?: string; url: string }) {
32+
return (
33+
<Text>
34+
<Text dimColor>{` ↳ ${label ? `${label.padEnd(8)} ` : ""}`}</Text>
35+
<Text color="cyan">{url}</Text>
36+
</Text>
37+
);
1738
}
1839

1940
export const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];

0 commit comments

Comments
 (0)