From f43768d4de425cedfde776865c2316577ffd1a0d Mon Sep 17 00:00:00 2001 From: ShivamChaudhary Date: Sat, 21 Feb 2026 03:37:56 +0530 Subject: [PATCH] fix: validate default template still has template tag before using it --- src/index.ts | 34 +++++++++++++++++++++++++++------- src/utils/templates.ts | 33 ++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index fbfdb73..8297df9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ import { CommandsPanel } from "./views/commandsPanel"; const DOCUMENTATION_URL = "https://github.com/joplin/plugin-templates#readme"; joplin.plugins.register({ - onStart: async function() { + onStart: async function () { // Register setting section await PluginSettingsRegistry.registerSettings(); @@ -199,22 +199,32 @@ joplin.plugins.register({ label: "Create note from default template", execute: async () => { let defaultTemplate: Note | null = null; + let defaultTemplateIdWasSet = false; const defaultTemplatesConfig = await DefaultTemplatesConfigSetting.get(); const currentFolderId = await getSelectedFolder(); if (currentFolderId in defaultTemplatesConfig) { - defaultTemplate = await getTemplateFromId(defaultTemplatesConfig[currentFolderId].defaultNoteTemplateId); + const notebookDefaultId = defaultTemplatesConfig[currentFolderId].defaultNoteTemplateId; + if (notebookDefaultId) defaultTemplateIdWasSet = true; + defaultTemplate = await getTemplateFromId(notebookDefaultId); } if (defaultTemplate === null) { - defaultTemplate = await getTemplateFromId(await DefaultNoteTemplateIdSetting.get()); + const globalDefaultId = await DefaultNoteTemplateIdSetting.get(); + if (globalDefaultId) defaultTemplateIdWasSet = true; + defaultTemplate = await getTemplateFromId(globalDefaultId); } if (defaultTemplate) { return await performActionWithParsedTemplate(TemplateAction.NewNote, defaultTemplate); } - await joplin.views.dialogs.showMessageBox("No default note template is set."); + + if (defaultTemplateIdWasSet) { + await joplin.views.dialogs.showMessageBox("The note set as the default template is no longer a template. Please set a new default template via Tools \u2192 Templates \u2192 Default templates."); + } else { + await joplin.views.dialogs.showMessageBox("No default note template is set."); + } } })); @@ -223,22 +233,32 @@ joplin.plugins.register({ label: "Create to-do from default template", execute: async () => { let defaultTemplate: Note | null = null; + let defaultTemplateIdWasSet = false; const defaultTemplatesConfig = await DefaultTemplatesConfigSetting.get(); const currentFolderId = await getSelectedFolder(); if (currentFolderId in defaultTemplatesConfig) { - defaultTemplate = await getTemplateFromId(defaultTemplatesConfig[currentFolderId].defaultTodoTemplateId); + const notebookDefaultId = defaultTemplatesConfig[currentFolderId].defaultTodoTemplateId; + if (notebookDefaultId) defaultTemplateIdWasSet = true; + defaultTemplate = await getTemplateFromId(notebookDefaultId); } if (defaultTemplate === null) { - defaultTemplate = await getTemplateFromId(await DefaultTodoTemplateIdSetting.get()); + const globalDefaultId = await DefaultTodoTemplateIdSetting.get(); + if (globalDefaultId) defaultTemplateIdWasSet = true; + defaultTemplate = await getTemplateFromId(globalDefaultId); } if (defaultTemplate) { return await performActionWithParsedTemplate(TemplateAction.NewTodo, defaultTemplate); } - await joplin.views.dialogs.showMessageBox("No default to-do template is set."); + + if (defaultTemplateIdWasSet) { + await joplin.views.dialogs.showMessageBox("The note set as the default template is no longer a template. Please set a new default template via Tools \u2192 Templates \u2192 Default templates."); + } else { + await joplin.views.dialogs.showMessageBox("No default to-do template is set."); + } } })); diff --git a/src/utils/templates.ts b/src/utils/templates.ts index 54e6429..2c1b92c 100644 --- a/src/utils/templates.ts +++ b/src/utils/templates.ts @@ -5,6 +5,7 @@ import { TemplatesSourceSetting, TemplatesSource } from "../settings/templatesSo import { LocaleGlobalSetting } from "../settings/global"; import { encode, decode } from "html-entities"; import { AUTO_FOCUS_SCRIPT } from "./dialogHelpers"; +import { fetchAllItems } from "./dataApi"; export interface Note { id: string; @@ -58,7 +59,7 @@ const getAllTemplates = async () => { export async function getUserTemplateSelection(dialogHandle: string, property?: NoteProperty, promptLabel = "Template:"): Promise { try { const templates = await getAllTemplates(); - + if (templates.length === 0) { await joplin.views.dialogs.showMessageBox("No templates found! Please create a template and try again."); return null; @@ -97,15 +98,15 @@ export async function getUserTemplateSelection(dialogHandle: string, property?: await joplin.views.dialogs.setFitToContent(dialogHandle, true); const result = await joplin.views.dialogs.open(dialogHandle); - + if (result.id === "cancel") { return null; } - + // Get the template value and decode HTML entities const templateValue = result.formData?.["templates-form"]?.template; const decodedValue = templateValue ? decode(templateValue) : null; - + return decodedValue; } catch (error) { console.error("Error in getUserTemplateSelection:", error); @@ -113,13 +114,35 @@ export async function getUserTemplateSelection(dialogHandle: string, property?: } } +/** + * Checks whether a given note still has the 'template' tag. + * Returns false if the note has no template tag or if the check fails. + */ +export const isNoteATemplate = async (noteId: string): Promise => { + try { + const tags = await fetchAllItems(["notes", noteId, "tags"], { fields: ["id", "title"] }); + return tags.some((tag: { title: string }) => tag.title === "template"); + } catch (error) { + console.error("Error checking if note is a template", error); + return false; + } +}; + export const getTemplateFromId = async (templateId: string | null): Promise => { if (!templateId) { return null; } try { - return await joplin.data.get([ "notes", templateId ], { fields: ["id", "title", "body"] }); + const note = await joplin.data.get(["notes", templateId], { fields: ["id", "title", "body"] }); + + const stillATemplate = await isNoteATemplate(templateId); + if (!stillATemplate) { + console.warn(`Note "${note.title}" (id: ${templateId}) is set as a default template but no longer has the 'template' tag.`); + return null; + } + + return note; } catch (error) { console.error("There was an error loading a template from id", error); return null;