From 0958e672ae6a87274be75bd47f13595da1ce3a78 Mon Sep 17 00:00:00 2001 From: Anna Effort Date: Wed, 23 Sep 2026 18:31:43 -0700 Subject: [PATCH 1/9] feat: show catalog add failures on the card that failed Extracts the presentational shell of ServerStatusIndicator so the catalog card can reuse the icon, muted label and popover without inheriting the server availability model. Open-auth add failures now render an error indicator in the card footer next to Add, with the reason in a popover, instead of a notification above the grid that pushed the cards down. The failures that have no card left to carry them, and every other action outcome, still use the page stack. Signed-off-by: Anna Effort --- .../server-catalog/CatalogResults.tsx | 23 +++++ .../servers/ServerStatusIndicator.tsx | 77 +++++++--------- src/components/ui/status-indicator.test.tsx | 65 ++++++++++++++ src/components/ui/status-indicator.tsx | 87 +++++++++++++++++++ src/i18n/locales/en-US/mcpServer.json | 4 + src/i18n/locales/es-ES/mcpServer.json | 4 + src/i18n/locales/pt-BR/mcpServer.json | 4 + src/pages/ServerCatalog.test.tsx | 57 ++++++++++-- src/pages/ServerCatalog.tsx | 58 ++++++++++--- 9 files changed, 316 insertions(+), 63 deletions(-) create mode 100644 src/components/ui/status-indicator.test.tsx create mode 100644 src/components/ui/status-indicator.tsx diff --git a/src/components/server-catalog/CatalogResults.tsx b/src/components/server-catalog/CatalogResults.tsx index 7d47fdb2..171359f8 100644 --- a/src/components/server-catalog/CatalogResults.tsx +++ b/src/components/server-catalog/CatalogResults.tsx @@ -23,6 +23,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { StatusIndicator } from "@/components/ui/status-indicator"; import type { CatalogServer } from "@/generated/types"; import { useDebouncedValue } from "@/hooks/useDebouncedValue"; import { getAuthTypeGroupId, getAuthTypeGroupLabelId } from "@/utils/catalogAuthTypes"; @@ -30,6 +31,7 @@ import { getTagLabels } from "@/utils/tags"; const EMPTY_PENDING_IDS: ReadonlySet = new Set(); const EMPTY_OAUTH_STATUSES: Readonly> = {}; +const EMPTY_ADD_ERRORS: Readonly> = {}; function getOAuthCardState(server: CatalogServer, status?: OAuthGatewayStatus) { const tokenState = status?.user_token_status?.status; @@ -77,6 +79,7 @@ function CatalogCard({ canTest, canDisconnect, oauthStatuses, + addError, }: { server: CatalogServer; onView: (trigger: HTMLElement) => void; @@ -90,6 +93,8 @@ function CatalogCard({ canTest: boolean; canDisconnect: boolean; oauthStatuses?: Readonly>; + /** Why the last add attempt failed, resolved to the server's reason or the fallback. */ + addError?: string; }) { const intl = useIntl(); const headingId = useId(); @@ -278,6 +283,21 @@ function CatalogCard({