Skip to content

Commit 110bcaf

Browse files
committed
Polish UI
1 parent a7b7ff7 commit 110bcaf

1 file changed

Lines changed: 94 additions & 78 deletions

File tree

webapp/_webapp/src/views/settings/sections/api-key-settings.tsx

Lines changed: 94 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useRef, useState } from "react";
2+
import { Icon } from "@iconify/react";
23
import { Modal } from "../../../components/modal";
34
import { SettingsSectionContainer, SettingsSectionTitle } from "./components";
4-
import { Button } from "@heroui/react";
5+
import { Button, Tooltip } from "@heroui/react";
56
import { useSettingStore } from "../../../stores/setting-store";
67
import { useLanguageModels } from "../../../hooks/useLanguageModels";
78

@@ -101,20 +102,21 @@ type CustomModelSectionProps = NewCustomModelSectionProps | ExistingCustomModelS
101102

102103
const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModelSectionProps) => {
103104
const { models } = useLanguageModels();
105+
const { settings } = useSettingStore();
104106

105107
const [isEditing, setIsEditing] = useState(isNew);
106-
const [modelName, setModelName] = useState(isNew ? "New Model" : customModel.name);
107108
const [baseUrl, setBaseUrl] = useState(customModel?.baseUrl || "");
108109
const [slug, setSlug] = useState(customModel?.slug || "");
109110
const [apiKey, setApiKey] = useState(customModel?.apiKey || "");
110111
const [contextWindow, setContextWindow] = useState<number>(customModel?.contextWindow || 0);
111112
const [maxOutput, setMaxOutput] = useState<number>(customModel?.maxOutput || 0);
112113
const [inputPrice, setInputPrice] = useState<number>(customModel?.inputPrice || 0);
113114
const [outputPrice, setOutputPrice] = useState<number>(customModel?.outputPrice || 0);
115+
const [modelName, setModelName] = useState(isNew ? models[0].name : customModel.name);
114116
const isModelNameEdited = useRef(false);
115117

116118
const baseInputClassName = "hover:cursor-pointer bg-transparent p-1 focus:outline-none";
117-
const nameInputClassName = `${baseInputClassName} text-sm text-default-900 font-bold`;
119+
const nameInputClassName = `${baseInputClassName} text-sm text-default-900 font-medium`;
118120
const labelClassName = `${baseInputClassName} text-xs text-default-900 w-auto`;
119121
const detailInputClassName = `${baseInputClassName} text-xs text-default-400 font-normal flex-1`;
120122

@@ -137,7 +139,7 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
137139
);
138140

139141
if (isNew) {
140-
setModelName("New Model");
142+
setModelName(models[0].name);
141143
setBaseUrl("");
142144
setSlug("");
143145
setApiKey("");
@@ -148,89 +150,102 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
148150
}
149151
};
150152

