Skip to content

Commit 6a63006

Browse files
remove app builder sidebar bubble (#1865)
1 parent 16a1d50 commit 6a63006

5 files changed

Lines changed: 31 additions & 253 deletions

File tree

mcpjam-inspector/client/src/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1625,7 +1625,6 @@ export default function App() {
16251625
hidden={appBuilderOnboarding}
16261626
onNavigate={handleNavigate}
16271627
activeTab={activeTab}
1628-
servers={workspaceServers}
16291628
workspaces={workspaces}
16301629
activeWorkspaceId={activeWorkspaceId}
16311630
onSwitchWorkspace={handleSidebarSwitchWorkspace}

mcpjam-inspector/client/src/components/__tests__/mcp-sidebar-feature-flags.test.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
filterByFeatureFlags,
55
getEvalsSubnavItems,
66
getHostedNavigationSections,
7-
shouldPrefetchSidebarTools,
87
} from "../mcp-sidebar";
98
import { HOSTED_LOCAL_ONLY_TOOLTIP } from "@/lib/hosted-ui";
109

@@ -381,32 +380,3 @@ describe("getHostedNavigationSections", () => {
381380
]);
382381
});
383382
});
384-
385-
describe("shouldPrefetchSidebarTools", () => {
386-
it("skips sidebar tool prefetch for hosted guests", () => {
387-
expect(
388-
shouldPrefetchSidebarTools({
389-
hostedMode: true,
390-
isAuthenticated: false,
391-
}),
392-
).toBe(false);
393-
});
394-
395-
it("allows sidebar tool prefetch for hosted signed-in users", () => {
396-
expect(
397-
shouldPrefetchSidebarTools({
398-
hostedMode: true,
399-
isAuthenticated: true,
400-
}),
401-
).toBe(true);
402-
});
403-
404-
it("allows sidebar tool prefetch outside hosted mode", () => {
405-
expect(
406-
shouldPrefetchSidebarTools({
407-
hostedMode: false,
408-
isAuthenticated: false,
409-
}),
410-
).toBe(true);
411-
});
412-
});

mcpjam-inspector/client/src/components/mcp-sidebar.tsx

Lines changed: 1 addition & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import { useState, useEffect, useMemo } from "react";
2+
import { useState, useMemo } from "react";
33
import {
44
Hammer,
55
MessageCircle,
@@ -57,15 +57,6 @@ import {
5757
TooltipTrigger,
5858
} from "@mcpjam/design-system/tooltip";
5959
import { HOSTED_MODE } from "@/lib/config";
60-
import {
61-
listTools,
62-
type ListToolsResultWithMetadata,
63-
} from "@/lib/apis/mcp-tools-api";
64-
import {
65-
isMCPApp,
66-
isOpenAIApp,
67-
isOpenAIAppAndMCPApp,
68-
} from "@/lib/mcp-ui/mcp-apps-utils";
6960
import {
7061
isHostedSidebarTabAllowed,
7162
normalizeHostedHashTab,
@@ -77,7 +68,6 @@ import { HOSTED_LOCAL_ONLY_TOOLTIP } from "@/lib/hosted-ui";
7768
import { useLearnMore } from "@/hooks/use-learn-more";
7869
import { LearnMoreExpandedPanel } from "@/components/learn-more/LearnMoreExpandedPanel";
7970
import type { BillingFeatureName } from "@/hooks/useOrganizationBilling";
80-
import type { ServerWithName } from "@/hooks/use-app-state";
8171
import type { Workspace } from "@/state/app-types";
8272
import type { OrganizationRouteSection } from "@/lib/hosted-navigation";
8373

@@ -163,17 +153,6 @@ export function applyBillingGateNavState(
163153
}));
164154
}
165155

