Skip to content

Commit 0aea4be

Browse files
committed
NoteHelpers v1.2.1
1 parent 279cb3a commit 0aea4be

File tree

7 files changed

+83
-49
lines changed

7 files changed

+83
-49
lines changed

.prettierrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
{
2-
"semi": false
2+
"semi": false,
3+
"quoteProps": "as-needed",
4+
"templateCurlySpacing": false,
5+
"experimentalOperatorPosition": "start",
6+
"bracketSameLine": false,
7+
"arrowParens": "always",
8+
"objectWrap": "preserve"
39
}

jgclark.NoteHelpers/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# What's changed in 📙 Note Helpers plugin?
22
For more details see the [plugin's README](https://github.com/NotePlan/plugins/tree/main/jgclark.NoteHelpers/).
33

4+
## [1.2.1] - 2025-09-19
5+
- improve and fix folder picker in various commands (including updating the sort order to match the app -- thanks for pointing this out, @tastapod)
6+
- allow **delete note** command to run on Teamspace notes (if running v3.18.2 or above).
7+
- stop **inconsistent file name** commands from running on Teamspace notes, which are stored in a SQL DB instead of having filenames
8+
49
## [1.2.0] - 2025-08-23
510
- improved display of lists of notes and headings in **jump to heading** and **jump to note's heading**, and include Teamspace notes
611
- various improvements/fixes to the **inconsistent file name** commands. Resolves issues #640, #642, #643 raised by @tastapod.

jgclark.NoteHelpers/plugin.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
"plugin.author": "Jonathan Clark & Eduard Metzger",
88
"plugin.url": "https://github.com/NotePlan/plugins/tree/main/jgclark.NoteHelpers/",
99
"plugin.changelog": "https://github.com/NotePlan/plugins/blob/main/jgclark.NoteHelpers/CHANGELOG.md",
10-
"plugin.version": "1.2.0",
11-
"plugin.lastUpdateInfo": "1.2.0: improvements to displays in 'jump to heading' and 'jump to note heading' commands, and include Teamspace notes. Improvements to 'inconsistent file name' commands.\n1.1.1: add initial support for Teamspaces + bug fix.\n1.1.0: new 'list published notes' command.\n1.1.0: added 'write modified' command to write the modified date to frontmatter (on each save). Can be run by hand or can be included as a trigger using the 'add trigger to note' command. Small improvements to \"new note from selection\".\n1.0.0: move '/new note from ...' commands here from Filer plugin, and revived '/new note' command.\n0.20.3: New 'printEditorDetailed' command to log all paragraph details as well.\n0.20.2: 'printNote' extended to cover backlinks.\n0.20.1: new command 'printNote' for debugging purposes.\n0.20.0: new commands \"unlinked note finder\" and \"delete note\". Bug fix to \"rename note filename\" command.\n0.19.2: fix edge cases with \"add trigger to note\".",
10+
"plugin.version": "1.2.1",
11+
"plugin.lastUpdateInfo": "1.2.1: Allow 'delete note' command to run on Teamspace notes. Stop 'inconsistent file name' commands from running on Teamspace notes. Bug fixes.\n1.2.0: improvements to displays in 'jump to heading' and 'jump to note heading' commands, and include Teamspace notes. Improvements to 'inconsistent file name' commands.\n1.1.1: add initial support for Teamspaces + bug fix.\n1.1.0: new 'list published notes' command.\n1.1.0: added 'write modified' command to write the modified date to frontmatter (on each save). Can be run by hand or can be included as a trigger using the 'add trigger to note' command. Small improvements to \"new note from selection\".\n1.0.0: move '/new note from ...' commands here from Filer plugin, and revived '/new note' command.\n0.20.3: New 'printEditorDetailed' command to log all paragraph details as well.\n0.20.2: 'printNote' extended to cover backlinks.\n0.20.1: new command 'printNote' for debugging purposes.\n0.20.0: new commands \"unlinked note finder\" and \"delete note\". Bug fix to \"rename note filename\" command.\n0.19.2: fix edge cases with \"add trigger to note\".",
1212
"plugin.dependencies": [],
1313
"plugin.script": "script.js",
1414
"plugin.commands": [
@@ -263,6 +263,16 @@
263263
"jsFunction": "triggerFindUnlinkedNotes",
264264
"hidden": true
265265
},
266+
{
267+
"comment": "TODO: delete me soon",
268+
"name": "test: choose folder",
269+
"description": "Test the chooseFolder function",
270+
"jsFunction": "testChooseFolder",
271+
"alias": [
272+
"tcf"
273+
],
274+
"hidden": true
275+
},
266276
{
267277
"name": "Write changed/modified date to frontmatter",
268278
"description": "Write the modified date to frontmatter (on each save). Writes to 'modified' key.",

jgclark.NoteHelpers/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export { renameInconsistentNames } from './lib/commands/renameInconsistentNames'
2222
export { titleToFilename } from './lib/commands/titleToFilename'
2323
export { listPublishedNotes } from './listPublishedNotes'
2424
export { newNote, newNoteFromClipboard, newNoteFromSelection } from './newNote'
25-
export { addTriggerToNote, convertLocalLinksToPluginLinks, addFrontmatterToNote, moveNote, logEditorNoteDetailed, renameNoteFile, trashNote } from './noteHelpers'
25+
export { addTriggerToNote, convertLocalLinksToPluginLinks, addFrontmatterToNote, moveNote, logEditorNoteDetailed, renameNoteFile, trashNote, testChooseFolder } from './noteHelpers'
2626
export {
2727
jumpToDone,
2828
jumpToHeading,

jgclark.NoteHelpers/src/lib/commands/listInconsistentNames.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { chooseFolder, showMessage } from '@helpers/userInput'
1515

1616
/**
1717
* Shows a list of notes with inconsistent names (i.e. where the note title and filename are different).
18+
* Only makes sense for private regular notes.
1819
* @param {string} folderIn - Optional URL-encodedfolder to check for inconsistent names. If not provided, the user will be prompted to choose a folder.
1920
* @returns void
2021
*/
@@ -26,7 +27,8 @@ export async function listInconsistentNames(folderIn: string = ''): Promise<void
2627
folder = decodeURIComponent(folderIn)
2728
} else {
2829
logDebug(pluginJson, 'listInconsistentNames(): Checking for inconsistent names in project notes...')
29-
folder = await chooseFolder('Choose a folder to find inconsistent filenames in')
30+
// Find only private (non-teamspace) notes
31+
folder = await chooseFolder('Choose a note folder to find inconsistent filenames in', false, false, '', true, true)
3032
}
3133

3234
if (!folder) {

jgclark.NoteHelpers/src/lib/commands/renameInconsistentNames.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//-----------------------------------------------------------------------------
33
// Functions to identify and fix where note names and their filenames are inconsistent.
44
// by Leo Melo, readied for the plugin and maintained by @jgclark
5-
// Last updated 2025-06-11 for v1.2.0 by @jgclark
5+
// Last updated 2025-09-14 for v1.2.1 by @jgclark
66
//-----------------------------------------------------------------------------
77

88
import pluginJson from '../../../plugin.json'
@@ -14,10 +14,11 @@ import { chooseFolder, showMessage, showMessageWithList, showMessageYesNoCancel
1414
/**
1515
* Renames all project notes with inconsistent names (i.e. where the note title and filename are different (apart from case)).
1616
* Optionally prompts the user before renaming each note.
17+
* Note: currently only works for private regular notes.
1718
*/
1819
export async function renameInconsistentNames(): Promise<void> {
1920
try {
20-
const directory = await chooseFolder('Choose a folder to rename inconsistent notes in')
21+
const directory = await chooseFolder('Choose a folder to rename inconsistent notes in', true, false, '', true, true) // exclude Teamspace notes
2122

2223
if (!directory) {
2324
logWarn(pluginJson, 'renameInconsistentNames(): No folder chosen. Stopping.')

jgclark.NoteHelpers/src/noteHelpers.js

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,16 @@
22
//-----------------------------------------------------------------------------
33
// Note Helpers plugin for NotePlan
44
// Jonathan Clark & Eduard Metzger
5-
// Last updated 2025-06-06 for v1.2.0 by @jgclark
5+
// Last updated 2025-09-14 for v1.2.1 by @jgclark
66
//-----------------------------------------------------------------------------
77

88
import pluginJson from '../plugin.json'
99
import { clo, JSP, logDebug, logError, logInfo, logWarn, timer } from '@helpers/dev'
1010
import { displayTitle } from '@helpers/general'
1111
import { convertNoteToFrontmatter, printNote } from '@helpers/NPnote' // Note: not the one in 'NPTemplating'
1212
import { addTrigger, noteHasFrontMatter, updateFrontMatterVars, TRIGGER_LIST } from '@helpers/NPFrontMatter'
13-
import { parseTeamspaceFilename } from '@helpers/teamspace'
14-
import {
15-
chooseFolder,
16-
chooseOption,
17-
getInput,
18-
showMessage,
19-
} from '@helpers/userInput'
13+
import { getTeamspaceTitleFromNote } from '@helpers/NPTeamspace'
14+
import {chooseFolder,chooseOption,getInput,showMessage} from '@helpers/userInput'
2015

2116
//-----------------------------------------------------------------
2217
// Settings
@@ -58,9 +53,22 @@ export async function getSettings(): Promise<any> {
5853
//-----------------------------------------------------------------
5954

6055
/**
61-
* Command from Eduard to move a note to a different folder
62-
* @author @eduardme
56+
* Test the chooseFolder() function
57+
* Call: noteplan://x-callback-url/runPlugin?pluginID=jgclark.NoteHelpers&command=test%3A%20choose%20folder
58+
* @author @jgclark
6359
*/
60+
export async function testChooseFolder(): Promise<void> {
61+
try {
62+
const selectedFolder = await chooseFolder(`TEST: Select a folder`, true, true, '', true, false, true)
63+
logInfo('testChooseFolder', `Selected folder: ${selectedFolder}`)
64+
} catch (err) {
65+
logError('noteHelpers/testChooseFolder', err.message)
66+
await showMessage(err.message)
67+
}
68+
}
69+
70+
//-----------------------------------------------------------------
71+
6472
export async function logEditorNoteDetailed(): Promise<void> {
6573
try {
6674
if (!Editor || !Editor.note) {
@@ -95,7 +103,7 @@ export async function moveNote(): Promise<void> {
95103
const res = await showMessage(`NotePlan doesn't allow moving calendar notes.`)
96104
return
97105
}
98-
const selectedFolder = await chooseFolder(`Select a folder for '${title}'`, true, true) // include @Archive as an option, and to create a new folder
106+
const selectedFolder = await chooseFolder(`Select a folder for '${title}'`, true, true) // include @Archive, and new folder options
99107
logDebug('moveNote()', `move ${title} (filename = ${filename}) to ${selectedFolder}`)
100108

101109
const newFilename = DataStore.moveNote(filename, selectedFolder)
@@ -114,28 +122,41 @@ export async function moveNote(): Promise<void> {
114122
//-----------------------------------------------------------------
115123
/**
116124
* Delete a note -- by moving to the special @Trash folder.
117-
* Note: this cannot work on Teamspace notes (at least as of v3.18.1), because the API doesn't support this.
125+
* Note: the following NP API limitations:
126+
* - this does not work for Calendar notes
127+
* - this only works on Teamspace notes from v3.18.2 build 1431
118128
* @author @jgclark
119129
*/
120130
export async function trashNote(): Promise<void> {
121131
try {
122-
const { title, filename } = Editor
123-
if (title == null || filename == null) {
124-
// No note open, so don't do anything.
132+
const { note, filename, type, isTeamspaceNote } = Editor
133+
if (note == null || filename == null) {
125134
throw new Error('No note open. Stopping.')
126135
}
127-
const possibleTeamspaceDetails = parseTeamspaceFilename(filename)
128-
if (possibleTeamspaceDetails.isTeamspace) {
129-
throw new Error('Sorry, I cannot currently move Teamspace notes to the Trash. You will need to do this manually.')
136+
if (type === 'Calendar') {
137+
throw new Error(`Sorry, NotePlan doesn't allow moving Calendar notes to the Trash.`)
138+
}
139+
if (isTeamspaceNote) {
140+
if (NotePlan.environment.buildVersion < 1431) {
141+
throw new Error('Sorry, before NotePlan v3.18.2, I cannot move Teamspace notes to the Trash. You will need to do this manually.')
142+
} else {
143+
showMessage('Note: currently Teamspaces have no trash folder, but a copy will be made inside the Operating System Trash, if you need to recover the note.')
144+
}
130145
}
131146

132-
const newFilename = DataStore.moveNote(filename, '@Trash')
147+
const result = DataStore.trashNote(filename)
133148

134-
if (!newFilename) {
149+
if (result) {
150+
if (isTeamspaceNote) {
151+
logInfo('NoteHelpers/trashNote', `Note '${displayTitle(note)}' from Teamspace '${getTeamspaceTitleFromNote(note)}' (filename '${filename}') was deleted from the Teamspace, and copied to your local @Trash folder.`)
152+
} else {
153+
logInfo('NoteHelpers/trashNote', `Note '${displayTitle(note)}' (filename '${filename}') was moved to the Trash.`)
154+
}
155+
} else {
135156
throw new Error(`Error trying to move note to @Trash`)
136157
}
137158
} catch (err) {
138-
logError(pluginJson, `${err.name}: ${err.message}`)
159+
logError(`NoteHelpers/trashNote`, err.message)
139160
await showMessage(err.message)
140161
}
141162
}
@@ -205,7 +226,7 @@ export async function addTriggerToNote(triggerStringArg: string = ''): Promise<v
205226
logDebug('addTriggerToNote', `- result of updateFrontMatterVars = ${String(res)}`)
206227
} else {
207228
logDebug('addTriggerToNote', `- Editor "${displayTitle(Editor)}" doesn't already have frontmatter`)
208-
await convertNoteToFrontmatter(Editor, `triggers: ${triggerStringArg}`)
229+
await convertNoteToFrontmatter(Editor.note, `triggers: ${triggerStringArg}`)
209230
}
210231
return
211232
} else {
@@ -273,7 +294,7 @@ export function convertLocalLinksToPluginLinks(): void {
273294
let changed = false
274295
for (const para of paragraphs) {
275296
const content = para.content
276-
const newContent = content.replace(/\[(.*?)\]\(\#(.*?)\)/g, (match, label, link) => {
297+
const newContent = content.replace(/\[(.*?)\]\(\#(.*?)\)/g, (_match, label, link) => {
277298
const newLink = `noteplan://x-callback-url/runPlugin?pluginID=jgclark.NoteHelpers&command=jump%20to%20heading&arg1=${encodeURIComponent(link)}`
278299
return `[${label}](${newLink})`
279300
})
@@ -295,7 +316,7 @@ export function convertLocalLinksToPluginLinks(): void {
295316
*/
296317
export async function renameNoteFile(): Promise<void> {
297318
try {
298-
const { note } = Editor
319+
const { note, isTeamspaceNote } = Editor
299320
if (note == null || note.paragraphs.length < 1) {
300321
// No note open, so don't do anything.
301322
throw new Error('No note open, or no content, so nothing to rename.')
@@ -305,27 +326,14 @@ export async function renameNoteFile(): Promise<void> {
305326
throw new Error('Sorry, you cannot rename Calendar notes.')
306327
}
307328
// Don't continue if note is a Teamspace note
308-
const teamspaceDetailsFromFilename = parseTeamspaceFilename(note.filename)
309-
if (teamspaceDetailsFromFilename.isTeamspace) {
329+
if (isTeamspaceNote) {
310330
throw new Error('Sorry, you cannot rename Teamspace notes.')
311331
}
312332

313333
const currentFullPath = note.filename
314-
// TODO: could use chooseFolderV2() here first
334+
// TODO: could use chooseFolder() here first
315335
const requestedPath = await getInput(`Please enter new filename for file (including folder and file extension)`, 'OK', 'Rename file', currentFullPath)
316336
if (typeof requestedPath === 'string') {
317-
// let newFolder = ''
318-
// let newFilename = ''
319-
// if (requestedPath.lastIndexOf('/') > -1) {
320-
// newFolder = requestedPath.substr(0, requestedPath.lastIndexOf('/'))
321-
// newFilename = requestedPath.substr(requestedPath.lastIndexOf('/') + 1)
322-
// } else {
323-
// newFolder = '/'
324-
// newFilename = requestedPath
325-
// }
326-
// logDebug(pluginJson, `${newFolder} / ${newFilename}`)
327-
logDebug(pluginJson, `Requested new filepath = ${requestedPath}`)
328-
329337
const newFilename = note.rename(requestedPath)
330338
logDebug('renameNoteFile()', `Note file renamed from '${currentFullPath}' to '${newFilename}'`)
331339
} else {
@@ -349,10 +357,12 @@ export async function addFrontmatterToNote(note: TNote): Promise<void> {
349357
let thisNote: TNote
350358
if (note == null) {
351359
if (Editor == null) {
352-
throw new Error(`No note open to convert.`)
353-
} else {
354-
thisNote = Editor
360+
throw new Error(`No note open to convert. Stopping.`)
361+
}
362+
if (!Editor.note) {
363+
throw new Error(`No note open in the Editor. Stopping.`)
355364
}
365+
thisNote = Editor.note
356366
} else {
357367
thisNote = note
358368
}

0 commit comments

Comments
 (0)