Newbie needing help with shortcuts

Hi.
Would anyone be able to help with what I hope is a simple query. I’ve been using Actions with Todoist but need help running them from an iOS shortcut.

First example

I’d like to be able to query Todoist and get a project into Drafts, then import it into a new project (both project names need to be variables in the shortcut if possible to avoid having to change the script each time).

Second example is the same as above, but using an existing file (e.g. csv in iCloud or perhaps saved in Drafts) to create multiple tasks in a new or existing Todoist project. The individual tasks can use the Todost syntax to add labels, due dates, etc in each line so that part should be simple. Again, having both projects as variables in the shortcut would be great.

The end result would be to say ‘Hey Siri get ready for my trip’ and have my packing list for the new trip built for me.

It’s the scripting (particularly file management) in Draft and shortcuts which I’d appreciate help with. I can do the individual sections using Drafts scripts people on this group have already contributed, it’s putting them together seamlessly without user intervention which is the more difficult part.

Thanks in advance for any advice.

Could you perhaps narrow down what it is you are having issues with and share what you have working and where it is failing or you are stuck? You have indicated it is in Drafts and Shortcuts and particularly “file management”, but that doesn’t actually give us that much to work with in practical terms as there are so many ways you could be approaching this and the sorts of things we might explain to you may be things you already know and you may be having issues with things that we would overlook.

The best starting point for queries is always to show us what you have, explain what it is doing, and what you want it to do instead in as precise a way as possible. This may be multiple things. That’s okay. The more you can break it up and narrow it down the easier it will be for us all to help you resolve each piece of the puzzle.

Thanks for replying. I’ve copied an automation in Drafts which prompts for a project in Todist to import from and copy the content to a Draft.

I’d like to be able to either hard-code the project name so the automation runs without user intervention once triggered. Attempts I’ve made to do this (e.g. removing the prompt code) have failed.

The other option would be to have the project name in a text file in iCloud which used for the project name.

Once the project (with all tasks, due dates, tags, etc.) are in a Draft, I need the automation to write that project to a new project name (creating that project or, again, using a text file to provide the name).

The outcome would be an iOS shortcut which essentially duplicates an entire Todoist project to a new project name, with all dates, tags, sections intact.

Does that help?

Thanks.

Unfortunately that really doesn’t address the fundamentals of what I was asking which was for you to share what you actually have and what you are stuck on. I understand that you have taken one of the many possible actions and tried to do something with it by deleting some of its content, and something about it fails.

What I do think I understand now, is that you don’t want two things, but just one thing, and either would do.

So let’s try tackling this from a different angle. This isn’t a solution, but perhaps(?) a guess in the right direction.

Let’s take it that you will trigger a Drafts action via a voice command from a Shortcuts shortcut.

Here’s an example action that can do that.

Now I’ve happened to link this to a Todoist action I downloaded from the action directory.

When run, this allows me to copy the basic task listing from a Todoist project into a new draft with a Markdown heading on the first line as the project name and tasks added to lines below that as Markdown bulleted items.

