Skip to content

Commit d38a99d

Browse files
committed
simplify(scheduled-tasks): reuse date-fns for launch/end math; drop dead 'running' status + single-use helper
1 parent 5d4e054 commit d38a99d

6 files changed

Lines changed: 15 additions & 27 deletions

File tree

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/components/task-details-modal/task-details-modal.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ import type {
1616

1717
/**
1818
* Plaintext copy per task state: the status label and the verb that titles the
19-
* run-time field — the tense carries the state ("Started" is in flight, "Ran"
20-
* is done). No icons, no status colors, by design. Total over the status union
21-
* for type safety, though `pending` tasks open the edit `TaskModal` instead.
19+
* run-time field — the tense carries the state ("Ran" is done, "Failed" errored).
20+
* No icons, no status colors, by design. Total over the status union for type
21+
* safety, though `pending` tasks open the edit `TaskModal` instead.
2222
*/
2323
const STATUS_COPY: Record<ScheduledTaskStatus, { label: string; timeTitle: string }> = {
2424
pending: { label: 'Pending', timeTitle: 'Runs' },
25-
running: { label: 'Running', timeTitle: 'Started' },
2625
error: { label: 'Error', timeTitle: 'Failed' },
2726
completed: { label: 'Completed', timeTitle: 'Ran' },
2827
}

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/components/task-modal/task-modal.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useEffect, useState } from 'react'
4-
import { format, isSameDay } from 'date-fns'
4+
import { addHours, format, isSameDay, startOfHour } from 'date-fns'
55
import { useParams } from 'next/navigation'
66
import {
77
Calendar,
@@ -34,14 +34,6 @@ function isLaunchInPast(launchDate: string, launchTime: string): boolean {
3434
return new Date(`${launchDate}T${launchTime}`) < new Date()
3535
}
3636

37-
/** The next top of the hour from `from` (rolling to the next day at 23:xx). */
38-
function nextHour(from: Date): Date {
39-
const next = new Date(from)
40-
next.setMinutes(0, 0, 0)
41-
next.setHours(next.getHours() + 1)
42-
return next
43-
}
44-
4537
/**
4638
* Seeds the launch date/time for a create. A clicked time slot uses it
4739
* verbatim; otherwise the default lands on a valid future instant — the next
@@ -53,7 +45,7 @@ function defaultLaunch(slot: CalendarSlot | null | undefined): { date: string; t
5345
const now = new Date()
5446
const day = slot?.date ?? now
5547
const base = isSameDay(day, now)
56-
? nextHour(now)
48+
? addHours(startOfHour(now), 1)
5749
: new Date(`${format(day, 'yyyy-MM-dd')}T${DEFAULT_TIME}`)
5850
return { date: format(base, 'yyyy-MM-dd'), time: format(base, 'HH:mm') }
5951
}

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/utils/recurrence.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { endOfDay } from 'date-fns'
12
import { describe, expect, it } from 'vitest'
23
import {
34
cronToRecurrence,
@@ -81,7 +82,7 @@ describe('recurrenceToScheduleFields', () => {
8182
'2026-06-15',
8283
'09:00'
8384
)
84-
expect(fields.endsAt).toBe(new Date('2026-07-01T23:59:59').toISOString())
85+
expect(fields.endsAt).toBe(endOfDay(new Date('2026-07-01T00:00')).toISOString())
8586
expect(fields.maxRuns).toBeUndefined()
8687
expect(fields.lifecycle).toBe('persistent')
8788
})

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/utils/recurrence.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Cron } from 'croner'
2-
import { format } from 'date-fns'
2+
import { endOfDay, format } from 'date-fns'
33

44
/**
55
* Recurrence cadence the modal exposes. `once` is a one-time launch; `custom`
@@ -37,11 +37,6 @@ function localDateTime(date: string, time: string): Date {
3737
return new Date(`${date}T${time}`)
3838
}
3939

40-
/** The launch instant as an ISO 8601 string, for one-time scheduling. */
41-
export function launchInstantIso(date: string, time: string): string {
42-
return localDateTime(date, time).toISOString()
43-
}
44-
4540
/**
4641
* Builds the cron expression for a recurrence, evaluated in the schedule's
4742
* timezone against the launch day/time. Returns `null` for a one-time task and
@@ -92,7 +87,7 @@ export function recurrenceToScheduleFields(
9287
if (!cronExpression) {
9388
return {
9489
cronExpression: null,
95-
time: launchInstantIso(launchDate, launchTime),
90+
time: localDateTime(launchDate, launchTime).toISOString(),
9691
lifecycle: 'persistent',
9792
}
9893
}
@@ -101,7 +96,8 @@ export function recurrenceToScheduleFields(
10196
return {
10297
cronExpression,
10398
maxRuns: end.type === 'after' ? end.count : undefined,
104-
endsAt: end.type === 'on' ? new Date(`${end.date}T23:59:59`).toISOString() : undefined,
99+
endsAt:
100+
end.type === 'on' ? endOfDay(localDateTime(end.date, '00:00')).toISOString() : undefined,
105101
lifecycle: end.type === 'after' ? 'until_complete' : 'persistent',
106102
}
107103
}

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/utils/schedule-events.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ describe('taskToCalendarEvent', () => {
6868
})
6969

7070
it('derives the same event shape for every status', () => {
71-
const statuses = ['pending', 'running', 'error', 'completed'] as const
71+
const statuses = ['pending', 'error', 'completed'] as const
7272
const titles = statuses.map((status) => taskToCalendarEvent(makeTask({ status })).title)
7373
expect(new Set(titles).size).toBe(1)
7474
})

apps/sim/app/workspace/[workspaceId]/scheduled-tasks/utils/schedule-events.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { expandOccurrences } from '@/app/workspace/[workspaceId]/scheduled-tasks
55
import type { ChatContext } from '@/stores/panel'
66

77
/**
8-
* Lifecycle of a scheduled task occurrence: `pending` has not run yet, `running`
9-
* is executing now, and `error`/`completed` are terminal outcomes of a past run.
8+
* Lifecycle of a scheduled task occurrence: `pending` has not run yet, and
9+
* `error`/`completed` are terminal outcomes of a past run.
1010
*/
11-
export type ScheduledTaskStatus = 'pending' | 'running' | 'error' | 'completed'
11+
export type ScheduledTaskStatus = 'pending' | 'error' | 'completed'
1212

1313
/**
1414
* One occurrence of a scheduled task as the calendar renders it. A recurring

0 commit comments

Comments
 (0)