Files
multica/packages/views/common/github-url.ts
Rusty Raven 999f73e61f fix(projects): show owner/repo label for GitHub resource URLs (MUL-5221) (#5795)
* fix(projects): show owner/repo label for GitHub resource URLs instead of truncated full URL

Long GitHub URLs in the project-resources sidebar are end-truncated by CSS
`truncate`, making similar repos like org/very-long-repo-a and
org/very-long-repo-b indistinguishable from the visible prefix alone.

Extract just the `owner/repo` segment from the URL for display; keep the full
URL in the tooltip so it remains accessible on hover. Applied to both the
resource row and the repository picker popover. Custom labels are unaffected.

Fixes #5771

Co-authored-by: multica-agent <github@multica.ai>

* fix(projects): strip .git suffix and handle scp SSH URLs in githubShortLabel; add middle-truncation for long repo names

Addresses #5795 review feedback:
- Strip .git suffix (example-org/very-long-repo-name.git → without .git)
- Handle git@github.com:owner/repo.git (scp shorthand) which new URL() rejects
- Add midTruncate() so repos sharing a long common prefix are distinguishable
  by their tail (customer-alpha vs customer-beta) rather than being end-truncated
  identically by CSS

Fixes #5771.

Co-authored-by: multica-agent <github@multica.ai>

* refactor(projects): share githubShortLabel across project resource UIs

Move githubShortLabel/midTruncate out of project-resources-section into
packages/views/common/github-url.ts so the create-project repository picker
reuses the same owner/repo shortening (it was still rendering full URLs) and
recognize the www.github.com host. Add github-url.test.ts covering the
https / ssh / scp / enterprise / malformed cases plus middle-truncation.

Addresses #5795 review feedback: shared helper, create-project coverage, tests.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: multica-agent <github@multica.ai>
Co-authored-by: Bohan Jiang <52446949+Bohan-J@users.noreply.github.com>
2026-07-24 15:55:57 +08:00

36 lines
1.7 KiB
TypeScript

// For GitHub URLs, return "owner/repo" so truncated display labels stay
// meaningful when URLs share a long prefix. Handles:
// https://github.com/owner/repo[/...]
// https://www.github.com/owner/repo
// ssh://git@github.com/owner/repo.git
// git@github.com:owner/repo.git (scp shorthand)
// The .git suffix is stripped in all cases. When the resulting label is still
// long, middle-truncation keeps the distinguishing tail visible (the case where
// many repos share a long common prefix, e.g. customer-alpha vs customer-beta).
// Non-GitHub input (enterprise hosts, malformed strings) is returned unchanged.
export function githubShortLabel(url: string): string {
// scp shorthand — new URL() throws on these, so match before the try block.
const scp = url.match(/^(?:[^@/]+@)?github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
if (scp) return midTruncate(`${scp[1]}/${scp[2]}`);
try {
const u = new URL(url);
if (u.hostname === "github.com" || u.hostname === "www.github.com") {
const [owner, repo] = u.pathname.split("/").filter(Boolean);
if (owner && repo) return midTruncate(`${owner}/${repo.replace(/\.git$/, "")}`);
}
} catch {
// not a parseable URL — fall through and return as-is
}
return url;
}
// Middle-truncate a string to at most maxLen characters, preserving both the
// leading and trailing portions. The trailing portion is what distinguishes
// repos that share a long common prefix (e.g. customer-alpha vs customer-beta).
export function midTruncate(s: string, maxLen = 40): string {
if (s.length <= maxLen) return s;
const tail = Math.floor((maxLen - 1) / 2);
const head = maxLen - 1 - tail;
return `${s.slice(0, head)}${s.slice(-tail)}`;
}