tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 75f3480a4619d2fdb9e8cce5b0c2bec3f87ede49
parent dee48eda9aea422c67f6e279f9ed3d5257faffbe
Author: Omar Gonzalez <s9tpepper@apache.org>
Date:   Tue, 23 Dec 2025 21:53:28 +0000

Bug 2001501 - Chats options for app menu bar and hamburger menus r=ai-frontend-reviewers,fluent-reviewers,frontend-codestyle-reviewers,Gijs,bolsson

Differential Revision: https://phabricator.services.mozilla.com/D276780

Diffstat:
Mbrowser/base/content/appmenu-viewcache.inc.xhtml | 4++++
Mbrowser/base/content/browser-menubar.inc | 13+++++++++++++
Mbrowser/base/content/browser-menubar.js | 2++
Mbrowser/base/content/browser-sets.inc | 1+
Mbrowser/base/content/browser-sets.js | 4++++
Mbrowser/base/content/test/menubar/browser.toml | 2++
Abrowser/base/content/test/menubar/browser_aiwindow_options.js | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/aiwindow/ui/modules/AIWindow.sys.mjs | 27+++++++++++++++++++++++++++
Abrowser/components/aiwindow/ui/modules/AIWindowMenu.sys.mjs | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abrowser/components/aiwindow/ui/modules/moz.build | 6++++++
Mbrowser/components/aiwindow/ui/moz.build | 5+++++
Abrowser/components/aiwindow/ui/test/AIWindowTestUtils.sys.mjs | 24++++++++++++++++++++++++
Mbrowser/components/aiwindow/ui/test/browser/browser_open_aiwindow.js | 33++++++++++++++++++++++++++-------
Mbrowser/components/aiwindow/ui/test/xpcshell/test_ChatMessage.js | 2+-
Mbrowser/components/customizableui/content/panelUI.js | 6++++++
Mbrowser/locales/en-US/browser/appmenu.ftl | 2++
Mbrowser/locales/en-US/browser/menubar.ftl | 7+++++++
17 files changed, 497 insertions(+), 8 deletions(-)

