-
Notifications
You must be signed in to change notification settings - Fork 52
fix(connections): use canonical app_name for connection display titles #3090
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
a705f42
fix(connections): use canonical app_name for connection display titles
rafavalls 5eb3b71
fix(home): fix connections modal add button and added state
rafavalls 2f969dd
fix(connections): prevent stacked suffixes and defer connections fetch
rafavalls 1ea4993
fix(connections): use original title instead of slug for display names
rafavalls 64fd51a
fix(connections): preserve original casing for display titles
rafavalls 6fc8328
fix(connections): allow word-boundary prefix matching for display titles
rafavalls 4c1ddbe
fix(connections): use registry titles for connected cards
rafavalls 0de74e8
fix(connections): persist displayName in metadata for stable titles
rafavalls File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,92 @@ | ||||||
| import type { ConnectionEntity } from "@decocms/mesh-sdk"; | ||||||
| import { getConnectionSlug } from "./connection-slug"; | ||||||
| import { slugify } from "./slugify"; | ||||||
|
|
||||||
| /** | ||||||
| * Strip auto-generated instance suffixes like "(2)" or "(a1b2)" from a title. | ||||||
| */ | ||||||
| const INSTANCE_SUFFIX_RE = /\s*\([^)]{1,6}\)\s*$/; | ||||||
|
|
||||||
| /** | ||||||
| * Convert an app_name slug to a display title as a last resort. | ||||||
| * "google-gmail" → "Google Gmail", "@scope/tool" → "Tool" | ||||||
| */ | ||||||
| function slugToTitle(appName: string): string { | ||||||
| const slug = appName.replace(/^@[^/]+\//, ""); | ||||||
| return slug.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Check whether a stripped title looks like the original (not user-renamed) | ||||||
| * by comparing its slug against app_name. Allows partial matches at word | ||||||
| * boundaries so that "Vercel" matches "vercel-mcp" and "Vercel MCP Server" | ||||||
| * matches "vercel-mcp". | ||||||
| */ | ||||||
| function isOriginalTitle(titleSlug: string, appName: string): boolean { | ||||||
| return ( | ||||||
| titleSlug === appName || | ||||||
| appName.startsWith(titleSlug + "-") || | ||||||
| titleSlug.startsWith(appName + "-") | ||||||
| ); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Returns the canonical display title for a connection in catalog/card/header contexts. | ||||||
| * | ||||||
| * Strategy: | ||||||
| * 1. Strip auto-generated instance suffixes from the title ("Vercel MCP (2)" → "Vercel MCP") | ||||||
| * 2. If the stripped title still matches the app_name slug (exact or word-boundary prefix), | ||||||
| * use it — this preserves the original casing from the registry (e.g., "Vercel MCP") | ||||||
| * 3. If it doesn't match (user renamed the instance), fall back to slug → title conversion | ||||||
| * | ||||||
| * Use the raw connection.title only when showing the specific instance matters | ||||||
| * (e.g., the instance list inside a connection detail, or the binding selector). | ||||||
| */ | ||||||
| export function getConnectionDisplayTitle( | ||||||
| connection: ConnectionEntity, | ||||||
| ): string { | ||||||
| const stripped = connection.title.replace(INSTANCE_SUFFIX_RE, ""); | ||||||
| if (!connection.app_name) return stripped; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Custom connections now lose user-provided title suffixes because the function strips trailing Prompt for AI agents
Suggested change
|
||||||
|
|
||||||
| if (isOriginalTitle(slugify(stripped), connection.app_name)) { | ||||||
| return stripped; | ||||||
| } | ||||||
|
|
||||||
| // Title was renamed — fall back to slug conversion | ||||||
| return slugToTitle(connection.app_name); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * For a group of connections sharing the same app, pick the best canonical title. | ||||||
| * Prefers the original (non-renamed) title from any instance to preserve correct | ||||||
| * casing. Falls back to the shortest stripped title. | ||||||
| */ | ||||||
| export function getGroupDisplayTitle(connections: ConnectionEntity[]): string { | ||||||
| const appName = connections[0]!.app_name; | ||||||
|
|
||||||
| // First pass: look for an instance whose title still matches the app_name | ||||||
| // (i.e. hasn't been renamed). This preserves original casing like "Vercel MCP". | ||||||
| if (appName) { | ||||||
| for (const c of connections) { | ||||||
| const stripped = c.title.replace(INSTANCE_SUFFIX_RE, ""); | ||||||
| if (isOriginalTitle(slugify(stripped), appName)) { | ||||||
| return stripped; | ||||||
| } | ||||||
| } | ||||||
| // All instances were renamed — fall back to slug conversion | ||||||
| return slugToTitle(appName); | ||||||
| } | ||||||
|
|
||||||
| // No app_name — pick the shortest stripped title | ||||||
| let best = getConnectionDisplayTitle(connections[0]!); | ||||||
| for (let i = 1; i < connections.length; i++) { | ||||||
| const candidate = getConnectionDisplayTitle(connections[i]!); | ||||||
| if (candidate.length < best.length) { | ||||||
| best = candidate; | ||||||
| } | ||||||
| } | ||||||
| return best; | ||||||
| } | ||||||
|
|
||||||
| export interface ConnectionGroup { | ||||||
| type: "group"; | ||||||
|
|
@@ -47,9 +134,7 @@ export function groupConnections( | |||||
| type: "group", | ||||||
| key, | ||||||
| icon: first.icon, | ||||||
| title: first.app_name | ||||||
| ? first.title.replace(/\s*\(\d+\)\s*$/, "") | ||||||
| : first.title, | ||||||
| title: getGroupDisplayTitle(bucket), | ||||||
| connections: bucket, | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.