11"""Database dump tool for OmniFocus."""
22
33import json
4- from ...omnijs import execute_omnijs
4+
5+ from ...omnijs import execute_omnijs_with_params
56
67
78async def dump_database (
@@ -21,233 +22,14 @@ async def dump_database(
2122 Returns:
2223 Formatted database dump with hierarchical structure
2324 """
24- script = f'''
25- (() => {{
26- try {{
27- const hideCompleted = { str (hide_completed ).lower ()} ;
28- const hideRecurringDuplicates = { str (hide_recurring_duplicates ).lower ()} ;
29-
30- // Status mappings
31- const taskStatusMap = {{}};
32- taskStatusMap[Task.Status.Available] = "avail";
33- taskStatusMap[Task.Status.Blocked] = "block";
34- taskStatusMap[Task.Status.Completed] = "compl";
35- taskStatusMap[Task.Status.Dropped] = "drop";
36- taskStatusMap[Task.Status.DueSoon] = "due";
37- taskStatusMap[Task.Status.Next] = "next";
38- taskStatusMap[Task.Status.Overdue] = "over";
39-
40- const projectStatusMap = {{}};
41- projectStatusMap[Project.Status.Active] = "active";
42- projectStatusMap[Project.Status.Done] = "done";
43- projectStatusMap[Project.Status.Dropped] = "dropped";
44- projectStatusMap[Project.Status.OnHold] = "onHold";
45-
46- // Format date as M/D
47- function formatDate(date) {{
48- if (!date) return null;
49- return (date.getMonth() + 1) + "/" + date.getDate();
50- }}
51-
52- // Format duration
53- function formatDuration(minutes) {{
54- if (!minutes) return null;
55- if (minutes >= 60) {{
56- return Math.floor(minutes / 60) + "h";
57- }}
58- return minutes + "m";
59- }}
60-
61- // Track seen recurring task names to filter duplicates
62- const seenRecurring = new Set();
63-
64- // Build output
65- let output = [];
66-
67- // Legend
68- output.push("Legend: F:Folder P:Project \\ u2022:Task \\ uD83D\\ uDEA9:Flagged [M/D]:Date <tag>:Tags");
69- output.push("Status: #next #avail #block #due #over #compl #drop");
70- output.push("");
71-
72- // Process folders
73- flattenedFolders.forEach(folder => {{
74- output.push("F: " + folder.name);
75-
76- // Get projects in this folder
77- folder.projects.forEach(project => {{
78- if (hideCompleted && (project.status === Project.Status.Done ||
79- project.status === Project.Status.Dropped)) {{
80- return;
81- }}
82-
83- let projectLine = " P: " + project.name;
84- if (project.status !== Project.Status.Active) {{
85- projectLine += " #" + projectStatusMap[project.status];
86- }}
87- if (project.dueDate) {{
88- projectLine += " [" + formatDate(project.dueDate) + "]";
89- }}
90- output.push(projectLine);
91-
92- // Get tasks in this project
93- project.flattenedTasks.forEach(task => {{
94- if (hideCompleted && (task.taskStatus === Task.Status.Completed ||
95- task.taskStatus === Task.Status.Dropped)) {{
96- return;
97- }}
98-
99- // Filter recurring duplicates
100- if (hideRecurringDuplicates && task.repetitionRule) {{
101- const key = task.name + "|" + (task.containingProject ? task.containingProject.name : "");
102- if (seenRecurring.has(key)) {{
103- return;
104- }}
105- seenRecurring.add(key);
106- }}
107-
108- let taskLine = " \\ u2022 " + task.name;
109-
110- // Add status
111- const status = taskStatusMap[task.taskStatus];
112- if (status && status !== "avail") {{
113- taskLine += " #" + status;
114- }}
115-
116- // Add flag
117- if (task.flagged) {{
118- taskLine += " \\ uD83D\\ uDEA9";
119- }}
120-
121- // Add due date
122- if (task.dueDate) {{
123- taskLine += " [" + formatDate(task.dueDate) + "]";
124- }}
125-
126- // Add duration
127- if (task.estimatedMinutes) {{
128- taskLine += " " + formatDuration(task.estimatedMinutes);
129- }}
130-
131- // Add tags
132- if (task.tags && task.tags.length > 0) {{
133- taskLine += " <" + task.tags.map(t => t.name).join(",") + ">";
134- }}
135-
136- output.push(taskLine);
137- }});
138- }});
139-
140- output.push("");
141- }});
142-
143- // Also show projects not in any folder
144- flattenedProjects.forEach(project => {{
145- if (project.folder) return; // Already shown
146-
147- if (hideCompleted && (project.status === Project.Status.Done ||
148- project.status === Project.Status.Dropped)) {{
149- return;
150- }}
151-
152- let projectLine = "P: " + project.name;
153- if (project.status !== Project.Status.Active) {{
154- projectLine += " #" + projectStatusMap[project.status];
155- }}
156- if (project.dueDate) {{
157- projectLine += " [" + formatDate(project.dueDate) + "]";
158- }}
159- output.push(projectLine);
160-
161- // Get tasks in this project
162- project.flattenedTasks.forEach(task => {{
163- if (hideCompleted && (task.taskStatus === Task.Status.Completed ||
164- task.taskStatus === Task.Status.Dropped)) {{
165- return;
166- }}
167-
168- if (hideRecurringDuplicates && task.repetitionRule) {{
169- const key = task.name + "|" + project.name;
170- if (seenRecurring.has(key)) {{
171- return;
172- }}
173- seenRecurring.add(key);
174- }}
175-
176- let taskLine = " \\ u2022 " + task.name;
177-
178- const status = taskStatusMap[task.taskStatus];
179- if (status && status !== "avail") {{
180- taskLine += " #" + status;
181- }}
182-
183- if (task.flagged) {{
184- taskLine += " \\ uD83D\\ uDEA9";
185- }}
186-
187- if (task.dueDate) {{
188- taskLine += " [" + formatDate(task.dueDate) + "]";
189- }}
190-
191- if (task.estimatedMinutes) {{
192- taskLine += " " + formatDuration(task.estimatedMinutes);
193- }}
194-
195- if (task.tags && task.tags.length > 0) {{
196- taskLine += " <" + task.tags.map(t => t.name).join(",") + ">";
197- }}
198-
199- output.push(taskLine);
200- }});
201-
202- output.push("");
203- }});
204-
205- // Show inbox tasks
206- if (inbox.length > 0) {{
207- output.push("INBOX:");
208- inbox.forEach(task => {{
209- if (hideCompleted && (task.taskStatus === Task.Status.Completed ||
210- task.taskStatus === Task.Status.Dropped)) {{
211- return;
212- }}
213-
214- let taskLine = " \\ u2022 " + task.name;
215-
216- const status = taskStatusMap[task.taskStatus];
217- if (status && status !== "avail") {{
218- taskLine += " #" + status;
219- }}
220-
221- if (task.flagged) {{
222- taskLine += " \\ uD83D\\ uDEA9";
223- }}
224-
225- if (task.dueDate) {{
226- taskLine += " [" + formatDate(task.dueDate) + "]";
227- }}
228-
229- if (task.estimatedMinutes) {{
230- taskLine += " " + formatDuration(task.estimatedMinutes);
231- }}
232-
233- if (task.tags && task.tags.length > 0) {{
234- taskLine += " <" + task.tags.map(t => t.name).join(",") + ">";
235- }}
236-
237- output.push(taskLine);
238- }});
239- }}
240-
241- return output.join("\\ n");
242-
243- }} catch (error) {{
244- return "Error dumping database: " + error.toString();
245- }}
246- }})();
247- '''
248-
24925 try :
250- result = await execute_omnijs (script )
26+ result = await execute_omnijs_with_params (
27+ "dump_database" ,
28+ {
29+ "hide_completed" : hide_completed ,
30+ "hide_recurring_duplicates" : hide_recurring_duplicates ,
31+ },
32+ )
25133 # The result might be wrapped in quotes from JSON, handle both cases
25234 if isinstance (result , dict ):
25335 if "error" in result :
0 commit comments