mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(web): satisfy provider model gates
This commit is contained in:
@@ -18,7 +18,7 @@ import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-web-react'
|
||||
import { CustomProviderCard } from './CustomProviderCard.tsx'
|
||||
import { deriveKeyRef, messageOf, protocolChoices } from './store.ts'
|
||||
import type { ModelsSettingsState, ModelsSettingsStore, ProviderRow } from './store.ts'
|
||||
import { ProviderEditor } from './ProviderEditor.tsx'
|
||||
import { ProviderEditor, type ProviderEditorProps } from './ProviderEditor.tsx'
|
||||
import type { en } from './locales.ts'
|
||||
import styles from './ModelsSection.module.css'
|
||||
|
||||
@@ -56,6 +56,26 @@ interface EditorTarget extends ProviderIdentity {
|
||||
credentialRef?: string
|
||||
}
|
||||
|
||||
/** Values that vary around the shared provider-editor rendering. */
|
||||
interface ProviderEditorRenderProps extends Pick<
|
||||
ProviderEditorProps,
|
||||
'namespace' | 'api' | 't' | 'readOnly' | 'onClose'
|
||||
> {
|
||||
target: EditorTarget
|
||||
}
|
||||
|
||||
/** Render an editor for either the setup posture or an expanded provider row. */
|
||||
function renderProviderEditor({ target, ...props }: ProviderEditorRenderProps): ReactNode {
|
||||
return (
|
||||
<ProviderEditor
|
||||
provider={target.provider}
|
||||
displayName={target.displayName}
|
||||
settingsPath={target.settingsPath}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one user-added provider and its page-managed credential. Credential
|
||||
* removal comes first so a second-step failure leaves the provider row visible
|
||||
@@ -232,16 +252,14 @@ function Loaded({ injected }: { injected: ModelsSectionInjected }): ReactNode {
|
||||
// setup card IS its presence on the page.
|
||||
return (
|
||||
<li key={row.entry.provider} className={styles['setupCard']}>
|
||||
<ProviderEditor
|
||||
provider={target.provider}
|
||||
displayName={target.displayName}
|
||||
namespace={namespace}
|
||||
settingsPath={target.settingsPath}
|
||||
api={api}
|
||||
t={t}
|
||||
readOnly={!state.writable}
|
||||
onClose={(changed) => { closeEditor(changed, target) }}
|
||||
/>
|
||||
{renderProviderEditor({
|
||||
target,
|
||||
namespace,
|
||||
api,
|
||||
t,
|
||||
readOnly: !state.writable,
|
||||
onClose: (changed) => { closeEditor(changed, target) },
|
||||
})}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -312,18 +330,14 @@ function Loaded({ injected }: { injected: ModelsSectionInjected }): ReactNode {
|
||||
</span>
|
||||
</div>
|
||||
{open
|
||||
? (
|
||||
<ProviderEditor
|
||||
provider={target.provider}
|
||||
displayName={target.displayName}
|
||||
namespace={namespace}
|
||||
settingsPath={target.settingsPath}
|
||||
api={api}
|
||||
t={t}
|
||||
readOnly={!state.writable}
|
||||
onClose={(changed) => { closeEditor(changed, target) }}
|
||||
/>
|
||||
)
|
||||
? renderProviderEditor({
|
||||
target,
|
||||
namespace,
|
||||
api,
|
||||
t,
|
||||
readOnly: !state.writable,
|
||||
onClose: (changed) => { closeEditor(changed, target) },
|
||||
})
|
||||
: null}
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -142,7 +142,7 @@ async function mountSection(options: Parameters<typeof scriptedFace>[0] = {}) {
|
||||
t,
|
||||
}
|
||||
render(<ModelsSection {...injected} />)
|
||||
return scripted
|
||||
return { ...scripted, controller }
|
||||
}
|
||||
|
||||
/** Open the editor of one configured row and expand its customized fold. */
|
||||
@@ -862,4 +862,20 @@ describe('hand-declared providers', () => {
|
||||
await waitFor(() => { expect(screen.queryByText(en.customTitle)).toBeNull() })
|
||||
expect(screen.getByRole('button', { name: en.customAdd })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('reloads the section after creating a hand-declared provider', async () => {
|
||||
const { controller, mutate } = await mountSection()
|
||||
const load = vi.spyOn(controller, 'load')
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: en.customAdd }))
|
||||
fireEvent.change(screen.getByLabelText(en.customRoute), { target: { value: 'acme' } })
|
||||
fireEvent.change(screen.getByLabelText(en.baseUrl), { target: { value: 'https://acme.test/v1' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: en.addModel }))
|
||||
fireEvent.change(screen.getByLabelText(`${en.modelId} 1`), { target: { value: 'm' } })
|
||||
fireEvent.click(screen.getByText(en.create))
|
||||
|
||||
await waitFor(() => { expect(mutate).toHaveBeenCalledOnce() })
|
||||
await waitFor(() => { expect(load).toHaveBeenCalledOnce() })
|
||||
expect(screen.queryByText(en.customTitle)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user