fix(desktop): clear shared credential reveal state
This commit is contained in:
@@ -98,8 +98,8 @@ export function useEnvCredentials(profile?: string): UseEnvCredentials {
|
||||
setVars(c => (c ? { ...c, [key]: { ...c[key], ...patch } } : c))
|
||||
}
|
||||
|
||||
function clearLocalState(key: string) {
|
||||
setEdits(c => withoutKey(c, key))
|
||||
function clearLocalState(key: string, editKey = key) {
|
||||
setEdits(c => withoutKey(c, editKey))
|
||||
setRevealed(c => withoutKey(c, key))
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ export function useEnvCredentials(profile?: string): UseEnvCredentials {
|
||||
try {
|
||||
await setEnvVar(key, value, profile)
|
||||
patchVar(key, { is_set: true, redacted_value: redactedValue(value) })
|
||||
clearLocalState(editKey)
|
||||
clearLocalState(key, editKey)
|
||||
void queryClient.invalidateQueries({ queryKey: ['model-options'] })
|
||||
notify({ kind: 'success', title: toolsets.savedTitle, message: toolsets.savedMessage(key) })
|
||||
} catch (err) {
|
||||
@@ -164,7 +164,7 @@ export function useEnvCredentials(profile?: string): UseEnvCredentials {
|
||||
try {
|
||||
await deleteEnvVar(key, profile)
|
||||
patchVar(key, { is_set: false, redacted_value: null })
|
||||
clearLocalState(editKey)
|
||||
clearLocalState(key, editKey)
|
||||
void queryClient.invalidateQueries({ queryKey: ['model-options'] })
|
||||
notify({ kind: 'success', title: toolsets.removedTitle, message: toolsets.removedMessage(key) })
|
||||
} catch (err) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import type { EnvVarInfo, OAuthProvider } from '@/types/hermes'
|
||||
const listOAuthProviders = vi.fn()
|
||||
const disconnectOAuthProvider = vi.fn()
|
||||
const getEnvVars = vi.fn()
|
||||
const revealEnvVar = vi.fn()
|
||||
const setEnvVar = vi.fn()
|
||||
const startManualProviderOAuth = vi.fn()
|
||||
const startManualLocalEndpoint = vi.fn()
|
||||
@@ -25,10 +26,11 @@ vi.mock('@/store/profile', () => ({
|
||||
vi.mock('@/hermes', () => ({
|
||||
setApiRequestProfile: vi.fn(),
|
||||
getProfiles: async () => ({ profiles: (await import('@/store/profile')).$profiles.get() }),
|
||||
setEnvVar: (key: string, value: string, profile?: string) => setEnvVar(key, value, profile),
|
||||
disconnectOAuthProvider: (...args: unknown[]) => disconnectOAuthProvider(...args),
|
||||
getEnvVars: (...args: unknown[]) => getEnvVars(...args),
|
||||
listOAuthProviders: (...args: unknown[]) => listOAuthProviders(...args)
|
||||
listOAuthProviders: (...args: unknown[]) => listOAuthProviders(...args),
|
||||
revealEnvVar: (key: string, profile?: string) => revealEnvVar(key, profile),
|
||||
setEnvVar: (key: string, value: string, profile?: string) => setEnvVar(key, value, profile)
|
||||
}))
|
||||
|
||||
vi.mock('@/store/onboarding', () => ({
|
||||
@@ -81,6 +83,8 @@ beforeEach(() => {
|
||||
onboarding.set({ manual: false })
|
||||
getEnvVars.mockResolvedValue({})
|
||||
disconnectOAuthProvider.mockResolvedValue({ ok: true, provider: 'nous' })
|
||||
revealEnvVar.mockResolvedValue({ value: 'old-secret' })
|
||||
setEnvVar.mockResolvedValue({ ok: true })
|
||||
listOAuthProviders.mockResolvedValue({
|
||||
providers: [provider('nous', true), provider('minimax-oauth', false)]
|
||||
})
|
||||
@@ -279,6 +283,44 @@ describe('ProvidersSettings', () => {
|
||||
expect((inputs[1] as HTMLInputElement).value).toBe('')
|
||||
})
|
||||
|
||||
it('clears the shared reveal when a namespaced provider-card draft is saved', async () => {
|
||||
const varKey = 'DASHSCOPE_API_KEY'
|
||||
const editKey = `Qwen Cloud:${varKey}`
|
||||
getEnvVars.mockResolvedValue({
|
||||
[varKey]: keyVar({ is_set: true, redacted_value: '••••••••' })
|
||||
})
|
||||
|
||||
const { useEnvCredentials } = await import('./env-credentials')
|
||||
const state = { current: null as null | ReturnType<typeof useEnvCredentials> }
|
||||
|
||||
function Harness() {
|
||||
state.current = useEnvCredentials()
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
render(<Harness />)
|
||||
await waitFor(() => expect(state.current?.vars).not.toBeNull())
|
||||
|
||||
await act(async () => {
|
||||
await Promise.resolve(state.current!.rowProps.onReveal(varKey))
|
||||
})
|
||||
expect(state.current!.rowProps.revealed[varKey]).toBe('old-secret')
|
||||
|
||||
act(() => {
|
||||
state.current!.rowProps.setEdits(current => ({ ...current, [editKey]: 'new-secret' }))
|
||||
})
|
||||
await waitFor(() => expect(state.current!.rowProps.edits[editKey]).toBe('new-secret'))
|
||||
|
||||
await act(async () => {
|
||||
await Promise.resolve(state.current!.rowProps.onSave(varKey, editKey))
|
||||
})
|
||||
|
||||
expect(setEnvVar).toHaveBeenCalledWith(varKey, 'new-secret', undefined)
|
||||
expect(state.current!.rowProps.edits[editKey]).toBeUndefined()
|
||||
expect(state.current!.rowProps.revealed[varKey]).toBeUndefined()
|
||||
})
|
||||
|
||||
it('orders API-key providers by priority then name, and filters them via search', async () => {
|
||||
// These three providers have no curated PROVIDER_GROUPS priority, so they
|
||||
// share the default priority and fall back to alphabetical among themselves
|
||||
|
||||
Reference in New Issue
Block a user