Skip to content

Commit 8faa2ff

Browse files
committed
chore: cleanup
1 parent bdfd8f8 commit 8faa2ff

1 file changed

Lines changed: 130 additions & 142 deletions

File tree

packages/app/src/components/dialog-custom-provider.tsx

Lines changed: 130 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,8 @@ export function DialogCustomProvider(props: Props) {
221221

222222
setForm("saving", true)
223223

224-
const beforeProvider = globalSync.data.config.provider
225-
const beforeDisabled = globalSync.data.config.disabled_providers
226-
227-
const nextProvider = { ...(beforeProvider ?? {}), [result.providerID]: result.config }
228-
const nextDisabled = (beforeDisabled ?? []).filter((id) => id !== result.providerID)
229-
230-
globalSync.set("config", "provider", nextProvider)
231-
globalSync.set("config", "disabled_providers", nextDisabled)
224+
const disabledProviders = globalSync.data.config.disabled_providers ?? []
225+
const nextDisabled = disabledProviders.filter((id) => id !== result.providerID)
232226

233227
globalSync
234228
.updateConfig({ provider: { [result.providerID]: result.config }, disabled_providers: nextDisabled })
@@ -242,8 +236,6 @@ export function DialogCustomProvider(props: Props) {
242236
})
243237
})
244238
.catch((err: unknown) => {
245-
globalSync.set("config", "provider", beforeProvider)
246-
globalSync.set("config", "disabled_providers", beforeDisabled)
247239
const message = err instanceof Error ? err.message : String(err)
248240
showToast({ title: language.t("common.requestFailed"), description: message })
249241
})
@@ -265,153 +257,149 @@ export function DialogCustomProvider(props: Props) {
265257
}
266258
transition
267259
>
268-
<div class="flex flex-col gap-6 px-2.5 pb-3">
260+
<div class="flex flex-col gap-6 px-2.5 pb-3 overflow-y-auto max-h-[60vh]">
269261
<div class="px-2.5 flex gap-4 items-center">
270262
<ProviderIcon id="synthetic" class="size-5 shrink-0 icon-strong-base" />
271263
<div class="text-16-medium text-text-strong">Custom provider</div>
272264
</div>
273265

274-
<div class="px-2.5 pb-10 flex flex-col gap-6">
275-
<div class="text-14-regular text-text-base">
276-
Configure an OpenAI-compatible provider. Fields map to the
266+
<form onSubmit={save} class="px-2.5 pb-6 flex flex-col gap-6">
267+
<p class="text-14-regular text-text-base">
268+
Configure an OpenAI-compatible provider. See the{" "}
277269
<Link href="https://opencode.ai/docs/providers/#custom-provider" tabIndex={-1}>
278270
provider config docs
279271
</Link>
280272
.
273+
</p>
274+
275+
<div class="flex flex-col gap-4">
276+
<TextField
277+
autofocus
278+
label="Provider ID"
279+
placeholder="myprovider"
280+
description="Lowercase letters, numbers, hyphens, or underscores"
281+
value={form.providerID}
282+
onChange={setForm.bind(null, "providerID")}
283+
validationState={errors.providerID ? "invalid" : undefined}
284+
error={errors.providerID}
285+
/>
286+
<TextField
287+
label="Display name"
288+
placeholder="My AI Provider"
289+
value={form.name}
290+
onChange={setForm.bind(null, "name")}
291+
validationState={errors.name ? "invalid" : undefined}
292+
error={errors.name}
293+
/>
294+
<TextField
295+
label="Base URL"
296+
placeholder="https://api.myprovider.com/v1"
297+
value={form.baseURL}
298+
onChange={setForm.bind(null, "baseURL")}
299+
validationState={errors.baseURL ? "invalid" : undefined}
300+
error={errors.baseURL}
301+
/>
302+
<TextField
303+
label="API key"
304+
placeholder="{env:MYPROVIDER_API_KEY}"
305+
description="Optional. Leave empty if you manage auth via headers."
306+
value={form.apiKey}
307+
onChange={setForm.bind(null, "apiKey")}
308+
/>
281309
</div>
282310

