Skip to content

Commit 48c914f

Browse files
authored
Add recur field to task creation panel (CCExtractor#290)
Implemented recur dropdown in AddTaskDialog with daily, weekly, monthly, yearly options. Backend now handles recur field with proper validation requiring due date before setting recurrence. Updated all related types, handlers and tests to support task recurrence functionality.
1 parent ce15591 commit 48c914f

9 files changed

Lines changed: 49 additions & 4 deletions

File tree

backend/controllers/add_task.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) {
4747
priority := requestBody.Priority
4848
dueDate := requestBody.DueDate
4949
start := requestBody.Start
50+
recur := requestBody.Recur
5051
tags := requestBody.Tags
5152
annotations := requestBody.Annotations
5253

@@ -64,7 +65,7 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) {
6465
Name: "Add Task",
6566
Execute: func() error {
6667
logStore.AddLog("INFO", fmt.Sprintf("Adding task: %s", description), uuid, "Add Task")
67-
err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, start, tags, annotations)
68+
err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, start, recur, tags, annotations)
6869
if err != nil {
6970
logStore.AddLog("ERROR", fmt.Sprintf("Failed to add task: %v", err), uuid, "Add Task")
7071
return err

backend/models/request_body.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type AddTaskRequestBody struct {
1010
Priority string `json:"priority"`
1111
DueDate *string `json:"due"`
1212
Start string `json:"start"`
13+
Recur string `json:"recur"`
1314
Tags []string `json:"tags"`
1415
Annotations []Annotation `json:"annotations"`
1516
}

backend/utils/tw/add_task.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
)
1111

1212
// add task to the user's tw client
13-
func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start string, tags []string, annotations []models.Annotation) error {
13+
func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start, recur string, tags []string, annotations []models.Annotation) error {
1414
if err := utils.ExecCommand("rm", "-rf", "/root/.task"); err != nil {
1515
return fmt.Errorf("error deleting Taskwarrior data: %v", err)
1616
}
@@ -43,6 +43,11 @@ func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, p
4343
if start != "" {
4444
cmdArgs = append(cmdArgs, "start:"+start)
4545
}
46+
// Note: Taskwarrior requires a due date to be set before recur can be set
47+
// Only add recur if dueDate is also provided
48+
if recur != "" && dueDate != "" {
49+
cmdArgs = append(cmdArgs, "recur:"+recur)
50+
}
4651
// Add tags to the task
4752
if len(tags) > 0 {
4853
for _, tag := range tags {

backend/utils/tw/taskwarrior_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestExportTasks(t *testing.T) {
4242
}
4343

4444
func TestAddTaskToTaskwarrior(t *testing.T) {
45-
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", nil, []models.Annotation{{Description: "note"}})
45+
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "daily", nil, []models.Annotation{{Description: "note"}})
4646
if err != nil {
4747
t.Errorf("AddTaskToTaskwarrior failed: %v", err)
4848
} else {
@@ -60,7 +60,7 @@ func TestCompleteTaskInTaskwarrior(t *testing.T) {
6060
}
6161

6262
func TestAddTaskWithTags(t *testing.T) {
63-
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", []string{"work", "important"}, []models.Annotation{{Description: "note"}})
63+
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "daily", []string{"work", "important"}, []models.Annotation{{Description: "note"}})
6464
if err != nil {
6565
t.Errorf("AddTaskToTaskwarrior with tags failed: %v", err)
6666
} else {

frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,31 @@ export const AddTaskdialog = ({
245245
/>
246246
</div>
247247
</div>
248+
<div className="grid grid-cols-4 items-center gap-4">
249+
<Label htmlFor="recur" className="text-right">
250+
Recur
251+
</Label>
252+
<div className="col-span-1 flex items-center">
253+
<select
254+
id="recur"
255+
name="recur"
256+
value={newTask.recur}
257+
onChange={(e) =>
258+
setNewTask({
259+
...newTask,
260+
recur: e.target.value,
261+
})
262+
}
263+
className="border rounded-md px-2 py-1 w-full bg-white text-black dark:bg-black dark:text-white transition-colors"
264+
>
265+
<option value="">None</option>
266+
<option value="daily">Daily</option>
267+
<option value="weekly">Weekly</option>
268+
<option value="monthly">Monthly</option>
269+
<option value="yearly">Yearly</option>
270+
</select>
271+
</div>
272+
</div>
248273
<div className="grid grid-cols-8 items-center gap-4">
249274
<Label htmlFor="tags" className="text-right col-span-2">
250275
Tags

frontend/src/components/HomeComponents/Tasks/Tasks.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const Tasks = (
7373
project: '',
7474
due: '',
7575
start: '',
76+
recur: '',
7677
tags: [],
7778
annotations: [],
7879
});
@@ -308,6 +309,7 @@ export const Tasks = (
308309
priority: task.priority,
309310
due: task.due || undefined,
310311
start: task.start || '',
312+
recur: task.recur || '',
311313
tags: task.tags,
312314
annotations: task.annotations,
313315
backendURL: url.backendURL,
@@ -320,6 +322,7 @@ export const Tasks = (
320322
project: '',
321323
due: '',
322324
start: '',
325+
recur: '',
323326
tags: [],
324327
annotations: [],
325328
});

frontend/src/components/HomeComponents/Tasks/__tests__/AddTaskDialog.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ describe('AddTaskDialog Component', () => {
5959
project: '',
6060
due: '',
6161
start: '',
62+
recur: '',
6263
tags: [],
6364
annotations: [],
6465
},
@@ -221,6 +222,7 @@ describe('AddTaskDialog Component', () => {
221222
project: 'Work',
222223
due: '2024-12-25',
223224
start: '',
225+
recur: '',
224226
tags: ['urgent'],
225227
annotations: [],
226228
};

frontend/src/components/HomeComponents/Tasks/hooks.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export const addTaskToBackend = async ({
4343
priority,
4444
due,
4545
start,
46+
recur,
4647
tags,
4748
annotations,
4849
backendURL,
@@ -55,6 +56,7 @@ export const addTaskToBackend = async ({
5556
priority: string;
5657
due?: string;
5758
start: string;
59+
recur: string;
5860
tags: string[];
5961
annotations: { entry: string; description: string }[];
6062
backendURL: string;
@@ -79,6 +81,11 @@ export const addTaskToBackend = async ({
7981
requestBody.start = start;
8082
}
8183

84+
// Only include recur if it's provided
85+
if (recur !== undefined && recur !== '') {
86+
requestBody.recur = recur;
87+
}
88+
8289
// Add annotations to request body, filtering out empty descriptions
8390
requestBody.annotations = annotations.filter(
8491
(annotation) =>

frontend/src/components/utils/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export interface TaskFormData {
100100
project: string;
101101
due: string;
102102
start: string;
103+
recur: string;
103104
tags: string[];
104105
annotations: Annotation[];
105106
}

0 commit comments

Comments
 (0)