From 0257c55081ff32ca0f89469d399e55ba8102cb48 Mon Sep 17 00:00:00 2001 From: Valentyne Stigloher Date: Tue, 17 Dec 2024 20:29:53 +0100 Subject: [PATCH] (search)(terms) add search for terms --- components/search/SearchItemTerm.vue | 29 +++++++++++ pages/search.vue | 1 + server/api/search.get.ts | 73 ++++++++++++++++++++++++++++ server/express/terms.ts | 2 +- 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 components/search/SearchItemTerm.vue diff --git a/components/search/SearchItemTerm.vue b/components/search/SearchItemTerm.vue new file mode 100644 index 000000000..5d682e554 --- /dev/null +++ b/components/search/SearchItemTerm.vue @@ -0,0 +1,29 @@ + + + diff --git a/pages/search.vue b/pages/search.vue index 84a4cd1fd..e9644e357 100644 --- a/pages/search.vue +++ b/pages/search.vue @@ -38,6 +38,7 @@ const searchInput = useTemplateRef('searchInput'); + diff --git a/server/api/search.get.ts b/server/api/search.get.ts index 6cf7152ca..4835db47e 100644 --- a/server/api/search.get.ts +++ b/server/api/search.get.ts @@ -9,6 +9,7 @@ import type { Config } from '~/locale/config.ts'; import { getPosts, type PostMetadata } from '~/server/blog.ts'; import { getNounEntries } from '~/server/express/nouns.ts'; import { getSourcesEntries } from '~/server/express/sources.ts'; +import { getTermsEntries } from '~/server/express/terms.ts'; import { loadSuml, loadSumlFromBase } from '~/server/loader.ts'; import { rootDir } from '~/server/paths.ts'; import { parsePronouns } from '~/src/buildPronoun.ts'; @@ -430,6 +431,77 @@ class SearchIndexBlog extends SearchIndex } } +interface SearchDocumentTerm { + id: number; + type: SearchIndexTerm['TYPE']; + url: string; + title: string; + image: string | undefined; + content: string; +} + +export type SearchResultTerm = SearchDocumentTerm; + +class SearchIndexTerm extends SearchIndex { + TYPE = 'term' as const; + + constructor() { + super(['url', 'title', 'content']); + } + + async getDocuments(config: Config): Promise { + if (!config.terminology.enabled) { + return []; + } + + const runtimeConfig = useRuntimeConfig(); + + const base = encodeURIComponent(config.terminology.route); + + const db = useDatabase(); + const terms = await getTermsEntries(db, () => false); + return terms.map((term, id): SearchDocumentTerm => { + const title = term.term.replaceAll('|', ', '); + + let content = ''; + if (term.original) { + content += `${clearLinkedText(term.original.replaceAll('|', ';'), false)}`; + } + content += ` ${clearLinkedText(term.definition, false)}`; + + let image = undefined; + const flags = JSON.parse(term.flags); + if (flags.length > 0) { + image = `/flags/${flags[0]}.png`; + } else if (term.images) { + image = buildImageUrl(runtimeConfig.public.cloudfront, term.images.split(',')[0], 'flag'); + } + + return { + id, + type: this.TYPE, + url: `/${base}?filter=${term.key}`, + title, + image, + content, + }; + }); + } + + override transform(result: SearchResult): SearchResultTerm { + const document = this.documents[result.id]; + const termsByField = getTermsByField(result.match); + return { + id: document.id, + type: document.type, + url: document.url, + title: highlightMatches(document.title, termsByField.title), + image: document.image, + content: highlightMatches(document.content, termsByField.content, true), + }; + } +} + export default defineEventHandler(async (event) => { const indices = Object.fromEntries( [ @@ -439,6 +511,7 @@ export default defineEventHandler(async (event) => { new SearchIndexLink(), new SearchIndexFaq(), new SearchIndexBlog(), + new SearchIndexTerm(), ].map((index) => [index.TYPE, index]), ); await Promise.all(Object.values(indices).map((index) => index.init(config))); diff --git a/server/express/terms.ts b/server/express/terms.ts index ac920ea6b..7d9d22591 100644 --- a/server/express/terms.ts +++ b/server/express/terms.ts @@ -71,7 +71,7 @@ const linkOtherVersions = async (db: Database, isGranted: Request['isGranted'], const router = Router(); -const getTermsEntries = defineCachedFunction(async (db: Database, isGranted: Request['isGranted']) => { +export const getTermsEntries = defineCachedFunction(async (db: Database, isGranted: Request['isGranted']) => { return await linkOtherVersions( db, isGranted,