From 822b2865ed304386fcfcc43a4f71af6aeb6629ba Mon Sep 17 00:00:00 2001 From: Algis Dumbris Date: Tue, 9 Jun 2026 09:52:14 +0300 Subject: [PATCH] refactor(frontend): rename Settings "Teams" wording to "Server Edition" The server-edition Settings surface used legacy "Teams" wording (the tab label and the "Teams / Server" section heading). Align it to "Server Edition" to match the edition identity (`/api/v1/status` edition === "server"), which the frontend already keys off. Extract the section into SERVER_EDITION_FIELDS + label constants in settings/fields.ts and add a vitest guard. The config dot-paths stay on the legacy `teams.*` key on purpose: the backend config-key rename (`teams` -> `server_edition`, MCP-1085 / PR #607) is not merged, so a live config is still `teams`-keyed. Flipping the keys early would make `hasTeams` read `state.working.server_edition` and silently hide the whole tab. The key switch is tracked as a follow-up blocked by that backend change. Related MCP-1087 --- frontend/src/views/Settings.vue | 20 ++++++------- frontend/src/views/settings/fields.ts | 14 +++++++++ .../settings-server-edition-wording.spec.ts | 29 +++++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 frontend/tests/unit/settings-server-edition-wording.spec.ts diff --git a/frontend/src/views/Settings.vue b/frontend/src/views/Settings.vue index 86e2b18d..c7008bdc 100644 --- a/frontend/src/views/Settings.vue +++ b/frontend/src/views/Settings.vue @@ -119,11 +119,11 @@ - +
-

👥 Teams / Server

- +

{{ serverEditionTitle }}

+
@@ -187,6 +187,9 @@ import { SECURITY_FIELDS, GENERAL_FIELDS, ADVANCED_ACCORDIONS, + SERVER_EDITION_FIELDS, + SERVER_EDITION_TAB_LABEL, + SERVER_EDITION_SECTION_TITLE, DOCS_BASE, docsUrl, type SettingField, @@ -199,11 +202,8 @@ const systemStore = useSystemStore() const securityFields = SECURITY_FIELDS const generalFields = GENERAL_FIELDS const advancedAccordions = ADVANCED_ACCORDIONS -const teamsFields: SettingField[] = [ - { key: 'teams.enabled', label: 'Enable multi-user mode', control: 'toggle', restart: true }, - { key: 'teams.oauth.provider', label: 'OAuth provider', control: 'select', options: ['', 'google', 'github', 'microsoft'].map((v) => ({ value: v, label: v || '(none)' })) }, - { key: 'teams.max_user_servers', label: 'Max servers per user', control: 'number', min: 0 }, -] +const serverEditionFields = SERVER_EDITION_FIELDS +const serverEditionTitle = SERVER_EDITION_SECTION_TITLE // ---- form state ---- const loading = ref(false) @@ -220,7 +220,7 @@ const allFields = computed(() => [ ...securityFields, ...generalFields, ...advancedAccordions.flatMap((a) => a.fields), - ...(hasTeams.value ? teamsFields : []), + ...(hasTeams.value ? serverEditionFields : []), ]) const filteredFields = computed(() => { const q = search.value.trim().toLowerCase() @@ -255,7 +255,7 @@ const tabs = computed(() => { { id: 'general', label: 'General', icon: '⚙️' }, { id: 'advanced', label: 'Advanced', icon: '🧰' }, ] as Array<{ id: string; label: string; icon: string }> - if (hasTeams.value) base.push({ id: 'teams', label: 'Teams', icon: '👥' }) + if (hasTeams.value) base.push({ id: 'teams', label: SERVER_EDITION_TAB_LABEL, icon: '👥' }) base.push({ id: 'raw', label: 'Raw JSON', icon: '{ }' }) return base }) diff --git a/frontend/src/views/settings/fields.ts b/frontend/src/views/settings/fields.ts index 60573b4b..769799bc 100644 --- a/frontend/src/views/settings/fields.ts +++ b/frontend/src/views/settings/fields.ts @@ -261,6 +261,20 @@ export const GENERAL_FIELDS: SettingField[] = [ { key: 'enable_prompts', label: 'Expose MCP prompts to clients', help: 'Advertises mcpproxy’s built-in guided prompts to connected AI clients: “setup-new-mcp-server” (add a server) and “troubleshoot-mcp-server” (diagnose connection issues).', control: 'toggle' }, ] +// ---- Server edition (multi-user) section ---- +// User-facing wording is "Server Edition" (MCP-1087). The config dot-paths +// deliberately stay on the legacy `teams.*` key: the backend rename of the +// top-level config key (`teams` -> `server_edition`, MCP-1085 / PR #607) is +// not merged, so a live config is still `teams`-keyed. Flip these to +// `server_edition.*` in the follow-up only once that backend change lands. +export const SERVER_EDITION_TAB_LABEL = 'Server Edition' +export const SERVER_EDITION_SECTION_TITLE = '👥 Server Edition' +export const SERVER_EDITION_FIELDS: SettingField[] = [ + { key: 'teams.enabled', label: 'Enable multi-user mode', control: 'toggle', restart: true }, + { key: 'teams.oauth.provider', label: 'OAuth provider', control: 'select', options: ['', 'google', 'github', 'microsoft'].map((v) => ({ value: v, label: v || '(none)' })) }, + { key: 'teams.max_user_servers', label: 'Max servers per user', control: 'number', min: 0 }, +] + // ---- Section 3: Advanced (subsystem accordions) ---- export const ADVANCED_ACCORDIONS: SettingsAccordion[] = [ { diff --git a/frontend/tests/unit/settings-server-edition-wording.spec.ts b/frontend/tests/unit/settings-server-edition-wording.spec.ts new file mode 100644 index 00000000..dcbcaad3 --- /dev/null +++ b/frontend/tests/unit/settings-server-edition-wording.spec.ts @@ -0,0 +1,29 @@ +import { describe, it, expect } from 'vitest' +import { + SERVER_EDITION_TAB_LABEL, + SERVER_EDITION_SECTION_TITLE, + SERVER_EDITION_FIELDS, +} from '../../src/views/settings/fields' + +// MCP-1087: the Settings server-edition surface must read "Server Edition", +// not the legacy "Teams" wording. The config *keys*, however, deliberately +// stay on the legacy `teams.*` dot-paths until the backend rename of the +// config key (`teams` -> `server_edition`, MCP-1085 / PR #607, currently +// unmerged) lands. Flipping the keys early would make `hasTeams` read +// `state.working.server_edition`, which a live `teams`-keyed config doesn't +// have -> the whole server-edition tab silently disappears. +describe('Settings server-edition wording (MCP-1087)', () => { + it('uses "Server Edition" wording with no "Teams" left in user-facing labels', () => { + expect(SERVER_EDITION_TAB_LABEL).toBe('Server Edition') + expect(SERVER_EDITION_TAB_LABEL).not.toMatch(/team/i) + expect(SERVER_EDITION_SECTION_TITLE).not.toMatch(/team/i) + expect(SERVER_EDITION_SECTION_TITLE).toMatch(/Server Edition/) + }) + + it('keeps the config field keys on the legacy `teams.*` contract (backend rename pending)', () => { + expect(SERVER_EDITION_FIELDS.length).toBeGreaterThan(0) + for (const f of SERVER_EDITION_FIELDS) { + expect(f.key).toMatch(/^teams\./) + } + }) +})