fix(ui): heartbeat dialog tweaks — timezone select, interval width, layout

- Replace timezone text input with Select dropdown using shared IANA_TIMEZONES
- Extract IANA_TIMEZONES to constants.ts (reused by cron-section)
- Shrink interval input width (w-24 → w-[4.5rem]) for 3-digit fit
- Fix schedule section layout: flex-based with fixed-width time inputs
- Default isolatedSession to false
This commit is contained in:
viettranx committed 2026-03-19 08:39:13 +07:00
1 parent 2cc9d68cdc
commit 74cf7e52f5
3 files changed
+45 -38

No files matched your search

+24
View File
@@ -74,3 +74,27 @@ export const TIMEZONE_OPTIONS = [
{ value: "Asia/Singapore", label: "Singapore (SGT)" },
{ value: "Australia/Sydney", label: "Sydney (AEST)" },
] as const;
/** IANA timezones for server-side scheduling (cron, heartbeat). */
export const IANA_TIMEZONES = [
{ value: "UTC", label: "UTC" },
{ value: "Asia/Ho_Chi_Minh", label: "Asia/Ho_Chi_Minh (UTC+7)" },
{ value: "Asia/Bangkok", label: "Asia/Bangkok (UTC+7)" },
{ value: "Asia/Shanghai", label: "Asia/Shanghai (UTC+8)" },
{ value: "Asia/Tokyo", label: "Asia/Tokyo (UTC+9)" },
{ value: "Asia/Seoul", label: "Asia/Seoul (UTC+9)" },
{ value: "Asia/Singapore", label: "Asia/Singapore (UTC+8)" },
{ value: "Asia/Kolkata", label: "Asia/Kolkata (UTC+5:30)" },
{ value: "Asia/Dubai", label: "Asia/Dubai (UTC+4)" },
{ value: "Europe/London", label: "Europe/London (UTC+0)" },
{ value: "Europe/Paris", label: "Europe/Paris (UTC+1)" },
{ value: "Europe/Berlin", label: "Europe/Berlin (UTC+1)" },
{ value: "Europe/Moscow", label: "Europe/Moscow (UTC+3)" },
{ value: "America/New_York", label: "America/New_York (UTC-5)" },
{ value: "America/Chicago", label: "America/Chicago (UTC-6)" },
{ value: "America/Denver", label: "America/Denver (UTC-7)" },
{ value: "America/Los_Angeles", label: "America/Los_Angeles (UTC-8)" },
{ value: "America/Sao_Paulo", label: "America/Sao_Paulo (UTC-3)" },
{ value: "Australia/Sydney", label: "Australia/Sydney (UTC+11)" },
{ value: "Pacific/Auckland", label: "Pacific/Auckland (UTC+13)" },
] as const;
@@ -18,6 +18,7 @@ import { useChannels } from "@/pages/channels/hooks/use-channels";
import { useProviders } from "@/pages/providers/hooks/use-providers";
import { useUiStore } from "@/stores/use-ui-store";
import { ProviderModelSelect } from "@/components/shared/provider-model-select";
import { IANA_TIMEZONES } from "@/lib/constants";
import type { HeartbeatConfig, DeliveryTarget } from "@/pages/agents/hooks/use-agent-heartbeat";
interface HeartbeatConfigDialogProps {
@@ -54,7 +55,7 @@ export function HeartbeatConfigDialog({
const [intervalMin, setIntervalMin] = useState(30);
const [ackMaxChars, setAckMaxChars] = useState(300);
const [maxRetries, setMaxRetries] = useState(2);
const [isolatedSession, setIsolatedSession] = useState(true);
const [isolatedSession, setIsolatedSession] = useState(false);
const [lightContext, setLightContext] = useState(false);
const [activeHoursStart, setActiveHoursStart] = useState("");
const [activeHoursEnd, setActiveHoursEnd] = useState("");
@@ -182,7 +183,7 @@ export function HeartbeatConfigDialog({
min={5}
value={intervalMin}
onChange={(e) => setIntervalMin(Math.max(5, Number(e.target.value) || 5))}
className="w-24 text-center text-base md:text-sm"
className="w-[4.5rem] text-center text-base md:text-sm"
/>
<span className="text-xs text-muted-foreground">min</span>
</div>
@@ -298,8 +299,8 @@ export function HeartbeatConfigDialog({
{t("heartbeat.sectionSchedule")}
</h4>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
<div className="space-y-1">
<div className="flex flex-wrap items-end gap-3">
<div className="space-y-1 w-24">
<Label htmlFor="hb-start" className="text-xs">{t("heartbeat.activeHoursStart")}</Label>
<Input
id="hb-start"
@@ -309,7 +310,7 @@ export function HeartbeatConfigDialog({
className="text-base md:text-sm"
/>
</div>
<div className="space-y-1">
<div className="space-y-1 w-24">
<Label htmlFor="hb-end" className="text-xs">{t("heartbeat.activeHoursEnd")}</Label>
<Input
id="hb-end"
@@ -319,15 +320,19 @@ export function HeartbeatConfigDialog({
className="text-base md:text-sm"
/>
</div>
<div className="space-y-1">
<Label htmlFor="hb-tz" className="text-xs">{t("heartbeat.timezone")}</Label>
<Input
id="hb-tz"
placeholder="Asia/Ho_Chi_Minh"
value={timezone}
onChange={(e) => setTimezone(e.target.value)}
className="text-base md:text-sm"
/>
<div className="space-y-1 flex-1 min-w-[160px]">
<Label className="text-xs">{t("heartbeat.timezone")}</Label>
<Select value={timezone || "__auto__"} onValueChange={(v) => setTimezone(v === "__auto__" ? "" : v)}>
<SelectTrigger className="text-base md:text-sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="__auto__">{defaultTz}</SelectItem>
{IANA_TIMEZONES.map((tz) => (
<SelectItem key={tz.value} value={tz.value}>{tz.label}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<p className="text-xs text-muted-foreground">{t("heartbeat.scheduleHint")}</p>
@@ -6,29 +6,7 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { InfoLabel } from "@/components/shared/info-label";
const TIMEZONES = [
{ value: "UTC", label: "UTC" },
{ value: "Asia/Ho_Chi_Minh", label: "Asia/Ho_Chi_Minh (UTC+7)" },
{ value: "Asia/Bangkok", label: "Asia/Bangkok (UTC+7)" },
{ value: "Asia/Shanghai", label: "Asia/Shanghai (UTC+8)" },
{ value: "Asia/Tokyo", label: "Asia/Tokyo (UTC+9)" },
{ value: "Asia/Seoul", label: "Asia/Seoul (UTC+9)" },
{ value: "Asia/Singapore", label: "Asia/Singapore (UTC+8)" },
{ value: "Asia/Kolkata", label: "Asia/Kolkata (UTC+5:30)" },
{ value: "Asia/Dubai", label: "Asia/Dubai (UTC+4)" },
{ value: "Europe/London", label: "Europe/London (UTC+0)" },
{ value: "Europe/Paris", label: "Europe/Paris (UTC+1)" },
{ value: "Europe/Berlin", label: "Europe/Berlin (UTC+1)" },
{ value: "Europe/Moscow", label: "Europe/Moscow (UTC+3)" },
{ value: "America/New_York", label: "America/New_York (UTC-5)" },
{ value: "America/Chicago", label: "America/Chicago (UTC-6)" },
{ value: "America/Denver", label: "America/Denver (UTC-7)" },
{ value: "America/Los_Angeles", label: "America/Los_Angeles (UTC-8)" },
{ value: "America/Sao_Paulo", label: "America/Sao_Paulo (UTC-3)" },
{ value: "Australia/Sydney", label: "Australia/Sydney (UTC+11)" },
{ value: "Pacific/Auckland", label: "Pacific/Auckland (UTC+13)" },
];
import { IANA_TIMEZONES } from "@/lib/constants";
interface CronData {
max_retries?: number;
@@ -80,7 +58,7 @@ export function CronSection({ data, onSave, saving }: Props) {
</SelectTrigger>
<SelectContent>
<SelectItem value="__system__">{t("cron.defaultTimezonePlaceholder")}</SelectItem>
{TIMEZONES.map((tz) => (
{IANA_TIMEZONES.map((tz) => (
<SelectItem key={tz.value} value={tz.value}>{tz.label}</SelectItem>
))}
</SelectContent>