@@ -10,13 +10,20 @@ import { Switch } from "@posthog/quill";
1010import { CopyButton } from "@posthog/ui/features/agent-applications/components/CopyButton" ;
1111import { SettingsOptionSelect } from "@posthog/ui/features/settings/SettingsOptionSelect" ;
1212import { Button } from "@posthog/ui/primitives/Button" ;
13+ import { TimezonePicker } from "@posthog/ui/primitives/TimezonePicker" ;
14+ import { TimezoneTimestamp } from "@posthog/ui/primitives/TimezoneTimestamp" ;
15+ import {
16+ formatScheduleTimestamp ,
17+ systemTimezone ,
18+ } from "@posthog/ui/primitives/timezone" ;
1319import { Box , Checkbox , Flex , IconButton , Text } from "@radix-ui/themes" ;
1420import {
1521 compileCronSchedule ,
1622 DEFAULT_SCHEDULE_TIME ,
1723 parseCronSchedule ,
1824 type RecurringFrequency ,
1925} from "../loopCron" ;
26+ import { nextScheduleRun } from "../loopDisplay" ;
2027import {
2128 defaultLoopScheduleTrigger ,
2229 emptyLoopApiTriggerConfig ,
@@ -117,6 +124,7 @@ export function LoopTriggerEditor({
117124 variant = "outline"
118125 color = "gray"
119126 size = "1"
127+ className = "self-start"
120128 disabled = { disabled }
121129 onClick = { addTrigger }
122130 >
@@ -235,14 +243,6 @@ const WEEKDAY_OPTIONS = [
235243 { value : "6" , label : "Saturday" } ,
236244] ;
237245
238- function localTimezone ( ) : string {
239- try {
240- return Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone || "UTC" ;
241- } catch {
242- return "UTC" ;
243- }
244- }
245-
246246function ScheduleTriggerFields ( {
247247 config,
248248 disabled,
@@ -264,7 +264,12 @@ function ScheduleTriggerFields({
264264 : ( parsed ?. frequency ?? "daily" ) ;
265265 const time = parsed ?. time ?? DEFAULT_SCHEDULE_TIME ;
266266 const weekday = parsed ?. weekday ?? "1" ;
267- const timezone = config . timezone || localTimezone ( ) ;
267+ const timezone = config . timezone ?? "UTC" ;
268+ const nextRun = nextScheduleRun ( config ) ;
269+ const nextRunTimezone = frequency === "once" ? systemTimezone ( ) : timezone ;
270+ const nextRunLabel = nextRun
271+ ? formatScheduleTimestamp ( nextRun , nextRunTimezone )
272+ : null ;
268273 const frequencyOptions = isCustomCron
269274 ? [ CUSTOM_FREQUENCY_OPTION , ...FREQUENCY_OPTIONS ]
270275 : FREQUENCY_OPTIONS ;
@@ -289,7 +294,10 @@ function ScheduleTriggerFields({
289294 if ( next === "custom" ) return ;
290295 if ( next === "once" ) {
291296 // The backend rejects run_at values in the past; default an hour out.
292- onChange ( { run_at : new Date ( Date . now ( ) + 60 * 60 * 1000 ) . toISOString ( ) } ) ;
297+ onChange ( {
298+ run_at : new Date ( Date . now ( ) + 60 * 60 * 1000 ) . toISOString ( ) ,
299+ timezone,
300+ } ) ;
293301 return ;
294302 }
295303 setRecurring ( next , time , weekday ) ;
@@ -369,7 +377,27 @@ function ScheduleTriggerFields({
369377 </ Flex >
370378
371379 { frequency !== "once" ? (
372- < Text className = "text-[11px] text-gray-9" > Times in { timezone } </ Text >
380+ < Flex direction = "column" gap = "1" >
381+ < Text className = "text-[11px] text-gray-9" > Timezone</ Text >
382+ < TimezonePicker
383+ value = { timezone }
384+ disabled = { disabled }
385+ className = "w-[240px] max-w-full"
386+ onValueChange = { ( value ) => onChange ( { ...config , timezone : value } ) }
387+ />
388+ </ Flex >
389+ ) : null }
390+
391+ { nextRun && nextRunLabel ? (
392+ < Flex align = "center" gap = "2" className = "text-[12px]" >
393+ < Text className = "text-gray-10" > Next run</ Text >
394+ < TimezoneTimestamp
395+ timestamp = { nextRun }
396+ timezone = { nextRunTimezone }
397+ label = { nextRunLabel }
398+ className = "text-gray-12"
399+ />
400+ </ Flex >
373401 ) : null }
374402 </ Flex >
375403 ) ;
0 commit comments