Action
Todoist Bulk Add (No Prompt)
DISCLAIMER: I don’t do JS, so please go easy on me, I just tried to combine some ideas and after some LLM shenanigans I got this working. I’m sure there are better ways to do this, but it solves my issue.
The idea is to just format the tasks specially multiple ones in the same project/label without having to pick for each one.
The labels have to be setup previously to be correctly placed on tasks, but that is alright.
This script is a Todoist task creation utility that processes a text draft to create multiple tasks with advanced formatting options.
Core Features
Project Assignment
- Tasks can be assigned to projects using #projectname
- Default project can be set using #projectname on a separate line
- All subsequent tasks use the default project until changed
Label Management
- Default labels can be set using @label1,label2 on a separate line
- Individual tasks can override defaults with @label syntax
- When a task has explicit labels, they take precedence over defaults
Task Parameters
Each task can include additional parameters after – symbols:
- –note: Adds a description to the task
- –due: Sets the due date/time
- –pri: Sets priority (1-4)
Language Support
- Default language for due dates can be set using ++XX format (e.g., ++en)
Task Format
Tasks follow this structure:
[task content] #project @labels --parameter value
Example:
Changing the due language:
++pt
@work,personal
Buy groceries @shopping --pri 1
Ligar para John @calls #personal --pri 4 --due hoje --note Remember to discuss project timeline
Marcar dentista @health --pri 2 --due amanhã
Revisar Documentos @work #personal --pri 3 --due "Proxima segunda"
Using default language:
@work,personal
Buy groceries @shopping --pri 1
Call John @calls #personal --pri 4 --due tod--note Remember to discuss project timeline
Schedule dentist @health --pri 2 --due tomorrow
Review documents @work #personal --pri 3 --due "next monday"
Credit to @agiletortoise for Todoist integration guidance and @davenichols for parameter-based quick add implementation.
Steps
-
script
let createTasks = () => { let todoist = Todoist.create(); let content = draft.content; if (content.length == 0) { alert("Draft is blank"); return false; } // Get all projects for ID lookup let projects = todoist.getProjects(); let projectMap = {}; if (projects) { projects.forEach(p => { projectMap[p.name.toLowerCase()] = p.id; }); } // Get all labels for ID lookup let labels = todoist.getLabels(); let labelMap = {}; if (labels) { labels.forEach(l => { labelMap[l.name.toLowerCase()] = l.name; }); } let newDraft = ""; let defaultProject = ""; let defaultLang = ""; let defaultLabels = []; let lines = content.split("\n"); for (let line of lines) { if (line.length == 0) { newDraft += "\n"; continue; } // Check for default project setting let proj = line.match(/^#(\S+)\s*/m); if (proj) { defaultProject = proj[1].toLowerCase(); newDraft += line + "\n"; continue; } // Check for default language setting let lang = line.match(/^\+\+(\w{2})\s*/m); if (lang) { defaultLang = lang[1].toLowerCase(); newDraft += line + "\n"; continue; } // Check for default labels setting let labelLine = line.match(/^@(\S+)\s*/m); if (labelLine) { defaultLabels = labelLine[1].toLowerCase().split(','); newDraft += line + "\n"; continue; } let parts = line.split("--"); let mainText = parts[0]; // Handle project in content let projectInContent = mainText.match(/#(\S+)/); let projectName = projectInContent ? projectInContent[1].toLowerCase() : defaultProject; // Handle labels in content let labelsInContent = mainText.match(/@(\S+)/g); let taskLabels = []; // Only use default labels if no explicit labels are present if (labelsInContent) { labelsInContent.forEach(label => { taskLabels.push(label.slice(1).toLowerCase()); }); } else { taskLabels = defaultLabels.slice(); } // Clean up the main content mainText = mainText.replace(/#(\S+)/, '').replace(/@(\S+)/g, '').trim(); let params = { "content": mainText }; // Add project if specified if (projectName && projectMap[projectName]) { params["project_id"] = projectMap[projectName]; } // Add labels if specified if (taskLabels.length > 0) { let labelNames = taskLabels .filter(label => labelMap[label]) .map(label => labelMap[label]); if (labelNames.length > 0) { params["labels"] = labelNames; } } // Add default language if specified if (defaultLang) { params["due_lang"] = defaultLang; } // Handle additional parameters if (parts.length > 1) { for (let i = 1; i < parts.length; i++) { let opt = parts[i].split(" ", 1); let value = parts[i].slice(String(opt).length).trim(); switch (String(opt)) { case 'note': params['description'] = value; break; case 'due': params['due_string'] = value; break; case 'pri': let inputPriority = parseInt(value); if (inputPriority >= 1 && inputPriority <= 4) { params['priority'] = 5 - inputPriority; } break; } } } console.log("Creating task with params:", JSON.stringify(params, null, 2)); let result = todoist.createTask(params); if (result) { newDraft += line + " - OK\n"; console.log("Task created:", JSON.stringify(result, null, 2)); } else { newDraft += line + " - Failed\n"; console.log("Failed to create task"); } } editor.setText(newDraft); return true; } if (!createTasks()) { context.fail(); }
Options
-
After Success Trash Notification Info Log Level Info