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
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO
it('provider detail actions localize and sanitize model-test / model-fetch failures', async () => {
const providers = await readProviderSettingsCombinedSource();
const main = await readMainProcessCombinedSource();
const detail = providers.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = providers.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';
const addForm = providers.match(/function AddProviderForm[\s\S]*?function nextSlug/)?.[0] ?? '';

assert.match(
Expand Down Expand Up @@ -605,7 +605,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('OAuth model connection detail treats Base URL as fixed provider metadata, not an editable endpoint', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand Down Expand Up @@ -645,14 +645,16 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO
assert.ok(advanced > credential, 'credentials must remain the primary task before advanced settings');
assert.ok(models > advanced, 'enabled-model management must stay inside advanced settings');
assert.doesNotMatch(detail, /<ModelTable/, 'connection detail must not render a default-model picker');
assert.match(detail, /connectionLastTestMessageDisplay\(connection\.lastTestMessage\)/);
// The last-test message goes through the display helper in the extracted
// controller (use-connection-detail.ts); the view renders the derived value.
assert.match(src, /connectionLastTestMessageDisplay\(connection\.lastTestMessage\)/);
assert.match(detail, /<RelativeTime ts=\{lastTestAtMs\}/);
assert.doesNotMatch(detail, /<header>[\s\S]*\{connection\.name\}/, 'the shared DialogHeader must be the only title header');
});

it('does not let disabled OAuth connections become the default model', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand All @@ -668,7 +670,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('keeps each Save action beside its field, disabled until that field is dirty', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand All @@ -694,7 +696,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('forwards an empty service-address draft so the stored override can be cleared', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand Down Expand Up @@ -744,7 +746,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('automatically persists enabled-model edits without a second Save action', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';
const enabledModels = src.match(/function EnabledModelManager[\s\S]*?function modelDisplayLabel/)?.[0] ?? '';

assert.match(
Expand All @@ -760,7 +762,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('surfaces provider detail save/delete failures instead of leaking rejected promises from actions', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand All @@ -781,7 +783,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('surfaces provider detail credential-presence probe failures', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(src, /type CredentialPresenceStatus = boolean \| 'loading' \| 'error'/);
assert.match(detail, /useState<CredentialPresenceStatus>\([\s\S]*defaults\.authKind === 'none' \? true : 'loading'/);
Expand Down Expand Up @@ -809,7 +811,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('shows but does not require LocalAI optional credentials', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(detail, /const supportsApiKey = providerAuthSupportsApiKey\(connection\.providerType\)/);
assert.match(detail, /const requiresCredential = providerAuthRequiresSecret\(connection\.providerType\)/);
Expand All @@ -818,7 +820,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO

it('provider detail async actions stop writing UI after the detail sheet is closed or switched', async () => {
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
detail,
Expand Down Expand Up @@ -868,7 +870,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO
// props via useState would otherwise keep showing stale models /
// defaultModel until the sheet is closed and reopened.
const src = await readProviderSettingsCombinedSource();
const detail = src.match(/function ConnectionDetail[\s\S]*?function GitHubCopilotReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

assert.match(
src,
Expand Down Expand Up @@ -1377,7 +1379,7 @@ describe('Model OAuth catalog contract (PR-MODEL-OAUTH-ALL-0 + PR-CLAUDE-CARD-MO
const src = await readProviderSettingsCombinedSource();
const mapping = src.match(/function oauthLoginServiceFor\(providerType: ProviderType\): OAuthLoginService \| null \{[\s\S]*?\n\}/)?.[0] ?? '';
const notice = src.match(/function OAuthReloginNotice\([\s\S]*?\ntype ConnectionDetailSnapshot/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function OAuthReloginNotice/)?.[0] ?? '';
const detail = src.match(/function ConnectionDetail[\s\S]*?function modelIdListsEqual\(/)?.[0] ?? '';

// Loopback services (Codex, Antigravity) get a bridge; Claude's paste flow
// and plain API-key providers fall through to null so the notice renders
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ export interface ProviderSettingsSources {
displayCopy: string;
addForm: string;
detail: string;
// R7: the connection detail sheet's controller state machine + its
// enabled-model editor were extracted out of provider-connection-detail.tsx.
// Both stay part of the provider settings surface the contract tests pin, and
// are joined right after the detail view so the ConnectionDetail → controller
// slices stay contiguous.
detailController: string;
enabledModelManager: string;
shared: string;
combined: string;
}
Expand All @@ -31,11 +38,26 @@ const sourcePaths = {
displayCopy: resolve(SETTINGS_ROOT, 'provider-display-copy.ts'),
addForm: resolve(SETTINGS_ROOT, 'provider-add-form.tsx'),
detail: resolve(SETTINGS_ROOT, 'provider-connection-detail.tsx'),
detailController: resolve(SETTINGS_ROOT, 'use-connection-detail.ts'),
enabledModelManager: resolve(SETTINGS_ROOT, 'provider-enabled-model-manager.tsx'),
shared: resolve(SETTINGS_ROOT, 'provider-panel-shared.ts'),
} as const;

export async function readProviderSettingsSources(): Promise<ProviderSettingsSources> {
const [panel, dialog, catalog, oauth, claudeCard, display, displayCopy, addForm, detail, shared] = await Promise.all([
const [
panel,
dialog,
catalog,
oauth,
claudeCard,
display,
displayCopy,
addForm,
detail,
detailController,
enabledModelManager,
shared,
] = await Promise.all([
readFile(sourcePaths.panel, 'utf8'),
readFile(sourcePaths.dialog, 'utf8'),
readFile(sourcePaths.catalog, 'utf8'),
Expand All @@ -45,6 +67,8 @@ export async function readProviderSettingsSources(): Promise<ProviderSettingsSou
readFile(sourcePaths.displayCopy, 'utf8'),
readFile(sourcePaths.addForm, 'utf8'),
readFile(sourcePaths.detail, 'utf8'),
readFile(sourcePaths.detailController, 'utf8'),
readFile(sourcePaths.enabledModelManager, 'utf8'),
readFile(sourcePaths.shared, 'utf8'),
]);

Expand All @@ -58,6 +82,8 @@ export async function readProviderSettingsSources(): Promise<ProviderSettingsSou
displayCopy,
addForm,
detail,
detailController,
enabledModelManager,
shared,
combined: [
panel,
Expand All @@ -68,7 +94,12 @@ export async function readProviderSettingsSources(): Promise<ProviderSettingsSou
display,
displayCopy,
addForm,
// detail view, then its extracted controller, then its enabled-model
// editor — kept adjacent so `function ConnectionDetail … function
// modelIdListsEqual` slices span the view + controller contiguously.
detail,
detailController,
enabledModelManager,
shared,
].join('\n'),
};
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/main/__tests__/web-search-boundary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const RENDERER_FILES = [
'apps/desktop/src/renderer/settings/provider-catalog.tsx',
'apps/desktop/src/renderer/settings/provider-connection-dialog.tsx',
'apps/desktop/src/renderer/settings/provider-connection-detail.tsx',
'apps/desktop/src/renderer/settings/use-connection-detail.ts',
'apps/desktop/src/renderer/settings/provider-enabled-model-manager.tsx',
'apps/desktop/src/renderer/settings/provider-display.tsx',
'apps/desktop/src/renderer/settings/provider-oauth-section.tsx',
'apps/desktop/src/renderer/settings/claude-subscription-card.tsx',
Expand Down
Loading
Loading