diff --git a/scripts/translations/.translation_state.json b/scripts/translations/.translation_state.json index 81b72bd0ea..87c967532a 100644 --- a/scripts/translations/.translation_state.json +++ b/scripts/translations/.translation_state.json @@ -15539,7 +15539,6 @@ "actions": { "actionsRefresh": "3cf8d66227384dc2", "aiChatClose": "a619ab8971872dcf", - "aiChatExpand": "cb569c3ed515eb89", "aiChatToggle": "e5000da4d3f67a4c", "aiToolsetsRefresh": "3cf8d66227384dc2", "alertDestinationsAdd": "d0eb0b5fd8a15847", diff --git a/web/src/lib/vue-shortcut-manager/ShortcutCheatsheet.vue b/web/src/lib/vue-shortcut-manager/ShortcutCheatsheet.vue index 4321b08e3e..99d1bb4ad7 100644 --- a/web/src/lib/vue-shortcut-manager/ShortcutCheatsheet.vue +++ b/web/src/lib/vue-shortcut-manager/ShortcutCheatsheet.vue @@ -261,6 +261,7 @@ const capabilities = computed(() => ({ incidentsEnabled: Boolean(store.state.zoConfig?.incidents_enabled), modelPricingEnabled: Boolean(store.state.zoConfig?.model_pricing_enabled), rbacEnabled: Boolean(store.state.zoConfig?.rbac_enabled), + aiEnabled: Boolean(store.state.zoConfig?.ai_enabled), })); const open = computed({ @@ -315,11 +316,14 @@ const allModules = computed(() => { return [ { title: t(group.pageKey, PAGE_TITLE_PARAMS[group.pageKey] ?? {}), - entries: group.shortcuts.map((s) => ({ - id: s.id, - display: entryDisplay(s), - label: t(s.descriptionKey), - })), + entries: group.shortcuts + // Entry-level gate mirrors the feature's real availability (e.g. the AI chat shortcut only works on enterprise with ai_enabled). + .filter((s) => !s.visible || s.visible(caps)) + .map((s) => ({ + id: s.id, + display: entryDisplay(s), + label: t(s.descriptionKey), + })), }, ]; }), diff --git a/web/src/lib/vue-shortcut-manager/__tests__/shortcutRegistry.spec.ts b/web/src/lib/vue-shortcut-manager/__tests__/shortcutRegistry.spec.ts index 1ef4ec8f0c..3b1706c623 100644 --- a/web/src/lib/vue-shortcut-manager/__tests__/shortcutRegistry.spec.ts +++ b/web/src/lib/vue-shortcut-manager/__tests__/shortcutRegistry.spec.ts @@ -13,6 +13,7 @@ const OSS: ShortcutCapabilities = { incidentsEnabled: false, modelPricingEnabled: false, rbacEnabled: false, + aiEnabled: false, }; const ENTERPRISE: ShortcutCapabilities = { isEnterprise: true, @@ -22,6 +23,7 @@ const ENTERPRISE: ShortcutCapabilities = { incidentsEnabled: true, modelPricingEnabled: true, rbacEnabled: true, + aiEnabled: true, }; const CLOUD: ShortcutCapabilities = { isEnterprise: false, @@ -31,6 +33,7 @@ const CLOUD: ShortcutCapabilities = { incidentsEnabled: true, modelPricingEnabled: true, rbacEnabled: true, + aiEnabled: true, }; /** Mirrors ShortcutCheatsheet: a page shows unless its gate rejects the caps. */ @@ -50,6 +53,15 @@ function visibleModuleTitles(caps: ShortcutCapabilities): string[] { ); } +/** Entry-level gate, mirroring ShortcutCheatsheet: an entry shows unless its own gate rejects the caps. */ +function entryVisible(id: string, caps: ShortcutCapabilities): boolean { + for (const g of SHORTCUT_REGISTRY) { + const e = g.shortcuts.find((s) => s.id === id); + if (e) return !e.visible || e.visible(caps); + } + throw new Error(`entry ${id} not registered`); +} + const GATED_IN_OSS = [ "shortcuts.pages.searchSchedulers", "shortcuts.pages.alertSources", @@ -177,3 +189,21 @@ describe("shortcut cheatsheet OSS gating", () => { expect(cloudNonMeta.has("shortcuts.pages.orgManagement")).toBe(false); }); }); + +describe("aiChatToggle entry visibility", () => { + it("is hidden on OSS (the shortcut is never registered there)", () => { + expect(entryVisible("aiChatToggle", OSS)).toBe(false); + }); + + it("is hidden on cloud — the AI chat shortcut is enterprise-only", () => { + expect(entryVisible("aiChatToggle", CLOUD)).toBe(false); + }); + + it("is hidden on enterprise when ai_enabled is off (the handler no-ops)", () => { + expect(entryVisible("aiChatToggle", { ...ENTERPRISE, aiEnabled: false })).toBe(false); + }); + + it("is shown only on enterprise with ai_enabled on", () => { + expect(entryVisible("aiChatToggle", ENTERPRISE)).toBe(true); + }); +}); diff --git a/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts b/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts index 94fac4914c..93b5556950 100644 --- a/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts +++ b/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts @@ -42,6 +42,8 @@ export interface ShortcutEntry { display?: string; /** Fire even while a text input has focus (see `Shortcut.allowInInput`). */ allowInInput?: boolean; + /** Hide this entry in the cheatsheet unless the edition/config exposes it. */ + visible?: (caps: ShortcutCapabilities) => boolean; } export interface ShortcutGroup { @@ -63,6 +65,7 @@ export interface ShortcutCapabilities { incidentsEnabled: boolean; modelPricingEnabled: boolean; rbacEnabled: boolean; + aiEnabled: boolean; } export interface ShortcutModule { @@ -86,6 +89,7 @@ const incidents = (c: ShortcutCapabilities) => enterpriseOrCloud(c) && c.inciden const onlineEvals = (c: ShortcutCapabilities) => enterpriseOrCloud(c) && c.onlineEvalsEnabled; const modelPricing = (c: ShortcutCapabilities) => enterpriseOrCloud(c) && c.modelPricingEnabled; const rbac = (c: ShortcutCapabilities) => enterpriseOrCloud(c) && c.rbacEnabled; +const aiChat = (c: ShortcutCapabilities) => c.isEnterprise && c.aiEnabled; // Cluster-scoped admin surfaces only render inside the _meta org. const metaAdmin = (c: ShortcutCapabilities) => c.isEnterprise && c.isMetaOrg; const cloudMetaAdmin = (c: ShortcutCapabilities) => c.isCloud && c.isMetaOrg; @@ -207,6 +211,7 @@ export const SHORTCUT_REGISTRY: ShortcutGroup[] = [ keyForWindows: "ctrl+b", keyForMac: "meta+b", descriptionKey: "shortcuts.actions.aiChatToggle", + visible: aiChat, }, ], }, diff --git a/web/src/locales/languages/ar-SA.json b/web/src/locales/languages/ar-SA.json index 36f57978db..8e61c1c6f9 100644 --- a/web/src/locales/languages/ar-SA.json +++ b/web/src/locales/languages/ar-SA.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "تحديث قائمة الرموز", "aiChatToggle": "تبديل دردشة الذكاء الاصطناعي", "aiChatClose": "إغلاق دردشة الذكاء الاصطناعي", - "aiChatExpand": "توسيع/تقويم دردشة الذكاء الاصطناعي", "logsSaveView": "عرض حفظ كملف محفوظ", "logsExport": "نتائج التصدير CSV", "tracesCopyUrl": "رابط مشاركة التتبع للنسخ", diff --git a/web/src/locales/languages/de-DE.json b/web/src/locales/languages/de-DE.json index c17e149634..76656fa04b 100644 --- a/web/src/locales/languages/de-DE.json +++ b/web/src/locales/languages/de-DE.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Tokenliste aktualisieren", "aiChatToggle": "KI-Chat umschalten", "aiChatClose": "KI-Chat schließen", - "aiChatExpand": "KI-Chat erweitern/einklappen", "logsSaveView": "Als gespeicherte Ansicht speichern", "logsExport": "Ergebnisse als CSV exportieren", "tracesCopyUrl": "Trace-Share-URL kopieren", diff --git a/web/src/locales/languages/en-US.json b/web/src/locales/languages/en-US.json index 533cc951c4..c30b820a61 100644 --- a/web/src/locales/languages/en-US.json +++ b/web/src/locales/languages/en-US.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Refresh token list", "aiChatToggle": "Toggle AI chat", "aiChatClose": "Close AI chat", - "aiChatExpand": "Expand/collapse AI chat", "logsSaveView": "Save as saved view", "logsExport": "Export results as CSV", "tracesCopyUrl": "Copy trace share URL", diff --git a/web/src/locales/languages/es-ES.json b/web/src/locales/languages/es-ES.json index 6b3e7d66ce..e9811aa609 100644 --- a/web/src/locales/languages/es-ES.json +++ b/web/src/locales/languages/es-ES.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Actualizar lista de tokens", "aiChatToggle": "Alternar el chat de IA", "aiChatClose": "Cerrar chat de IA", - "aiChatExpand": "Expandir/contraer chat de IA", "logsSaveView": "Guardar como vista guardada", "logsExport": "Exportar los resultados como CSV", "tracesCopyUrl": "Copiar URL para compartir la traza", diff --git a/web/src/locales/languages/fr-FR.json b/web/src/locales/languages/fr-FR.json index 5c25f49508..dda498ec55 100644 --- a/web/src/locales/languages/fr-FR.json +++ b/web/src/locales/languages/fr-FR.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Actualiser la liste des jetons", "aiChatToggle": "Activer/désactiver le chat IA", "aiChatClose": "Fermer le chat IA", - "aiChatExpand": "Développer/réduire le chat IA", "logsSaveView": "Enregistrer en tant que vue enregistrée", "logsExport": "Exporter les résultats au format CSV", "tracesCopyUrl": "Copier l'URL de partage de la trace", diff --git a/web/src/locales/languages/it-IT.json b/web/src/locales/languages/it-IT.json index 15b23c826e..986971c45c 100644 --- a/web/src/locales/languages/it-IT.json +++ b/web/src/locales/languages/it-IT.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Aggiorna elenco token", "aiChatToggle": "Attiva la chat AI", "aiChatClose": "Chiudi chat AI", - "aiChatExpand": "Espandi/comprimi chat AI", "logsSaveView": "Salva come visualizzazione salvata", "logsExport": "Esporta i risultati in formato CSV", "tracesCopyUrl": "Copia URL di condivisione della traccia", diff --git a/web/src/locales/languages/ja-JP.json b/web/src/locales/languages/ja-JP.json index feadf149a0..4324e608db 100644 --- a/web/src/locales/languages/ja-JP.json +++ b/web/src/locales/languages/ja-JP.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "トークンリストを更新", "aiChatToggle": "AI チャットを切り替える", "aiChatClose": "AI チャットを閉じる", - "aiChatExpand": "AI チャットを展開/折りたたむ", "logsSaveView": "保存済みビューとして保存", "logsExport": "結果を CSV としてエクスポート", "tracesCopyUrl": "トレース共有URLをコピー", diff --git a/web/src/locales/languages/ko-KR.json b/web/src/locales/languages/ko-KR.json index f1c50af176..be7cd90bd6 100644 --- a/web/src/locales/languages/ko-KR.json +++ b/web/src/locales/languages/ko-KR.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "토큰 목록 새로고침", "aiChatToggle": "AI 채팅 켜기/끄기", "aiChatClose": "AI 채팅 닫기", - "aiChatExpand": "AI 채팅 펼치기/접기", "logsSaveView": "저장된 뷰로 저장", "logsExport": "결과를 CSV로 내보내기", "tracesCopyUrl": "트레이스 공유 URL 복사", diff --git a/web/src/locales/languages/nl-NL.json b/web/src/locales/languages/nl-NL.json index 59c2ed3583..4e2f747454 100644 --- a/web/src/locales/languages/nl-NL.json +++ b/web/src/locales/languages/nl-NL.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Tokenlijst vernieuwen", "aiChatToggle": "AI-chat inschakelen", "aiChatClose": "AI-chat sluiten", - "aiChatExpand": "AI-chat uitvouwen/invouwen", "logsSaveView": "Opslaan als opgeslagen weergave", "logsExport": "Exporteer resultaten als CSV", "tracesCopyUrl": "Kopieer trace-deel-URL", diff --git a/web/src/locales/languages/pl-PL.json b/web/src/locales/languages/pl-PL.json index d63e476ca9..3f57ac0de1 100644 --- a/web/src/locales/languages/pl-PL.json +++ b/web/src/locales/languages/pl-PL.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Odśwież listę tokenów", "aiChatToggle": "Przełącz czat AI", "aiChatClose": "Zamknij czat AI", - "aiChatExpand": "Rozwiń/zwiń czat AI", "logsSaveView": "Zapisz jako zapisany widok", "logsExport": "Eksportuj wyniki jako CSV", "tracesCopyUrl": "Kopiuj URL do udostępnienia śladu", diff --git a/web/src/locales/languages/pt-PT.json b/web/src/locales/languages/pt-PT.json index 0b373f7b48..574c17d03e 100644 --- a/web/src/locales/languages/pt-PT.json +++ b/web/src/locales/languages/pt-PT.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Atualizar lista de tokens", "aiChatToggle": "Alternar bate-papo com IA", "aiChatClose": "Fechar chat de IA", - "aiChatExpand": "Expandir/recolher chat de IA", "logsSaveView": "Salvar como visualização salva", "logsExport": "Exportar resultados como CSV", "tracesCopyUrl": "Copiar URL de compartilhamento do rastreamento", diff --git a/web/src/locales/languages/ru-RU.json b/web/src/locales/languages/ru-RU.json index 46f3c79454..10c3632557 100644 --- a/web/src/locales/languages/ru-RU.json +++ b/web/src/locales/languages/ru-RU.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Обновить список токенов", "aiChatToggle": "Переключить AI-чат", "aiChatClose": "Закрыть чат ИИ", - "aiChatExpand": "Развернуть/свернуть чат ИИ", "logsSaveView": "Сохранить как сохранённое представление", "logsExport": "Экспортировать результаты в CSV", "tracesCopyUrl": "Скопировать общую ссылку на трассировку", diff --git a/web/src/locales/languages/tr-TR.json b/web/src/locales/languages/tr-TR.json index 0ddfe7a397..2dd2e09d23 100644 --- a/web/src/locales/languages/tr-TR.json +++ b/web/src/locales/languages/tr-TR.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Belirteç listesini yenile", "aiChatToggle": "AI sohbetini aç/kapat", "aiChatClose": "AI sohbetini kapat", - "aiChatExpand": "AI sohbetini genişlet/daralt", "logsSaveView": "Kayıtlı görünüm olarak kaydet", "logsExport": "Sonuçları CSV olarak dışa aktarın", "tracesCopyUrl": "İz paylaşım URL'sini kopyala", diff --git a/web/src/locales/languages/vi-VN.json b/web/src/locales/languages/vi-VN.json index 4ee9970c41..c6464e388a 100644 --- a/web/src/locales/languages/vi-VN.json +++ b/web/src/locales/languages/vi-VN.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "Làm mới danh sách token", "aiChatToggle": "Bật/tắt trò chuyện AI", "aiChatClose": "Đóng trò chuyện AI", - "aiChatExpand": "Mở rộng/thu gọn trò chuyện AI", "logsSaveView": "Lưu dưới dạng chế độ xem đã lưu", "logsExport": "Xuất kết quả dưới dạng CSV", "tracesCopyUrl": "Sao chép URL chia sẻ dấu vết", diff --git a/web/src/locales/languages/zh-CN.json b/web/src/locales/languages/zh-CN.json index ced65c508d..ec9c420490 100644 --- a/web/src/locales/languages/zh-CN.json +++ b/web/src/locales/languages/zh-CN.json @@ -15164,7 +15164,6 @@ "syntheticsTokensRefresh": "刷新令牌列表", "aiChatToggle": "切换 AI 聊天", "aiChatClose": "关闭 AI 聊天", - "aiChatExpand": "展开/折叠 AI 聊天", "logsSaveView": "另存为已保存视图", "logsExport": "将结果导出为 CSV", "tracesCopyUrl": "复制追踪分享链接", diff --git a/web/src/locales/languages/zh-TW.json b/web/src/locales/languages/zh-TW.json index 6c7e779185..5efe2e180b 100644 --- a/web/src/locales/languages/zh-TW.json +++ b/web/src/locales/languages/zh-TW.json @@ -15159,7 +15159,6 @@ "syntheticsTokensRefresh": "重新整理 Token 清單", "aiChatToggle": "切換AI聊天", "aiChatClose": "關閉 AI 聊天", - "aiChatExpand": "展開/收合 AI 聊天", "logsSaveView": "另存為已儲存檢視", "logsExport": "匯出結果為CSV", "tracesCopyUrl": "複製追蹤分享網址",