update styles and descs

This commit is contained in:
Andrew Pareles 2024-12-19 18:44:26 -08:00
parent 702d11ed3e
commit 298423928e
6 changed files with 93 additions and 55 deletions

View file

@ -36,7 +36,7 @@ const refreshBasedOn: { [k in RefreshableProviderName]: (keyof SettingsOfProvide
openAICompatible: ['enabled', 'endpoint', 'apiKey'],
}
const REFRESH_INTERVAL = 5_000
const COOLDOWN_TIMEOUT = 300
// const COOLDOWN_TIMEOUT = 300
// element-wise equals
function eq<T>(a: T[], b: T[]): boolean {
@ -92,18 +92,23 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ
this.voidSettingsService.onDidChangeState(() => { // we might want to debounce this
const newVals = relevantVals()
if (!eq(prevVals, newVals)) {
prevVals = newVals
const { enabled } = this.voidSettingsService.state.settingsOfProvider[providerName]
if (enabled) {
const prevEnabled = prevVals[0] as boolean
const enabled = newVals[0] as boolean
// if it was just enabled, or there was a change and it wasn't to the enabled state, refresh
if ((enabled && !prevEnabled) || (!enabled && !prevEnabled)) {
// if user just clicked enable, refresh
this.refreshModels(providerName, !enabled)
}
else {
// else if user just clicked disable, give cooldown before re-enabling (or at least re-fetching)
const timeoutId = setTimeout(() => this.refreshModels(providerName, !enabled), COOLDOWN_TIMEOUT)
this._setTimeoutId(providerName, timeoutId)
// else if user just clicked disable, don't refresh
// //give cooldown before re-enabling (or at least re-fetching)
// const timeoutId = setTimeout(() => this.refreshModels(providerName, !enabled), COOLDOWN_TIMEOUT)
// this._setTimeoutId(providerName, timeoutId)
}
prevVals = newVals
}
})
)

View file

@ -155,22 +155,47 @@ export type SettingName = keyof SettingsForProvider<ProviderName>
type DisplayInfoForProviderName = {
title: string,
}
export const titleOfProviderName = (providerName: ProviderName) => {
if (providerName === 'anthropic')
return 'Anthropic'
else if (providerName === 'openAI')
return 'OpenAI'
else if (providerName === 'ollama')
return 'Ollama'
else if (providerName === 'openRouter')
return 'OpenRouter'
else if (providerName === 'openAICompatible')
return 'OpenAI-Compatible'
else if (providerName === 'gemini')
return 'Gemini'
else if (providerName === 'groq')
return 'Groq'
export const displayInfoOfProviderName = (providerName: ProviderName): DisplayInfoForProviderName => {
if (providerName === 'anthropic') {
return {
title: 'Anthropic',
}
}
else if (providerName === 'openAI') {
return {
title: 'OpenAI',
}
}
else if (providerName === 'openRouter') {
return {
title: 'OpenRouter',
}
}
else if (providerName === 'ollama') {
return {
title: 'Ollama',
}
}
else if (providerName === 'openAICompatible') {
return {
title: 'OpenAI-Compatible',
}
}
else if (providerName === 'gemini') {
return {
title: 'Gemini',
}
}
else if (providerName === 'groq') {
return {
title: 'Groq',
}
}
throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`)
}
@ -178,9 +203,7 @@ export const titleOfProviderName = (providerName: ProviderName) => {
type DisplayInfo = {
title: string,
placeholder: string,
helpfulUrl?: string,
urlPurpose?: string,
subTextMd?: string,
}
export const displayInfoOfSettingName = (providerName: ProviderName, settingName: SettingName): DisplayInfo => {
if (settingName === 'apiKey') {
@ -194,15 +217,13 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'openAICompatible' ? 'sk-key...' :
'(never)',
helpfulUrl: providerName === 'anthropic' ? 'https://console.anthropic.com/settings/keys' :
providerName === 'openAI' ? 'https://platform.openai.com/api-keys' :
providerName === 'openRouter' ? 'https://openrouter.ai/settings/keys' :
providerName === 'gemini' ? 'https://aistudio.google.com/apikey' :
providerName === 'groq' ? 'https://console.groq.com/keys' :
subTextMd: providerName === 'anthropic' ? 'Get your [API Key here](https://console.anthropic.com/settings/keys).' :
providerName === 'openAI' ? 'Get your [API Key here](https://platform.openai.com/api-keys).' :
providerName === 'openRouter' ? 'Get your [API Key here](https://openrouter.ai/settings/keys).' :
providerName === 'gemini' ? 'Get your [API Key here](https://aistudio.google.com/apikey).' :
providerName === 'groq' ? 'Get your [API Key here](https://console.groq.com/keys).' :
providerName === 'openAICompatible' ? undefined :
undefined,
urlPurpose: 'to get your API key.',
}
}
else if (settingName === 'endpoint') {
@ -215,11 +236,8 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
: providerName === 'openAICompatible' ? 'https://my-website.com/v1'
: '(never)',
helpfulUrl: providerName === 'ollama' ? 'https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network'
: providerName === 'openAICompatible' ? undefined
: undefined,
urlPurpose: 'for more information.',
subTextMd: providerName === 'ollama' ? 'Read about Ollama [Endpoints here](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network).' :
undefined,
}
}
else if (settingName === 'enabled') {

View file

@ -169,7 +169,7 @@ const RenderToken = ({ token, nested = false }: { token: Token | string, nested?
if (t.type === "link") {
return (
<a href={t.href} title={t.title ?? undefined}>
<a className='underline' onClick={() => { window.open(t.href) }} href={t.href} title={t.title ?? undefined}>
{t.text}
</a>
)

View file

@ -8,12 +8,10 @@
@tailwind utilities;
@layer components {
.select-ellipsis select {
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 24px;
}
.select-child-restyle select {
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 24px;
}
* {
@ -22,6 +20,7 @@
/* html {
font-size: var(--vscode-font-size);
}

View file

@ -194,7 +194,7 @@ export const VoidSelectBox = <T,>({ onChangeSelection, onCreateInstance, selectB
let containerRef = useRef<HTMLDivElement | null>(null);
return <WidgetComponent
className='@@select-ellipsis'
className='@@select-child-restyle'
ctor={SelectBox}
propsFn={useCallback((container) => {
containerRef.current = container

View file

@ -1,10 +1,11 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js'
import { ProviderName, SettingName, displayInfoOfSettingName, titleOfProviderName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidModelInfo, featureFlagNames, displayInfoOfFeatureFlag, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName } from '../../../../../../../platform/void/common/voidSettingsTypes.js'
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
import { VoidCheckBox, VoidInputBox, VoidSelectBox, VoidSwitch } from '../util/inputs.js'
import { useIsDark, useRefreshModelListener, useRefreshModelState, useService, useSettingsState } from '../util/services.js'
import { X, RefreshCw, Loader2, Check } from 'lucide-react'
import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js'
@ -30,12 +31,14 @@ const RefreshModelButton = ({ providerName }: { providerName: RefreshableProvide
const { state } = refreshModelState[providerName]
const isRefreshing = state === 'refreshing'
const providerTitle = titleOfProviderName(providerName)
const { title: providerTitle } = displayInfoOfProviderName(providerName)
return <div className='flex items-center py-1 px-3 rounded-sm overflow-hidden gap-2 hover:bg-black/10 dark:hover:bg-gray-200/10'>
<button className='flex items-center' disabled={isRefreshing || justFinished} onClick={() => { refreshModelService.refreshModels(providerName) }}>
{isRefreshing ? <Loader2 className='size-3 animate-spin' /> : (justFinished ? <Check className='stroke-green-500 size-3' /> : <RefreshCw className='size-3' />)}
</button>
<span className='opacity-50'>Refresh Default Models for {providerTitle}.</span>
<span className='opacity-50'>{
justFinished ? `${providerTitle} Models are up-to-date!` : `Refresh Models List for ${providerTitle}.`
}</span>
</div>
}
@ -65,7 +68,8 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => {
const [errorString, setErrorString] = useState('')
const providerOptions = useMemo(() => providerNames.map(providerName => ({ text: titleOfProviderName(providerName), value: providerName })), [providerNames])
const providerOptions = useMemo(() => providerNames.map(providerName => ({ text: displayInfoOfProviderName(providerName).title, value: providerName })), [providerNames])
return <>
<div className='flex items-center gap-4'>
@ -129,7 +133,7 @@ const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => {
const AddModelMenuFull = () => {
const [open, setOpen] = useState(false)
return <div className='my-2 hover:bg-black/10 dark:hover:bg-gray-200/10 py-1 px-3 rounded-sm overflow-hidden '>
return <div className='hover:bg-black/10 dark:hover:bg-gray-200/10 py-1 px-3 rounded-sm overflow-hidden '>
{open ?
<AddModelMenu onSubmit={() => { setOpen(false) }} />
: <button
@ -163,6 +167,8 @@ export const ModelDump = () => {
{modelDump.map(m => {
const { isHidden, isDefault, modelName, providerName, providerEnabled } = m
const disabled = !providerEnabled
return <div key={`${modelName}${providerName}`} className='flex items-center justify-between gap-4 hover:bg-black/10 dark:hover:bg-gray-200/10 py-1 px-3 rounded-sm overflow-hidden cursor-default'>
{/* left part is width:full */}
<div className={`w-full flex items-center gap-4`}>
@ -173,9 +179,9 @@ export const ModelDump = () => {
<span className='opacity-50 whitespace-nowrap'>{isDefault ? '' : '(custom model)'}</span>
<VoidSwitch
value={!isHidden}
value={disabled ? false : !isHidden}
onChange={() => { settingsStateService.toggleModelHidden(providerName, modelName) }}
disabled={!providerEnabled}
disabled={disabled}
size='sm'
/>
@ -194,8 +200,10 @@ export const ModelDump = () => {
const ProviderSetting = ({ providerName, settingName }: { providerName: ProviderName, settingName: SettingName }) => {
const providerTitle = titleOfProviderName(providerName)
const { title: settingTitle, placeholder, } = displayInfoOfSettingName(providerName, settingName)
const { title: providerTitle, } = displayInfoOfProviderName(providerName)
const { title: settingTitle, placeholder, subTextMd } = displayInfoOfSettingName(providerName, settingName)
const voidSettingsService = useService('settingsStateService')
let weChangedTextRef = false
@ -225,6 +233,10 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider
}, [voidSettingsService, providerName, settingName])}
multiline={false}
/>
{subTextMd === undefined ? null : <div className='py-1 px-3 opacity-50 text-xs'>
<ChatMarkdownRender string={subTextMd} />
</div>}
</div>
</ErrorBoundary>
}
@ -236,9 +248,12 @@ const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) =
const { enabled } = voidSettingsState.settingsOfProvider[providerName]
const settingNames = customSettingNamesOfProvider(providerName)
const { title: providerTitle } = displayInfoOfProviderName(providerName)
return <div className='my-4'>
<div className='flex items-center w-full gap-4'>
<h3 className='text-xl truncate'>{titleOfProviderName(providerName)}</h3>
<h3 className='text-xl truncate'>{providerTitle}</h3>
{/* enable provider switch */}
<VoidSwitch
value={!!enabled}
@ -250,6 +265,7 @@ const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) =
size='sm+'
/>
</div>
<div className='px-0'>
{/* settings besides models (e.g. api key) */}
{settingNames.map((settingName, i) => {