diff --git a/src/cmd/addsubtask.js b/src/cmd/addsubtask.js new file mode 100644 index 0000000..c7b4e58 --- /dev/null +++ b/src/cmd/addsubtask.js @@ -0,0 +1,116 @@ +'use strict'; + +const log = require('../utils/log.js'); +const config = require('../utils/config.js'); +const { prompt } = require('../utils/prompt.js'); + +const finish = require('../utils/finish.js'); + + +/** + * This command adds a subtask to an existing task (Pro accounts only) + * @param args [parentTaskIndex, subtaskName...] + * @param env + */ +function action(args, env) { + + // Need at least a parent task index + if ( args.length === 0 || args[0].length === 0 ) { + prompt('Parent Task Index:', 'Subtask Name:', _promptFinished); + } + else if ( args[0].length === 1 ) { + // Have parent index but no subtask name + let parentIndex = parseInt(args[0][0]); + if ( isNaN(parentIndex) ) { + log.spinner.error("Parent task index must be a number"); + return finish(); + } + prompt('Subtask Name:', function(answers) { + for ( let i = 0; i < answers.length; i++ ) { + _process(parentIndex, answers[i][0], i+1, answers.length); + } + }); + } + else { + // Have both parent index and subtask name + let parentIndex = parseInt(args[0][0]); + if ( isNaN(parentIndex) ) { + log.spinner.error("Parent task index must be a number"); + return finish(); + } + let subtaskName = args[0].slice(1).join(' '); + _process(parentIndex, subtaskName); + } + +} + + +/** + * Process the returned prompt answers + * @private + */ +function _promptFinished(answers) { + for ( let i = 0; i < answers.length; i++ ) { + let parentIndex = parseInt(answers[i][0]); + let subtaskName = answers[i][1]; + if ( isNaN(parentIndex) ) { + log.spinner.error("Parent task index must be a number"); + continue; + } + _process(parentIndex, subtaskName, i+1, answers.length); + } +} + + +/** + * Process the request to add a subtask + * @private + */ +function _process(parentIndex, subtaskName, count=1, max=1) { + log.spinner.start("Adding Subtask..."); + config.user(function(user) { + + // Add Subtask + user.tasks.addSubtask(parentIndex, subtaskName, function(err) { + if ( err ) { + if ( err.code === 4040 ) { + log.spinner.error("Subtasks require a Pro account"); + } + else if ( err.code === 4050 ) { + log.spinner.error("Invalid parent task (index: " + parentIndex + ")"); + } + else if ( err.code === 4060 ) { + log.spinner.error("Subtask nested too deep (max 3 levels)"); + } + else if ( err.code === 4070 ) { + log.spinner.error("Cannot add subtask: repeating task in hierarchy"); + } + else { + log.spinner.error("Could not add subtask (" + err.msg + ")"); + } + } + _processFinished(count, max); + }); + }); +} + +/** + * Request Callback + * @private + */ +function _processFinished(count, max) { + log.spinner.start("Adding Subtask [" + count + "/" + max + "]..."); + if ( count === max ) { + log.spinner.success("Subtask(s) Added"); + return finish(); + } +} + + + +module.exports = { + command: 'addsubtask [args...]', + alias: 'as', + description: 'Add a subtask to an existing task (Pro accounts only)', + action: action +}; diff --git a/src/cmd/ls.js b/src/cmd/ls.js index 636d6f6..47fec13 100644 --- a/src/cmd/ls.js +++ b/src/cmd/ls.js @@ -97,6 +97,11 @@ function action(args, env) { printIndicator('subtask',task); } + // Display parent task indicator + if (task.hasSubtasks) { + printIndicator('parentTask',task); + } + // Add the Task Name log.style(task.name+' ', namestyle); diff --git a/src/cmd/lsd.js b/src/cmd/lsd.js index ab6ed51..d0ff01d 100644 --- a/src/cmd/lsd.js +++ b/src/cmd/lsd.js @@ -113,6 +113,12 @@ function action(args, env) { printIndicator('subtask',task); } + // Display parent task indicator + if (task.hasSubtasks) { + log.style(' '); + printIndicator('parentTask',task); + } + // Print the Task Name log.style(' '); log.style(task.name + ' ', priStyle); diff --git a/src/cmd/lsp.js b/src/cmd/lsp.js index 07d891c..3d15b86 100644 --- a/src/cmd/lsp.js +++ b/src/cmd/lsp.js @@ -86,6 +86,12 @@ function action(args, env) { printIndicator('subtask',task); } + // Display parent task indicator + if (task.hasSubtasks) { + log.style(' '); + printIndicator('parentTask',task); + } + // Print the Task Name log.style(' '); log.style(task.name + ' ', priStyle); diff --git a/src/cmd/task.js b/src/cmd/task.js index ea1c213..98d8c76 100644 --- a/src/cmd/task.js +++ b/src/cmd/task.js @@ -106,7 +106,7 @@ function displayTask(taskDetails) { debug(taskDetails) let index = taskDetails.index; // eslint-disable-next-line no-unused-vars - const { _list, list_id, location_id, taskseries_id, task_id, _index, name, priority, start, due, completed, isRecurring, recurrenceRuleRaw, isSubtask, estimate, url, tags, notes, ...otherAttributes } = taskDetails.task; + const { _list, list_id, location_id, taskseries_id, task_id, _index, name, priority, start, due, completed, isRecurring, recurrenceRuleRaw, isSubtask, hasSubtasks, estimate, url, tags, notes, ...otherAttributes } = taskDetails.task; const listName = LIST_MAP.get(list_id) || "Not found"; const locationName = LOCATION_MAP.get(location_id) || "Not found"; @@ -133,6 +133,8 @@ function displayTask(taskDetails) { log.style(`Is Subtask: `,styles.index) log(`${isSubtask}`) + log.style(`Has Subtasks: `,styles.index) + log(`${hasSubtasks}`) log.style(`Estimate: `,styles.index) log(humanizeDuration(estimate)) log.style(`Location: `,styles.index) diff --git a/src/utils/printIndicator.js b/src/utils/printIndicator.js index b6ef4ff..82f1657 100644 --- a/src/utils/printIndicator.js +++ b/src/utils/printIndicator.js @@ -14,7 +14,7 @@ function printIndicator(type,task) { let iconType = config.get().iconType; let indicatorStyle = task.isCompleted ? styles.completed : styles[type]; - let notesIndicator,urlIndicator,recurringIndicator,subTaskIndicator; + let notesIndicator,urlIndicator,recurringIndicator,subTaskIndicator,parentTaskIndicator; iconType = iconType || 'text'; // defaults to text if nothing included switch (iconType) { case 'emoji': @@ -22,6 +22,7 @@ function printIndicator(type,task) { urlIndicator = '๐Ÿ”—'; recurringIndicator = '๐Ÿ”'; subTaskIndicator = 'โคด๏ธ ' + parentTaskIndicator = '๐Ÿ“‹ ' break; case 'text': default: @@ -29,13 +30,15 @@ function printIndicator(type,task) { urlIndicator = '+'; recurringIndicator = 'r'; subTaskIndicator = '(s) ' + parentTaskIndicator = '(p) ' break; } let indicators = { notes: notesIndicator, url: urlIndicator, recurring: recurringIndicator, - subtask: subTaskIndicator + subtask: subTaskIndicator, + parentTask: parentTaskIndicator } log.style(indicators[type], indicatorStyle); }