diff --git a/assets/js/search-manager.js b/assets/js/search-manager.js index 395011f..26e1c4e 100644 --- a/assets/js/search-manager.js +++ b/assets/js/search-manager.js @@ -26,6 +26,27 @@ threshold: 0.4, }; + const INTERNAL_SEARCH_PATTERNS = [ + /https:\/\/blogs\.comphy-lab\.org\/Private-ToDo/i, + /https:\/\/blogs\.comphy-lab\.org\/0_ToDo/i, + /^Private todo blog public/i, + /^0_todo blog public/i, + ]; + + function isInternalSearchEntry(entry) { + const entryIdentityText = [entry?.title, entry?.url] + .filter(Boolean) + .join(" "); + + return INTERNAL_SEARCH_PATTERNS.some((pattern) => + pattern.test(entryIdentityText) + ); + } + + function sanitizeSearchData(data) { + return data.filter((entry) => !isInternalSearchEntry(entry)); + } + /** * Loads the search database from the server * @returns {Promise} Promise that resolves to search data array @@ -61,9 +82,14 @@ ); } - searchData = data; - console.log(`Search database loaded: ${data.length} items`); - return data; + const sanitizedData = sanitizeSearchData(data); + + searchData = sanitizedData; + console.log( + `Search database loaded: ${sanitizedData.length} items ` + + `(${data.length - sanitizedData.length} internal items filtered)` + ); + return sanitizedData; } catch (error) { console.warn("Could not load search database:", error.message); searchData = []; // Set empty array to prevent further attempts diff --git a/tests/search-manager.test.js b/tests/search-manager.test.js new file mode 100644 index 0000000..6a80385 --- /dev/null +++ b/tests/search-manager.test.js @@ -0,0 +1,80 @@ +describe("search-manager sanitization", () => { + beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + document.body.innerHTML = ""; + delete window.SearchManager; + delete window.searchDatabaseForCommandPalette; + }); + + it("filters internal backlog pages from search results", async () => { + global.fetch = jest.fn().mockResolvedValue({ + ok: true, + json: () => + Promise.resolve([ + { + title: "Private todo blog public - Elasticity and viscoelasticity", + url: + "https://blogs.comphy-lab.org/Private-ToDo-Blog-public/" + + "#elasticity-and-viscoelasticity", + content: "internal planning item", + priority: 3, + }, + { + title: "0_todo blog public", + url: "https://blogs.comphy-lab.org/0_ToDo-Blog-public/", + content: "internal backlog page", + priority: 3, + }, + { + title: "Teaching - Teaching: Methods", + url: "https://comphy-lab.org/teaching/#teaching", + content: "public teaching overview", + priority: 3, + }, + ]), + }); + + require("../assets/js/search-manager.js"); + + const data = await window.SearchManager.loadSearchDatabase(); + + expect(data).toHaveLength(1); + expect(data[0].title).toBe("Teaching - Teaching: Methods"); + expect(data[0].url).toBe("https://comphy-lab.org/teaching/#teaching"); + }); + + it("keeps public pages whose content references internal backlog URLs", async () => { + global.fetch = jest.fn().mockResolvedValue({ + ok: true, + json: () => + Promise.resolve([ + { + title: "Skill - Badge Shapes", + url: "https://comphy-lab.org/.agents/skills/add-paper/SKILL/#badge-shapes", + content: + "Example badge config referencing https://blogs.comphy-lab.org/0_ToDo-Blog-public/ for documentation only.", + priority: 3, + }, + { + title: "Private todo blog public - Elasticity and viscoelasticity", + url: + "https://blogs.comphy-lab.org/Private-ToDo-Blog-public/" + + "#elasticity-and-viscoelasticity", + content: "internal planning item", + priority: 3, + }, + ]), + }); + + require("../assets/js/search-manager.js"); + + const data = await window.SearchManager.loadSearchDatabase(); + + expect(data).toHaveLength(1); + expect(data[0].title).toBe("Skill - Badge Shapes"); + expect(data[0].url).toBe( + "https://comphy-lab.org/.agents/skills/add-paper/SKILL/#badge-shapes" + ); + }); +});