Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-docs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid O'Regan <doregan@gitlab.com>2023-02-18 09:20:53 +0300
committerDavid O'Regan <doregan@gitlab.com>2023-02-18 09:20:53 +0300
commit0f33faabd5810059187b1996fa3a92ba0179c41d (patch)
treec03b0ca7a6183497352d79283a7a8be005d0d38a
parent8593a8ca83f96738661baec8c48e4e3838adfbf8 (diff)
parentf15693455391c9d5403bc91437a055246d0447bf (diff)
Merge branch '1311-gps-filters' into 'main'
Add search filtering options Closes #1311 See merge request https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/3554 Merged-by: David O'Regan <doregan@gitlab.com> Approved-by: Suzanne Selhorn <sselhorn@gitlab.com> Approved-by: David O'Regan <doregan@gitlab.com> Co-authored-by: Sarah German <sgerman@gitlab.com>
-rw-r--r--content/_data/navigation.yaml7
-rw-r--r--content/assets/stylesheets/_utilities.scss11
-rw-r--r--content/assets/stylesheets/stylesheet.scss20
-rw-r--r--content/frontend/search/components/google_results.vue144
-rw-r--r--content/frontend/search/components/search_filters.vue37
-rw-r--r--package.json1
6 files changed, 166 insertions, 54 deletions
diff --git a/content/_data/navigation.yaml b/content/_data/navigation.yaml
index b04ee9e3..943aa3ce 100644
--- a/content/_data/navigation.yaml
+++ b/content/_data/navigation.yaml
@@ -17,6 +17,13 @@
# Options:
#
# - Use "external_url: true" for external URLs in docs and categories
+#
+# Section titles:
+#
+# Section titles are also used as options for filtering search results.
+# If you add, edit, or remove a section_title, you will need to also update
+# the filters in /content/frontend/search/components/search_filters.vue.
+# You may want to get a frontend engineer to assist with this.
sections:
# Documentation from https://gitlab.com/gitlab-org/gitlab
diff --git a/content/assets/stylesheets/_utilities.scss b/content/assets/stylesheets/_utilities.scss
index 5afd4303..4e982393 100644
--- a/content/assets/stylesheets/_utilities.scss
+++ b/content/assets/stylesheets/_utilities.scss
@@ -65,3 +65,14 @@
.gl-fill-blue-400 {
fill: $blue-400;
}
+
+.lg-w-20p {
+ @media (min-width: $bp-lg) {
+ width: 20%;
+ }
+}
+.lg-w-70p {
+ @media (min-width: $bp-lg) {
+ width: 70%;
+ }
+}
diff --git a/content/assets/stylesheets/stylesheet.scss b/content/assets/stylesheets/stylesheet.scss
index a13e0248..b5da36e2 100644
--- a/content/assets/stylesheets/stylesheet.scss
+++ b/content/assets/stylesheets/stylesheet.scss
@@ -596,3 +596,23 @@ select[name='removal_milestone'],
select[name='breaking'] {
background-image: $gl-icon-select-chevron-down;
}
+
+// GitLab UI does not export vendor prefixes in the build we use, so we need to add them here.
+// Otherwise we don't get checkmarks in Chrome and Safari.
+// @see https://caniuse.com/css-masks
+$gl-icon-check: 'data:image/svg+xml,%3Csvg width="8" height="7" viewBox="0 0 8 7" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath d="M1 3.05299L2.99123 5L7 1" stroke="white" stroke-width="2"/%3E%3C/svg%3E%0A';
+
+.custom-control-input[type='checkbox']:checked ~ .custom-control-label,
+.custom-control-input[type='checkbox']:indeterminate ~ .custom-control-label,
+.custom-control-input[type='radio']:checked ~ .custom-control-label {
+ &::after {
+ -webkit-mask-repeat: no-repeat;
+ mask-repeat: no-repeat;
+ -webkit-mask-position: center center;
+ mask-position: center center;
+ }
+}
+.custom-control-input[type='checkbox']:checked ~ .custom-control-label::after {
+ -webkit-mask-image: url('#{$gl-icon-check}');
+ mask-image: url('#{$gl-icon-check}');
+}
diff --git a/content/frontend/search/components/google_results.vue b/content/frontend/search/components/google_results.vue
index 31c1ffaf..cc078674 100644
--- a/content/frontend/search/components/google_results.vue
+++ b/content/frontend/search/components/google_results.vue
@@ -7,11 +7,14 @@ import {
GlSafeHtmlDirective as SafeHtml,
GlPagination,
} from '@gitlab/ui';
+import isEqual from 'lodash.isequal';
import { getSearchQueryFromURL, updateURLParams } from '../search_helpers';
import { GPS_ENDPOINT, GPS_ID } from '../../services/google_search_api';
+import SearchFilters from './search_filters.vue';
export default {
components: {
+ SearchFilters,
GlSearchBoxByClick,
GlLink,
GlLoadingIcon,
@@ -30,6 +33,7 @@ export default {
pageNumber: 1,
response: {},
results: [],
+ activeFilters: [],
};
},
computed: {
@@ -39,11 +43,14 @@ export default {
return `Showing ${startIndex}-${end} of ${this.response.searchInformation.formattedTotalResults} results`;
},
noResults() {
- return this.submitted && !this.loading && !this.results.length && !this.error;
+ return this.query && !this.loading && !this.results.length && !this.error;
},
showPager() {
return (
- this.submitted && this.response.searchInformation.totalResults > this.MAX_RESULTS_PER_PAGE
+ this.submitted &&
+ this.results.length &&
+ this.response.searchInformation.totalResults > this.MAX_RESULTS_PER_PAGE &&
+ !this.loading
);
},
pagerMaxItems() {
@@ -57,22 +64,28 @@ export default {
},
mounted() {
if (this.query) {
- this.search(this.query);
+ this.search(this.query, this.activeFilters);
}
},
methods: {
cleanTitle(title) {
return title.replace(' | GitLab', '');
},
- async fetchGoogleResults() {
+ async fetchGoogleResults(filters) {
let data = {};
+
+ // Construct the query string for additional filters if needed.
+ const filterQuery = filters.length
+ ? `+more:pagemap:metatags-gitlab-docs-section:${filters.join(',')}`
+ : '';
+
try {
const response = await fetch(
GPS_ENDPOINT +
new URLSearchParams({
key: GOOGLE_SEARCH_KEY,
cx: GPS_ID,
- q: this.query,
+ q: `${this.query}${filterQuery}`.replaceAll(' ', '*'),
start: (this.pageNumber - 1) * this.MAX_RESULTS_PER_PAGE + 1,
}),
);
@@ -85,29 +98,36 @@ export default {
},
handleError(error) {
this.error = true;
+ this.loading = false;
throw new Error(`Error code ${error.code}: ${error.message}`);
},
- onSubmit() {
- if (this.query) {
- this.search(this.query);
- }
- },
- async search(query) {
- this.query = query;
+ async search(query, filters = []) {
this.results = [];
+ if (!query) return;
- this.loading = true;
- this.response = await this.fetchGoogleResults();
- this.results = this.response.items ? this.response.items : [];
- this.loading = false;
- this.submitted = true;
- updateURLParams(this.query);
+ // If the query or filters changed, return to page 1 of results.
+ if (query !== this.query || !isEqual(filters, this.activeFilters)) this.pageNumber = 1;
+
+ this.query = query;
+ this.activeFilters = filters;
- // Add a relative link to each result object.
- this.results = this.results.map((obj) => ({
- ...obj,
- relativeLink: obj.link.replace('https://docs.gitlab.com/', '/'),
- }));
+ try {
+ this.loading = true;
+ this.response = await this.fetchGoogleResults(filters);
+ this.results = this.response.items ? this.response.items : [];
+ } catch (error) {
+ this.handleError(error);
+ } finally {
+ this.loading = false;
+ this.submitted = true;
+ updateURLParams(this.query);
+
+ // Add a relative link to each result object.
+ this.results = this.results.map((obj) => ({
+ ...obj,
+ relativeLink: obj.link.replace('https://docs.gitlab.com/', '/'),
+ }));
+ }
},
},
};
@@ -116,46 +136,62 @@ export default {
<template>
<div class="google-search gl-mb-9">
<h1>Search</h1>
- <gl-search-box-by-click v-model="query" :value="query" @submit="onSubmit" />
- <div v-if="results.length" class="gl-font-sm gl-mb-5">
- {{ resultSummary }}
+ <div class="gl-h-11 gl-mb-5">
+ <gl-search-box-by-click v-model="query" :value="query" @submit="search(query)" />
+ <div v-if="results.length" class="gl-font-sm gl-mb-5 gl-ml-1">
+ {{ resultSummary }}
+ </div>
</div>
- <gl-loading-icon v-if="loading" size="lg" class="gl-mt-5" />
+ <div class="results-container gl-lg-display-flex">
+ <div v-if="submitted" class="results-sidebar gl-mb-5 lg-w-20p">
+ <h2 class="gl-mt-0! gl-mb-5!">Filter results</h2>
+ <search-filters @filteredSearch="(filters) => search(query, filters)" />
+ </div>
- <ul
- v-if="results.length"
- class="gl-list-style-none gl-pl-2 gl-max-w-80"
- data-testid="search-results"
- >
- <li v-for="result in results" :key="result.cacheId" class="gl-mb-5!">
- <gl-link
- :href="`${result.relativeLink}`"
- class="gl-font-lg gl-border-bottom-0! gl-hover-text-decoration-underline:hover gl-mb-2"
- >{{ cleanTitle(result.title) }}</gl-link
- >
- <p v-safe-html="result.htmlSnippet" class="result-snippet"></p>
- </li>
- </ul>
+ <div class="lg-w-70p">
+ <gl-loading-icon v-if="loading" size="lg" class="gl-mt-5 gl-text-center" />
- <gl-pagination
- v-if="showPager"
- v-model="pageNumber"
- :per-page="MAX_RESULTS_PER_PAGE"
- :total-items="pagerMaxItems"
- class="gl-mt-9"
- @input="search(query)"
- />
+ <ul v-if="results.length" class="gl-list-style-none gl-pl-2" data-testid="search-results">
+ <li v-for="result in results" :key="result.cacheId" class="gl-mb-5!">
+ <gl-link
+ :href="`${result.relativeLink}`"
+ class="gl-font-lg gl-border-bottom-0! gl-hover-text-decoration-underline:hover gl-mb-2"
+ >{{ cleanTitle(result.title) }}
+ </gl-link>
+ <p v-safe-html="result.htmlSnippet" class="result-snippet"></p>
+ </li>
+ </ul>
- <p v-if="noResults" class="gl-py-5">No results found.</p>
- <p v-if="error" class="gl-py-5" data-testid="search-error">
- Error fetching results. Please try again later.
- </p>
+ <gl-pagination
+ v-if="showPager"
+ v-model="pageNumber"
+ :per-page="MAX_RESULTS_PER_PAGE"
+ :total-items="pagerMaxItems"
+ class="gl-mt-9"
+ @input="search(query, activeFilters)"
+ />
+
+ <p v-if="noResults" class="gl-py-5">
+ No results found. Try adjusting your search terms, or searching the
+ <gl-link class="gl-font-base" href="https://forum.gitlab.com/">community forum</gl-link>.
+ </p>
+ <p v-if="error" class="gl-py-5" data-testid="search-error">
+ Error fetching results. Please try again later.
+ </p>
+ </div>
+ </div>
</div>
</template>
-<style scoped>
+<style>
+html {
+ overflow-y: scroll;
+}
.result-snippet {
font-size: 0.875rem;
}
+.results-sidebar h2 {
+ font-size: 1.5rem;
+}
</style>
diff --git a/content/frontend/search/components/search_filters.vue b/content/frontend/search/components/search_filters.vue
new file mode 100644
index 00000000..6bfec780
--- /dev/null
+++ b/content/frontend/search/components/search_filters.vue
@@ -0,0 +1,37 @@
+<script>
+import { GlFormCheckboxGroup } from '@gitlab/ui';
+
+export default {
+ name: 'SearchFilters',
+ components: {
+ GlFormCheckboxGroup,
+ },
+ data() {
+ return {
+ selected: [],
+ };
+ },
+ created() {
+ this.filters = [
+ {
+ title: 'Sections',
+ options: ['Tutorials', 'Install', 'Administer', 'Use GitLab', 'Develop', 'Contribute'],
+ },
+ ];
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div v-for="filter in filters" :key="filter.title">
+ <h3 class="gl-font-lg! gl-mt-5! gl-mb-3!">{{ filter.title }}</h3>
+ <gl-form-checkbox-group
+ v-model="selected"
+ :label="filter.title"
+ :options="filter.options"
+ @input="$emit('filteredSearch', selected)"
+ />
+ </div>
+ </div>
+</template>
diff --git a/package.json b/package.json
index 615ac8fa..fa8af755 100644
--- a/package.json
+++ b/package.json
@@ -63,6 +63,7 @@
"instantsearch.js": "^4.50.3",
"jquery": "^3.6.3",
"js-yaml": "^4.1.0",
+ "lodash.isequal": "^4.5.0",
"lunr": "^2.3.9",
"mermaid": "^9.3.0",
"pikaday": "^1.8.2",