Skip to content

Commit 4b85730

Browse files
committed
Event Automations 1.21.0 update
1 parent 9545360 commit 4b85730

6 files changed

Lines changed: 49 additions & 27 deletions

File tree

dwertheimer.EventAutomations/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ README: [How to use AutoTimeBlocking](https://noteplan.co/n/#/1EF12392-B544-4044
44

55
## What's New in AutoTimeBlocking
66

7+
## [1.21.0] 2024-05-26 @dwertheimer
8+
9+
- added MANUAL_ORDERING mode (for @Thor)
10+
711
## [1.20.0] 2024-02-23 @dwertheimer - thx @Werwowolf
812

913
- Feature: add named timeframes in settings (e.g. "morning", "early", "afternoon") and a task tagged with #afternoon will get placed there

dwertheimer.EventAutomations/plugin.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"plugin.name": "🗓 AutoTimeBlocking / Events",
66
"plugin.description": "Various Event Automations:\n- Automatically find time in your calendar and create Time Blocks for items marked for today,\n- Write out synced copies of Today's todos (without the AutoTimeBlocking), and\n- Create calendar events for all text items under a specific heading",
77
"plugin.author": "dwertheimer",
8-
"plugin.version": "1.20.0",
9-
"plugin.lastUpdateInfo": "1.20.0: Add timeframes tags to have tasks placed in a time of day (see readme). Also Sort todos by priority then date (oldest to newest), then duration. Bug fix: Ignore backlinks which are not todos",
8+
"plugin.version": "1.21.0",
9+
"plugin.lastUpdateInfo": "1.21.0: Add Manual Ordering mode (orders todos in today's note by the order in the note) -- feature request from @Thor\n Previously:\n- Add timeframes tags to have tasks placed in a time of day (see readme). Also Sort todos by priority then date (oldest to newest), then duration. Bug fix: Ignore backlinks which are not todos",
1010
"plugin.dependencies": [],
1111
"plugin.script": "script.js",
1212
"plugin.url": "https://noteplan.co/n/#/1EF12392-B544-4044-AC7A-428F57EB2DFC",
@@ -345,9 +345,10 @@
345345
"choices": [
346346
"PRIORITY_FIRST",
347347
"LARGEST_FIRST",
348-
"BY_TIMEBLOCK_TAG"
348+
"BY_TIMEBLOCK_TAG",
349+
"MANUAL_ORDERING"
349350
],
350-
"description": "PRIORITY_FIRST places the highest priority (most !'s) first (if there's a slot) and then continues down the priority stack. LARGEST_FIRST tries to place the longest/largest duration item first. BY_TIMEBLOCK_TAG will try to slot items into a pre-existing timeblock that matches a tag on the task (e.g. a pre-existing timeblock called \"production\" and a task \"* do something #production\"). Will then fall back to PRIORITY_FIRST if no matching timeblock is found.",
351+
"description": "PRIORITY_FIRST places the highest priority (most !'s) first (if there's a slot) and then continues down the priority stack. LARGEST_FIRST tries to place the longest/largest duration item first. BY_TIMEBLOCK_TAG will try to slot items into a pre-existing timeblock that matches a tag on the task (e.g. a pre-existing timeblock called \"production\" and a task \"* do something #production\"). Will then fall back to PRIORITY_FIRST if no matching timeblock is found. MANUAL_ORDERING limits tasks to ones in today's note and orders them in the order they appear in the note.",
351352
"default": "PRIORITY_FIRST",
352353
"required": true
353354
},

