Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions frontend/src/views/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@
</div>
</div>

<!-- Teams (server edition only) -->
<!-- Server edition / multi-user settings (server edition only) -->
<div v-if="hasTeams" v-show="activeTab === 'teams'" class="card bg-base-100 shadow-md">
<div class="card-body">
<h2 class="card-title text-lg">👥 Teams / Server</h2>
<SettingsSection section-id="teams" :fields="teamsFields" :working="state.working" :original="state.original" />
<h2 class="card-title text-lg" data-test="settings-server-edition-title">{{ serverEditionTitle }}</h2>
<SettingsSection section-id="teams" :fields="serverEditionFields" :working="state.working" :original="state.original" />
</div>
</div>

Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -220,7 +220,7 @@ const allFields = computed<SettingField[]>(() => [
...securityFields,
...generalFields,
...advancedAccordions.flatMap((a) => a.fields),
...(hasTeams.value ? teamsFields : []),
...(hasTeams.value ? serverEditionFields : []),
])
const filteredFields = computed<SettingField[]>(() => {
const q = search.value.trim().toLowerCase()
Expand Down Expand Up @@ -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
})
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/views/settings/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = [
{
Expand Down
29 changes: 29 additions & 0 deletions frontend/tests/unit/settings-server-edition-wording.spec.ts
Original file line number Diff line number Diff line change
@@ -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\./)
}
})
})
Loading