From 313a8df6a6fcae52c27b7633e49ee720503ea89b Mon Sep 17 00:00:00 2001 From: sreedharsreeram <141047751+sreedharsreeram@users.noreply.github.com> Date: Thu, 18 Jun 2026 04:43:06 +0000 Subject: [PATCH] feat(web): show import status on X bookmarks integration card (#1130) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What The X bookmarks ("Import X bookmarks") card on the integrations page never reflected any state, even after importing tweets — unlike connectors and plugins, which show "Connected"/"Active". After this change, once you've imported at least one tweet the card shows an **"Imported · {last import time}"** pill (mirroring the plugin "Active · {time}" style) and is included in the **Connected** filter. Since importing X bookmarks is a one-time/occasional action rather than a live connection, it intentionally says **"Imported"** with the last-import timestamp, not "Connected". ## Why The page's status logic (`isItemConnected` + `renderStatus`) only handled the `plugin` and `connector` item kinds. The X bookmarks card is an `import` kind, so it always rendered just "Connect". This was a regression from #979 (the integrations overhaul), which rebuilt the page around item kinds and dropped the previous "{N} tweets imported" indicator. ## How - Add a single documents query (`@post/documents/documents`, `categories: ["tweet"]`, `limit: 1`, newest first) that yields both the org-wide tweet count (`pagination.totalItems`) and the latest tweet's `createdAt`. - `isItemConnected` returns `true` for `import` when the count is `> 0`. - `renderStatus` renders a new `ImportedPill` ("Imported · {relative time}") for `import` when there's ≥1 tweet. ## Testing - `tsc` and Biome pass; no new errors introduced by this change. - Verified the status source of truth against a local backend by seeding `type='tweet'` documents — the count/latest-timestamp the pill renders reflect them. > Note: `tsc` reports two **pre-existing**, unrelated `granola` errors in this file (`CONNECTOR_META` + an icon record missing the `granola` provider). They exist on `main` and are not touched by this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- apps/web/components/integrations-view.tsx | 61 ++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/apps/web/components/integrations-view.tsx b/apps/web/components/integrations-view.tsx index 047dd6e1..fe68d153 100644 --- a/apps/web/components/integrations-view.tsx +++ b/apps/web/components/integrations-view.tsx @@ -1059,6 +1059,29 @@ function ConnectionsCountPill({ count }: { count: number }) { ) } +function ImportedPill({ + lastImportedAt, +}: { + lastImportedAt: string | number | Date | null +}) { + return ( + + + Imported + {lastImportedAt && ( + + · {formatRelativeTime(lastImportedAt)} + + )} + + ) +} + const CONNECTOR_META: Record< ConnectorProvider, { name: string; icon: ReactNode; documentLabel: string } @@ -2463,6 +2486,35 @@ export function IntegrationsView({ staleTime: 30 * 1000, }) + const { data: xBookmarksImport } = useQuery({ + queryKey: ["x-bookmarks-import-status"], + queryFn: async () => { + const response = await $fetch("@post/documents/documents", { + body: { + page: 1, + limit: 1, + sort: "createdAt", + order: "desc", + categories: ["tweet"], + }, + disableValidation: true, + }) + if (response.error) + throw new Error( + response.error?.message || "Failed to load X bookmarks status", + ) + return { + count: response.data?.pagination?.totalItems ?? 0, + lastImportedAt: response.data?.documents?.[0]?.createdAt ?? null, + } + }, + staleTime: 5 * 60 * 1000, + enabled: !publicMode, + }) + + const tweetCount = xBookmarksImport?.count ?? 0 + const lastTweetImportAt = xBookmarksImport?.lastImportedAt ?? null + const keyPrefix = useCallback((key: ListedApiKey): string | null => { return key.start ?? (key.name?.startsWith("sm_") ? key.name : null) }, []) @@ -2675,9 +2727,12 @@ export function IntegrationsView({ if (item.kind === "connector") { return connectionsByProvider[item.provider].length > 0 } + if (item.kind === "import") { + return tweetCount > 0 + } return false }, - [activePluginById, connectionsByProvider, publicMode], + [activePluginById, connectionsByProvider, publicMode, tweetCount], ) const counts = useMemo>( @@ -3286,6 +3341,10 @@ export function IntegrationsView({ if (count <= 0) return null return } + case "import": { + if (tweetCount <= 0) return null + return + } default: return null }