Skip to content

Commit a4faf5b

Browse files
committed
fixup! feat: add user quiet hours settings page
1 parent 37e26da commit a4faf5b

File tree

6 files changed

+704
-37
lines changed

6 files changed

+704
-37
lines changed

coderd/schedule/cron.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,19 @@ func (s Schedule) Min() time.Duration {
173173
return durMin
174174
}
175175

176+
// TimeParsed returns the parsed time.Time of the minute and hour fields. If the
177+
// time cannot be represented in a valid time.Time, a zero time is returned.
178+
func (s Schedule) TimeParsed() time.Time {
179+
minute := strings.Fields(s.cronStr)[0]
180+
hour := strings.Fields(s.cronStr)[1]
181+
maybeTime := fmt.Sprintf("%s:%s", hour, minute)
182+
t, err := time.ParseInLocation("15:4", maybeTime, s.sched.Location)
183+
if err != nil {
184+
return time.Time{}
185+
}
186+
return t
187+
}
188+
176189
// Time returns a humanized form of the minute and hour fields.
177190
func (s Schedule) Time() string {
178191
minute := strings.Fields(s.cronStr)[0]

enterprise/coderd/users.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (api *API) userQuietHoursSchedule(rw http.ResponseWriter, r *http.Request)
6868
httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserQuietHoursScheduleResponse{
6969
RawSchedule: opts.Schedule.String(),
7070
UserSet: opts.UserSet,
71-
Time: opts.Schedule.Time(),
71+
Time: opts.Schedule.TimeParsed().Format("15:40"),
7272
Timezone: opts.Schedule.Location().String(),
7373
Next: opts.Schedule.Next(time.Now().In(opts.Schedule.Location())),
7474
})
@@ -114,7 +114,7 @@ func (api *API) putUserQuietHoursSchedule(rw http.ResponseWriter, r *http.Reques
114114
httpapi.Write(ctx, rw, http.StatusOK, codersdk.UserQuietHoursScheduleResponse{
115115
RawSchedule: opts.Schedule.String(),
116116
UserSet: opts.UserSet,
117-
Time: opts.Schedule.Time(),
117+
Time: opts.Schedule.TimeParsed().Format("15:40"),
118118
Timezone: opts.Schedule.Location().String(),
119119
Next: opts.Schedule.Next(time.Now().In(opts.Schedule.Location())),
120120
})

enterprise/coderd/users_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ func TestUserQuietHours(t *testing.T) {
2121
t.Run("OK", func(t *testing.T) {
2222
t.Parallel()
2323

24-
defaultQuietHoursSchedule := "CRON_TZ=America/Chicago 0 0 * * *"
24+
defaultQuietHoursSchedule := "CRON_TZ=America/Chicago 0 1 * * *"
2525
defaultScheduleParsed, err := schedule.Daily(defaultQuietHoursSchedule)
2626
require.NoError(t, err)
2727
nextTime := defaultScheduleParsed.Next(time.Now().In(defaultScheduleParsed.Location()))
2828
if time.Until(nextTime) < time.Hour {
2929
// Use a different default schedule instead, because we want to avoid
3030
// the schedule "ticking over" during this test run.
31-
defaultQuietHoursSchedule = "CRON_TZ=America/Chicago 0 12 * * *"
31+
defaultQuietHoursSchedule = "CRON_TZ=America/Chicago 0 13 * * *"
3232
defaultScheduleParsed, err = schedule.Daily(defaultQuietHoursSchedule)
3333
require.NoError(t, err)
3434
}
@@ -55,7 +55,7 @@ func TestUserQuietHours(t *testing.T) {
5555
require.NoError(t, err)
5656
require.Equal(t, defaultScheduleParsed.String(), sched1.RawSchedule)
5757
require.False(t, sched1.UserSet)
58-
require.Equal(t, defaultScheduleParsed.Time(), sched1.Time)
58+
require.Equal(t, defaultScheduleParsed.TimeParsed().Format("15:40"), sched1.Time)
5959
require.Equal(t, defaultScheduleParsed.Location().String(), sched1.Timezone)
6060
require.WithinDuration(t, defaultScheduleParsed.Next(time.Now()), sched1.Next, 15*time.Second)
6161

@@ -78,7 +78,7 @@ func TestUserQuietHours(t *testing.T) {
7878
require.NoError(t, err)
7979
require.Equal(t, customScheduleParsed.String(), sched2.RawSchedule)
8080
require.True(t, sched2.UserSet)
81-
require.Equal(t, customScheduleParsed.Time(), sched2.Time)
81+
require.Equal(t, customScheduleParsed.TimeParsed().Format("15:40"), sched2.Time)
8282
require.Equal(t, customScheduleParsed.Location().String(), sched2.Timezone)
8383
require.WithinDuration(t, customScheduleParsed.Next(time.Now()), sched2.Next, 15*time.Second)
8484

@@ -87,7 +87,7 @@ func TestUserQuietHours(t *testing.T) {
8787
require.NoError(t, err)
8888
require.Equal(t, customScheduleParsed.String(), sched3.RawSchedule)
8989
require.True(t, sched3.UserSet)
90-
require.Equal(t, customScheduleParsed.Time(), sched3.Time)
90+
require.Equal(t, customScheduleParsed.TimeParsed().Format("15:40"), sched3.Time)
9191
require.Equal(t, customScheduleParsed.Location().String(), sched3.Timezone)
9292
require.WithinDuration(t, customScheduleParsed.Next(time.Now()), sched3.Next, 15*time.Second)
9393

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { Story } from "@storybook/react"
2+
import { ScheduleForm, ScheduleFormProps } from "./ScheduleForm"
3+
import { mockApiError } from "testHelpers/entities"
4+
5+
export default {
6+
title: "pages/UserSettingsPage/SchedulePage/ScheduleForm",
7+
component: ScheduleForm,
8+
argTypes: {
9+
onSubmit: { action: "Submit" },
10+
},
11+
}
12+
13+
const Template: Story<ScheduleFormProps> = (args: ScheduleFormProps) => (
14+
<ScheduleForm {...args} />
15+
)
16+
17+
export const ExampleDefault = Template.bind({})
18+
ExampleDefault.args = {
19+
submitting: false,
20+
initialValues: {
21+
raw_schedule: "CRON_TZ=Australia/Sydney 0 2 * * *",
22+
user_set: false,
23+
time: "02:00",
24+
timezone: "Australia/Sydney",
25+
next: "2023-09-05T02:00:00+10:00",
26+
},
27+
updateErr: undefined,
28+
onSubmit: () => {
29+
return Promise.resolve()
30+
},
31+
now: new Date("2023-09-04T15:00:00+10:00"),
32+
}
33+
34+
export const ExampleUserSet = Template.bind({})
35+
ExampleUserSet.args = {
36+
...ExampleDefault.args,
37+
initialValues: {
38+
raw_schedule: "CRON_TZ=America/Chicago 0 2 * * *",
39+
user_set: true,
40+
time: "02:00",
41+
timezone: "America/Chicago",
42+
next: "2023-09-05T02:00:00-05:00",
43+
},
44+
now: new Date("2023-09-04T15:00:00-05:00"),
45+
}
46+
47+
export const Submitting = Template.bind({})
48+
Submitting.args = {
49+
...ExampleDefault.args,
50+
submitting: true,
51+
}
52+
53+
export const WithError = Template.bind({})
54+
WithError.args = {
55+
...ExampleDefault.args,
56+
updateErr: mockApiError({
57+
message: "Invalid schedule",
58+
validations: [
59+
{
60+
field: "schedule",
61+
detail: "Could not validate cron schedule.",
62+
},
63+
],
64+
}),
65+
}

0 commit comments

Comments
 (0)