content/frontend/search/components/lunr_results.vue (106 lines of code) (raw):
<script>
/* global lunr */
import { GlSearchBoxByClick, GlLink } from '@gitlab/ui';
import { getSearchParamsFromURL, updateURLParams } from '../search_helpers';
import { isArchivesSite } from '../../default/environment';
export default {
components: {
GlSearchBoxByClick,
GlLink,
},
data() {
return {
query: '',
submitted: false,
error: false,
results: [],
contentMap: [],
relevancy_threshold: 15,
};
},
computed: {
noResults() {
return this.submitted && !this.results.length && !this.error;
},
version() {
return document.querySelector('meta[name="gitlab-docs-version"]').content;
},
},
async created() {
try {
// Load the search index and content map.
const [indexResp, mapResp] = await Promise.all([
fetch('/assets/javascripts/lunr-index.json'),
fetch('/assets/javascripts/lunr-map.json'),
]);
const lindex = await indexResp.json();
this.contentMap = await mapResp.json();
// Initialize Lunr.
const idx = lunr.Index.load(lindex);
window.idx = idx;
// If we have a query string in the URL, run the search.
const { qParam } = getSearchParamsFromURL();
if (qParam) {
this.search(qParam);
}
} catch (e) {
this.handleError(e);
}
},
methods: {
onSubmit() {
if (this.query) {
this.search(this.query);
}
},
search(query) {
this.query = query;
this.submitted = true;
// Run the search.
this.results = window.idx.search(this.query);
// Limit the results by relevancy score.
this.results = this.results.filter((key) => key.score > this.relevancy_threshold);
// Add page titles and link paths to the result set.
Object.keys(this.results).forEach((key) => {
const contentItem = this.contentMap.find(({ id }) => id === this.results[key].ref);
this.results[key].title = contentItem.h1;
this.results[key].link = `/${this.results[key].ref}`;
});
// Rewrite links to include the version prefix if this is an archive site.
if (isArchivesSite()) {
this.rewriteResultLinks();
}
updateURLParams({ q: this.query });
},
handleError() {
this.error = true;
},
rewriteResultLinks() {
const pathPrefix = document.querySelector('meta[name="gitlab-docs-version"]').content;
this.results = this.results.map((obj) => ({
...obj,
link: `/${pathPrefix}/${obj.ref}`,
}));
},
},
};
</script>
<template>
<div class="lunr-search gl-mb-9">
<h1 data-testid="version-header">Search the {{ version }} docs</h1>
<gl-search-box-by-click v-model="query" :value="query" @submit="onSubmit" />
<div v-if="results.length" class="gl-font-sm gl-mb-6">
{{ results.length }} results found via
<a href="https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/search.md#lunrjs-search">
Lunr.js
</a>
</div>
<ul v-if="results.length">
<li v-for="result in results" :key="result.ref">
<gl-link :href="result.link">{{ result.title }}</gl-link>
</li>
</ul>
<p v-if="noResults" class="gl-py-5">No results found.</p>
<p v-if="error" class="gl-py-5" data-testid="lunr-error">Error fetching search index.</p>
</div>
</template>