Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions ui/app/workspace/providers/fragments/networkFormFragment.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { HeadersTable } from "@/components/ui/headersTable";
import { Input } from "@/components/ui/input";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
Expand All @@ -20,6 +20,37 @@ interface NetworkFormFragmentProps {
provider: ModelProvider;
}

// seconds to human readable time
const secondsToHumanReadable = (seconds: number) => {
// Handle edge cases
if (!seconds || seconds < 0 || isNaN(seconds)) {
return "0 seconds";
}
seconds = Math.floor(seconds);
if (seconds < 60) {
return `${seconds} ${seconds === 1 ? "second" : "seconds"}`;
}
if (seconds < 3600) {
const minutes = Math.floor(seconds / 60);
return `${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
}
if (seconds < 86400) {
const hours = Math.floor(seconds / 3600);
return `${hours} ${hours === 1 ? "hour" : "hours"}`;
}
// For >= 1 day, only show non-zero components
const days = Math.floor(seconds / 86400);
const hours = Math.floor((seconds % 86400) / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
const parts: string[] = [];
parts.push(`${days} ${days === 1 ? "day" : "days"}`);
if (hours > 0) parts.push(`${hours} ${hours === 1 ? "hour" : "hours"}`);
if (minutes > 0) parts.push(`${minutes} ${minutes === 1 ? "minute" : "minutes"}`);
if (remainingSeconds > 0) parts.push(`${remainingSeconds} ${remainingSeconds === 1 ? "second" : "seconds"}`);
return parts.join(" ");
};

export function NetworkFormFragment({ provider }: NetworkFormFragmentProps) {
const dispatch = useAppDispatch();
const hasUpdateProviderAccess = useRbac(RbacResource.ModelProvider, RbacOperation.Update);
Expand Down Expand Up @@ -130,8 +161,21 @@ export function NetworkFormFragment({ provider }: NetworkFormFragmentProps) {
<FormItem className="flex-1">
<FormLabel>Timeout (seconds)</FormLabel>
<FormControl>
<Input placeholder="30" {...field} onChange={(e) => field.onChange(Number(e.target.value))} />
<Input
placeholder="30"
{...field}
onChange={(e) => {
if (isNaN(Number(e.target.value))) {
if (e.target.value.trim() === "") {
field.onChange(0);
}
return;
}
field.onChange(Number(e.target.value));
}}
/>
</FormControl>
<FormDescription>{secondsToHumanReadable(field.value)}</FormDescription>
<FormMessage />
</FormItem>
)}
Expand Down
2 changes: 1 addition & 1 deletion ui/lib/types/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export const networkFormConfigSchema = z
default_request_timeout_in_seconds: z.coerce
.number("Timeout must be a number")
.min(1, "Timeout must be greater than 0 seconds")
.max(3600, "Timeout must be less than 3600 seconds"),
.max(172800, "Timeout must be less than 172800 seconds i.e. 48 hours"),
max_retries: z.coerce
.number("Max retries must be a number")
.min(0, "Max retries must be greater than 0")
Expand Down