From 8202d378cac76f6a3f49058c78e9988daa5432e6 Mon Sep 17 00:00:00 2001 From: Danielo Rodriguez Date: Thu, 14 Sep 2023 13:22:00 +0200 Subject: [PATCH] feat: show better errors fix: dataview input was not filtering --- src/suggesters/suggestFile.ts | 82 +++++++++++++-------------- src/suggesters/suggestFromDataview.ts | 19 ++++--- src/utils/Error.ts | 13 ++++- src/utils/Log.ts | 11 ++-- 4 files changed, 68 insertions(+), 57 deletions(-) diff --git a/src/suggesters/suggestFile.ts b/src/suggesters/suggestFile.ts index f5ae0193..04197ef2 100644 --- a/src/suggesters/suggestFile.ts +++ b/src/suggesters/suggestFile.ts @@ -3,54 +3,54 @@ import { App, TAbstractFile, TFile } from "obsidian"; import { TextInputSuggest } from "./suggest"; import { get_tfiles_from_folder } from "../utils/files"; -import { errorWrapperSync } from "../utils/Error"; +import { tryCatch } from "../utils/Error"; // Instead of hardcoding the logic in separate and almost identical classes, // we move this little logic parts into an interface and we can use the samme // input type and configure it to render file-like, note-like, or whatever we want. export interface FileStrategy { - renderSuggestion(file: TFile): string; - selectSuggestion(file: TFile): string; + renderSuggestion(file: TFile): string; + selectSuggestion(file: TFile): string; } export class FileSuggest extends TextInputSuggest { - constructor( - protected app: App, - public inputEl: HTMLInputElement, - private strategy: FileStrategy, - private folder: string, - ) { - super(app, inputEl); - } - - getSuggestions(input_str: string): TFile[] { - const all_files = errorWrapperSync( - () => get_tfiles_from_folder(this.folder, this.app), - "The folder does not exist" - ); - if (!all_files) { - return []; - } - - const lower_input_str = input_str.toLowerCase(); - - return all_files.filter((file: TAbstractFile) => { - return ( - file instanceof TFile && - file.extension === "md" && - file.path.toLowerCase().contains(lower_input_str) - ); - }); - } - - renderSuggestion(file: TFile, el: HTMLElement): void { - el.setText(this.strategy.renderSuggestion(file)); - } - - selectSuggestion(file: TFile): void { - this.inputEl.value = this.strategy.selectSuggestion(file); - this.inputEl.trigger("input"); - this.close(); - } + constructor( + protected app: App, + public inputEl: HTMLInputElement, + private strategy: FileStrategy, + private folder: string, + ) { + super(app, inputEl); + } + + getSuggestions(input_str: string): TFile[] { + const all_files = tryCatch( + () => get_tfiles_from_folder(this.folder, this.app), + "The folder does not exist" + ); + if (!all_files) { + return []; + } + + const lower_input_str = input_str.toLowerCase(); + + return all_files.filter((file: TAbstractFile) => { + return ( + file instanceof TFile && + file.extension === "md" && + file.path.toLowerCase().contains(lower_input_str) + ); + }); + } + + renderSuggestion(file: TFile, el: HTMLElement): void { + el.setText(this.strategy.renderSuggestion(file)); + } + + selectSuggestion(file: TFile): void { + this.inputEl.value = this.strategy.selectSuggestion(file); + this.inputEl.trigger("input"); + this.close(); + } } diff --git a/src/suggesters/suggestFromDataview.ts b/src/suggesters/suggestFromDataview.ts index 2569264b..8521bfbb 100644 --- a/src/suggesters/suggestFromDataview.ts +++ b/src/suggesters/suggestFromDataview.ts @@ -1,7 +1,8 @@ // Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes import { App, TAbstractFile, TFolder } from "obsidian"; import { TextInputSuggest } from "./suggest"; -import { ModalFormError } from "src/utils/Error"; +import { ModalFormError, tryCatch } from "src/utils/Error"; +import { log_error } from "src/utils/Log"; /** * Offers suggestions based on a dataview query. @@ -13,24 +14,28 @@ export class DataviewSuggest extends TextInputSuggest { constructor( public inputEl: HTMLInputElement, - private dvQuery: string, + dvQuery: string, protected app: App, ) { super(app, inputEl); - this.sandboxedQuery = eval(`(function sandboxedQuery(dv, pages) { return ${dvQuery} })`) - + this.sandboxedQuery = tryCatch( + () => eval(`(function sandboxedQuery(dv, pages) { return ${dvQuery} })`), + "Invalid dataview query" + ) } getSuggestions(inputStr: string): string[] { const dv = this.app.plugins.plugins.dataview?.api if (!dv) { - throw new ModalFormError("Dataview plugin is not enabled") + log_error(new ModalFormError("Dataview plugin is not enabled")) + return []; } const result = this.sandboxedQuery(dv, dv.pages) if (!Array.isArray(result)) { - throw new ModalFormError("The dataview query did not return an array") + log_error(new ModalFormError("The dataview query did not return an array")) + return []; } - return result + return result.filter(r => r.toLowerCase().includes(inputStr.toLowerCase())) } renderSuggestion(option: string, el: HTMLElement): void { diff --git a/src/utils/Error.ts b/src/utils/Error.ts index 80912f96..452eb234 100644 --- a/src/utils/Error.ts +++ b/src/utils/Error.ts @@ -21,10 +21,19 @@ export async function errorWrapper( log_error(e); } return null; -} + } } -export function errorWrapperSync(fn: () => T, msg: string): T | null { +/** + * I case of error, logs it to the console and to the UI + * and returns null + * @export + * @template T + * @param {() => T} fn + * @param {string} msg + * @return {*} {(T | null)} + */ +export function tryCatch(fn: () => T, msg: string): T | null { try { return fn(); } catch (e: any) { diff --git a/src/utils/Log.ts b/src/utils/Log.ts index ec38ea21..133aea2e 100644 --- a/src/utils/Log.ts +++ b/src/utils/Log.ts @@ -5,18 +5,15 @@ export function log_update(msg: string): void { const notice = new Notice("", 15000); // TODO: Find better way for this // @ts-ignore - notice.noticeEl.innerHTML = `Templater update:
${msg}`; + notice.noticeEl.innerHTML = `Modal form update:
${msg}`; } export function log_error(e: Error | ModalFormError): void { const notice = new Notice("", 8000); if (e instanceof ModalFormError && e.console_msg) { - // TODO: Find a better way for this - // @ts-ignore - notice.noticeEl.innerHTML = `Templater Error:
${e.message}
Check console for more information`; - console.error(`Templater Error:`, e.message, "\n", e.console_msg); + notice.noticeEl.innerHTML = `Modal form Error:
${e.message}
Check console for more information`; + console.error(`Modal form Error:`, e.message, "\n", e.console_msg); } else { - // @ts-ignore - notice.noticeEl.innerHTML = `Templater Error:
${e.message}`; + notice.noticeEl.innerHTML = `Modal form Error:
${e.message}`; } }