MilkScriptでプロジェクトレポートと、年次レビュー用タスクリストを取得する

MilkScriptに関する記事は、これで最後です。
今回も条件を指定してタスクリストを取得し、ウィンドウ表示させるといったものです。

プロジェクトレポート

プロジェクト内のすべてのタスクを完了できればいいのですが、たまに手つかずのタスクを残したままプロジェクトを閉じるときがあります。
他にやるべきことがあった場合など一時的にプロジェクトを保留状態にするとき、どんなことをやり終え、これから何をしようとしていたのか、何が手つかずだったのかを後で思い出すため、ノートアプリに転記しておいて現状をメモしておくためのスクリプトです。

スクリプト実行後


if (rtm.getSelectedTasks().length !== 1) {
    throw new Error("1つのタスクを選択してください");
    }
    
    // 選択タスクの最初の一つを『selectedTask』に格納する
    const [selectedTask] = rtm.getSelectedTasks();
    const subTasks = selectedTask.getSubtasks();
    
    if (subTasks.length === 0) {
    throw new Error("選択されたタスクにサブタスクがありません");
    }
    
    // サブタスク群から完了したものと未完了のものを選り分ける
    const completedTasks = subTasks.filter(task => task.isCompleted());
    const unCompletedTasks = subTasks.filter(task => !task.isCompleted());
    
    const ProjectName = formatProjectName(selectedTask.getName());
    const StartDate = formatDateToYYMMDD(selectedTask.getCreatedDate());
    const EndDate = formatDateToYYMMDD(new Date());
    
    const Duration = `${StartDate}-${EndDate}`;
    
    const completedList = formatTaskList(completedTasks, "completed");
    const uncompletedList = formatTaskList(unCompletedTasks, "uncompleted");
    
    const NoteContent = `${ProjectName}(${Duration})\n`
    + `### 完了: ${completedTasks.length}(タスク名 タグ名 完了日)\n`
    + `${completedList.join('')}\n`
    + `### 未完了: ${unCompletedTasks.length}(タスク名 タグ名 締切日)\n`
    + `${uncompletedList.join('')}`;
    
    selectedTask.addNote(NoteContent);
    
    function formatProjectName(name) {
    const stMatch = name.match(/^(.*)(?:\s[0-9]{4})$/);
    return stMatch ? `## ${stMatch[1]}` : `## ${name}`;
    }
    
    function formatTaskList(tasks, status) {
    if (status === "completed") {
        tasks.sort((a, b) => a.getCompletedDate() - b.getCompletedDate());
        return tasks.map(task => `- ${formatTaskInfo(task)}\n`);
    } else {
        // 未完了タスクを作成日、あいうえお順でソート
        tasks.sort((a, b) => {
        const dateA = new Date(a.getCreatedDate());
        const dateB = new Date(b.getCreatedDate());
        // 時間の部分を無視して、日付だけで比較
        const dateComparison = dateA.toISOString().slice(0, 10).localeCompare(dateB.toISOString().slice(0, 10));
    
        if (dateComparison !== 0) {
            return dateComparison; // 日付が異なる場合は日付でソート
        } else {
            // 日付が同じ場合はあいうえお順にソート
            return a.getName().localeCompare(b.getName());
        }
    });
        return tasks.map(task => `- ${formatTaskInfo(task)}\n`);
    }
    }
    
    function formatTaskInfo(task) {
    const tags = formatTags(task);
    const completedDate = task.isCompleted() ? formatDateToYYMMDD(task.getCompletedDate()) : "";
    const dueDate = task.getDueDate() && !task.isCompleted() ? formatDateToYYMMDD(task.getDueDate()) : "";
    
    return `${task.getName()} ${tags} ${completedDate} ${dueDate}`;
    }
    
    function formatTags(task) {
    const tags = task.getTags().map(tag => `#${tag.getName()}`).join(' ');
    return tags.length > 0 ? ` ${tags}` : "";
    }
    
    function formatDateToYYMMDD(date) {
    const year = date.getFullYear().toString().slice(-2);
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');
    return `${year}${month}${day}`;
    }
                    

完了したタスクリストと、未完了のタスクリストをそれぞれ取得します。
完了したタスクは完了日でソート。未完了タスクは作成日順にソートさせています。

年次レビュー用タスクリスト

毎年、年末に未完了のタスクをレビューして「本当にやるべきかどうか」を改めて判定しています。
そのため今までは印刷に出していたのですが、このスクリプトを使って未完了のタスクをリストごとに羅列できるようにしてみました。


const lists = rtm.getLists().filter(list => (list.getName() !== `Note`) && (list.getName() !== `Sent`));

let context = [];
lists.forEach(list => {
    const listTasks = list.getTasks().filter(task => (!task.isCompleted() && task.getParent() === null));
    listTasks.sort((a, b) => a.getCreatedDate() - b.getCreatedDate());
    const tasks =listTasks.map(task => 
        `- ${task.getName()}${formatSubtaskLength(task)} ${formatTags(task)} ${formatDateToYYMMDD(task.getDueDate())}\n`);
    context = context.concat([
        `## ${list.getName()}: ${list.getTasks().filter(task => !task.isCompleted()).length}\n`,
        ...tasks.join(``) + `\n`,
    ]);
})

rtm.newFile(context.join(``), rtm.MediaType.TEXT, 'RTM_Tasklist.txt');

function formatSubtaskLength(task) {
    const subTasks = task.getSubtasks();
    const count = subTasks.filter(task => !task.isCompleted()).length;
    if (count === 0) {
        return ``;
    } else {
        return `(${count})`;
    }
}

function formatTags(task) {
    const tags = task.getTags().map(tag => `#${tag.getName()}`).join(' ');
    return tags.length > 0 ? ` ${tags}` : "";
}

function formatDateToYYMMDD(date) {
    if (date !== null) {
        const year = date.getFullYear().toString().slice(-2);
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const day = date.getDate().toString().padStart(2, '0');
        return `${year}${month}${day}`;
    } else {
        return ``;
    }
}
                    

作成日順でソート。サブタスクは表示させず、『親タスク名(子タスク数)』のようにまとめるようになってます。