diff --git a/src/SearchBar.tsx b/src/SearchBar.tsx index baa061e..dcd8bcb 100644 --- a/src/SearchBar.tsx +++ b/src/SearchBar.tsx @@ -1,18 +1,19 @@ import React, { useEffect, useRef, useState } from 'react'; -import * as SearchFuncs from './search'; +import * as SearchMethods from './search'; import { clearDriftless, setDriftlessTimeout } from "driftless"; import './SearchBar.css' -const SearchBar: React.FC = () => { +const SearchBar: React.FC<{ books: SearchMethods.CalibreItem[] }> = ( {books} ) => { const searchDivRef = useRef(null); const searchBarRef = useRef(null); const searchResultsRef = useRef(null); const [typingTimer, setTypingTimer] = useState(undefined); const exitSearch = () => { - SearchFuncs.exitSearch(); + SearchMethods.exitSearch(); }; useEffect(() => { + searchBarRef.current?.focus(); const handleKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') { exitSearch(); @@ -28,18 +29,17 @@ const SearchBar: React.FC = () => { }, []); useEffect(() => { - searchBarRef.current?.focus(); - }, []); + SearchMethods.searchBook("", books); + }, [books]); const handleInput = () => { if (searchResultsRef.current) { - SearchFuncs.clearSearchResults(); + SearchMethods.clearSearchResults(); clearDriftless(typingTimer); setTypingTimer( setDriftlessTimeout(() => { - if (searchBarRef.current?.value) { - SearchFuncs.getCalibreItems(searchBarRef.current.value); - } + const inputValue = searchBarRef.current?.value || ""; + SearchMethods.searchBook(inputValue, books); }, 750) as unknown as number ); } diff --git a/src/main.tsx b/src/main.tsx index ab64431..dc3abdf 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,9 +4,9 @@ import ReactDOM from 'react-dom' import DigestClient from "digest-fetch"; import Viewer from './Viewer' import SearchBar from './SearchBar' +import * as SearchMethods from './search'; import { SettingSchemaDesc } from "@logseq/libs/dist/LSPlugin.user"; - const settings: SettingSchemaDesc[] = [ { key: "pageHeading", @@ -162,7 +162,9 @@ async function main() { ` , }) - renderSearchbar() + let books = await SearchMethods.getCalibreItems(); + renderSearchbar(books) + // SearchMethods.searchBook("", books); logseq.showMainUI(); const search_bar: HTMLInputElement = document.getElementById("search-bar") as HTMLInputElement; search_bar.focus(); @@ -426,10 +428,10 @@ function renderViewer(srcLink: string) { ) } -function renderSearchbar() { +function renderSearchbar(books: SearchMethods.CalibreItem[]) { ReactDOM.render( - + , document.getElementById('root') ) diff --git a/src/search.ts b/src/search.ts index 0381fda..dbe71d1 100644 --- a/src/search.ts +++ b/src/search.ts @@ -3,42 +3,70 @@ import Fuse from "fuse.js"; import DigestClient from "digest-fetch"; -export async function getCalibreItems(search_input: string): Promise { +export async function getCalibreItems(): Promise { const calibreLibrary = logseq.settings?.calibreLibrary.replace(/ /g, '_'); let fetch_link = `${logseq.settings?.serverLink}/ajax/books/${calibreLibrary}`; - - // Check for double slashes in the URL (excluding the `http://` or `https://` part) - const client = new DigestClient(logseq.settings?.username, logseq.settings?.password); + + // Remove double slashes in the URL (excluding the protocol part) fetch_link = fetch_link.replace(/([^:]\/)\/+/g, '$1'); - + console.log(fetch_link); - + + const client = new DigestClient(logseq.settings?.username, logseq.settings?.password); + try { - const response = await client.fetch(fetch_link); - // const response = await client.fetch(fetch_link); - - if (!response.ok) { - logseq.UI.showMsg("Request to Calibre Content Server failed.", "error"); - console.log(response); - return; - } - - const data = await response.json(); - const books: CalibreItem[] = Object.values(data); - const options = { - threshold: 0.2, - keys: ["title", "authors"], - distance: 1000, - }; - const fuse = new Fuse(books, options); - const search_results: Fuse.FuseResult[] = fuse.search(search_input); - - searchCalibreItems(search_results); + const response = await client.fetch(fetch_link, { + method: 'GET', + headers: { + 'Cache-Control': 'no-cache', // Prevent caching + 'Pragma': 'no-cache' // Older HTTP/1.0 cache control + } + }); + + if (!response.ok) { + logseq.UI.showMsg(` + Failed to fetch data from ${fetch_link}. The server returned status code ${response.status}. Please check the following: + 1. Verify that the URL is correct and accessible in the browser. + 2. Ensure that the Content Server is running. + 3. Confirm that the library ID is accurate. + `, "error"); + return []; + } + + const data = await response.json(); + const books: CalibreItem[] = Object.values(data); + + return books; } catch (error) { - console.error('Fetch or other error:', error); - logseq.UI.showMsg("calibreMetadata: Fail to fetch from Calibre API. Make sure to start the Content Server.", "error"); + console.error(`Unable to fetch data from ${fetch_link}:`, error); + logseq.UI.showMsg(` + Unable to fetch data from ${fetch_link}. + Please ensure that the Content Server is running. + `, "error"); + return []; } - } +} + +export async function searchBook(search_input: string, books: CalibreItem[]): Promise { + // Fetch all Calibre items + + if (search_input === "") { + // If no search input, display all items + displayCalibreItems(books.map(book => ({ item: book, refIndex: -1 }))); + } else { + // Configure Fuse.js options + const options = { + threshold: 0.2, + keys: ["title", "authors"], + distance: 1000, + }; + const fuse = new Fuse(books, options); + const search_results: Fuse.FuseResult[] = fuse.search(search_input); + + // Display the search results + displayCalibreItems(search_results); + } +} function setAttributes(element, attrs) { @@ -72,7 +100,7 @@ export function clearSearchResults() { } // search_results: a list of dictionaries with one key "item" and value metadata of 1 book. -function searchCalibreItems(search_results) { +function displayCalibreItems(search_results) { let calibre_item; let calibre_item_key; @@ -287,7 +315,7 @@ async function create(page_title, page_properties, calibre_item) { } -interface CalibreItem { +export interface CalibreItem { application_id: string; title: string; authors: string[];