151-
// TODO: 1 key per model
152153
// TODO: Multiple models per key
153154
return (
154-
<div className="flex flex-col w-full">
155-
{isNew ? (
156-
<Button size="sm" onPress={() => handleOnChange(false)}>
157-
Add (TODO)
158-
</Button>
159-
) : (
160-
<>
161-
<Button size="sm" onPress={() => handleOnChange(true)}>
162-
Delete (TODO)
163-
</Button>
164-
<Button size="sm" onPress={() => setIsEditing(true)}>
165-
Edit (TODO)
166-
</Button>
167-
<Button
168-
size="sm"
169-
onPress={() => {
170-
setIsEditing(false);
171-
handleOnChange(false);
172-
}}
173-
>
174-
Save (TODO)
175-
</Button>
176-
</>
177-
)}
178-
179-
<input
180-
className={nameInputClassName}
181-
value={modelName}
182-
type="text"
183-
disabled={!isEditing}
184-
onChange={(e) => {
185-
isModelNameEdited.current = true;
186-
setModelName(e.target.value);
187-
}}
188-
></input>
189-
190-
<div className="flex flex-row">
191-
<label className={labelClassName}>Slug</label>
192-
<select
193-
className={detailInputClassName}
155+
<div className="flex flex-col w-full pl-1">
156+
<div className="flex flex-row justify-between">
157+
<input
158+
className={nameInputClassName}
159+
value={modelName}
160+
type="text"
194161
disabled={!isEditing}
195162
onChange={(e) => {
196-
setSlug(e.target.value);
197-
if (!isModelNameEdited.current) {
198-
// Custom name not yet defined, default to the selected model's name
199-
setModelName(models.filter((m) => m.slug == e.target.value)[0].name);
200-
}
163+
isModelNameEdited.current = true;
164+
setModelName(e.target.value);
201165
}}
202-
>
203-
{models.map((m) => (
204-
<option selected={slug == m.slug} key={m.slug} value={m.slug}>
205-
{m.slug}
206-
</option>
207-
))}
208-
</select>
209-
</div>
166+
></input>
210167

211-
<div className="flex flex-row">
212-
<label className={labelClassName}>Base URL</label>
213-
<input
214-
className={detailInputClassName}
215-
value={baseUrl}
216-
type="text"
217-
disabled={!isEditing}
218-
onChange={(e) => setBaseUrl(e.target.value)}
219-
/>
168+
{isNew ? (
169+
<Tooltip content="Add" placement="bottom" className="noselect" delay={500}>
170+
<button onClick={() => handleOnChange(false)} className="p-1 hover:bg-default-100 rounded">
171+
<Icon icon="tabler:device-floppy" width="16" />
172+
</button>
173+
</Tooltip>
174+
) : (
175+
<div>
176+
<Tooltip content="Edit" placement="bottom" className="noselect" delay={500}>
177+
<button
178+
onClick={() => {
179+
if (isEditing) {
180+
handleOnChange(false);
181+
}
182+
setIsEditing((i) => !i);
183+
}}
184+
className="p-1 hover:bg-default-100 rounded"
185+
>
186+
<Icon icon={isEditing ? "tabler:device-floppy" : "tabler:pencil"} width="16" />
187+
</button>
188+
</Tooltip>
189+
<Tooltip content="Delete" placement="bottom" className="noselect" delay={500}>
190+
<button onClick={() => handleOnChange(true)} className="p-1 hover:bg-default-100 rounded">
191+
<Icon icon="tabler:trash" width="16" />
192+
</button>
193+
</Tooltip>
194+
</div>
195+
)}
220196
</div>
221197

222-
<div className="flex flex-row">
223-
<label className={labelClassName}>API Key</label>
224-
<input
225-
className={detailInputClassName}
226-
value={apiKey}
227-
type="text"
228-
disabled={!isEditing}
229-
onChange={(e) => setApiKey(e.target.value)}
230-
/>
231-
</div>
198+
<div className="pr-1">
199+
<div className="flex flex-row">
200+
<label className={labelClassName}>Slug</label>
201+
<select
202+
className={detailInputClassName}
203+
disabled={!isEditing}
204+
onChange={(e) => {
205+
setSlug(e.target.value);
206+
if (!isModelNameEdited.current) {
207+
// Custom name not yet defined, default to the selected model's name
208+
setModelName(models.filter((m) => m.slug == e.target.value)[0].name);
209+
}
210+
}}
211+
>
212+
{models
213+
.filter(
214+
(m) =>
215+
(!isNew && m.slug == slug) ||
216+
!Array.from(settings?.customModels || []).some((cm) => cm.slug == m.slug),
217+
)
218+
.map((m) => (
219+
<option selected={slug == m.slug} key={m.slug} value={m.slug}>
220+
{m.slug}
221+
</option>
222+
))}
223+
</select>
224+
</div>
232225

233-
<div className="flex flex-row">
226+
<div className="flex flex-row">
227+
<label className={labelClassName}>Base URL</label>
228+
<input
229+
className={detailInputClassName}
230+
value={baseUrl}
231+
type="text"
232+
disabled={!isEditing}
233+
onChange={(e) => setBaseUrl(e.target.value)}
234+
/>
235+
</div>
236+
237+
<div className="flex flex-row">
238+
<label className={labelClassName}>API Key</label>
239+
<input
240+
className={detailInputClassName}
241+
value={apiKey}
242+
type={!isEditing && !isNew ? "password" : "text"}
243+
disabled={!isEditing}
244+
onChange={(e) => setApiKey(e.target.value)}
245+
/>
246+
</div>
247+
248+
{/* <div className="flex flex-row">
234249
<label className={labelClassName}>Context Window</label>
235250
<input
236251
className={detailInputClassName}
@@ -272,6 +287,7 @@ const CustomModelSection = ({ isNew, onChange, model: customModel }: CustomModel
272287
disabled={!isEditing}
273288
onChange={(e) => setOutputPrice(e.target.valueAsNumber)}
274289
/>
290+
</div> */}
275291
</div>
276292
</div>
277293
);

0 commit comments

Comments
 (0)