Action
Archive
Posted by zigzagjeff,
Last update
16 days ago
UPDATES
16 days ago
Fixed making double headers for archived tasks.
Archive Tasks — Heading-Aware + Timestamp
This action adds two functions to the “Archive Tasks” action.
- Retains existing H2, H3, etc. groupings allowing you to maintain a log of the projects, areas, or outcomes the archived tasks were from.
- Time stamps creation and completion date.
Steps
-
script
// ===================================================== // Archive Tasks — Heading-Aware + Timestamped // // Moves - [x] tasks to ## Archive, grouped under their // original H2/H3/H4 heading, with creation date (draft) // and completion datetime (system clock, to the minute). // // HOW TO INSTALL: // 1. In Drafts, create a new Action // 2. Add a single "Script" step // 3. Paste this entire file into that step // 4. Save. Run on any daily draft. // ===================================================== (() => { const ARCHIVE_HDR = '## Archive'; const COMPLETED_RE = /^(\s*-\s\[x\]\s)/i; const HEADING_RE = /^#{1,6}\s/; const pad = n => String(n).padStart(2, '0'); // --- Timestamps --- const now = new Date(); const completionStamp = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())}` + ` ${pad(now.getHours())}:${pad(now.getMinutes())}`; const cd = draft.createdAt; const creationStamp = `${cd.getFullYear()}-${pad(cd.getMonth()+1)}-${pad(cd.getDate())}`; // --- Split draft at archive boundary --- const text = editor.getText(); const lines = text.split('\n'); const archiveIdx = lines.findIndex(l => l.trim() === ARCHIVE_HDR); const activeLines = archiveIdx >= 0 ? lines.slice(0, archiveIdx) : [...lines]; const existingLines = archiveIdx >= 0 ? lines.slice(archiveIdx + 1) : []; // --- Walk active section --- // Track the most recent heading; collect completed tasks grouped by it. let currentHeading = null; const groups = new Map(); // heading string → [stamped task lines] const remaining = []; for (const line of activeLines) { if (HEADING_RE.test(line)) { currentHeading = line.trim(); remaining.push(line); continue; } if (COMPLETED_RE.test(line)) { const stamped = line.trimEnd() + ` ➕ ${creationStamp} ✅ ${completionStamp}`; if (!groups.has(currentHeading)) groups.set(currentHeading, []); groups.get(currentHeading).push(stamped); } else { remaining.push(line); } } // --- Nothing to archive --- if (groups.size === 0) { app.displayInfoMessage('No completed tasks found.'); context.cancel('No completed tasks found.'); return; } // --- Parse existing archive lines --- // Group existing tasks by their headings to avoid duplicate headers let existingHeading = null; const existingGroups = new Map(); for (const line of existingLines) { if (HEADING_RE.test(line)) { existingHeading = line.trim(); if (!existingGroups.has(existingHeading)) existingGroups.set(existingHeading, []); } else if (line.trim() !== '') { if (!existingGroups.has(existingHeading)) existingGroups.set(existingHeading, []); existingGroups.get(existingHeading).push(line.trimEnd()); } } // --- Merge new groups into existing groups --- // We want new tasks to appear before old tasks under the same heading. // To keep "newest at top" behavior for the whole archive, we list headings // from the new groups first, followed by any unique headings from old groups. const finalHeadings = []; const seenHeadings = new Set(); for (const heading of groups.keys()) { finalHeadings.push(heading); seenHeadings.add(heading); } for (const heading of existingGroups.keys()) { if (!seenHeadings.has(heading)) { finalHeadings.push(heading); seenHeadings.add(heading); } } // --- Build merged archive block --- const mergedBlock = []; for (const heading of finalHeadings) { if (heading) mergedBlock.push(heading); const newTasks = groups.get(heading) || []; const oldTasks = existingGroups.get(heading) || []; mergedBlock.push(...newTasks); mergedBlock.push(...oldTasks); mergedBlock.push(''); // blank line between groups } // --- Tidy whitespace at seams --- while (remaining.length && remaining[remaining.length - 1].trim() === '') { remaining.pop(); } // --- Reconstruct --- // Order: active content → ## Archive → merged archived tasks const output = [ remaining.join('\n'), '', ARCHIVE_HDR, '', ...mergedBlock ].join('\n').trimEnd(); editor.setText(output); })();
Options
-
After Success Nothing Notification Info Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.