diff --git a/frontend/__tests__/components/context-menu/account-settings-context-menu.test.tsx b/frontend/__tests__/components/context-menu/account-settings-context-menu.test.tsx
index 5eeafbc51d..c0a9264fe5 100644
--- a/frontend/__tests__/components/context-menu/account-settings-context-menu.test.tsx
+++ b/frontend/__tests__/components/context-menu/account-settings-context-menu.test.tsx
@@ -1,9 +1,27 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-import { afterEach, describe, expect, it, test, vi } from "vitest";
+import { afterEach, beforeEach, describe, expect, it, test, vi } from "vitest";
import { AccountSettingsContextMenu } from "#/components/features/context-menu/account-settings-context-menu";
import { MemoryRouter } from "react-router";
import { renderWithProviders } from "../../../test-utils";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { createMockWebClientConfig } from "../../helpers/mock-config";
+
+const mockTrackAddTeamMembersButtonClick = vi.fn();
+
+vi.mock("#/hooks/use-tracking", () => ({
+ useTracking: () => ({
+ trackAddTeamMembersButtonClick: mockTrackAddTeamMembersButtonClick,
+ }),
+}));
+
+// Mock posthog feature flag
+vi.mock("posthog-js/react", () => ({
+ useFeatureFlagEnabled: vi.fn(),
+}));
+
+// Import the mocked module to get access to the mock
+import * as posthog from "posthog-js/react";
describe("AccountSettingsContextMenu", () => {
const user = userEvent.setup();
@@ -11,15 +29,45 @@ describe("AccountSettingsContextMenu", () => {
const onLogoutMock = vi.fn();
const onCloseMock = vi.fn();
+ let queryClient: QueryClient;
+
+ beforeEach(() => {
+ queryClient = new QueryClient({
+ defaultOptions: { queries: { retry: false } },
+ });
+ // Set default feature flag to false
+ vi.mocked(posthog.useFeatureFlagEnabled).mockReturnValue(false);
+ });
+
// Create a wrapper with MemoryRouter and renderWithProviders
const renderWithRouter = (ui: React.ReactElement) => {
return renderWithProviders({ui});
};
+ const renderWithSaasConfig = (ui: React.ReactElement) => {
+ queryClient.setQueryData(["web-client-config"], createMockWebClientConfig({ app_mode: "saas" }));
+ return render(
+
+ {ui}
+
+ );
+ };
+
+ const renderWithOssConfig = (ui: React.ReactElement) => {
+ queryClient.setQueryData(["web-client-config"], createMockWebClientConfig({ app_mode: "oss" }));
+ return render(
+
+ {ui}
+
+ );
+ };
+
afterEach(() => {
onClickAccountSettingsMock.mockClear();
onLogoutMock.mockClear();
onCloseMock.mockClear();
+ mockTrackAddTeamMembersButtonClick.mockClear();
+ vi.mocked(posthog.useFeatureFlagEnabled).mockClear();
});
it("should always render the right options", () => {
@@ -93,4 +141,59 @@ describe("AccountSettingsContextMenu", () => {
expect(onCloseMock).toHaveBeenCalledOnce();
});
+
+ it("should show Add Team Members button in SaaS mode when feature flag is enabled", () => {
+ vi.mocked(posthog.useFeatureFlagEnabled).mockReturnValue(true);
+ renderWithSaasConfig(
+ ,
+ );
+
+ expect(screen.getByTestId("add-team-members-button")).toBeInTheDocument();
+ expect(screen.getByText("SETTINGS$NAV_ADD_TEAM_MEMBERS")).toBeInTheDocument();
+ });
+
+ it("should not show Add Team Members button in SaaS mode when feature flag is disabled", () => {
+ vi.mocked(posthog.useFeatureFlagEnabled).mockReturnValue(false);
+ renderWithSaasConfig(
+ ,
+ );
+
+ expect(screen.queryByTestId("add-team-members-button")).not.toBeInTheDocument();
+ expect(screen.queryByText("SETTINGS$NAV_ADD_TEAM_MEMBERS")).not.toBeInTheDocument();
+ });
+
+ it("should not show Add Team Members button in OSS mode even when feature flag is enabled", () => {
+ vi.mocked(posthog.useFeatureFlagEnabled).mockReturnValue(true);
+ renderWithOssConfig(
+ ,
+ );
+
+ expect(screen.queryByTestId("add-team-members-button")).not.toBeInTheDocument();
+ expect(screen.queryByText("SETTINGS$NAV_ADD_TEAM_MEMBERS")).not.toBeInTheDocument();
+ });
+
+ it("should call tracking function and onClose when Add Team Members button is clicked", async () => {
+ vi.mocked(posthog.useFeatureFlagEnabled).mockReturnValue(true);
+ renderWithSaasConfig(
+ ,
+ );
+
+ const addTeamMembersButton = screen.getByTestId("add-team-members-button");
+ await user.click(addTeamMembersButton);
+
+ expect(mockTrackAddTeamMembersButtonClick).toHaveBeenCalledOnce();
+ expect(onCloseMock).toHaveBeenCalledOnce();
+ });
});
diff --git a/frontend/src/components/features/context-menu/account-settings-context-menu.tsx b/frontend/src/components/features/context-menu/account-settings-context-menu.tsx
index 0c2541237d..6dddd52620 100644
--- a/frontend/src/components/features/context-menu/account-settings-context-menu.tsx
+++ b/frontend/src/components/features/context-menu/account-settings-context-menu.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
+import { useFeatureFlagEnabled } from "posthog-js/react";
import { ContextMenu } from "#/ui/context-menu";
import { ContextMenuListItem } from "./context-menu-list-item";
import { Divider } from "#/ui/divider";
@@ -8,7 +9,10 @@ import { useClickOutsideElement } from "#/hooks/use-click-outside-element";
import { I18nKey } from "#/i18n/declaration";
import LogOutIcon from "#/icons/log-out.svg?react";
import DocumentIcon from "#/icons/document.svg?react";
+import PlusIcon from "#/icons/plus.svg?react";
import { useSettingsNavItems } from "#/hooks/use-settings-nav-items";
+import { useConfig } from "#/hooks/query/use-config";
+import { useTracking } from "#/hooks/use-tracking";
interface AccountSettingsContextMenuProps {
onLogout: () => void;
@@ -21,9 +25,17 @@ export function AccountSettingsContextMenu({
}: AccountSettingsContextMenuProps) {
const ref = useClickOutsideElement(onClose);
const { t } = useTranslation();
+ const { trackAddTeamMembersButtonClick } = useTracking();
+ const { data: config } = useConfig();
+ const isAddTeamMemberEnabled = useFeatureFlagEnabled(
+ "exp_add_team_member_button",
+ );
// Get navigation items and filter out LLM settings if the feature flag is enabled
const items = useSettingsNavItems();
+ const isSaasMode = config?.app_mode === "saas";
+ const showAddTeamMembers = isSaasMode && isAddTeamMemberEnabled;
+
const navItems = items.map((item) => ({
...item,
icon: React.cloneElement(item.icon, {
@@ -33,6 +45,11 @@ export function AccountSettingsContextMenu({
}));
const handleNavigationClick = () => onClose();
+ const handleAddTeamMembers = () => {
+ trackAddTeamMembersButtonClick();
+ onClose();
+ };
+
return (
+ {showAddTeamMembers && (
+
+
+
+ {t(I18nKey.SETTINGS$NAV_ADD_TEAM_MEMBERS)}
+
+
+ )}
{navItems.map(({ to, text, icon }) => (
{
});
};
+ const trackAddTeamMembersButtonClick = () => {
+ posthog.capture("exp_add_team_members", {
+ ...commonProperties,
+ });
+ };
+
return {
trackLoginButtonClick,
trackConversationCreated,
@@ -109,5 +115,6 @@ export const useTracking = () => {
trackUserSignupCompleted,
trackCreditsPurchased,
trackCreditLimitReached,
+ trackAddTeamMembersButtonClick,
};
};
diff --git a/frontend/src/i18n/declaration.ts b/frontend/src/i18n/declaration.ts
index 2d9599e810..71f4c963b4 100644
--- a/frontend/src/i18n/declaration.ts
+++ b/frontend/src/i18n/declaration.ts
@@ -693,6 +693,7 @@ export enum I18nKey {
TIPS$PROTIP = "TIPS$PROTIP",
FEEDBACK$SUBMITTING_LABEL = "FEEDBACK$SUBMITTING_LABEL",
FEEDBACK$SUBMITTING_MESSAGE = "FEEDBACK$SUBMITTING_MESSAGE",
+ SETTINGS$NAV_ADD_TEAM_MEMBERS = "SETTINGS$NAV_ADD_TEAM_MEMBERS",
SETTINGS$NAV_USER = "SETTINGS$NAV_USER",
SETTINGS$USER_TITLE = "SETTINGS$USER_TITLE",
SETTINGS$USER_EMAIL = "SETTINGS$USER_EMAIL",
diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json
index 91530fe633..8db2e15e4f 100644
--- a/frontend/src/i18n/translation.json
+++ b/frontend/src/i18n/translation.json
@@ -11087,6 +11087,22 @@
"de": "Feedback senden, bitte warten...",
"uk": "Відправляємо відгук, будь ласка, почекайте..."
},
+ "SETTINGS$NAV_ADD_TEAM_MEMBERS": {
+ "en": "Add Team Members",
+ "ja": "チームメンバーを追加",
+ "zh-CN": "添加团队成员",
+ "zh-TW": "新增團隊成員",
+ "ko-KR": "팀원 추가",
+ "no": "Legg til teammedlemmer",
+ "it": "Aggiungi membri del team",
+ "pt": "Adicionar membros da equipe",
+ "es": "Agregar miembros del equipo",
+ "ar": "إضافة أعضاء الفريق",
+ "fr": "Ajouter des membres de l'équipe",
+ "tr": "Takım üyeleri ekle",
+ "de": "Teammitglieder hinzufügen",
+ "uk": "Додати учасників команди"
+ },
"SETTINGS$NAV_USER": {
"en": "User",
"ja": "ユーザー",