refactor: remove unused buttons and enhance API and Tools display in Settings component

This commit is contained in:
ecwu
2025-01-06 12:37:29 +08:00
parent af6ccad35b
commit 5effd0a3f4
3 changed files with 210 additions and 40 deletions

View File

@@ -107,37 +107,6 @@ function APIsDropdownList({
</p> </p>
</a> </a>
</NavigationMenuLink> </NavigationMenuLink>
<div className="mt-2 flex justify-between">
<Button
variant="ghost"
size="sm"
onClick={() => {
const name = prompt(`Give **${label}** template a name`);
if (!name) return;
t.name = name;
ctx.setTemplateAPIs(structuredClone(ctx.templateAPIs));
}}
>
Edit
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => {
if (
!confirm(
`Are you sure to delete this **${label}** template?`
)
) {
return;
}
ctx.templateAPIs.splice(index, 1);
ctx.setTemplateAPIs(structuredClone(ctx.templateAPIs));
}}
>
Delete
</Button>
</div>
</li> </li>
))} ))}
</ul> </ul>

View File

@@ -3,12 +3,7 @@ import { themeChange } from "theme-change";
import { useRef } from "react"; import { useRef } from "react";
import { useContext, useEffect, useState, Dispatch } from "react"; import { useContext, useEffect, useState, Dispatch } from "react";
import { clearTotalCost, getTotalCost } from "@/utils/totalCost"; import { clearTotalCost, getTotalCost } from "@/utils/totalCost";
import { import { ChatStore, TemplateChatStore, TemplateTools } from "@/types/chatstore";
ChatStore,
TemplateChatStore,
TemplateAPI,
TemplateTools,
} from "@/types/chatstore";
import { models } from "@/types/models"; import { models } from "@/types/models";
import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; import { tr, Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
import { isVailedJSON } from "@/utils/isVailedJSON"; import { isVailedJSON } from "@/utils/isVailedJSON";
@@ -62,13 +57,13 @@ import {
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { Badge } from "@/components/ui/badge";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { import {
BanIcon, BanIcon,
CheckIcon, CheckIcon,
CircleEllipsisIcon, CircleEllipsisIcon,
CogIcon, CogIcon,
Ellipsis,
EyeIcon, EyeIcon,
InfoIcon, InfoIcon,
KeyIcon, KeyIcon,
@@ -478,6 +473,151 @@ const Choice = (props: {
); );
}; };
const APIShowBlock = (props: {
ctx: any;
index: number;
label: string;
type: string;
apiField: string;
keyField: string;
}) => {
return (
<div className="border-b border-gray-200 pb-4 pt-4">
<Badge variant="outline">{props.type}</Badge> <Label>{props.label}</Label>
<div className="mt-4">
<div className="grid w-full max-w-sm items-center gap-1.5 mt-2">
<Label>Endpoint</Label> {props.apiField}
</div>
<div className="grid w-full max-w-sm items-center gap-1.5 mt-2">
<Label>Key</Label>
{props.keyField ? (
props.keyField
) : (
<span className="text-gray-500 italic">empty</span>
)}
</div>
</div>
<Button
variant="outline"
size="sm"
className="mt-2 mr-2"
onClick={() => {
const name = prompt(`Give template ${props.label} a new name`);
if (!name) return;
if (props.type === "Chat") {
props.ctx.templateAPIs[props.index].name = name;
props.ctx.setTemplateAPIs(structuredClone(props.ctx.templateAPIs));
} else if (props.type === "Whisper") {
props.ctx.templateAPIsWhisper[props.index].name = name;
props.ctx.setTemplateAPIsWhisper(
structuredClone(props.ctx.templateAPIsWhisper)
);
} else if (props.type === "TTS") {
props.ctx.templateAPIsTTS[props.index].name = name;
props.ctx.setTemplateAPIsTTS(
structuredClone(props.ctx.templateAPIsTTS)
);
} else if (props.type === "ImgGen") {
props.ctx.templateAPIsImageGen[props.index].name = name;
props.ctx.setTemplateAPIsImageGen(
structuredClone(props.ctx.templateAPIsImageGen)
);
}
}}
>
Change Name
</Button>
<Button
variant="destructive"
size="sm"
className="mt-2"
onClick={() => {
if (!props.ctx) return;
if (
!confirm(
`Are you sure to delete ${props.label}(${props.type}) API?`
)
) {
return;
}
if (props.type === "Chat") {
props.ctx.templateAPIs.splice(props.index, 1);
props.ctx.setTemplateAPIs(structuredClone(props.ctx.templateAPIs));
} else if (props.type === "Whisper") {
props.ctx.templateAPIsWhisper.splice(props.index, 1);
props.ctx.setTemplateAPIsWhisper(
structuredClone(props.ctx.templateAPIsWhisper)
);
} else if (props.type === "TTS") {
props.ctx.templateAPIsTTS.splice(props.index, 1);
props.ctx.setTemplateAPIsTTS(
structuredClone(props.ctx.templateAPIsTTS)
);
} else if (props.type === "ImgGen") {
props.ctx.templateAPIsImageGen.splice(props.index, 1);
props.ctx.setTemplateAPIsImageGen(
structuredClone(props.ctx.templateAPIsImageGen)
);
}
}}
>
Delete
</Button>
</div>
);
};
const ToolsShowBlock = (props: {
ctx: any;
index: number;
label: string;
content: string;
}) => {
return (
<div className="border-b border-gray-200 pb-4 pt-4">
<Badge variant="outline">Tool</Badge> <Label>{props.label}</Label>
<div className="mt-4">
<div className="grid w-full max-w-sm items-center gap-1.5 mt-2">
<Label>Content</Label>
<ScrollArea className="w-72 whitespace-nowrap rounded-md border">
<pre className="text-xs">
{JSON.stringify(JSON.parse(props.content), null, 2)}
</pre>
</ScrollArea>
</div>
</div>
<Button
variant="outline"
size="sm"
className="mt-2 mr-2"
onClick={() => {
const name = prompt(`Give the tool ${props.label} a new name`);
if (!name) return;
props.ctx.templateTools[props.index].name = name;
props.ctx.setTemplateTools(structuredClone(props.ctx.templateTools));
}}
>
Edit
</Button>
<Button
variant="destructive"
size="sm"
className="mt-2"
onClick={() => {
if (!props.ctx) return;
if (!confirm(`Are you sure to delete ${props.label} Tool?`)) {
return;
}
props.ctx.templateTools.splice(props.index, 1);
props.ctx.setTemplateTools(structuredClone(props.ctx.templateTools));
}}
>
Delete
</Button>
</div>
);
};
export default (props: {}) => { export default (props: {}) => {
const ctx = useContext(AppContext); const ctx = useContext(AppContext);
if (ctx === null) return <></>; if (ctx === null) return <></>;
@@ -1174,6 +1314,69 @@ export default (props: {}) => {
</Card> </Card>
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
<AccordionItem value="templates">
<AccordionTrigger>Saved Template</AccordionTrigger>
<AccordionContent>
{ctx.templateAPIs.map((template, index) => (
<div key={index}>
<APIShowBlock
ctx={ctx}
index={index}
label={template.name}
type="Chat"
apiField={template.endpoint}
keyField={template.key}
/>
</div>
))}
{ctx.templateAPIsWhisper.map((template, index) => (
<div key={index}>
<APIShowBlock
ctx={ctx}
index={index}
label={template.name}
type="Whisper"
apiField={template.endpoint}
keyField={template.key}
/>
</div>
))}
{ctx.templateAPIsTTS.map((template, index) => (
<div key={index}>
<APIShowBlock
ctx={ctx}
index={index}
label={template.name}
type="TTS"
apiField={template.endpoint}
keyField={template.key}
/>
</div>
))}
{ctx.templateAPIsImageGen.map((template, index) => (
<div key={index}>
<APIShowBlock
ctx={ctx}
index={index}
label={template.name}
type="ImgGen"
apiField={template.endpoint}
keyField={template.key}
/>
</div>
))}
{ctx.templateTools.map((template, index) => (
<div key={index}>
<ToolsShowBlock
ctx={ctx}
index={index}
label={template.name}
content={template.toolsString}
/>
</div>
))}
</AccordionContent>
</AccordionItem>
</Accordion> </Accordion>
<div className="pt-4 space-y-2"> <div className="pt-4 space-y-2">
<p className="text-sm text-muted-foreground text-center"> <p className="text-sm text-muted-foreground text-center">

View File

@@ -33,9 +33,7 @@ import {
CornerDownLeftIcon, CornerDownLeftIcon,
CornerLeftUpIcon, CornerLeftUpIcon,
CornerRightUpIcon, CornerRightUpIcon,
ImageIcon,
InfoIcon, InfoIcon,
PaintBucketIcon,
ScissorsIcon, ScissorsIcon,
} from "lucide-react"; } from "lucide-react";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";