Skip to content

Commit

Permalink
feat: deconfigure model provider option
Browse files Browse the repository at this point in the history
  • Loading branch information
ivyjeong13 committed Dec 27, 2024
1 parent db96799 commit e199bad
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 13 deletions.
23 changes: 13 additions & 10 deletions ui/admin/app/components/model-providers/ModelProviderConfigure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,19 @@ export function ModelProviderConfigureContent({
}) {
const revealModelProvider = useSWR(
ModelProviderApiService.revealModelProviderById.key(modelProvider.id),
({ modelProviderId }) =>
ModelProviderApiService.revealModelProviderById(modelProviderId),
{
keepPreviousData: true,
// 404: no credential found = no need to retry
shouldRetryOnError: (error) =>
error instanceof NotFoundError &&
error.message.toLowerCase().includes("no credential found")
? false
: true,
async ({ modelProviderId }) => {
try {
return await ModelProviderApiService.revealModelProviderById(
modelProviderId
);
} catch (error) {
// 404: no credential found = just return empty object
if (error instanceof NotFoundError) {
return {};
}
// other errors = continue throw
throw error;
}
}
);

Expand Down
102 changes: 102 additions & 0 deletions ui/admin/app/components/model-providers/ModelProviderDeconfigure.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { useState } from "react";
import { toast } from "sonner";
import { mutate } from "swr";

import { ModelProvider } from "~/lib/model/modelProviders";
import { ModelApiService } from "~/lib/service/api/modelApiService";
import { ModelProviderApiService } from "~/lib/service/api/modelProviderApiService";

import { TypographyP } from "~/components/Typography";
import { Button } from "~/components/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { DropdownMenuItem } from "~/components/ui/dropdown-menu";
import { useAsync } from "~/hooks/useAsync";

export function ModelProviderDeconfigure({
modelProvider,
}: {
modelProvider: ModelProvider;
}) {
const [open, setOpen] = useState(false);
const handleDeconfigure = async () => {
deconfigure.execute(modelProvider.id);
};

const deconfigure = useAsync(
ModelProviderApiService.deconfigureModelProviderById,
{
onSuccess: () => {
toast.success(`${modelProvider.name} deconfigured.`);
mutate(ModelProviderApiService.getModelProviders.key());
mutate(ModelApiService.getModels.key());
},
onError: () =>
toast.error(`Failed to deconfigure ${modelProvider.name}`),
}
);

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger>
<DropdownMenuItem
onClick={(event) => {
event.preventDefault();
setOpen(true);
}}
className="text-destructive"
>
Deconfigure Model Provider
</DropdownMenuItem>
</DialogTrigger>

<DialogDescription hidden>
Configure Model Provider
</DialogDescription>

<DialogContent hideCloseButton>
<DialogHeader>
<DialogTitle>Deconfigure {modelProvider.name}</DialogTitle>
</DialogHeader>
<TypographyP>
Deconfiguring this model provider will remove all models
associated with it and reset it to its unconfigured state.
You will need to set up the model provider once again to use
it.
</TypographyP>

<TypographyP>
Are you sure you want to deconfigure{" "}
<b>{modelProvider.name}</b>?
</TypographyP>

<DialogFooter>
<div className="w-full flex justify-center items-center gap-10 pt-4">
<DialogClose asChild>
<Button className="w-1/2" variant="outline">
Cancel
</Button>
</DialogClose>
<DialogClose asChild>
<Button
className="w-1/2"
onClick={handleDeconfigure}
variant="destructive"
>
Confirm
</Button>
</DialogClose>
</div>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
37 changes: 37 additions & 0 deletions ui/admin/app/components/model-providers/ModelProviderDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { EllipsisVerticalIcon } from "lucide-react";

import { ModelProvider } from "~/lib/model/modelProviders";

import { ModelProviderDeconfigure } from "~/components/model-providers/ModelProviderDeconfigure";
import { Button } from "~/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "~/components/ui/dropdown-menu";

export function ModelProviderMenu({
modelProvider,
}: {
modelProvider: ModelProvider;
}) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<EllipsisVerticalIcon />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" side="bottom" align="start">
<DropdownMenuGroup>
<DropdownMenuLabel>{modelProvider.name}</DropdownMenuLabel>
<DropdownMenuSeparator />
<ModelProviderDeconfigure modelProvider={modelProvider} />
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}
14 changes: 14 additions & 0 deletions ui/admin/app/components/model-providers/ModelProviderForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { CircleAlertIcon } from "lucide-react";
import { useEffect } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { mutate } from "swr";
import { z } from "zod";
Expand Down Expand Up @@ -151,6 +152,19 @@ export function ModelProviderForm({
},
});

useEffect(() => {
form.reset({
requiredConfigParams: getInitialRequiredParams(
requiredParameters,
parameters
),
additionalConfirmParams: getInitialAdditionalParams(
requiredParameters,
parameters
),
});
}, [requiredParameters, parameters, form]);

const requiredConfigParamFields = useFieldArray({
control: form.control,
name: "requiredConfigParams",
Expand Down
12 changes: 9 additions & 3 deletions ui/admin/app/components/model-providers/ModelProviderLists.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Link } from "react-router";
import { ModelProvider } from "~/lib/model/modelProviders";

import { ModelProviderConfigure } from "~/components/model-providers/ModelProviderConfigure";
import { ModelProviderMenu } from "~/components/model-providers/ModelProviderDropdown";
import { ModelProviderIcon } from "~/components/model-providers/ModelProviderIcon";
import { ModelProvidersModels } from "~/components/model-providers/ModelProviderModels";
import {
Expand All @@ -28,9 +29,14 @@ export function ModelProviderList({
modelProvider.id
) && <Badge variant="faded">Recommended</Badge>}
{modelProvider.configured ? (
<ModelProvidersModels
modelProvider={modelProvider}
/>
<div className="flex flex-row items-center gap-2">
<ModelProvidersModels
modelProvider={modelProvider}
/>
<ModelProviderMenu
modelProvider={modelProvider}
/>
</div>
) : (
<div className="w-9 h-9" />
)}
Expand Down
2 changes: 2 additions & 0 deletions ui/admin/app/lib/routers/apiRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ export const ApiRoutes = {
buildUrl(`/model-providers/${modelProviderKey}/configure`),
revealModelProviderById: (modelProviderKey: string) =>
buildUrl(`/model-providers/${modelProviderKey}/reveal`),
deconfigureModelProviderById: (modelProviderKey: string) =>
buildUrl(`/model-providers/${modelProviderKey}/deconfigure`),
},
defaultModelAliases: {
base: () => buildUrl("/default-model-aliases"),
Expand Down
13 changes: 13 additions & 0 deletions ui/admin/app/lib/service/api/modelProviderApiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,22 @@ revealModelProviderById.key = (modelProviderId?: string) => {
};
};

const deconfigureModelProviderById = async (modelProviderKey: string) => {
const res = await request<ModelProvider>({
url: ApiRoutes.modelProviders.deconfigureModelProviderById(
modelProviderKey
).url,
method: "POST",
errorMessage: "Failed to deconfigure the requested modal provider.",
});

return res.data;
};

export const ModelProviderApiService = {
getModelProviders,
getModelProviderById,
configureModelProviderById,
revealModelProviderById,
deconfigureModelProviderById,
};

0 comments on commit e199bad

Please sign in to comment.