Action

Add to Obsidian Daily Note Section

Posted by FlohGro, Last update almost 2 years ago

UPDATES

almost 2 years ago

Bugfixing

show all updates...

almost 2 years ago

Bugfixing

almost 2 years ago

Fix for adding text to wrong section

almost 2 years ago

added the ability to append or prepend to a section

almost 2 years ago

Added textAddPrefix to newly added line

almost 2 years ago

Added quotes around configured section in alert

created by @FlohGro / more on my Website

Add to Obsidian Daily Note Section

This action will add the contents of the current draft into the configured section in todays Daily Note in Obsidian.
If the configured section is not present, you can choose if the action should append or prepend the content. You can also configure if you want to add a text prefix (e.g. to add a todo or a bullet point to the daily note). If you want to use different prefixes, you can duplicate the action and configure and rename the duplicate accordingly.

[Configuration]

Before you can use the action you need to configure it depending on your setup in Obsidian and personal preference.

All configuration parameters are adapted in the „Define Template Tag“ steps in the Action. To change the configurations edit them to match your setup - don’t change the names of the template tags since the action won’t work anymore afterwards. The following parameters must be adapted:

  • obsidianVaultBookmarkName: the name of the folder bookmark that will be created to access the files in your vault (see the Drafts documentation for more information about Folder Bookmarks). When you run the Action the first time it should prompt you to select a folder for that bookmark. Default: Obsidian Vault
  • dateFormat: the date format of your daily notes in Obsidian. You need to use the Drafts specific notation documented here Default: %Y-%m-%d which matches YYYY-MM-DD in Obsidian
  • dailyNotesFolderPath: the path where obsidian creates the daily notes (matches the setting for „New file location“ in the daily notes settings section). Default: empty
  • dailyNotesSection: the section in the daily note to where you want to add the content of the current draft. the section must be unique in the Daily Note. Default: UNCONFIGURED
  • textAddMode: you can choose if the action should prepend or append the draft to the configured daily note section - only prepend or append are allowed. Default: append
  • textAddPrefix: an optional prefix that will be prepended to the content of the Draft

IMPORTANT: If you‘re running the Action the first time and it shows an error that the file is not existing even when the file exists in Obsidian then please go into the Settings of Drafts, navigate to „Bookmarks“ and make sure that the configured bookmark name is not set to „-unknown-“. If it is set to Unknown then tap „Select Folder“ and navigate to your Obsidian Vault in the files UI, select it and tap „Done“ in the upper right corner.

[Usage]

The action directly accessed the files so Obsidian won’t be opened when adding something to the daily note. If you didn’t open obsidian on that day, the daily note file will not be created or synced into the folder. Make sure to open Obsidian on the device if you see the alert that the file is missing. This is to prevent sync issues and ensure that potential templates for daily notes are applied first.

Simply run the the Action to add the content of the current draft into the configured section of your Daily Note in Obsidian. When you e.g. want to use the Action to add tasks to your Daily Note then you need to configure - [ ] as textAddPrefix. If you have different usecases, just duplicate the Action and configure it differently.


If you find this useful and want to support me you can

Buy Me A Coffee

