diff --git a/apps/web/src/components/chat/global-chat-sheet.tsx b/apps/web/src/components/chat/global-chat-sheet.tsx
index 1822cac4f2..7c7995db56 100644
--- a/apps/web/src/components/chat/global-chat-sheet.tsx
+++ b/apps/web/src/components/chat/global-chat-sheet.tsx
@@ -2,6 +2,7 @@ import { lazy, Suspense, useState } from "react"
import { useMountEffect } from "@/hooks/use-mount-effect"
import { useMapleOrganizationId } from "@/hooks/use-maple-organization"
import { isDialogOpen, isEditableTarget } from "@maple/ui/lib/keyboard"
+import { aiChatEnabled } from "@/lib/region"
const OPEN_CHAT_EVENT = "maple:open-chat-sheet"
@@ -35,6 +36,10 @@ export function openGlobalChat() {
* history restores from the durable stream on reopen, same as AlertChatSheet.
*/
export function GlobalChatSheet() {
+ return aiChatEnabled ? : null
+}
+
+function GlobalChatSheetInner() {
const [open, setOpen] = useState(false)
const orgId = useMapleOrganizationId()
diff --git a/apps/web/src/components/command-palette/command-palette.tsx b/apps/web/src/components/command-palette/command-palette.tsx
index 5fad4fc87f..a92a765558 100644
--- a/apps/web/src/components/command-palette/command-palette.tsx
+++ b/apps/web/src/components/command-palette/command-palette.tsx
@@ -27,6 +27,7 @@ import {
} from "@/components/icons"
import { isClerkAuthEnabled } from "@/lib/services/common/auth-mode"
import { openGlobalChat } from "@/components/chat/global-chat-sheet"
+import { aiChatEnabled } from "@/lib/region"
import { paletteNavItems } from "@/components/dashboard/nav-items"
import { useDashboardPreferences } from "@/hooks/use-dashboard-preferences"
import { useDashboardsRead } from "@/hooks/use-dashboard-store"
@@ -197,15 +198,19 @@ function PaletteContent({
const isDark = theme === "dark"
const actions: PaletteEntry[] = [
- {
- id: "action:ask-maple-ai",
- title: "Ask Maple AI",
- group: "Actions",
- keywords: "chat ai assistant maple ask question",
- icon: ChatBubbleSparkleIcon,
- run: openGlobalChat,
- shortcut: "C",
- },
+ ...(aiChatEnabled
+ ? [
+ {
+ id: "action:ask-maple-ai",
+ title: "Ask Maple AI",
+ group: "Actions",
+ keywords: "chat ai assistant maple ask question",
+ icon: ChatBubbleSparkleIcon,
+ run: openGlobalChat,
+ shortcut: "C",
+ } satisfies PaletteEntry,
+ ]
+ : []),
{
id: "action:toggle-theme",
title: isDark ? "Switch to light mode" : "Switch to dark mode",
diff --git a/apps/web/src/components/dashboard-builder/widgets/widget-actions-context.tsx b/apps/web/src/components/dashboard-builder/widgets/widget-actions-context.tsx
index e88f28fc8a..b333fe49c0 100644
--- a/apps/web/src/components/dashboard-builder/widgets/widget-actions-context.tsx
+++ b/apps/web/src/components/dashboard-builder/widgets/widget-actions-context.tsx
@@ -9,6 +9,7 @@ import {
type WidgetFixContext,
} from "@/components/chat/widget-fix-context"
import { encodeAlertChartToSearchParam } from "@/lib/alerts/widget-chart-param"
+import { aiChatEnabled } from "@/lib/region"
import { dataSourceRawSql, isQueryDataSource } from "@maple/widgets/dashboard"
import { Result, useAtomValue } from "@/lib/effect-atom"
import { dashboardSharesAtom } from "@/components/dashboard-builder/toolbar/dashboard-shares"
@@ -147,7 +148,7 @@ export function WidgetActionsProvider({
: undefined
const fix =
- dashboardId && errorKind === "decode"
+ aiChatEnabled && dashboardId && errorKind === "decode"
? () => {
const ctx: WidgetFixContext = {
dashboardId,
diff --git a/apps/web/src/components/layout/dashboard-layout.tsx b/apps/web/src/components/layout/dashboard-layout.tsx
index a0e404c968..3c8ccc6b21 100644
--- a/apps/web/src/components/layout/dashboard-layout.tsx
+++ b/apps/web/src/components/layout/dashboard-layout.tsx
@@ -17,6 +17,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@maple/ui/components/ui
import { Kbd } from "@maple/ui/components/ui/kbd"
import { ChatBubbleSparkleIcon, LayoutLeftIcon, LayoutRightIcon } from "@/components/icons"
import { openGlobalChat } from "@/components/chat/global-chat-sheet"
+import { aiChatEnabled } from "@/lib/region"
import { ConnectButton } from "@/components/header/connect-button"
import { OnboardingChecklistButton } from "@/components/header/onboarding-checklist-button"
import { QuotaBanner } from "@/components/billing/quota-banner"
@@ -112,23 +113,25 @@ function Breadcrumbs({ items, children }: { items: BreadcrumbEntry[]; children?:
-
-
- }
- >
-
-
-
- Ask Maple AI C
-
-
+ {aiChatEnabled && (
+
+
+ }
+ >
+
+
+
+ Ask Maple AI C
+
+
+ )}
{/* Self-gating: renders only when the sidebar has collapsed to a sheet *and* a
diff --git a/apps/web/src/lib/region.ts b/apps/web/src/lib/region.ts
index cf89dfeb80..9f7c1577e2 100644
--- a/apps/web/src/lib/region.ts
+++ b/apps/web/src/lib/region.ts
@@ -22,3 +22,6 @@ export function regionAppUrl(region: MapleRegion): string | undefined {
/** Whether this deployment has more than one region, and so whether regions are worth showing. */
export const hasMultipleRegions = Object.keys(regionAppUrls).length > 1
+
+/** Maple AI chat is off on the EU instance for now; every chat entry point checks this. */
+export const aiChatEnabled = currentRegion !== "eu"
diff --git a/apps/web/src/routes/chat.tsx b/apps/web/src/routes/chat.tsx
index a7d26faada..fd4326f9d7 100644
--- a/apps/web/src/routes/chat.tsx
+++ b/apps/web/src/routes/chat.tsx
@@ -1,6 +1,7 @@
-import { createFileRoute } from "@tanstack/react-router"
+import { createFileRoute, redirect } from "@tanstack/react-router"
import { Schema } from "effect"
import { ChatPage } from "@/components/chat/chat-page"
+import { aiChatEnabled } from "@/lib/region"
import { decodeAlertContextFromSearchParam } from "@/components/chat/alert-context"
import {
alertContextToInvestigation,
@@ -29,6 +30,9 @@ const ChatSearch = Schema.Struct({
export const Route = createFileRoute("/chat")({
component: ChatRoute,
validateSearch: Schema.toStandardSchemaV1(ChatSearch),
+ beforeLoad: () => {
+ if (!aiChatEnabled) throw redirect({ to: "/" })
+ },
})
function ChatRoute() {