SamVerschueren/listr

Can't edit title of parent task

KristerV opened this issue · 2 comments

There is no way how to change the title of a parent task. Here's some boilerplate code to test with:

const Listr = require('listr')

const tasks = new Listr([
    {
        title: "My task",
        task: (ctx, majorTask) => new Listr([
            {
                title: "Minor task 1",
                task: (ctx, minorTask) => new Promise((res, rej) => {
                    setTimeout(res, 2000)
                }).then(() => minorTask.title += " DONE")
            },
            {
                title: "Minor task 2",
                task: (ctx, minorTask) => new Promise((res, rej) => {
                    setTimeout(res, 2000)
                }).then(() => minorTask.title += " DONE")
            },
        ], { concurrent: false }).then(() => {
            majorTask.title += ' DONE'
        })
    }
])

tasks.run()

The new Listr().then() part doesn't work of course.

The only way I can think of is wrapping new Listr().run() into my own Promise, but what a hassle.

Instead of 'DONE' I would of course like to use something more practical like counting minutes that the task took to complete.

Well I made a hack. Would be nice for a cleaner way of doing this:

function isLastTask(task) is the main part.

const Listr = require('listr')

const tasks = new Listr([
    {
        title: "My task",
        task: (ctx, majorTask) => new Listr([
            {
                title: "Minor task 1",
                task: (ctx, minorTask) => myTask(1, minorTask, majorTask)
            },
            {
                title: "Minor task 2",
                task: (ctx, minorTask) => myTask(2, minorTask, majorTask)
            },
            {
                title: "Minor task 3",
                task: (ctx, minorTask) => myTask(3, minorTask, majorTask)
            },
        ], { concurrent: false })
    }
])

tasks.run()

function isLastTask(task) {
    let waiting = 0
    for (const t of task._task._listr._tasks) {
        if (t.isStopped !== true)
            waiting++
    }
    return waiting <= 1
}

function myTask(nr, minorTask, majorTask) {
    return new Promise((res, rej) => {
        setTimeout(() => {
            if (isLastTask(minorTask))
                majorTask.title += " DONE"
            res()
        }, 2000)
    })
}

I have the same requirement. Might be nice to have a complete task property that is called when a task completes.

In the meantime my approach is to override the subtask instance's run method to add a promise handler that updates the parent title:

new Listr([{
  title: 'Parent',
  task: (ctx, task) => {
    const list = new Listr(subtasks);
    const runFn = list.run.bind(list);

    list.run = () => {
      return runFn().then(() => {
        task.title += " is done"; // "Parent is done"
      });
    };

    return list;
  },
}]);