Add error handling for create entry errors

This commit is contained in:
Evan Fiordeliso 2025-07-01 11:06:45 -04:00
parent 09d1b08f7d
commit e64e28cbe3
5 changed files with 44 additions and 44 deletions

View File

@ -8,7 +8,7 @@ const GOODREADS_URL_PATTERN = /https:\/\/www.goodreads.com\/book\/show\/(\d+)/;
export class CreateBookFromGoodreadsUrlCommand extends Command { export class CreateBookFromGoodreadsUrlCommand extends Command {
constructor( constructor(
private readonly goodreads: Goodreads, private readonly goodreads: Goodreads,
private readonly cb: (book: Book) => void | PromiseLike<void> private readonly createEntry: (book: Book) => void | PromiseLike<void>
) { ) {
super( super(
"create-book-from-goodreads-url", "create-book-from-goodreads-url",
@ -40,7 +40,14 @@ export class CreateBookFromGoodreadsUrlCommand extends Command {
return; return;
} }
await this.cb(book); try {
await this.createEntry(book);
} catch (error) {
console.error("Failed to create book:", error);
new Notice("Failed to create book. Check console for details.");
return;
}
new Notice("Book created from Goodreads URL."); new Notice("Book created from Goodreads URL.");
} }
} }

View File

@ -8,7 +8,7 @@ export class SearchGoodreadsCommand extends Command {
constructor( constructor(
private readonly app: App, private readonly app: App,
private readonly goodreads: Goodreads, private readonly goodreads: Goodreads,
private readonly cb: (book: Book) => void private readonly createEntry: (book: Book) => void | PromiseLike<void>
) { ) {
super("search-goodreads", "Search Goodreads"); super("search-goodreads", "Search Goodreads");
} }
@ -50,6 +50,14 @@ export class SearchGoodreadsCommand extends Command {
return; return;
} }
this.cb(book); try {
await this.createEntry(book);
} catch (error) {
console.error("Failed to create book:", error);
new Notice("Failed to create book. Check console for details.");
return;
}
new Notice("Book created from search result.");
} }
} }

View File

@ -140,34 +140,30 @@ export default class BookTrackerPlugin extends Plugin {
} }
async createEntry(book: Book): Promise<void> { async createEntry(book: Book): Promise<void> {
try { const fileName = this.templater
const fileName = this.templater .renderTemplate(this.settings.fileNameFormat, {
.renderTemplate(this.settings.fileNameFormat, { title: book.title,
title: book.title, authors: book.authors.map((a) => a.name).join(", "),
authors: book.authors.map((a) => a.name).join(", "), })
}) .replace(/[/:*?<>|""]/g, "");
.replace(/[/:*?<>|""]/g, "");
const data: Record<string, unknown> = { book }; const data: Record<string, unknown> = { book };
if (this.settings.downloadCovers && book.coverImageUrl) { if (this.settings.downloadCovers && book.coverImageUrl) {
const coverImageFile = await this.downloadCoverImage( const coverImageFile = await this.downloadCoverImage(
book.coverImageUrl, book.coverImageUrl,
fileName fileName
);
data.coverImagePath = coverImageFile.path;
}
const renderedContent = await this.templater.renderTemplateFile(
this.settings.templateFile,
data
); );
data.coverImagePath = coverImageFile.path;
const filePath = this.settings.tbrFolder + "/" + fileName + ".md";
const file = await this.app.vault.create(filePath, renderedContent);
await this.app.workspace.getLeaf().openFile(file);
} catch (error) {
console.error("Failed to create book entry:", error);
} }
const renderedContent = await this.templater.renderTemplateFile(
this.settings.templateFile,
data
);
const filePath = this.settings.tbrFolder + "/" + fileName + ".md";
const file = await this.app.vault.create(filePath, renderedContent);
await this.app.workspace.getLeaf().openFile(file);
} }
} }

View File

@ -8,14 +8,12 @@
<script lang="ts"> <script lang="ts">
import { clickOutside } from "@ui/directives"; import { clickOutside } from "@ui/directives";
import { App, Scope } from "obsidian";
import { onMount, type Snippet } from "svelte"; import { onMount, type Snippet } from "svelte";
import { createPopperActions } from "svelte-popperjs"; import { createPopperActions } from "svelte-popperjs";
type T = $$Generic; type T = $$Generic;
type Props = { type Props = {
app: App;
id: string; id: string;
items: Item<T>[]; items: Item<T>[];
value?: T; value?: T;
@ -26,7 +24,6 @@
}; };
let { let {
app,
id, id,
items, items,
value = $bindable(), value = $bindable(),
@ -41,8 +38,8 @@
let selectedIndex = $state(0); let selectedIndex = $state(0);
let listEl: HTMLUListElement | null = $state(null); let listEl: HTMLUListElement | null = $state(null);
onMount(async () => { $effect(() => {
await onChange?.(query); onChange?.(query);
}); });
$effect.root(() => { $effect.root(() => {
@ -101,7 +98,6 @@
const item = items[index]; const item = items[index];
if (!item) return; if (!item) return;
const { text: newQuery, value: newValue } = item; const { text: newQuery, value: newValue } = item;
selectedIndex = index; selectedIndex = index;
expanded = false; expanded = false;
query = newQuery; query = newQuery;
@ -110,11 +106,6 @@
await onSelected?.(newValue); await onSelected?.(newValue);
} }
async function handleInput() {
expanded = true;
await onChange?.(query);
}
async function clearSearch() { async function clearSearch() {
query = ""; query = "";
value = undefined; value = undefined;
@ -159,7 +150,6 @@
class:is-loading={loading} class:is-loading={loading}
aria-busy={loading} aria-busy={loading}
use:clickOutside={() => (expanded = false)} use:clickOutside={() => (expanded = false)}
onfocusout={() => (expanded = false)}
> >
<div class="search-input-container"> <div class="search-input-container">
<input <input
@ -171,7 +161,7 @@
spellcheck="false" spellcheck="false"
role="combobox" role="combobox"
bind:value={query} bind:value={query}
oninput={handleInput} oninput={() => (expanded = true)}
onfocusin={() => (expanded = true)} onfocusin={() => (expanded = true)}
aria-controls={`${id}-list`} aria-controls={`${id}-list`}
aria-autocomplete="list" aria-autocomplete="list"

View File

@ -8,7 +8,6 @@
import type BookTrackerPlugin from "@src/main"; import type BookTrackerPlugin from "@src/main";
import { createSettingsStore } from "./store"; import { createSettingsStore } from "./store";
import { onMount } from "svelte"; import { onMount } from "svelte";
import FieldSuggest from "@ui/components/suggesters/FieldSuggest.svelte";
type Props = { type Props = {
plugin: BookTrackerPlugin; plugin: BookTrackerPlugin;
@ -45,7 +44,7 @@
id="read-folder" id="read-folder"
name="Read Books Folder" name="Read Books Folder"
description="Select the folder to use for Read entries." description="Select the folder to use for Read entries."
bind:value={$settings.tbrFolder} bind:value={$settings.readBooksFolder}
/> />
<ToggleItem <ToggleItem
id="organize-read-books" id="organize-read-books"