If I then modify the title (or even if I don’t), I then could use a second action (this could be triggered by a Siri voice command via Shortcuts to create a new project based on the title and then reverse the process.

Next a couple of caveats.

Caveat 1:
Todoist assigns unique identifiers to projects. The project name is not a unique identifier. Todoist allows you to have multiple distinct projects with the same name … which makes it impossible to reliably use quick add to add a task to the correct project by name.

Caveat 2:
Project names with spaces cannot be reference by Todoist’s quick add. At lest it never used to back when I used Todoist a lot, and I don’t see anything in a quick Google search to convince me that has changed.

I mention these because the next part uses quick add. Its just a demo after all, but if you have unique project names with no whitespaces, then quick add can be sufficient.

Next I picked up an action from the Action Directory that looked like it would do this sort of thing.

It turned out that this was based on a previous suggestion I’d made to someone on the forum last year … and that also references the spaces in project names limitation.

I took that as a starting point and made a modification such that rather than hard coding the project name, it simply took it from the heading on the first line (the draft’s title).

The result was this action.

Now we have a known set of actions that will copy a project out of Todoist into Drafts, that we can then modify the first line of and have it create a project and populate it in Todoist with the same tasks; or others if we happen to modify the source draft.

Perhaps yo already have something like this? Perhaps this is not the sort of thing you are after ad I’ve got it entirely wrong. But now we have some specific examples to reference and that maybe you can tailor to meet your requirements now, or with further guidance from the community.

Let’s see what’s next.

Hi. Perhaps this will make things clearer.

In the import action (importing a project from todoist) the existing action (Import Todoist Project) requires the user to input a project name via a user prompt. I don’t want to do that - I want to specify a known existing project name already in my todoist account. I’m assuming that if the name is known, a project ID can then be extracted (the existing code seems to be reading project IDs when it queries todoist to generate the selection list).

So, I either want the action to read a text file (in iCloud/Drafts) which contains the existing project name, or hard-code the existing project name into the action itself (i.e. not to put up a prompt for the user to enter it).

Assuming I don’t want spaces in my new project name, I was hoping that the action would be able to create a new project name (again, hard coded into the action, not asking for input from the user) and place all the existing project’s tasks (along with their sections, due dates, tags, etc) into the new project.

Assuming this can be coded as a single action, I would then want to be able to trigger it with Siri.

Does that help?

Thanks again for your help.

Replace Prompt for input from file

I guess you use the action posted by agile tortoise … in the script action you find the prompt creation and handling like this. Remove the code from creste prompt until read values from prompt and set your project name as a string.

Better would be as mentioned to reference the project by ID but that would change more code and would get more complex…

Next step would be to get the project name from a file in your iCloud / Drafts folder…

// create prompt
let p = Prompt.create();
p.title = "Select Project to Import";

// add projects
let projectLookup = mapIds(projects, "name", "id");
let projectNames = Object.keys(projectLookup);
p.addPicker("project", "Project", [projectNames], [0]);

p.addButton("Import Project");
if (!p.show()) {
	context.cancel();
	return true;
}

// read values from prompt
let projectIndex = p.fieldValues["project"][0];
let projectName = projectNames[projectIndex]; //<< index from user selection in prompt
let projectID = projectLookup[projectName];

would shrink down to

let projectName =„projectNsmeToBeDuplicated“; //<< index from user selection in prompt
let projectID = projectLookup[projectName];
// Reading from a file in iCloud from Drafts folder!!! 
let fmCloud = FileManager.createCloud(); // iCloud
let create_project = false;
if(create_project)
  fmCloud.writeString("/project.txt", "travel_checklist");
let project_name = fmCloud.readString("/project.txt")
if(project_name == undefined)
  alert('EROR: file not found');
else
  alert(project_name);

Let’s start with my example actions from above then as a common base that does indeed seem to do 80-90% of what it seems like you are after.

First of all, I’ve combined two of the actions I referenced above into a single action as you are looking for a single hands off, all project names predefined, approach.

There are some additional modifications I’ll cover briefly, but the second step in the action is derived from Import Todoist Project, and the third step is derived from Save Tasks into New Todoist project.

I’ve set the dependencies in terms of two project names to reference the two variables in the “new” first step in the action.

let strProjectTemplate = "General";
let strProjectNew = "Packing";

These replace the need for selection of a source project and picking the name of the destination prompt from the draft title respectively.

If you just want to maintain the project names directly, you can edit them there. strProjectTemplate is the source template being read in from Todoist. strProjectNew is the project being written back out to Todoist with the content taken from the template project.

If you want to store a project name in projectTemplate.txt and the other in projectNew.txt in the Drafts iCloud directory, you could modify the first action step to just read in the file content directly, as per the example in the scripting documentation for FileManager.

let fmCloud = FileManager.createCloud();
let strProjectTemplate = fmCloud.readString("/projectTemplate.txt");
let strProjectNew = fmCloud.readString("/projectNew.txt");

If you wanted to store both settings in the same file, this could be done easily with JSON in say project.json like this.

{
	"template" : "General",
	"new" : "Packing"
}

Then you could change the first action step to this.

let fmCloud = FileManager.createCloud();
let objProjects = fmCloud.readJSON("/projects.json");
let strProjectTemplate = objProjects.template;
let strProjectNew = objProjects.new;

The only other change is that I have reworked the second and third action steps not to use a draft to temporarily store the content that is the project content. I’ve simply stored this in a variable as it isn’t being manually modified and saves any draft tidying that would result otherwise.

Beyond that I’ve tried to keep the content as close to the originals as possible so you can review the changes.

Hopefully, this is now much closer to what you are after.

Hi
Thanks so much for this - I’ve just tested it and it’s almost perfect! I removed the dash in front of the destination task names as they weren’t required.

However, what it doesn’t so (and which may not be possible) is to include and Todoist due dates, section names and tags from the source project.

Is there a way to add these?

Thank you again for your help - very much appreciated.

Thank you for this - getting my head around the coding. Much to learn!

You need to look at the Todoist API for the retrieval.

From the change you mentioned, I assume that you now have a line that you edited to look like this:

content.push(task.content);

As well as content, you should see, for example, that the due date is held against the due property, so you should be able to access the due date using task.due.

However, the example uses quick add for tasks. Again, you can read about what that can and cannot do in the Todoist API documentation.

That doesn’t support the additional features you noted, therefore you have to use the more powerful (but not quick) task addition function.

See Todoist.CreateTask() in the Drafts scripting documentation.

Above you can see how a task is being retrieved and has properties. To use the CreateTask() function you need to create the task object and have it added.

Now that may sound overly complicated, but think about the import action and that push line. The example I put together was just that, and just to give us some starting point for properly discussing what you are doing. As I noted, specific and actuals really make the difference. Consider if we didn’t use that third action step at all. What if when we loop over the tasks like this:

for (let task of tasks) {
	content.push(task.content);
}

… we add in a few line to take the task that was read in with all of its properties, and we amend any properties we want to, or copy just the properties we want to a new task object (whichever is the least amount of effort for what you want to keep), and write that back out to the new project.

Based on the information I’ve provided here for the Todoist API and Todoist Drafts functions, and the code already provided, why not give it a try? See how far you get, and then share back what you come up with?

Thanks for the very detailed and helpful reply - I’ll spend some time experimenting!

Hi, I think I need some sort of ‘basics of coding’ as I can’t work it out. The Todoist.CreateTask() needs inputs of date, comments, tags, etc. and I can’t see how to take the output of the ‘imported’ tasks (task.content) into its constituent parts (if indeed that’s how it needs to be done).

Thanks for your help, but I think I need some basics first.

do you have any programming experience?

a good start would be https://eloquentjavascript.net/

JavaScript is very close to C on its core keywords and semantics.