283-
<form onSubmit={save} class="flex flex-col gap-6">
284-
<div class="grid grid-cols-1 gap-4">
285-
<TextField
286-
autofocus
287-
label="Provider ID"
288-
placeholder="myprovider"
289-
value={form.providerID}
290-
onChange={setForm.bind(null, "providerID")}
291-
validationState={errors.providerID ? "invalid" : undefined}
292-
error={errors.providerID}
293-
/>
294-
<TextField
295-
label="Display name"
296-
placeholder="My AI Provider"
297-
value={form.name}
298-
onChange={setForm.bind(null, "name")}
299-
validationState={errors.name ? "invalid" : undefined}
300-
error={errors.name}
301-
/>
302-
<TextField
303-
label="Base URL"
304-
placeholder="https://api.myprovider.com/v1"
305-
value={form.baseURL}
306-
onChange={setForm.bind(null, "baseURL")}
307-
validationState={errors.baseURL ? "invalid" : undefined}
308-
error={errors.baseURL}
309-
/>
310-
<TextField
311-
label="API key (optional)"
312-
placeholder="{env:MYPROVIDER_API_KEY}"
313-
description="Leave empty if you manage auth elsewhere."
314-
value={form.apiKey}
315-
onChange={setForm.bind(null, "apiKey")}
316-
/>
317-
</div>
318-
319-
<div class="flex flex-col gap-3">
320-
<div class="text-14-medium text-text-strong">Models</div>
321-
<For each={form.models}>
322-
{(m, i) => (
323-
<div class="flex gap-3 items-start">
324-
<div class="flex-1 grid grid-cols-1 gap-3">
325-
<TextField
326-
label={i() === 0 ? "Model ID" : undefined}
327-
hideLabel={i() !== 0}
328-
placeholder="my-model-name"
329-
value={m.id}
330-
onChange={(v) => setForm("models", i(), "id", v)}
331-
validationState={errors.models[i()]?.id ? "invalid" : undefined}
332-
error={errors.models[i()]?.id}
333-
/>
334-
<TextField
335-
label={i() === 0 ? "Model name" : undefined}
336-
hideLabel={i() !== 0}
337-
placeholder="My Model"
338-
value={m.name}
339-
onChange={(v) => setForm("models", i(), "name", v)}
340-
validationState={errors.models[i()]?.name ? "invalid" : undefined}
341-
error={errors.models[i()]?.name}
342-
/>
343-
</div>
344-
<IconButton
345-
type="button"
346-
icon="trash"
347-
variant="ghost"
348-
onClick={() => removeModel(i())}
349-
aria-label="Remove model"
311+
<div class="flex flex-col gap-3">
312+
<label class="text-12-medium text-text-weak">Models</label>
313+
<For each={form.models}>
314+
{(m, i) => (
315+
<div class="flex gap-2 items-start">
316+
<div class="flex-1">
317+
<TextField
318+
label="ID"
319+
hideLabel
320+
placeholder="model-id"
321+
value={m.id}
322+
onChange={(v) => setForm("models", i(), "id", v)}
323+
validationState={errors.models[i()]?.id ? "invalid" : undefined}
324+
error={errors.models[i()]?.id}
350325
/>
351326
</div>
352-
)}
353-
</For>
354-
<Button type="button" size="large" variant="secondary" icon="plus-small" onClick={addModel}>
355-
Add model
356-
</Button>
357-
</div>
358-
359-
<div class="flex flex-col gap-3">
360-
<div class="text-14-medium text-text-strong">Headers (optional)</div>
361-
<For each={form.headers}>
362-
{(h, i) => (
363-
<div class="flex gap-3 items-start">
364-
<div class="flex-1 grid grid-cols-1 gap-3">
365-
<TextField
366-
label={i() === 0 ? "Header" : undefined}
367-
hideLabel={i() !== 0}
368-
placeholder="Authorization"
369-
value={h.key}
370-
onChange={(v) => setForm("headers", i(), "key", v)}
371-
validationState={errors.headers[i()]?.key ? "invalid" : undefined}
372-
error={errors.headers[i()]?.key}
373-
/>
374-
<TextField
375-
label={i() === 0 ? "Value" : undefined}
376-
hideLabel={i() !== 0}
377-
placeholder="Bearer ..."
378-
value={h.value}
379-
onChange={(v) => setForm("headers", i(), "value", v)}
380-
validationState={errors.headers[i()]?.value ? "invalid" : undefined}
381-
error={errors.headers[i()]?.value}
382-
/>
383-
</div>
384-
<IconButton
385-
type="button"
386-
icon="trash"
387-
variant="ghost"
388-
onClick={() => removeHeader(i())}
389-
aria-label="Remove header"
327+
<div class="flex-1">
328+
<TextField
329+
label="Name"
330+
hideLabel
331+
placeholder="Display Name"
332+
value={m.name}
333+
onChange={(v) => setForm("models", i(), "name", v)}
334+
validationState={errors.models[i()]?.name ? "invalid" : undefined}
335+
error={errors.models[i()]?.name}
390336
/>
391337
</div>
392-
)}
393-
</For>
394-
<Button type="button" size="large" variant="secondary" icon="plus-small" onClick={addHeader}>
395-
Add header
396-
</Button>
397-
</div>
398-
399-
<div class="flex items-center gap-3">
400-
<Button
401-
type="button"
402-
size="large"
403-
variant="secondary"
404-
onClick={() => dialog.close()}
405-
disabled={form.saving}
406-
>
407-
{language.t("common.cancel")}
408-
</Button>
409-
<Button type="submit" size="large" variant="primary" disabled={form.saving}>
410-
{form.saving ? language.t("common.saving") : language.t("common.save")}
411-
</Button>
412-
</div>
413-
</form>
414-
</div>
338+
<IconButton
339+
type="button"
340+
icon="trash"
341+
variant="ghost"
342+
class="mt-1.5"
343+
onClick={() => removeModel(i())}
344+
disabled={form.models.length <= 1}
345+
aria-label="Remove model"
346+
/>
347+
</div>
348+
)}
349+
</For>
350+
<Button type="button" size="small" variant="ghost" icon="plus-small" onClick={addModel} class="self-start">
351+
Add model
352+
</Button>
353+
</div>
354+
355+
<div class="flex flex-col gap-3">
356+
<label class="text-12-medium text-text-weak">Headers (optional)</label>
357+
<For each={form.headers}>
358+
{(h, i) => (
359+
<div class="flex gap-2 items-start">
360+
<div class="flex-1">
361+
<TextField
362+
label="Header"
363+
hideLabel
364+
placeholder="Header-Name"
365+
value={h.key}
366+
onChange={(v) => setForm("headers", i(), "key", v)}
367+
validationState={errors.headers[i()]?.key ? "invalid" : undefined}
368+
error={errors.headers[i()]?.key}
369+
/>
370+
</div>
371+
<div class="flex-1">
372+
<TextField
373+
label="Value"
374+
hideLabel
375+
placeholder="value"
376+
value={h.value}
377+
onChange={(v) => setForm("headers", i(), "value", v)}
378+
validationState={errors.headers[i()]?.value ? "invalid" : undefined}
379+
error={errors.headers[i()]?.value}
380+
/>
381+
</div>
382+
<IconButton
383+
type="button"
384+
icon="trash"
385+
variant="ghost"
386+
class="mt-1.5"
387+
onClick={() => removeHeader(i())}
388+
disabled={form.headers.length <= 1}
389+
aria-label="Remove header"
390+
/>
391+
</div>
392+
)}
393+
</For>
394+
<Button type="button" size="small" variant="ghost" icon="plus-small" onClick={addHeader} class="self-start">
395+
Add header
396+
</Button>
397+
</div>
398+
399+
<Button class="w-auto self-start" type="submit" size="large" variant="primary" disabled={form.saving}>
400+
{form.saving ? "Saving..." : language.t("common.submit")}
401+
</Button>
402+
</form>
415403
</div>
416404
</Dialog>
417405
)

0 commit comments

Comments
 (0)