Merge remote-tracking branch 'origin/master' into worktree/open-settings-config-file
# Conflicts: # packages/client/connection/README.i18n.yaml # packages/client/connection/README.md # packages/client/connection/README.zh.md
This commit is contained in:
@@ -65,8 +65,6 @@
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/client.js",
|
||||
"lib/types/**/*.d.ts",
|
||||
"lib/types/**/*.d.ts.map",
|
||||
"src"
|
||||
"lib/types/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
.rows {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
/* Extra air between the title/intro block and the first provider card. */
|
||||
margin: 12px 0 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -70,6 +71,10 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.primaryButton:hover:not(:disabled) {
|
||||
background: var(--dsw-alias-button-primary-hover);
|
||||
}
|
||||
|
||||
.secondaryButton {
|
||||
border: 1px solid var(--dsw-alias-border-l2);
|
||||
border-radius: 999px;
|
||||
@@ -80,14 +85,24 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.secondaryButton:hover:not(:disabled) {
|
||||
background: var(--dsw-alias-interactive-bg-hover-solid);
|
||||
}
|
||||
|
||||
.dangerButton {
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 4px 8px;
|
||||
background: none;
|
||||
color: var(--dsw-alias-state-error-primary);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dangerButton:hover:not(:disabled) {
|
||||
background: var(--dsw-alias-interactive-bg-hover-danger);
|
||||
}
|
||||
|
||||
.primaryButton:disabled,
|
||||
.secondaryButton:disabled,
|
||||
.dangerButton:disabled {
|
||||
@@ -147,6 +162,10 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.linkButton:hover:not(:disabled) {
|
||||
color: var(--dsw-alias-label-secondary);
|
||||
}
|
||||
|
||||
.linkButton:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
@@ -171,17 +190,23 @@
|
||||
}
|
||||
|
||||
.addButton {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
align-self: flex-start;
|
||||
border: 1px solid var(--dsw-alias-border-l2);
|
||||
border-radius: 999px;
|
||||
padding: 8px 16px;
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
background: var(--dsw-alias-bg-layer-3);
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.addButton:hover:not(:disabled) {
|
||||
background: var(--dsw-alias-interactive-bg-hover-solid);
|
||||
}
|
||||
|
||||
.addButton:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
@@ -246,6 +271,20 @@
|
||||
color: var(--dsw-alias-label-dimmed);
|
||||
}
|
||||
|
||||
/* Select variant of .input: replaces the OS arrow (which sits flush against
|
||||
the right edge) with the shared 12px chevron inset like the composer's
|
||||
.select chips; the right pad reserves its cell. */
|
||||
.selectInput {
|
||||
appearance: none;
|
||||
padding-right: 32px;
|
||||
/* Data-URI SVGs cannot resolve CSS variables; #81858C is the caption gray
|
||||
shared by both themes. */
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 12px center;
|
||||
background-size: 12px 12px;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import { useState } from 'react'
|
||||
import type { ReactNode } from 'react'
|
||||
import type { IApiClient } from '@deepseek-ai/dsh-client-connection/client'
|
||||
import { Button, Modal } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { Button, IconPlusOutline16, Modal } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-web-react'
|
||||
import { messageOf } from './store.ts'
|
||||
import type { ModelsSettingsState, ModelsSettingsStore, ProviderRow } from './store.ts'
|
||||
@@ -245,7 +245,7 @@ function Loaded({ injected }: { injected: ModelsSectionInjected }): ReactNode {
|
||||
<div className={styles['field']}>
|
||||
<span className={styles['fieldLabel']}>{t('provider')}</span>
|
||||
<select
|
||||
className={styles['input']}
|
||||
className={`${styles['input']} ${styles['selectInput']}`}
|
||||
value={addTarget.provider}
|
||||
aria-label={t('provider')}
|
||||
onChange={(event) => {
|
||||
@@ -287,7 +287,9 @@ function Loaded({ injected }: { injected: ModelsSectionInjected }): ReactNode {
|
||||
setEditing(targetOf(first))
|
||||
}}
|
||||
>
|
||||
{`+ ${t('add')}`}
|
||||
{/* Same glyph as the composer's attach button. */}
|
||||
<IconPlusOutline16 size={14} />
|
||||
{t('add')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -275,7 +275,7 @@ export function ProviderEditor(props: ProviderEditorProps): ReactNode {
|
||||
<div className={styles['field']}>
|
||||
<span className={styles['fieldLabel']}>{t('effort')}</span>
|
||||
<select
|
||||
className={styles['input']}
|
||||
className={`${styles['input']} ${styles['selectInput']}`}
|
||||
value={stringAt(draft, effortField) ?? ''}
|
||||
aria-label={t('effort')}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -155,7 +155,7 @@ describe('ModelsSection', () => {
|
||||
expect(screen.getByText('openai')).toBeTruthy()
|
||||
expect(screen.queryByText('Active')).toBeNull()
|
||||
expect(screen.queryByText('Inactive')).toBeNull()
|
||||
expect(screen.getByText(`+ ${en.add}`)).toBeTruthy()
|
||||
expect(screen.getByText(en.add)).toBeTruthy()
|
||||
})
|
||||
|
||||
it('turns the setup card into a row once the credential reports configured', async () => {
|
||||
@@ -332,7 +332,7 @@ describe('ModelsSection', () => {
|
||||
|
||||
it('adds a dormant provider with a derived reference and stores its key', async () => {
|
||||
const { mutate, set } = await mountSection()
|
||||
fireEvent.click(screen.getByText(`+ ${en.add}`))
|
||||
fireEvent.click(screen.getByText(en.add))
|
||||
const pick = await screen.findByLabelText<HTMLSelectElement>(en.provider)
|
||||
expect([...pick.options].map(option => option.value)).toEqual(['anthropic', 'broken', 'plain'])
|
||||
expect(pick.value).toBe('anthropic')
|
||||
@@ -356,7 +356,7 @@ describe('ModelsSection', () => {
|
||||
|
||||
it('switches the add card target and degrades unknown or broken targets loudly', async () => {
|
||||
await mountSection()
|
||||
fireEvent.click(screen.getByText(`+ ${en.add}`))
|
||||
fireEvent.click(screen.getByText(en.add))
|
||||
const pick = await screen.findByLabelText<HTMLSelectElement>(en.provider)
|
||||
fireEvent.change(pick, { target: { value: 'broken' } })
|
||||
await screen.findByText(/unresolvable settings path/)
|
||||
@@ -374,7 +374,7 @@ describe('ModelsSection', () => {
|
||||
const { set } = await mountSection({
|
||||
mutate: vi.fn(() => Promise.resolve(fail('llm-pi-ai: unknown pi-ai provider "bogus"'))),
|
||||
})
|
||||
fireEvent.click(screen.getByText(`+ ${en.add}`))
|
||||
fireEvent.click(screen.getByText(en.add))
|
||||
await screen.findByLabelText(en.provider)
|
||||
const keys = screen.getAllByLabelText<HTMLInputElement>(en.keyInput)
|
||||
fireEvent.change(keys[keys.length - 1] as HTMLInputElement, { target: { value: 'sk-x' } })
|
||||
@@ -555,7 +555,7 @@ describe('ModelsSection', () => {
|
||||
/>)
|
||||
expect(screen.getByText(en.readOnly)).toBeTruthy()
|
||||
expect(screen.getAllByText<HTMLButtonElement>(en.remove).every(button => button.disabled)).toBe(true)
|
||||
expect(screen.getByText<HTMLButtonElement>(`+ ${en.add}`).disabled).toBe(true)
|
||||
expect(screen.getByText<HTMLButtonElement>(en.add).disabled).toBe(true)
|
||||
})
|
||||
|
||||
it('toggles the row editor closed on a second edit click and on cancel', async () => {
|
||||
@@ -574,10 +574,10 @@ describe('ModelsSection', () => {
|
||||
|
||||
it('cancels the add card back to the add button', async () => {
|
||||
await mountSection()
|
||||
fireEvent.click(screen.getByText(`+ ${en.add}`))
|
||||
fireEvent.click(screen.getByText(en.add))
|
||||
await screen.findByLabelText(en.provider)
|
||||
fireEvent.click(screen.getAllByText(en.cancel)[1] as HTMLElement)
|
||||
await screen.findByText(`+ ${en.add}`)
|
||||
await screen.findByText(en.add)
|
||||
expect(screen.queryByLabelText(en.provider)).toBeNull()
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user