dwertheimer.EventAutomations/src/NPTimeblocking.js

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -298,13 +298,17 @@ export async function insertSyncedCopiesOfTodayTodos(passBackResults?: string):
298298
await saveEditorIfNecessary()
299299
logDebug(pluginJson, `insertSyncedCopiesOfTodayTodos after saveEditorIfNecessary`)
300300
const start = Editor.selection?.start // try to keep it from scrolling to end of doc
301-
const todosParagraphs = await getTodaysFilteredTodos(config)
302-
clof(todosParagraphs, 'insertSyncedCopiesOfTodayTodos todosParagraphs', ['filename', 'content'], true)
301+
const todosParagraphs = await getTodaysFilteredTodos(config, true)
302+
clof(todosParagraphs, 'insertSyncedCopiesOfTodayTodos todosParagraphs', ['filename', 'type', 'content'], true)
303303
const sortedParasExcludingCurrentNote = sortListBy(
304304
todosParagraphs.filter((p) => p.filename !== Editor.filename),
305305
'content',
306306
)
307-
clof(sortedParasExcludingCurrentNote, 'insertSyncedCopiesOfTodayTodos sortedParasExcludingCurrentNote', ['filename', 'content'])
307+
clof(sortedParasExcludingCurrentNote, 'insertSyncedCopiesOfTodayTodos sortedParasExcludingCurrentNote ${sortedParasExcludingCurrentNote.length} items', [
308+
'filename',
309+
'type',
310+
'content',
311+
])
308312
if (passBackResults && /[Yy]es/.test(passBackResults)) {
309313
// called from a template, so send a string back
310314
const syncedList = getSyncedCopiesAsList(sortedParasExcludingCurrentNote)
@@ -445,7 +449,7 @@ export async function markDoneAndRecreateTimeblocks(incoming: string | null = nu
445449
* @param {AutoTimeBlockingConfig} config - The configuration object for auto time blocking.
446450
* @param {Object} pluginJson - Plugin metadata for logging purposes.
447451
*/
448-
function initializeAndLogStart(config: AutoTimeBlockingConfig, pluginJson: Object): void {
452+
function initializeAndLogStart(config: AutoTimeBlockingConfig): void {
449453
const { timeBlockTag } = config
450454

451455
// Log the start of the operation with the current time
@@ -468,7 +472,7 @@ function initializeAndLogStart(config: AutoTimeBlockingConfig, pluginJson: Objec
468472
* @param {Object} pluginJson - Plugin metadata for logging purposes.
469473
* @returns {Array<TParagraph>} - The sorted list of todo items, ready for time block allocation.
470474
*/
471-
function categorizeAndSortTasks(todosWithLinks: $ReadOnlyArray<TParagraph>, pluginJson: Object): Array<SortableParagraphSubset> {
475+
function categorizeAndSortTasks(todosWithLinks: $ReadOnlyArray<TParagraph>, config: AutoTimeBlockingConfig): Array<SortableParagraphSubset> {
472476
if (todosWithLinks.length === 0) {
473477
logDebug(pluginJson, `No todos to categorize and sort.`)
474478
return []
@@ -481,7 +485,8 @@ function categorizeAndSortTasks(todosWithLinks: $ReadOnlyArray<TParagraph>, plug
481485
// Combine open and scheduled tasks, then sort by priority
482486
const openOrScheduledForToday = [...(tasksByType.open ?? []), ...(tasksByType.scheduled ?? [])]
483487
clof(openOrScheduledForToday, `categorizeAndSortTasks openOrScheduledForToday`, ['filename', 'type', 'content'], true)
484-
const sortedTodos = sortListBy(openOrScheduledForToday, ['-priority', 'filename', '-duration'])
488+
const sortKeys = config.mode === 'MANUAL_ORDERING' ? ['lineIndex'] : ['-priority', 'filename', '-duration']
489+
const sortedTodos = sortListBy(openOrScheduledForToday, sortKeys)
485490
clof(sortedTodos, `categorizeAndSortTasks sortedTodos`, ['priority', 'filename', 'duration', 'content'], true)
486491
logDebug(pluginJson, `After sortListBy, sorted ${sortedTodos.length} tasks by priority.`)
487492

@@ -499,7 +504,7 @@ function categorizeAndSortTasks(todosWithLinks: $ReadOnlyArray<TParagraph>, plug
499504
* @param {Object} pluginJson - Plugin metadata for logging and debugging.
500505
* @returns {Promise<?Array<string>>} - The results to be passed back, if any.
501506
*/
502-
function handleNoTodosOrResults(passBackResults: boolean, timeBlockTextList: ?Array<string>, pluginJson: Object): Array<string> {
507+
function handleNoTodosOrResults(passBackResults: boolean, timeBlockTextList: ?Array<string>): Array<string> {
503508
// Check if there are no todos or results to pass back
504509
if (!passBackResults) {
505510
const message =
@@ -574,12 +579,16 @@ async function generateTimeBlocks(
574579
): Promise<{ blockList: Array<string>, noTimeForTasks: Object, timeBlockTextList: Array<string> }> {
575580
// Generate a populated time map for today
576581
const calendarMapWithEvents = await getPopulatedTimeMapForToday(dateStr, config.intervalMins, config)
577-
logDebug(pluginJson, `After getPopulatedTimeMapForToday, ${calendarMapWithEvents.length} timeMap slots`)
578-
582+
logDebug(pluginJson, `generateTimeBlocks: After getPopulatedTimeMapForToday, ${calendarMapWithEvents.length} timeMap slots`)
583+
clof(sortedTodos, `generateTimeBlocks sortedTodos`, ['lineIndex', 'content'], true)
579584
// Calculate time blocks for events based on the populated time map and sorted todo tasks
580585
const eventsToTimeblock = getTimeBlockTimesForEvents(calendarMapWithEvents, sortedTodos, config)
581-
logDebug(pluginJson, `After getTimeBlockTimesForEvents`)
582-
586+
logDebug(
587+
pluginJson,
588+
`generateTimeBlocks after getTimeBlockTimesForEvents; eventsToTimeblock.timeMap.length=${eventsToTimeblock.timeMap.length}, eventsToTimeblock.blockList.length=${
589+
eventsToTimeblock.blockList.length
590+
} eventsToTimeblock.timeBlockTextList.length=${eventsToTimeblock?.timeBlockTextList?.toString() || ''}`,
591+
)
583592
// Prepare the list of text entries for time blocks
584593
const { blockList, noTimeForTasks } = eventsToTimeblock
585594
let { timeBlockTextList } = eventsToTimeblock
@@ -610,26 +619,26 @@ async function generateTimeBlocks(
610619
*/
611620
export async function createTimeBlocksForTodaysTasks(config: AutoTimeBlockingConfig = getConfig(), completedItems: Array<TParagraph> = []): Promise<?Array<string>> {
612621
// Step 1: Initialize and log start
613-
initializeAndLogStart(config, pluginJson)
622+
initializeAndLogStart(config)
614623

615624
// Step 2: Fetch and prepare todos
616-
const cleanTodayTodoParas = await gatherAndPrepareTodos(config, completedItems, pluginJson)
625+
const cleanTodayTodoParas = await gatherAndPrepareTodos(config, completedItems)
617626

618627
// Step 3: Categorize and sort tasks
619-
const sortedTodos = categorizeAndSortTasks(cleanTodayTodoParas, pluginJson)
628+
const sortedTodos = categorizeAndSortTasks(cleanTodayTodoParas, config)
620629

621630
// Step 4: Generate time blocks
622631
const dateStr = getDateStringFromCalendarFilename(Editor.filename) // Assuming this utility function exists and is accurate
623632
if (!dateStr) {
624-
return handleNoTodosOrResults(config.passBackResults || false, null, pluginJson)
633+
return handleNoTodosOrResults(config.passBackResults || false, null)
625634
}
626635

627-
const { blockList, noTimeForTasks, timeBlockTextList } = await generateTimeBlocks(sortedTodos, dateStr, config, pluginJson)
636+
const { blockList, noTimeForTasks, timeBlockTextList } = await generateTimeBlocks(sortedTodos, dateStr, config)
628637

629638
// Check if time blocks were successfully generated
630639
if (blockList.length === 0 && Object.keys(noTimeForTasks).length === 0) {
631640
// If no blocks were created and no tasks are without time, handle accordingly
632-
return handleNoTodosOrResults(config.passBackResults || false, null, pluginJson)
641+
return handleNoTodosOrResults(config.passBackResults || false, null)
633642
}
634643

635644
// Step 5: Insert and finalize time blocks
@@ -640,5 +649,5 @@ export async function createTimeBlocksForTodaysTasks(config: AutoTimeBlockingCon
640649
}
641650

642651
// Step 6: Handle no todos or results scenario and return results
643-
return handleNoTodosOrResults(config.passBackResults || false, timeBlockTextList, pluginJson)
652+
return handleNoTodosOrResults(config.passBackResults || false, timeBlockTextList)
644653
}

dwertheimer.EventAutomations/src/byTagMode.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export function handleUnprocessedTasks(
7676
}
7777

7878
config.mode = 'PRIORITY_FIRST'
79-
clof(finalUnprocessedTasks, `handleUnprocessedTasks finalUnprocessedTasks=`)
79+
clof(finalUnprocessedTasks, `handleUnprocessedTasks finalUnprocessedTasks=`, 'content', true)
8080

8181
return matchTasksToSlots(finalUnprocessedTasks, { blockList: newBlockList, timeMap }, config)
8282
}

dwertheimer.EventAutomations/src/timeblocking-helpers.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,10 @@ export function getTimeBlockTimesForEvents(timeMap: IntervalMap, todos: Array<So
658658
newInfo = processByTimeBlockTag(sortedTaskList, { blockList: blocksAvailable, timeMap: availableTimes }, config)
659659
break
660660
}
661+
case 'MANUAL_ORDERING': {
662+
const sortedTaskList = sortListBy(todosWithDurations, ['lineIndex'])
663+
newInfo = matchTasksToSlots(sortedTaskList, { blockList: blocksAvailable, timeMap: availableTimes }, config)
664+
}
661665
}
662666
} else {
663667
logDebug(

dwertheimer.EventAutomations/src/timeblocking-shared.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export async function createSyncedCopies(todos: Array<SortableParagraphSubset>,
6262
* @param {Object} pluginJson - Plugin metadata for logging purposes.
6363
* @returns {Promise<Array<TParagraph>>} - The prepared list of todo items for today.
6464
*/
65-
export async function gatherAndPrepareTodos(config: AutoTimeBlockingConfig, completedItems: Array<TParagraph>, pluginJson: Object): Promise<$ReadOnlyArray<TParagraph>> {
65+
export async function gatherAndPrepareTodos(config: AutoTimeBlockingConfig, completedItems: Array<TParagraph>): Promise<$ReadOnlyArray<TParagraph>> {
6666
deleteParagraphsContainingString(Editor, config.timeBlockTag)
6767

6868
// Fetch todo items for today
@@ -118,17 +118,19 @@ export function getConfig(): AutoTimeBlockingConfig {
118118
* - items in the current note that are synced tasks to elsewhere (will be in references also)
119119
*
120120
* @param {*} config
121+
* @param {Boolean} isSyncedCopyRun - true if we are just trying to get synced copies output (makes a difference in MANUAL_ORDERING mode)
121122
* @returns
122123
*/
123-
export function getTodaysFilteredTodos(config: AutoTimeBlockingConfig): Array<TParagraph> {
124+
export function getTodaysFilteredTodos(config: AutoTimeBlockingConfig, isSyncedCopyRun = false): Array<TParagraph> {
124125
const { includeTasksWithText, excludeTasksWithText, includeAllTodos, timeBlockTag } = config
125126
// filter down to just the open todos
126127
const backlinkParas = getTodaysReferences(Editor.note).filter((p) => p.type === 'open')
127128
logDebug(pluginJson, `Found ${backlinkParas.length} backlink paras`)
128129
clof(backlinkParas, `getTodaysFilteredTodos backlinkParas filtered to open`, ['filename', 'type', 'content'], true)
129-
let todosInNote = Editor.note ? findOpenTodosInNote(Editor.note, includeAllTodos) : []
130+
let todosInNote = Editor.note ? findOpenTodosInNote(Editor.note, includeAllTodos).filter((p) => p.type === 'open') : []
130131
if (todosInNote.length > 0) {
131132
logDebug(pluginJson, ` getTodaysFilteredTodos: todosInNote Found ${todosInNote.length} items in today's note. Adding them to the possibilities.`)
133+
clof(todosInNote, `getTodaysFilteredTodos todosInNote filtered to open`, ['filename', 'type', 'content'], true)
132134
// we want to eliminate linked lines (for synced lines on the page)
133135
// because these should be in the references from other pages
134136
// but it's possible that this is a normal task in the note that is not in references, so for now, commenting this filter out
@@ -141,7 +143,8 @@ export function getTodaysFilteredTodos(config: AutoTimeBlockingConfig): Array<TP
141143
todosInNote = todosInNote.filter((todo) => !isTimeBlockLine(todo.content)) // if a user is using the todo character for timeblocks, eliminate those lines
142144
todosInNote = todosInNote.filter((todo) => !new RegExp(timeBlockTag).test(todo.content)) // just to be extra safe, make sure we're not adding our own timeblocks
143145
}
144-
const backLinksAndNoteTodos = [...backlinkParas, ...todosInNote]
146+
const backLinksAndNoteTodos = config.mode === 'MANUAL_ORDERING' && !isSyncedCopyRun ? todosInNote : [...backlinkParas, ...todosInNote]
147+
145148
logDebug(pluginJson, `Found ${backLinksAndNoteTodos.length} backlinks+today-note items (may include completed items)`)
146149
const undupedBackLinkParas = eliminateDuplicateSyncedParagraphs(backLinksAndNoteTodos, 'first', true)
147150
logDebug(pluginJson, `Found ${undupedBackLinkParas.length} undupedBackLinkParas after duplicate elimination`)
@@ -152,6 +155,7 @@ export function getTodaysFilteredTodos(config: AutoTimeBlockingConfig): Array<TP
152155
logDebug(pluginJson, `After includeTasksWithPatterns (${(includeTasksWithText ?? []).join(', ')}), ${todosParagraphs.length} potential items`)
153156
todosParagraphs = Array.isArray(excludeTasksWithText) && excludeTasksWithText?.length > 0 ? excludeTasksWithPatterns(todosParagraphs, excludeTasksWithText) : todosParagraphs
154157
logDebug(pluginJson, `After excludeTasksWithPatterns (${(excludeTasksWithText ?? []).join(', ')}), ${todosParagraphs.length} potential items`)
158+
clof(todosParagraphs, `getTodaysFilteredTodos todosParagraphs`, ['filename', 'type', 'content'], true)
155159
return todosParagraphs.filter((t) => t.content)
156160
}
157161

0 commit comments

Comments
 (0)