diff --git a/browser/base/content/appmenu-viewcache.inc.xhtml b/browser/base/content/appmenu-viewcache.inc.xhtml @@ -73,6 +73,10 @@ data-l10n-id="appmenuitem-history" closemenu="none" /> + <toolbarbutton id="appMenu-chats-history-button" + class="subviewbutton" + data-l10n-id="appmenuitem-chats" + command="Tools:ChatsHistory"/> <toolbarbutton id="appMenu-downloads-button" class="subviewbutton" data-l10n-id="appmenuitem-downloads" diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc @@ -214,6 +214,11 @@ <menuitem id="menu_showAllHistory" key="showAllHistoryKb" command="Browser:ShowAllHistory" data-l10n-id="menu-history-show-all-history"/> + + <menuitem id="chatsHistoryMenu" class="chats-history-menuitem" + data-l10n-id="appmenuitem-chats" + disabled="true" hidden="true" command="Tools:ChatsHistory"/> + <menuitem id="sanitizeItem" key="key_sanitize" command="Tools:Sanitize" data-l10n-id="menu-history-clear-recent-history"/> @@ -255,8 +260,16 @@ #endif </menupopup> </menu> + + <menuseparator id="startChatHistorySeparator" hidden="true"/> + <menuitem id="recentChatsHeader" class="recent-chats-header" + data-l10n-id="menu-history-chats-recent" + disabled="true" hidden="true"/> + # Chat history menu items are added dynamically in browser-menubar.js + <menuseparator id="startHistorySeparator" class="hide-if-empty-places-result"/> + </menupopup> </menu> diff --git a/browser/base/content/browser-menubar.js b/browser/base/content/browser-menubar.js @@ -181,6 +181,8 @@ document.addEventListener( if (!event.target.parentNode._placesView) { new HistoryMenu(event); } + + AIWindow.appMenu(event, window); break; case "historyUndoPopup": document diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc @@ -98,6 +98,7 @@ <command id="Tools:Addons" /> <command id="cmd_openUnifiedExtensionsPanel" /> <command id="Tools:AIWindow" /> + <command id="Tools:ChatsHistory" /> <command id="Tools:ClassicWindow" /> <command id="Tools:Sanitize" /> <command id="Tools:PrivateBrowsing" /> diff --git a/browser/base/content/browser-sets.js b/browser/base/content/browser-sets.js @@ -230,6 +230,10 @@ document.addEventListener( case "Tools:AIWindow": OpenBrowserWindow({ aiWindow: true }); break; + case "Tools:ChatsHistory": + // @todo Bug 2006543 + // Implement opening the chat history view + break; case "Tools:Sanitize": Sanitizer.showUI(window); break; diff --git a/browser/base/content/test/menubar/browser.toml b/browser/base/content/test/menubar/browser.toml @@ -5,6 +5,8 @@ prefs = [ ] tags = "os_integration" +["browser_aiwindow_options.js"] + ["browser_file_close_tabs.js"] ["browser_file_menu_import_wizard.js"] diff --git a/browser/base/content/test/menubar/browser_aiwindow_options.js b/browser/base/content/test/menubar/browser_aiwindow_options.js @@ -0,0 +1,230 @@ +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + sinon: "resource://testing-common/Sinon.sys.mjs", +}); + +const { AIWindowTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AIWindowTestUtils.sys.mjs" +); + +function makeMenuItem(id) { + const menuItem = document.createXULElement("menuitem"); + menuItem.setAttribute("id", id); + + const node = document.childNodes[0]; + document.documentElement.appendChild(menuItem, node); + + return menuItem; +} + +let gSandbox = null, + gAiWindow = null; + +async function test_AiWindowMenu_setup( + returnRecentConversations = true, + openAiWindow = true +) { + gSandbox = lazy.sinon.createSandbox(); + + const testMenuItem = makeMenuItem("historyMenuItem"); + const testEvent = new Event("popupShowing"); + testMenuItem.dispatchEvent(testEvent); + + // add mock menuitem that the Chats option is added before + const sanitizeItem = makeMenuItem("sanitizeItem"); + testMenuItem.appendChild(sanitizeItem); + + const startChatHistorySeparator = makeMenuItem("startChatHistorySeparator"); + testMenuItem.appendChild(startChatHistorySeparator); + + const recentChatsHeader = makeMenuItem("recentChatsHeader"); + testMenuItem.appendChild(recentChatsHeader); + + gSandbox + .stub(AIWindow.chatStore, "findRecentConversations") + .callsFake(amount => { + const conversations = []; + + if (!returnRecentConversations) { + return conversations; + } + + for (let i = 0; i < amount; i++) { + conversations.push({ title: `Conversation ${i}`, id: i.toString() }); + } + + return conversations; + }); + + gAiWindow = await AIWindowTestUtils.openAIWindow(openAiWindow); + if (openAiWindow) { + gAiWindow.document.documentElement.setAttribute("ai-window", true); + } + + return [testEvent, testMenuItem]; +} + +async function test_AiWindowMenu_cleanup() { + await BrowserTestUtils.closeWindow(gAiWindow); + gSandbox.restore(); +} + +describe("AiWindow Menu options", () => { + let testEvent, testMenuItem; + describe("AIWindow enabled and active and there are chats", () => { + beforeEach(async () => { + await AIWindowTestUtils.toggleAIWindowPref(SpecialPowers, true); + const testObjects = await test_AiWindowMenu_setup(true); + + testEvent = testObjects[0]; + testMenuItem = testObjects[1]; + }); + + afterEach(async () => { + await test_AiWindowMenu_cleanup(); + }); + + it("adds the Chats option to History menu", () => { + AIWindow.appMenu(testEvent, gAiWindow); + + const chatsOption = testMenuItem.querySelector("#menu_chats"); + + Assert.ok(chatsOption, "Could not find the Chats option"); + }); + + it("enables the Recent Chats label", async () => { + AIWindow.appMenu(testEvent, gAiWindow); + + await waitForElement(gAiWindow, "#recentChatsHeader"); + + const recentChatsHeader = + testMenuItem.querySelector("#recentChatsHeader"); + + Assert.ok(recentChatsHeader); + Assert.equal(recentChatsHeader.hasAttribute("hidden"), false); + }); + + it("adds recent chats in the history menu", async () => { + await AIWindow.appMenu(testEvent, gAiWindow); + + await waitForElement(gAiWindow, "#recentChatsHeader"); + + const conversationItems = + gAiWindow.document.documentElement.querySelectorAll( + ".recent-chat-item" + ); + Assert.equal(conversationItems.length, 4); + }); + }); + + describe("AIWindow enabled and active and no chats", () => { + beforeEach(async () => { + await AIWindowTestUtils.toggleAIWindowPref(SpecialPowers, true); + const testObjects = await test_AiWindowMenu_setup(false); + + testEvent = testObjects[0]; + testMenuItem = testObjects[1]; + }); + + afterEach(async () => { + await test_AiWindowMenu_cleanup(); + }); + + it("doesnt add chats options when there arent any", async () => { + await AIWindow.appMenu(testEvent, gAiWindow); + + const conversationItems = + gAiWindow.document.documentElement.querySelectorAll( + ".recent-chat-item" + ); + Assert.equal( + conversationItems.length, + 0, + "Found recent chat items but should be none" + ); + + const recentChatsHeader = + gAiWindow.document.documentElement.querySelector("#recentChatsHeader"); + Assert.ok( + recentChatsHeader.hasAttribute("hidden"), + "Found chats header but should be hidden" + ); + }); + }); + + describe("AIWindow enabled but not active", () => { + beforeEach(async () => { + await AIWindowTestUtils.toggleAIWindowPref(SpecialPowers, true); + const testObjects = await test_AiWindowMenu_setup(false, false); + + testEvent = testObjects[0]; + testMenuItem = testObjects[1]; + }); + + afterEach(async () => { + await test_AiWindowMenu_cleanup(); + }); + + it("does not add chats options", async () => { + await AIWindow.appMenu(testEvent, gAiWindow); + + const recentChatsHeader = + gAiWindow.document.documentElement.querySelector("#recentChatsHeader"); + Assert.ok( + recentChatsHeader.hasAttribute("hidden"), + "Found chats header visible but should be hidden" + ); + + const chatsOption = + gAiWindow.document.documentElement.querySelector("#menu_chats"); + + Assert.ok(!chatsOption, "Found the Chats option"); + }); + }); + + describe("AIWindow enabled but not active", () => { + beforeEach(async () => { + await AIWindowTestUtils.toggleAIWindowPref(SpecialPowers, false); + const testObjects = await test_AiWindowMenu_setup(false, false); + + testEvent = testObjects[0]; + testMenuItem = testObjects[1]; + }); + + afterEach(async () => { + await test_AiWindowMenu_cleanup(); + }); + + it("does not add chats options", async () => { + await AIWindow.appMenu(testEvent, gAiWindow); + + const recentChatsHeader = + gAiWindow.document.documentElement.querySelector("#recentChatsHeader"); + Assert.ok( + recentChatsHeader.hasAttribute("hidden"), + "Found chats header visible but should be hidden" + ); + + const chatsOption = + gAiWindow.document.documentElement.querySelector("#menu_chats"); + + Assert.ok(!chatsOption, "Found the Chats option"); + }); + }); + + // @todo Bug 2007583 + // Add test for clicking Recent Chat item +}); + +async function waitForElement(win, elementSelector) { + await BrowserTestUtils.waitForMutationCondition( + win, + { childList: true }, + () => { + const elements = + win.document.documentElement.querySelectorAll(elementSelector); + return elements.length; + } + ); +} diff --git a/browser/components/aiwindow/ui/modules/AIWindow.sys.mjs b/browser/components/aiwindow/ui/modules/AIWindow.sys.mjs @@ -6,6 +6,14 @@ import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; const AIWINDOW_URL = "chrome://browser/content/aiwindow/aiWindow.html"; +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + ChatStore: + "moz-src:///browser/components/aiwindow/ui/modules/ChatStore.sys.mjs", + + AIWindowMenu: + "moz-src:///browser/components/aiwindow/ui/modules/AIWindowMenu.sys.mjs", +}); /** * AI Window Service @@ -14,6 +22,7 @@ const AIWINDOW_URL = "chrome://browser/content/aiwindow/aiWindow.html"; export const AIWindow = { _initialized: false, _windowStates: new Map(), + _aiWindowMenu: null, /** * Handles startup tasks @@ -31,6 +40,8 @@ export const AIWindow = { false ); + ChromeUtils.defineLazyGetter(this, "chatStore", () => new lazy.ChatStore()); + this._initialized = true; this._windowStates.set(win, {}); }, @@ -109,6 +120,22 @@ export const AIWindow = { return this.isAIWindowActive(win) && this.AIWindowEnabled; }, + /** + * Adds the AI Window app menu options + * + * @param {Event} event - History menu click event + * @param {Window} win - current Window reference + * + * @returns {Promise} - Resolves when menu is done being added + */ + appMenu(event, win) { + if (!this._aiWindowMenu) { + this._aiWindowMenu = new lazy.AIWindowMenu(); + } + + return this._aiWindowMenu.addMenuitems(event, win); + }, + get newTabURL() { return AIWINDOW_URL; }, diff --git a/browser/components/aiwindow/ui/modules/AIWindowMenu.sys.mjs b/browser/components/aiwindow/ui/modules/AIWindowMenu.sys.mjs @@ -0,0 +1,137 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { AIWindow } from "moz-src:///browser/components/aiwindow/ui/modules/AIWindow.sys.mjs"; + +const lazy = {}; +ChromeUtils.defineESModuleGetters(lazy, { + BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs", + URILoadingHelper: "resource:///modules/URILoadingHelper.sys.mjs", +}); + +const MAX_RECENT_CHATS = 4; + +/** + * Adds the AI Window menuitems to the app menu + */ +export class AIWindowMenu { + constructor() {} + + /** + * Adds the AI menu bar menuitems + * + * @param {Event} event - Event from clicking the History app menu item + * @param {Window} win - Window reference + */ + async addMenuitems(event, win) { + this.#addChatsMenuitem(win, event.target); + await this.#addRecentChats(win, event.target); + } + + #addChatsMenuitem(win, menu) { + this.#removeChatsMenuitem(menu); + + if (!AIWindow.isAIWindowActiveAndEnabled(win)) { + return; + } + + this.#addChatsMenuitemToHistory(menu); + } + + #removeChatsMenuitem(menu) { + const chatsMenuitem = menu.querySelector("#chatsHistoryMenu"); + chatsMenuitem.hidden = true; + } + + #addChatsMenuitemToHistory(menu) { + const chatsMenuitem = menu.querySelector("#chatsHistoryMenu"); + chatsMenuitem.hidden = false; + } + + async #addRecentChats(win, menu) { + this.#removeChatsMenuitems(menu); + + if (!AIWindow.isAIWindowActiveAndEnabled(win)) { + return; + } + + const items = + await AIWindow.chatStore.findRecentConversations(MAX_RECENT_CHATS); + + if (!items.length) { + return; + } + + this.#addRecentChatsMenuitemHeader(menu); + this.#addRecentChatMenuitems(items, win); + } + + #removeChatsMenuitems(menu) { + const separator = menu.querySelector("#startChatHistorySeparator"); + separator.hidden = true; + + const startingElement = menu.querySelector("#recentChatsHeader"); + startingElement.hidden = true; + + let next = startingElement?.nextElementSibling; + + while (next && next.hasAttribute && next.hasAttribute("data-conv-id")) { + const toRemove = next; + next = next.nextSibling; + toRemove.remove(); + } + } + + #addRecentChatsMenuitemHeader(menu) { + const separator = menu.querySelector("#startChatHistorySeparator"); + separator.hidden = false; + + const chatsHeader = menu.querySelector("#recentChatsHeader"); + chatsHeader.hidden = false; + } + + #addRecentChatMenuitems(items, win) { + const document = win.document; + const chatsHeader = document.getElementById("recentChatsHeader"); + + while (items.length) { + const item = items.pop(); + const menuItem = document.createXULElement("menuitem"); + menuItem.classList.add("recent-chat-item"); + menuItem.setAttribute("label", item.title); + menuItem.setAttribute("data-conv-id", item.id); + menuItem.addEventListener("command", this.#onRecentChatMenuitemClick); + + chatsHeader.insertAdjacentElement("afterend", menuItem); + } + } + + async #onRecentChatMenuitemClick(event) { + const convId = event.target.getAttribute("data-conv-id"); + const conversation = await AIWindow.chatStore.findConversationById(convId); + + if (!conversation) { + return; + } + + newBrowserTabUrl += `#convId/${convId}`; + + const win = event.target.ownerGlobal; + let newBrowserTabUrl = win.BROWSER_NEW_TAB_URL; + const site = conversation.getMostRecentPageVisited(); + if (site) { + newBrowserTabUrl += `#convId/${convId}/site/${site}`; + } + + // @todo Bug 2007484 + // Verify this behavior should differ from the rest of the history menu items + let where = lazy.BrowserUtils.whereToOpenLink(event); + if (where === "current") { + where = "tab"; + } + + lazy.URILoadingHelper.openTrustedLinkIn(win, newBrowserTabUrl, where); + } +} diff --git a/browser/components/aiwindow/ui/modules/moz.build b/browser/components/aiwindow/ui/modules/moz.build @@ -0,0 +1,6 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Core", "Machine Learning: Frontend") diff --git a/browser/components/aiwindow/ui/moz.build b/browser/components/aiwindow/ui/moz.build @@ -13,6 +13,7 @@ MOZ_SRC_FILES += [ "actors/AIChatContentParent.sys.mjs", "modules/AIWindow.sys.mjs", "modules/AIWindowAccountAuth.sys.mjs", + "modules/AIWindowMenu.sys.mjs", "modules/ChatConstants.sys.mjs", "modules/ChatConversation.sys.mjs", "modules/ChatMessage.sys.mjs", @@ -22,4 +23,8 @@ MOZ_SRC_FILES += [ "modules/ChatUtils.sys.mjs", ] +TESTING_JS_MODULES += [ + "test/AIWindowTestUtils.sys.mjs", +] + JAR_MANIFESTS += ["jar.mn"] diff --git a/browser/components/aiwindow/ui/test/AIWindowTestUtils.sys.mjs b/browser/components/aiwindow/ui/test/AIWindowTestUtils.sys.mjs @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { BrowserTestUtils } from "resource://testing-common/BrowserTestUtils.sys.mjs"; + +export const AIWindowTestUtils = { + async toggleAIWindowPref(SpecialPowers, enabled) { + await SpecialPowers.pushPrefEnv({ + set: [["browser.aiwindow.enabled", enabled]], + }); + }, + + isAIWindow(win) { + return win.document.documentElement.hasAttribute("ai-window"); + }, + + async openAIWindow(aiWindow = true) { + return BrowserTestUtils.openNewBrowserWindow({ + openerWindow: null, + aiWindow, + }); + }, +}; diff --git a/browser/components/aiwindow/ui/test/browser/browser_open_aiwindow.js b/browser/components/aiwindow/ui/test/browser/browser_open_aiwindow.js @@ -16,7 +16,8 @@ add_task(async function test_window_type_and_menu_visibility() { checkMenuItemVisibility( false, document.getElementById("appMenu-new-ai-window-button"), - document.getElementById("appMenu-new-classic-window-button") + document.getElementById("appMenu-new-classic-window-button"), + document.getElementById("appMenu-chats-history-button") ); await closeHamburgerMenu(); @@ -26,7 +27,8 @@ add_task(async function test_window_type_and_menu_visibility() { checkMenuItemVisibility( false, document.getElementById("menu_newAIWindow"), - document.getElementById("menu_newClassicWindow") + document.getElementById("menu_newClassicWindow"), + document.getElementById("appMenu-chats-history-button") ); await closeFileMenu(fileMenuPopup); } @@ -42,7 +44,8 @@ add_task(async function test_window_type_and_menu_visibility() { checkMenuItemVisibility( true, document.getElementById("appMenu-new-ai-window-button"), - document.getElementById("appMenu-new-classic-window-button") + document.getElementById("appMenu-new-classic-window-button"), + document.getElementById("appMenu-chats-history-button") ); await closeHamburgerMenu(); @@ -51,7 +54,8 @@ add_task(async function test_window_type_and_menu_visibility() { checkMenuItemVisibility( true, document.getElementById("menu_newAIWindow"), - document.getElementById("menu_newClassicWindow") + document.getElementById("menu_newClassicWindow"), + document.getElementById("appMenu-chats-history-button") ); await closeFileMenu(fileMenuPopup); } @@ -97,7 +101,8 @@ add_task(async function test_button_actions() { checkMenuItemVisibility( true, newWin.document.getElementById("appMenu-new-ai-window-button"), - newWin.document.getElementById("appMenu-new-classic-window-button") + newWin.document.getElementById("appMenu-new-classic-window-button"), + newWin.document.getElementById("appMenu-chats-history-button") ); await closeHamburgerMenu(newWin); @@ -106,7 +111,8 @@ add_task(async function test_button_actions() { checkMenuItemVisibility( true, newWin.document.getElementById("menu_newAIWindow"), - newWin.document.getElementById("menu_newClassicWindow") + newWin.document.getElementById("menu_newClassicWindow"), + newWin.document.getElementById("appMenu-chats-history-button") ); await closeFileMenu(fileMenuPopup); } @@ -187,7 +193,8 @@ add_task(async function test_openNewBrowserWindow_and_ai_inherit() { function checkMenuItemVisibility( aiWindowEnabled, aiOpenerButton, - classicOpenerButton + classicOpenerButton, + chatsButton ) { const doc = aiOpenerButton?.ownerDocument || @@ -204,6 +211,10 @@ function checkMenuItemVisibility( !classicOpenerButton || classicOpenerButton.hidden, `Classic Window button should not be visible when browser.aiwindow.enabled is false` ); + Assert.ok( + !chatsButton || chatsButton.hidden, + `Chats history button should not be visible when browser.aiwindow.enabled is false` + ); } else if (currentWindowIsAIWindow) { Assert.ok( !aiOpenerButton || aiOpenerButton.hidden, @@ -213,6 +224,10 @@ function checkMenuItemVisibility( classicOpenerButton && !classicOpenerButton.hidden, `Classic Window button should be visible in AI Window when browser.aiwindow.enabled is true` ); + Assert.ok( + chatsButton && !chatsButton.hidden, + `Chats history button should be visible when browser.aiwindow.enabled is true and in AI window` + ); } else { Assert.ok( aiOpenerButton && !aiOpenerButton.hidden, @@ -222,6 +237,10 @@ function checkMenuItemVisibility( !classicOpenerButton || classicOpenerButton.hidden, `Classic Window button should be hidden in Classic Window when browser.aiwindow.enabled is true` ); + Assert.ok( + !chatsButton || chatsButton.hidden, + `Chats history button should be hidden in when browser.aiwindow.enabled is true but not in AI Window` + ); } } diff --git a/browser/components/aiwindow/ui/test/xpcshell/test_ChatMessage.js b/browser/components/aiwindow/ui/test/xpcshell/test_ChatMessage.js @@ -7,7 +7,7 @@ const { ChatMessage } = ChromeUtils.importESModule( "moz-src:///browser/components/aiwindow/ui/modules/ChatStore.sys.mjs" ); -add_task(function test_ChatConversation_constructor_defaults() { +add_task(function test_ChatMessage_constructor_defaults() { const message = new ChatMessage({ ordinal: 0, role: 0, diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js @@ -1073,9 +1073,15 @@ const PanelUI = { document, "appMenu-new-classic-window-button" ); + const chatHistoryMenuItem = PanelMultiView.getViewNode( + document, + "appMenu-chats-history-button" + ); aiMenuItem.hidden = !this.isAIWindowEnabled || isAIWindowActive; classicWindowMenuItem.hidden = !this.isAIWindowEnabled || !isAIWindowActive; + + chatHistoryMenuItem.hidden = !this.isAIWindowEnabled || !isAIWindowActive; }, _showBadge(notification) { diff --git a/browser/locales/en-US/browser/appmenu.ftl b/browser/locales/en-US/browser/appmenu.ftl @@ -43,6 +43,8 @@ appmenuitem-translate = .label = Translate page… appmenuitem-zoom = .value = Zoom +appmenuitem-chats = + .label = Chats appmenuitem-more-tools = .label = More tools appmenuitem-help = diff --git a/browser/locales/en-US/browser/menubar.ftl b/browser/locales/en-US/browser/menubar.ftl @@ -223,6 +223,13 @@ menu-history-undo-window-menu = menu-history-search = .label = Search History +# Chat History + +menu-history-chats = + .label = Chats +menu-history-chats-recent = + .label = Recent Chats + ## Bookmarks Menu menu-bookmarks-menu =