Skip to content

Commit 9d19f42

Browse files
committed
Refine the settings UI by adding per-item insert actions, enabling disabled icon buttons, and updating model provider credential handling with snake_case fields, localhost-aware key/token behavior, and revised credential messaging
- we're also storing access tokens, account for it in texts by using word "credentials" - in [Fragment] instead of [Fragment] say shorter "Credentials" - "Change API Key" should be changed to "Refresh token" in the case of ChatGPT provider - don't show "change api key" action for localhost providers - move insert action outside the `packages/ui/src/components/editor/settings/SortableList/SortableList.tsx` - keep showing "api key" for localhost providers, but make it in disabled state - when changing api key is disabled, show appropriate title text - if api key is not required show "—" in place of shrotened api key - use snake case [Pasted text]
1 parent 4a2f807 commit 9d19f42

12 files changed

Lines changed: 189 additions & 118 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Install the [browser extension](https://github.com/robertpiosik/CodeWebChat/tree
7777
From code editing to commit messages, CWC supports your software development efforts on every step. Bring Your Own Key (BYOK) or authenticate with ChatGPT account. Self-host with [Ollama](https://ollama.com/search) or [LM Studio](https://lmstudio.ai/).
7878

7979
> [!NOTE]
80-
> With its smart context files ordering, [prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching/) is utilized across tasks.
80+
> With its smart context files ordering, [prompt caching](https://developers.openai.com/api/docs/guides/prompt-caching/) is heavily utilized across tasks.
8181
8282
> [!IMPORTANT]
8383
> Not all providers offer 90% discount on cached input tokens. [Google](https://aistudio.google.com/api-keys) and [OpenAI](https://platform.openai.com/settings/organization/api-keys) are your safe bets.

‎apps/editor/src/views/settings/backend/message-handlers/handle-get-model-providers.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ export const handle_get_model_providers = async (
99
const saved_providers = await providers_manager.get_providers()
1010

1111
const providers_for_client = saved_providers.map((p) => {
12-
const apiKeyMask = p.api_key ? `...${p.api_key.slice(-4)}` : ''
12+
const api_key_mask = p.api_key ? `...${p.api_key.slice(-4)}` : ''
1313

14-
const baseUrl =
14+
const base_url =
1515
p.type == 'built-in' ? PROVIDERS[p.name].base_url : p.base_url
1616

1717
return {
1818
name: p.name,
1919
type: p.type,
20-
apiKeyMask,
21-
baseUrl
20+
api_key_mask,
21+
base_url
2222
}
2323
})
2424

‎apps/editor/src/views/settings/frontend/Home/Home.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ export const Home: React.FC<Props> = (props) => {
384384
>
385385
<UiNotice type="info">
386386
<Translation
387-
id="model-providers.notice.api-keys"
387+
id="model-providers.notice.credentials"
388388
components={{
389389
link: (
390390
<a

‎apps/editor/src/views/settings/frontend/Home/sections/ApiToolConfigurationSection.tsx‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export const ApiToolConfigurationSection: React.FC<
4949
on_add={props.on_add}
5050
translations={{
5151
add_title: t('action.add-new'),
52-
insert_title: t('action.insert-configuration'),
5352
item_text: t('action.configuration'),
5453
items_text: t('action.configurations'),
5554
items_text_many: t('action.configurations-many')
@@ -97,8 +96,13 @@ export const ApiToolConfigurationSection: React.FC<
9796
</div>
9897
</>
9998
)}
100-
render_actions={(config) => (
99+
render_actions={(config, index) => (
101100
<>
101+
<IconButton
102+
codicon_icon="insert"
103+
title={t('action.insert-configuration')}
104+
on_click={() => props.on_add({ insertion_index: index })}
105+
/>
102106
<IconButton
103107
codicon_icon="edit"
104108
title={t('action.edit-configuration')}

‎apps/editor/src/views/settings/frontend/Home/sections/ModelProvidersSection.tsx‎

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -32,66 +32,89 @@ export const ModelProvidersSection: React.FC<ModelProvidersSectionProps> = (
3232
on_add={props.on_add_provider}
3333
translations={{
3434
add_title: t('action.add-new'),
35-
insert_title: t('action.insert-provider'),
3635
item_text: t('action.model-provider'),
3736
items_text: t('action.model-providers')
3837
}}
39-
render_content={(provider) => (
40-
<>
41-
<div
42-
style={{
43-
width: 90,
44-
whiteSpace: 'nowrap',
45-
overflow: 'hidden',
46-
textOverflow: 'ellipsis'
47-
}}
48-
>
49-
{provider.name}
50-
</div>
51-
<div
52-
style={{
53-
width: 50,
54-
whiteSpace: 'nowrap',
55-
overflow: 'hidden',
56-
textOverflow: 'ellipsis'
57-
}}
58-
>
59-
{provider.apiKeyMask}
60-
</div>
61-
<div
62-
style={{
63-
flex: 1,
64-
whiteSpace: 'nowrap',
65-
overflow: 'hidden',
66-
textOverflow: 'ellipsis'
67-
}}
68-
>
69-
{provider.baseUrl}
70-
</div>
71-
</>
72-
)}
73-
render_actions={(provider) => (
74-
<>
75-
{provider.type == 'custom' ? (
38+
render_content={(provider) => {
39+
const is_localhost =
40+
provider.base_url.includes('localhost') ||
41+
provider.base_url.includes('127.0.0.1')
42+
43+
return (
44+
<>
45+
<div
46+
style={{
47+
width: 90,
48+
whiteSpace: 'nowrap',
49+
overflow: 'hidden',
50+
textOverflow: 'ellipsis'
51+
}}
52+
>
53+
{provider.name}
54+
</div>
55+
<div
56+
style={{
57+
width: 50,
58+
whiteSpace: 'nowrap',
59+
overflow: 'hidden',
60+
textOverflow: 'ellipsis'
61+
}}
62+
>
63+
{is_localhost ? '⠀⠀—' : provider.api_key_mask}
64+
</div>
65+
<div
66+
style={{
67+
flex: 1,
68+
whiteSpace: 'nowrap',
69+
overflow: 'hidden',
70+
textOverflow: 'ellipsis'
71+
}}
72+
>
73+
{provider.base_url}
74+
</div>
75+
</>
76+
)
77+
}}
78+
render_actions={(provider, index) => {
79+
const is_localhost =
80+
provider.base_url.includes('localhost') ||
81+
provider.base_url.includes('127.0.0.1')
82+
83+
return (
84+
<>
7685
<IconButton
77-
codicon_icon="edit"
78-
title={t('action.edit-provider')}
79-
on_click={() => props.on_edit_provider(provider.name)}
86+
codicon_icon="insert"
87+
title={t('action.insert-provider')}
88+
on_click={() => props.on_add_provider({ insertion_index: index })}
8089
/>
81-
) : (
90+
{provider.type == 'custom' ? (
91+
<IconButton
92+
codicon_icon="edit"
93+
title={t('action.edit-provider')}
94+
on_click={() => props.on_edit_provider(provider.name)}
95+
/>
96+
) : (
97+
<IconButton
98+
codicon_icon={provider.name == 'ChatGPT' ? 'refresh' : 'key'}
99+
title={
100+
is_localhost
101+
? t('action.api-key-not-required')
102+
: provider.name == 'ChatGPT'
103+
? t('action.refresh-token')
104+
: t('action.change-api-key')
105+
}
106+
on_click={() => props.on_change_api_key(provider.name)}
107+
disabled={is_localhost}
108+
/>
109+
)}
82110
<IconButton
83-
codicon_icon="key"
84-
title={t('action.change-api-key')}
85-
on_click={() => props.on_change_api_key(provider.name)}
111+
codicon_icon="trash"
112+
title={t('action.delete-provider')}
113+
on_click={() => props.on_delete_provider(provider.name)}
86114
/>
87-
)}
88-
<IconButton
89-
codicon_icon="trash"
90-
title={t('action.delete-provider')}
91-
on_click={() => props.on_delete_provider(provider.name)}
92-
/>
93-
</>
94-
)}
115+
</>
116+
)
117+
}}
95118
/>
96119
)
97120
}

‎apps/editor/src/views/settings/frontend/i18n/translations/actions.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,42 @@ export const actions = {
7171
hu: 'API kulcs módosítása',
7272
bg: 'Промяна на API ключ'
7373
},
74+
'action.api-key-not-required': {
75+
en: 'API key not required',
76+
pl: 'Klucz API nie jest wymagany',
77+
'zh-cn': '不需要 API 密钥',
78+
ja: 'APIキーは不要です',
79+
'zh-tw': '不需要 API 金鑰',
80+
de: 'API-Schlüssel nicht erforderlich',
81+
es: 'Clave API no requerida',
82+
fr: 'Clé API non requise',
83+
'pt-br': 'Chave de API não necessária',
84+
ru: 'Ключ API не требуется',
85+
ko: 'API 키가 필요하지 않습니다',
86+
it: 'Chiave API non richiesta',
87+
tr: 'API anahtarı gerekli değil',
88+
cs: 'API klíč není vyžadován',
89+
hu: 'API kulcs nem szükséges',
90+
bg: 'API ключ не е задължителен'
91+
},
92+
'action.refresh-token': {
93+
en: 'Refresh token',
94+
pl: 'Odśwież token',
95+
'zh-cn': '刷新令牌',
96+
ja: 'トークンを更新',
97+
'zh-tw': '重新整理權杖',
98+
de: 'Token aktualisieren',
99+
es: 'Actualizar token',
100+
fr: 'Actualiser le jeton',
101+
'pt-br': 'Atualizar token',
102+
ru: 'Обновить токен',
103+
ko: '토큰 새로고침',
104+
it: 'Aggiorna token',
105+
tr: 'Belirteci yenile',
106+
cs: 'Obnovit token',
107+
hu: 'Token frissítése',
108+
bg: 'Обновяване на токен'
109+
},
74110
'action.delete-provider': {
75111
en: 'Delete provider',
76112
pl: 'Usuń dostawcę',

‎apps/editor/src/views/settings/frontend/i18n/translations/model-providers.ts‎

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
export const model_providers = {
22
'model-providers.subtitle': {
3-
en: 'Manage API keys.',
4-
pl: 'Zarządzaj kluczami API.',
5-
'zh-cn': '管理 API 密钥。',
6-
ja: 'API キーを管理します。',
7-
'zh-tw': '管理 API 金鑰。',
8-
de: 'API-Schlüssel verwalten.',
9-
es: 'Gestionar claves API.',
10-
fr: 'Gérer les clés API.',
11-
'pt-br': 'Gerenciar chaves de API.',
12-
ru: 'Управление API ключами.',
13-
ko: 'API 키를 관리합니다.',
14-
it: 'Gestisci le chiavi API.',
15-
tr: 'API anahtarını yönetin.',
16-
cs: 'Správa API klíčů.',
17-
hu: 'API kulcsok kezelése.',
18-
bg: 'Управление на API ключове.'
3+
en: 'Manage API keys and access tokens.',
4+
pl: 'Zarządzaj kluczami API i tokenami dostępu.',
5+
'zh-cn': '管理 API 密钥和访问令牌。',
6+
ja: 'API キーとアクセストークンを管理します。',
7+
'zh-tw': '管理 API 金鑰和存取權杖。',
8+
de: 'API-Schlüssel und Zugriffstoken verwalten.',
9+
es: 'Gestionar claves API y tokens de acceso.',
10+
fr: "Gérer les clés API et les jetons d'accès.",
11+
'pt-br': 'Gerenciar chaves de API e tokens de acesso.',
12+
ru: 'Управление API ключами и токенами доступа.',
13+
ko: 'API 키 및 액세스 토큰을 관리합니다.',
14+
it: 'Gestisci le chiavi API e i token di accesso.',
15+
tr: 'API anahtarlarını ve erişim belirteçlerini yönetin.',
16+
cs: 'Správa API klíčů a přístupových tokenů.',
17+
hu: 'API kulcsok és hozzáférési tokenek kezelése.',
18+
bg: 'Управление на API ключове и токени за достъп.'
1919
},
20-
'model-providers.notice.api-keys': {
21-
en: 'API keys are stored securely in the {link} on your machine.',
22-
pl: 'Klucze API są bezpiecznie przechowywane w {link} na twoim komputerze.',
23-
'zh-cn': 'API 密钥安全地存储在您机器上的 {link} 中。',
24-
ja: 'API キーはマシンの {link} に安全に保存されます。',
25-
'zh-tw': 'API 金鑰安全地儲存在您機器的 {link} 中。',
26-
de: 'API-Schlüssel werden sicher im {link} auf Ihrem Computer gespeichert.',
27-
es: 'Las claves API se almacenan de forma segura en {link} en tu máquina.',
28-
fr: 'Les clés API sont stockées de manière sécurisée dans {link} sur votre machine.',
20+
'model-providers.notice.credentials': {
21+
en: 'Credentials are stored securely in the {link} on your machine.',
22+
pl: 'Dane uwierzytelniające są bezpiecznie przechowywane w {link} na twoim komputerze.',
23+
'zh-cn': '凭据安全地存储在您机器上的 {link} 中。',
24+
ja: '認証情報はマシンの {link} に安全に保存されます。',
25+
'zh-tw': '憑證安全地儲存在您機器的 {link} 中。',
26+
de: 'Anmeldedaten werden sicher im {link} auf Ihrem Computer gespeichert.',
27+
es: 'Las credenciales se almacenan de forma segura en {link} en tu máquina.',
28+
fr: 'Les identifiants sont stockés de manière sécurisée dans {link} sur votre machine.',
2929
'pt-br':
30-
'As chaves de API são armazenadas com segurança no {link} em sua máquina.',
31-
ru: 'API ключи безопасно хранятся в {link} на вашей машине.',
32-
ko: 'API 키는 컴퓨터의 {link}에 안전하게 저장됩니다.',
33-
it: 'Le chiavi API sono archiviate in modo sicuro nel {link} sul tuo computer.',
34-
tr: 'API anahtarları güvenli bir şekilde bilgisayarınızdaki {link} içinde saklanır.',
35-
cs: 'API klíče jsou bezpečně uloženy v {link} na vašem počítači.',
36-
hu: 'Az API kulcsok biztonságosan vannak tárolva a {link} a gépén.',
37-
bg: 'API ключовете се съхраняват сигурно в {link} на вашата машина.'
30+
'As credenciais são armazenadas com segurança no {link} em sua máquina.',
31+
ru: 'Учетные данные безопасно хранятся в {link} на вашей машине.',
32+
ko: '자격 증명은 컴퓨터의 {link}에 안전하게 저장됩니다.',
33+
it: 'Le credenziali sono archiviate in modo sicuro nel {link} sul tuo computer.',
34+
tr: 'Kimlik bilgileri bilgisayarınızdaki {link} içinde güvenli bir şekilde saklanır.',
35+
cs: 'Přihlašovací údaje jsou bezpečně uloženy v {link} na vašem počítači.',
36+
hu: 'A hitelesítő adatok biztonságosan vannak tárolva a {link} a gépén.',
37+
bg: 'Идентификационните данни се съхраняват сигурно в {link} на вашата машина.'
3838
},
3939
'model-providers.notice.missing': {
4040
en: 'Missing model provider.',

‎apps/editor/src/views/settings/types/messages.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { ToolType } from './tools'
33
export type ProviderForClient = {
44
name: string
55
type: 'built-in' | 'custom'
6-
apiKeyMask: string
7-
baseUrl: string
6+
api_key_mask: string
7+
base_url: string
88
}
99

1010
export type ConfigurationForClient = {

‎packages/ui/src/components/editor/common/IconButton/IconButton.module.scss‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
outline: none;
1515
}
1616

17-
&:hover {
17+
&:disabled {
18+
opacity: var(--disabled-opacity);
19+
cursor: default;
20+
}
21+
22+
&:hover:not(:disabled) {
1823
background-color: var(--vscode-toolbar-hoverBackground);
1924
text-decoration: none;
2025
}

‎packages/ui/src/components/editor/common/IconButton/IconButton.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Props = {
99
title?: string
1010
label?: string
1111
style?: React.CSSProperties
12+
disabled?: boolean
1213
}
1314

1415
export const IconButton: React.FC<Props> = (props) => {
@@ -46,6 +47,7 @@ export const IconButton: React.FC<Props> = (props) => {
4647
onMouseDown={props.on_mouse_down}
4748
onClick={props.on_click}
4849
title={props.title}
50+
disabled={props.disabled}
4951
style={props.style}
5052
>
5153
{label_element}

0 commit comments

Comments
 (0)