166-
export function shouldPrefetchSidebarTools(options: {
167-
hostedMode: boolean;
168-
isAuthenticated: boolean;
169-
}): boolean {
170-
const { hostedMode, isAuthenticated } = options;
171-
// Hosted guests can briefly hydrate stale "connected" local servers before
172-
// runtime status sync clears them, which causes speculative tools/list calls
173-
// against guest server configs. Only signed-in hosted users should prefetch.
174-
return !hostedMode || isAuthenticated;
175-
}
176-
177156
// Define sections with their respective items
178157
const navigationSections: NavSection[] = [
179158
{
@@ -347,8 +326,6 @@ const hostedNavigationSections =
347326
interface MCPSidebarProps extends React.ComponentProps<typeof Sidebar> {
348327
onNavigate?: (section: string) => void;
349328
activeTab?: string;
350-
/** Servers to check for app capabilities */
351-
servers?: Record<string, ServerWithName>;
352329
/** Workspace state for the sidebar workspace picker */
353330
workspaces: Record<string, Workspace>;
354331
activeWorkspaceId: string;
@@ -373,8 +350,6 @@ interface MCPSidebarProps extends React.ComponentProps<typeof Sidebar> {
373350
createWorkspaceDisabledReason?: string;
374351
}
375352

376-
const APP_BUILDER_VISITED_KEY = "mcp-app-builder-visited";
377-
378353
function navigateToEvalsExploreList() {
379354
window.location.hash = withTestingSurface(buildEvalsHash({ type: "list" }));
380355
}
@@ -520,7 +495,6 @@ export function SidebarEvalsNavGroup({
520495
export function MCPSidebar({
521496
onNavigate,
522497
activeTab,
523-
servers = {},
524498
workspaces,
525499
activeWorkspaceId,
526500
onSwitchWorkspace,
@@ -553,12 +527,6 @@ export function MCPSidebar({
553527
const themeMode = usePreferencesStore((s) => s.themeMode);
554528
const { updateReady, restartAndInstall } = useUpdateNotification();
555529
const [showInviteDialog, setShowInviteDialog] = useState(false);
556-
const [toolsDataMap, setToolsDataMap] = useState<
557-
Record<string, ListToolsResultWithMetadata | null>
558-
>({});
559-
const [hasVisitedAppBuilder, setHasVisitedAppBuilder] = useState(() => {
560-
return localStorage.getItem(APP_BUILDER_VISITED_KEY) === "true";
561-
});
562530
const learnMore = useLearnMore();
563531
const { state, isMobile } = useSidebar();
564532
const activeWorkspace = workspaces[activeWorkspaceId];
@@ -576,70 +544,9 @@ export function MCPSidebar({
576544
}, [activeWorkspace?.organizationId, workspaces]);
577545
const shouldShowInviteCta = isAuthenticated && !!user && !!activeWorkspace;
578546

579-
// Get list of connected server names
580-
const connectedServerNames = useMemo(() => {
581-
return Object.entries(servers)
582-
.filter(([, server]) => server.connectionStatus === "connected")
583-
.map(([name]) => name);
584-
}, [servers]);
585-
586-
// Fetch tools data for connected servers
587-
useEffect(() => {
588-
const fetchToolsData = async () => {
589-
if (
590-
!shouldPrefetchSidebarTools({
591-
hostedMode: HOSTED_MODE,
592-
isAuthenticated,
593-
}) ||
594-
connectedServerNames.length === 0
595-
) {
596-
setToolsDataMap({});
597-
return;
598-
}
599-
600-
const newToolsDataMap: Record<
601-
string,
602-
ListToolsResultWithMetadata | null
603-
> = {};
604-
605-
await Promise.all(
606-
connectedServerNames.map(async (serverName) => {
607-
try {
608-
const result = await listTools({ serverId: serverName });
609-
newToolsDataMap[serverName] = result;
610-
} catch {
611-
newToolsDataMap[serverName] = null;
612-
}
613-
}),
614-
);
615-
616-
setToolsDataMap(newToolsDataMap);
617-
};
618-
619-
fetchToolsData();
620-
}, [connectedServerNames.join(","), isAuthenticated]);
621-
622-
// Check if any connected server is an app
623-
const hasAppServer = useMemo(() => {
624-
return Object.values(toolsDataMap).some(
625-
(toolsData) =>
626-
isMCPApp(toolsData) ||
627-
isOpenAIApp(toolsData) ||
628-
isOpenAIAppAndMCPApp(toolsData),
629-
);
630-
}, [toolsDataMap]);
631-
632-
const showAppBuilderBubble =
633-
hasAppServer && activeTab !== "app-builder" && !hasVisitedAppBuilder;
634-
635547
const handleNavClick = (url: string) => {
636548
if (onNavigate && url.startsWith("#")) {
637549
const section = url.slice(1);
638-
// Mark App Builder as visited when clicked (always, not just when bubble is visible)
639-
if (section === "app-builder" && showAppBuilderBubble) {
640-
localStorage.setItem(APP_BUILDER_VISITED_KEY, "true");
641-
setHasVisitedAppBuilder(true);
642-
}
643550
posthog.capture("sidebar_nav_clicked", {
644551
...standardEventProps("mcp_sidebar"),
645552
section,
@@ -649,19 +556,6 @@ export function MCPSidebar({
649556
window.open(url, "_blank");
650557
}
651558
};
652-
653-
const dismissAppBuilderBubble = () => {
654-
localStorage.setItem(APP_BUILDER_VISITED_KEY, "true");
655-
setHasVisitedAppBuilder(true);
656-
};
657-
658-
const appBuilderBubble = showAppBuilderBubble
659-
? {
660-
message: "Build your UI app with App Builder.",
661-
subMessage: "Get started",
662-
onDismiss: dismissAppBuilderBubble,
663-
}
664-
: null;
665559
const featureFlags = useMemo(
666560
() => ({
667561
"mcpjam-learning": !!learningEnabled,
@@ -794,9 +688,6 @@ export function MCPSidebar({
794688
isActive: item.url === `#${activeTab}`,
795689
}))}
796690
onItemClick={handleNavClick}
797-
appBuilderBubble={
798-
section.id === "mcp-apps" ? appBuilderBubble : null
799-
}
800691
learnMore={
801692
learnMoreEnabled
802693
? {

mcpjam-inspector/client/src/components/sidebar/__tests__/nav-main.test.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,31 @@ describe("NavMain", () => {
207207
);
208208
expect(screen.getByTestId("learn-more-servers")).toBeInTheDocument();
209209
});
210+
211+
it("renders App Builder without the removed guide bubble UI", () => {
212+
render(
213+
<NavMain
214+
items={[{ title: "App Builder", url: "#app-builder", icon: FakeIcon }]}
215+
/>,
216+
);
217+
218+
expect(
219+
screen.getByRole("button", { name: "App Builder" }),
220+
).toBeInTheDocument();
221+
expect(
222+
screen.queryByText("Build your UI app with App Builder."),
223+
).not.toBeInTheDocument();
224+
expect(screen.queryByLabelText("Dismiss")).not.toBeInTheDocument();
225+
});
226+
227+
it("uses the standard Learn More hover card for App Builder", () => {
228+
render(
229+
<NavMain
230+
items={[{ title: "App Builder", url: "#app-builder", icon: FakeIcon }]}
231+
learnMore={{ onExpand: vi.fn() }}
232+
/>,
233+
);
234+
235+
expect(screen.getByTestId("learn-more-app-builder")).toBeInTheDocument();
236+
});
210237
});

0 commit comments

Comments
 (0)