Skip to content

Commit f867dbe

Browse files
committed
Add a tools unlock CTA for empty integrations
1 parent 2c30eab commit f867dbe

1 file changed

Lines changed: 40 additions & 1 deletion

File tree

packages/react/src/pages/integration-detail.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ export function IntegrationDetailPage(props: { namespace: string }) {
9090
const [refreshing, setRefreshing] = useState(false);
9191
const [editSheetOpen, setEditSheetOpen] = useState(false);
9292
const [activeTab, setActiveTab] = useState<"accounts" | "tools">("accounts");
93+
const [manualAccountHandoff, setManualAccountHandoff] =
94+
useState<IntegrationAccountHandoff | null>(null);
9395
const [locationSearch] = useState(() =>
9496
typeof window === "undefined" ? "" : window.location.search,
9597
);
@@ -105,7 +107,7 @@ export function IntegrationDetailPage(props: { namespace: string }) {
105107
const currentTab = isBuiltInIntegration ? "tools" : activeTab;
106108
const canRefresh = integrationData?.canRefresh ?? false;
107109
const canRemove = integrationData?.canRemove ?? false;
108-
const accountHandoff = useMemo<IntegrationAccountHandoff | null>(() => {
110+
const urlAccountHandoff = useMemo<IntegrationAccountHandoff | null>(() => {
109111
if (locationSearch.length === 0) return null;
110112
const search = new URLSearchParams(locationSearch);
111113
if (search.get("addAccount") !== "1") return null;
@@ -140,6 +142,8 @@ export function IntegrationDetailPage(props: { namespace: string }) {
140142
...(oauthClient !== undefined ? { oauthClient } : {}),
141143
};
142144
}, [locationSearch]);
145+
const accountHandoff = manualAccountHandoff ?? urlAccountHandoff;
146+
143147
useEffect(() => {
144148
if (accountHandoff && !isBuiltInIntegration) {
145149
setActiveTab("accounts");
@@ -338,6 +342,11 @@ export function IntegrationDetailPage(props: { namespace: string }) {
338342
setRefreshing(false);
339343
};
340344

345+
const handleOpenAddConnection = () => {
346+
setActiveTab("accounts");
347+
setManualAccountHandoff({ key: `manual:${String(slug)}:${Date.now()}` });
348+
};
349+
341350
return (
342351
<div className="flex min-h-0 flex-1 flex-col overflow-hidden">
343352
{/* Header bar */}
@@ -491,6 +500,11 @@ export function IntegrationDetailPage(props: { namespace: string }) {
491500
}
492501
: {})}
493502
/>
503+
) : !isBuiltInIntegration && integrationConnections.length === 0 ? (
504+
<NoConnectionToolsEmptyState
505+
onAddConnection={handleOpenAddConnection}
506+
canAddConnection={accountsMethods.length > 0}
507+
/>
494508
) : (
495509
<ToolDetailEmpty hasTools={integrationTools.length > 0} />
496510
)}
@@ -514,6 +528,31 @@ export function IntegrationDetailPage(props: { namespace: string }) {
514528
);
515529
}
516530

531+
function NoConnectionToolsEmptyState(props: {
532+
readonly onAddConnection: () => void;
533+
readonly canAddConnection: boolean;
534+
}) {
535+
return (
536+
<div className="flex h-full items-center justify-center">
537+
<div className="max-w-sm text-center">
538+
<p className="text-sm font-medium text-foreground">No tools yet</p>
539+
<p className="mt-1.5 text-sm text-muted-foreground">
540+
Add a connection to unlock this integration's tools.
541+
</p>
542+
<Button
543+
type="button"
544+
size="sm"
545+
className="mt-4"
546+
onClick={props.onAddConnection}
547+
disabled={!props.canAddConnection}
548+
>
549+
Add connection
550+
</Button>
551+
</div>
552+
</div>
553+
);
554+
}
555+
517556
function IntegrationDetailSkeleton() {
518557
return (
519558
<div className="flex min-h-0 flex-1 overflow-hidden">

0 commit comments

Comments
 (0)