From 1d1c73d7e0f5b8d64bcbbab64e9ea63d57f0cd2b Mon Sep 17 00:00:00 2001 From: Shrinath Rao Date: Thu, 3 Sep 2026 11:54:16 +0000 Subject: [PATCH] fix(web): stop O2 AI 'Ask AI' bar appearing in the query editor on OSS builds (#14161) --- web/src/components/QueryEditor.spec.ts | 43 ++++++++++++++++++++++++++ web/src/components/QueryEditor.vue | 16 +++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/web/src/components/QueryEditor.spec.ts b/web/src/components/QueryEditor.spec.ts index 2b5b6c30ba..83f33f17e4 100644 --- a/web/src/components/QueryEditor.spec.ts +++ b/web/src/components/QueryEditor.spec.ts @@ -50,6 +50,7 @@ vi.mock("@/aws-exports", () => ({ // Component import must come after all vi.mock() declarations. import QueryEditor from "./QueryEditor.vue"; +import config from "@/aws-exports"; // ── CodeQueryEditor stub ───────────────────────────────────────────────────── @@ -151,6 +152,48 @@ describe("QueryEditor", () => { ai_enabled: false, }); }); + + it("should NOT show AI bar on auto-detected NL when ai_enabled is false (OSS)", async () => { + store.commit("setConfig", { ...store.state.zoConfig, ai_enabled: false }); + + wrapper = mountQueryEditor({ hideNlToggle: true }); + await nextTick(); + + wrapper.findComponent(codeQueryEditorStub).vm.$emit("nlpModeDetected", true); + await nextTick(); + + expect(wrapper.find('[data-test="query-editor-ai-input-bar"]').exists()).toBe(false); + }); + + it("should NOT show AI bar on auto-detected NL on OSS builds (isEnterprise false) even when ai_enabled is true", async () => { + config.isEnterprise = "false"; + store.commit("setConfig", { ...store.state.zoConfig, ai_enabled: true }); + + wrapper = mountQueryEditor({ hideNlToggle: true }); + await nextTick(); + + wrapper.findComponent(codeQueryEditorStub).vm.$emit("nlpModeDetected", true); + await nextTick(); + + expect(wrapper.find('[data-test="query-editor-ai-input-bar"]').exists()).toBe(false); + + config.isEnterprise = "true"; + store.commit("setConfig", { ...store.state.zoConfig, ai_enabled: false }); + }); + + it("should show AI bar on auto-detected NL when ai_enabled is true", async () => { + store.commit("setConfig", { ...store.state.zoConfig, ai_enabled: true }); + + wrapper = mountQueryEditor({ hideNlToggle: false }); + await nextTick(); + + wrapper.findComponent(codeQueryEditorStub).vm.$emit("nlpModeDetected", true); + await nextTick(); + + expect(wrapper.find('[data-test="query-editor-ai-input-bar"]').exists()).toBe(true); + + store.commit("setConfig", { ...store.state.zoConfig, ai_enabled: false }); + }); }); describe("isAIMode — external control", () => { diff --git a/web/src/components/QueryEditor.vue b/web/src/components/QueryEditor.vue index f94858bada..1cfab60119 100644 --- a/web/src/components/QueryEditor.vue +++ b/web/src/components/QueryEditor.vue @@ -109,12 +109,7 @@ { // Computed: AI input field class based on theme const aiInputFieldClass = computed(() => "h-7! flex-1 my-px"); +// AI features require an enterprise build with ai_enabled; OSS/AI-off must never surface the AI bar. +const aiFeatureEnabled = computed( + () => config.isEnterprise == "true" && store.state.zoConfig.ai_enabled, +); + // Computed: Is in AI mode? // When externally controlled (nlpMode prop passed), only show AI bar when nlpMode is explicitly ON. // The parent decides when the AI bar appears (e.g., after generation success). @@ -279,8 +279,8 @@ const isAIMode = computed(() => { // External control: only nlpMode matters for showing the AI bar return nlpMode.value; } - // Internal control: nlpMode OR auto-detected NL - return nlpMode.value || isNaturalLanguageDetected.value; + // Internal control: explicit toggle, or auto-detected NL only where AI is available + return nlpMode.value || (aiFeatureEnabled.value && isNaturalLanguageDetected.value); }); // Computed: Root container style - sets overall height