Steps

  • defineTemplateTag

    name
    obsidianVaultBookmarkName
    template
    Obsidian Vault
  • defineTemplateTag

    name
    dateFormat
    template
    %Y-%m-%d
  • defineTemplateTag

    name
    dailyNotesFolderPath
    template
  • defineTemplateTag

    name
    dailyNotesSection
    template
    UNCONFIGURED
  • defineTemplateTag

    name
    textAddMode
    template
    append
  • defineTemplateTag

    name
    textAddPrefix
    template
  • script

    // add to section in obsidian daily note
    
    const obsidianVaultBookmarkName = draft.processTemplate("[[obsidianVaultBookmarkName]]")
    const dateFormat = draft.processTemplate("[[dateFormat]]");
    
    let dailyNoteFileName = draft.processTemplate("[[date|" + dateFormat + "]]") + ".md";
    
    const dailyNotesFolderPath = draft.processTemplate("[[dailyNotesFolderPath]]") + "/";
    
    let tmpDailyNoteSection = draft.processTemplate("[[dailyNotesSection]]").trim()
    
    while(tmpDailyNoteSection.length > 0 &&tmpDailyNoteSection.startsWith("#")){
      tmpDailyNoteSection = tmpDailyNoteSection.slice(1)
    }
    
    const dailyNoteSection = tmpDailyNoteSection.trim();
    
    
    
    
    dailyNoteFileName = dailyNotesFolderPath + dailyNoteFileName //"2022\.10\.25.md"
    let bookmark = Bookmark.findOrCreate(obsidianVaultBookmarkName);
    
    
    const configEntryPrefix = "- "
    const textAddPrefix = draft.processTemplate("[[textAddPrefix]]");
    const textAddMode = draft.processTemplate("[[textAddMode]]");
    let gLinesToRepace = []
    let gFirstSection = ""
    let gSecondSection = ""
    let gFoundSections = [];
    
    let fm = FileManager.createForBookmark(bookmark);
    
    if (fm.exists(dailyNoteFileName)) {
        // file exists
        let fileContent = fm.readString(dailyNoteFileName)
    
        let fileSections = getMdSections(fileContent)
    
        if (fileSections.includes(dailyNoteSection)) {
    
            if (fileSections.filter(x => x === dailyNoteSection).length > 1) {
                const errorStr = "Section \"" + dailyNoteSection + "\" was found multiple times in the Daily Note. Clean up this mess and try again"
                context.fail(errorStr)
                alert("Error:\n" + errorStr)
                
            } else {
                let relevantSections = getConfiguredAndFollowingSection(fileSections, dailyNoteSection)
                let adaptText = true;
                let relevantText = ""
                if (relevantSections.length == 1) {
                    // its the last section in the note
                    // send some random generated text that noone will ever have in a note into the function to enforce that it will be identified as the last section in the note
                    relevantText = getTextBetweenSections(fileContent, relevantSections[0], "dad45439-1713-426e-b873-2c6a4883381a-28a6d320-3859-4d8f-b71c-05b3a0c8d323-a2f46eb4-2c86-42d8-a23b-26fa2c8f5f94")
                } else if (relevantSections.length == 2) {
                    // get text between the two sections
                    relevantText = getTextBetweenSections(fileContent, relevantSections[0], relevantSections[1])
                }
    				let textToInsert = ""
    				let linesToInsert = [gFirstSection,gSecondSection]
    				// distinguish newline amount if there is currently no text between the two sections:
    				alert(gSecondSection)
    				let firstSectionInsert = ""
    				let secondSectionInsert = ""
    				if(gLinesToReplace.join("\n") == linesToInsert.join("\n"))				{
    					firstSectionInsert = gFirstSection + "\n"
    					secondSectionInsert = (gSecondSection == "" ? "" : "\n\n" + gSecondSection)
    				} else{
    					firstSectionInsert = gFirstSection + "\n\n"
    					secondSectionInsert = (gSecondSection == "" ? "" : "\n\n" + gSecondSection)
    				}
                // check text add mode and add text accordingly:
                if (textAddMode == "append") {
                alert(relevantText)
                		textToInsert = fileContent.replace(gLinesToReplace.join("\n"), firstSectionInsert + relevantText + "\n" + textAddPrefix + draft.content + secondSectionInsert)
                } else if (textAddMode == "prepend") {
                    textToInsert = fileContent.replace(gLinesToReplace.join("\n"), firstSectionInsert + textAddPrefix + draft.content + "\n" + relevantText + secondSectionInsert)
                } else {
                    console.log("invalid text add mode")
            		alert("invalid text add mode configured - only \"append\" or \"prepend\" are allowed")
            		context.fail()
            		adaptText = false;
                }
    
                if (adaptText && !fm.writeString(dailyNoteFileName, textToInsert)) {
                    console.log("failed writing content to file")
                    alert("failed writing content to file - this should not happen. please contact FlohGro via Twitter or the Drafts Forum.")
                    context.fail()
                }
            }
    
        } else {
            let p = new Prompt()
            p.title = "Section not existing"
            p.message = "the configured section \"" + draft.processTemplate("[[dailyNotesSection]]") + "\" is not existing in the Daily Note right now.\nFound the following sections:\n" + gFoundSections + "\nmaybe check for additional space characters in your configuration or the daily note sections.\n\nSelect one of the following options:"
            p.addButton("append draft to Daily Note", 1)
            p.addButton("prepend draft to Daily Note", 2)
            p.addButton("abort adding draft to Daily Note", 0)
            p.isCancellable = false
    
            p.show()
    
            switch (p.buttonPressed) {
                case 0:
                    context.cancel("aborted by user");
                    app.displayWarningMessage("Aborted adding to Daily Note");
                    break;
                case 1:
                    fileContent = fileContent + "\n\n" + textAddPrefix + draft.content;
                    break;
                case 2:
                    fileContent = textAddPrefix + draft.content + "\n\n" + fileContent;
                    break;
            }
            if (!fm.writeString(dailyNoteFileName, fileContent)) {
                    console.log("failed writing content to file")
                    alert("failed writing content to file - this should not happen. please contact FlohGro via Twitter or the Drafts Forum.")
                    context.fail()
                }
        }
    
    
    } else {
        // file does note exist
        console.log("daily notes file does not (yet) exist")
        alert("daily notes file does not (yet) exist, create it in obsidian")
        context.fail()
    }
    
    function getMdSections(content) {
        // regex based on this thread: https://stackoverflow.com/questions/70801756/regex-extract-all-headers-from-markdown-string
        const regex = /#{1,6} (.+)(?=\n)/g;
        let sections = [];
        let m;
    		let trimmedSections = [];
        while ((m = regex.exec(content)) !== null) {
            if (m.index === regex.lastIndex) {
                regex.lastIndex++;
            }
    
            m.forEach((match, groupIndex) => {
                if (groupIndex == 1) {
                    sections.push(match)
                }
    
            });
        }
    	 gFoundSections = sections
        return sections
    }
    
    function getConfiguredAndFollowingSection(sections, configuredSection) {
        let result = []
        // get index of the configuredSection
        let sectionIndex = sections.indexOf(configuredSection)
    
        // check if another section is existing after the configured one
        if (sections.length > sectionIndex) {
            result.push(sections[sectionIndex])
            result.push(sections[sectionIndex + 1])
        } else {
            result.push(sections[sectionIndex])
        }
    
        return result
    }
    
    function getTextBetweenSections(content, firstSection, secondSection) {
    
        let lines = content.split("\n");
        firstIndex = -1
        secondIndex = -1
        let curIndex = 0;
        for (line of lines) {
    
            if (line.endsWith(firstSection) && line.startsWith("#")) {
                firstIndex = curIndex;
                gFirstSection = line
            }
    
            // prevent that secondSection is found above first section
            if (firstIndex != -1) {
                if (line.endsWith(secondSection) && line.startsWith("#")) {
                    secondIndex = curIndex;
                    gSecondSection = line
                }
            }
            curIndex++
        }
    
        // if secondIndex is still -1 the configured section is the last section in the document
        if (secondIndex == -1) {
            secondIndex = lines.length 
        }
    
        // get lines between the two sections into an array
        let relevantLines = lines.slice(firstIndex + 1, secondIndex)
        gLinesToReplace = lines.slice(firstIndex, secondIndex + 1);
    
        // remove empty lines at the beginning
        let i = 0
    
    
        while (relevantLines.length > 0 && relevantLines[0].trim() == "") {
            relevantLines.shift()
        }
    
        // remove empty lines at the end
        while (relevantLines.length > 0 && relevantLines[relevantLines.length - 1].trim() == "") {
            relevantLines.pop()
        }
        return relevantLines.join("\n")
    
    }

Options

  • After Success Trash
    Notification Info
    Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.