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:
authorSuzanne Selhorn <sselhorn@gitlab.com>2022-12-12 20:12:59 +0300
committerSuzanne Selhorn <sselhorn@gitlab.com>2022-12-12 20:12:59 +0300
commit6ed1eba87a989a36f3203da03be1a49c237d9da7 (patch)
treeeedaa840f41915be5c4f435d6e0ae25e6815d042
parent170cdf3858f92643751f4e4f67189e050c6a1e55 (diff)
parent44a6968c0e93823b3a28a720a6214ae8d87cd903 (diff)
Merge branch 'sarahg/breaking-change-filter' into 'main'
Add a breaking changes filter to the deprecations list See merge request https://gitlab.com/gitlab-org/gitlab-docs/-/merge_requests/3342 Merged-by: Suzanne Selhorn <sselhorn@gitlab.com> Reviewed-by: Brian Rhea <brhea@gitlab.com> Co-authored-by: Sarah German <sgerman@gitlab.com>
-rw-r--r--content/assets/stylesheets/_variables.scss3
-rw-r--r--content/assets/stylesheets/stylesheet.scss5
-rw-r--r--content/frontend/deprecations/components/deprecation_filters.vue164
-rw-r--r--content/frontend/deprecations/filters.js17
-rw-r--r--spec/frontend/deprecations/deprecation_filters_spec.js26
5 files changed, 124 insertions, 91 deletions
diff --git a/content/assets/stylesheets/_variables.scss b/content/assets/stylesheets/_variables.scss
index c71275b5..e1c00677 100644
--- a/content/assets/stylesheets/_variables.scss
+++ b/content/assets/stylesheets/_variables.scss
@@ -375,3 +375,6 @@ $gl-font-size-markdown-h3-md: 1.25rem;
$gl-font-size-markdown-h1-xl: 2.813rem;
$gl-font-size-markdown-h2-xl: 2rem;
$gl-font-size-markdown-h3-xl: 1.438rem;
+
+// Workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2095
+$gl-icon-select-chevron-down: url('data:image/svg+xml,%3Csvg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg"%3E%3Cpath fill-rule="evenodd" clip-rule="evenodd" d="M0.21967 0.21967C0.512563 -0.0732232 0.987437 -0.0732232 1.28033 0.21967L4 2.93934L6.71967 0.21967C7.01256 -0.073223 7.48744 -0.0732229 7.78033 0.21967C8.07322 0.512563 8.07322 0.987437 7.78033 1.28033L4.53033 4.53033C4.23744 4.82322 3.76256 4.82322 3.46967 4.53033L0.21967 1.28033C-0.0732233 0.987437 -0.0732233 0.512563 0.21967 0.21967Z" fill="%23666666"/%3E%3C/svg%3E%0A');
diff --git a/content/assets/stylesheets/stylesheet.scss b/content/assets/stylesheets/stylesheet.scss
index 44a97ef1..256c05ec 100644
--- a/content/assets/stylesheets/stylesheet.scss
+++ b/content/assets/stylesheets/stylesheet.scss
@@ -583,3 +583,8 @@ a.gl-tab-nav-item:hover {
box-shadow: 0 0 0.125rem $landing-gl-black-50, 0 0.25rem 1.5rem $landing-gl-blue-950;
}
}
+
+select[name='removal_milestone'],
+select[name='breaking'] {
+ background-image: $gl-icon-select-chevron-down;
+}
diff --git a/content/frontend/deprecations/components/deprecation_filters.vue b/content/frontend/deprecations/components/deprecation_filters.vue
index b8381d8d..fb9042a2 100644
--- a/content/frontend/deprecations/components/deprecation_filters.vue
+++ b/content/frontend/deprecations/components/deprecation_filters.vue
@@ -1,12 +1,13 @@
<script>
-import { GlFormSelect } from '@gitlab/ui';
+import { GlFormSelect, GlToggle } from '@gitlab/ui';
export default {
components: {
GlFormSelect,
+ GlToggle,
},
props: {
- milestonesList: {
+ milestonesOptions: {
type: Array,
required: true,
},
@@ -17,88 +18,125 @@ export default {
},
data() {
return {
- selected: this.showAllText,
+ emptyText: 'No deprecations found.',
+ hiddenClass: 'gl-display-none',
+ selected: {
+ removal_milestone: this.showAllText,
+ breaking_only: false,
+ },
+ deprecations: [],
+ selectedDeprecations: [],
+ filtered: false,
};
},
+ computed: {
+ noResults() {
+ return this.filtered && this.selectedDeprecations.length === 0;
+ },
+ },
created() {
- // Pre-filter the page if the URL includes a valid version parameter.
+ // Initialize with an array of all deprecations.
+ document.querySelectorAll('.deprecation').forEach((el) => {
+ this.deprecations.push(el.getAttribute('data-deprecation-id'));
+ });
+
+ // Pre-filter the page if the URL includes a parameter.
const searchParams = new URLSearchParams(window.location.search);
- if (!searchParams.has('removal_milestone')) {
- return;
- }
- const version = searchParams.get('removal_milestone').replace(/\./g, '');
- if (this.isValidVersion(version)) {
- this.filterDeprecationList(version);
- this.selected = version;
+ if (searchParams.has('removal_milestone') || searchParams.has('breaking_only')) {
+ this.selected.removal_milestone = searchParams.get('removal_milestone');
+ this.selected.breaking_only = searchParams.get('breaking_only') === 'true';
+ this.filterList();
}
},
methods: {
- isValidVersion(version) {
- return this.milestonesList.some((e) => e.value === version);
- },
- updateURLParams(option) {
- const item = this.milestonesList.find((x) => x.value === option);
+ updateURLParams() {
const url = new URL(window.location);
-
- if (item.text.length > 0 && item.text !== this.showAllText) {
- url.searchParams.set('removal_milestone', item.text);
- } else {
- url.searchParams.delete('removal_milestone');
- }
+ Object.keys(this.selected).forEach((selectName) => {
+ if (this.selected[selectName] !== this.showAllText) {
+ url.searchParams.set(selectName, this.selected[selectName]);
+ }
+ });
window.history.pushState(null, '', url.toString());
},
- /**
- * Filters the page down to a specified removal version.
- *
- * This method hides all deprecations that do not have the selected version
- * in their wrapper div's class lists.
- *
- * @param {String} option
- */
- filterDeprecationList(option) {
- const hiddenClass = 'd-none';
+ filterList() {
+ // Run the deprecations list through both filters.
+ this.selectedDeprecations = this.filterByBreaking(this.filterByVersion(this.deprecations));
- // Reset the list and show all deprecations and headers.
- document.querySelectorAll('.deprecation, h2').forEach(function showAllSections(el) {
- el.classList.remove(hiddenClass);
+ // Hide all headers initially.
+ document.querySelectorAll('.announcement-milestone').forEach((section) => {
+ section.children[0].classList.add(this.hiddenClass);
});
- if (option !== this.showAllText) {
- // Hide deprecations with non-selected versions.
- document
- .querySelectorAll(`.deprecation:not(.removal-${option})`)
- .forEach(function hideDeprecationsAndHeader(el) {
- el.classList.add(hiddenClass);
- // Hide the "announcement version" section header.
- el.parentElement.children[0].classList.add(hiddenClass);
- });
+ // Show selected deprecations; hide the others.
+ this.deprecations.forEach((depId) => {
+ const element = document.querySelector(`[data-deprecation-id="${depId}"]`);
+ if (this.selectedDeprecations.includes(depId)) {
+ element.classList.remove(this.hiddenClass);
+ // Ensure the section header is visible.
+ element.parentElement.children[0].classList.remove(this.hiddenClass);
+ } else {
+ element.classList.add(this.hiddenClass);
+ }
+ });
- // Show the "announcement version" header if we have deprecations in this section.
- document
- .querySelectorAll(`.deprecation.removal-${option}`)
- .forEach(function showHeader(el) {
- el.parentElement.children[0].classList.remove(hiddenClass);
- });
+ this.updateURLParams();
+ this.filtered = true;
+ },
+ filterByVersion(deps) {
+ let filteredDeps = deps;
+ if (this.selected.removal_milestone !== this.showAllText) {
+ filteredDeps = deps.filter((depID) =>
+ document
+ .querySelector(`[data-deprecation-id="${depID}"]`)
+ .classList.contains(`removal-${this.selected.removal_milestone}`),
+ );
}
-
- // Update the removal_milestone parameter in the URL.
- this.updateURLParams(option);
+ return filteredDeps;
+ },
+ filterByBreaking(deps) {
+ let filteredDeps = deps;
+ if (this.selected.breaking_only === true) {
+ filteredDeps = deps.filter((depID) =>
+ document
+ .querySelector(`[data-deprecation-id="${depID}"]`)
+ .classList.contains('breaking-change'),
+ );
+ }
+ return filteredDeps;
},
},
};
</script>
<template>
- <div class="mt-3 row">
- <div class="col-4">
- <label for="milestone" class="d-block col-form-label">Filter by removal version:</label>
- <gl-form-select
- v-model="selected"
- name="milestone"
- :options="milestonesList"
- data-testid="removal-milestone-filter"
- @change="filterDeprecationList(selected)"
- />
+ <div>
+ <div class="gl-mt-7 row">
+ <div class="col gl-md-display-flex">
+ <label
+ for="removal_milestone"
+ class="gl-font-weight-bold gl-mb-0 gl-mr-4 gl-display-flex gl-align-items-center"
+ >Filter by removal version</label
+ >
+ <gl-form-select
+ v-model="selected.removal_milestone"
+ class="gl-md-max-w-15p gl-mr-6"
+ name="removal_milestone"
+ :options="milestonesOptions"
+ data-testid="removal-milestone-filter"
+ @change="filterList()"
+ />
+
+ <gl-toggle
+ v-model="selected.breaking_only"
+ label="Show only breaking changes"
+ class="gl-mt-5 gl-md-mt-0"
+ name="breaking_only"
+ data-testid="breaking-filter"
+ label-position="left"
+ @change="filterList()"
+ />
+ </div>
</div>
+ <p v-if="noResults" class="gl-mt-5!">{{ emptyText }}</p>
</div>
</template>
diff --git a/content/frontend/deprecations/filters.js b/content/frontend/deprecations/filters.js
index 1be9d3a8..472cba50 100644
--- a/content/frontend/deprecations/filters.js
+++ b/content/frontend/deprecations/filters.js
@@ -3,28 +3,33 @@ import { compareVersions } from 'compare-versions';
import DeprecationFilters from './components/deprecation_filters.vue';
/**
+ * Add some helper markup to allow for simpler filter logic.
+ */
+document.querySelectorAll('.deprecation').forEach((el, index) => {
+ el.setAttribute('data-deprecation-id', index + 1);
+});
+
+/**
* Builds an array of removal milestone options from page content.
*
* Each milestone object contains:
* - A text string, used for labels in the select options list.
- * This also appears as a query string value in the URL when filtering.
* - A value string, which is the same as the text string, but without periods.
* This is used to match the query with CSS classes on deprecations.
* CSS classes cannot include periods, so we drop those for this element.
*
* @param {String} showAllText
- * Label for default/unselected state.
* @return {Array}
*/
const buildMilestonesList = (showAllText) => {
let milestones = [];
- document.querySelectorAll('.removal-milestone').forEach(function addOption(el) {
+ document.querySelectorAll('.removal-milestone').forEach((el) => {
if (!milestones.includes(el.innerText)) {
milestones.push(el.innerText);
}
});
milestones.sort(compareVersions).reverse();
- milestones = milestones.map(function addValues(el) {
+ milestones = milestones.map((el) => {
return { value: el.replaceAll('.', ''), text: el };
});
milestones.unshift({ value: showAllText, text: showAllText });
@@ -33,7 +38,7 @@ const buildMilestonesList = (showAllText) => {
document.addEventListener('DOMContentLoaded', () => {
const showAllText = 'Show all';
- const milestonesList = buildMilestonesList(showAllText);
+ const milestonesOptions = buildMilestonesList(showAllText);
return new Vue({
el: '.js-deprecation-filters',
@@ -43,7 +48,7 @@ document.addEventListener('DOMContentLoaded', () => {
render(createElement) {
return createElement(DeprecationFilters, {
props: {
- milestonesList,
+ milestonesOptions,
showAllText,
},
});
diff --git a/spec/frontend/deprecations/deprecation_filters_spec.js b/spec/frontend/deprecations/deprecation_filters_spec.js
index d5149792..5cf28357 100644
--- a/spec/frontend/deprecations/deprecation_filters_spec.js
+++ b/spec/frontend/deprecations/deprecation_filters_spec.js
@@ -5,32 +5,14 @@
import { mount } from '@vue/test-utils';
import DeprecationFilters from '../../../content/frontend/deprecations/components/deprecation_filters.vue';
-const propsData = { showAllText: 'Show all', milestonesList: [{ value: '160', text: '16.0' }] };
+const propsData = { showAllText: 'Show all', milestonesOptions: [{ value: '160', text: '16.0' }] };
const removalsFilterSelector = '[data-testid="removal-milestone-filter"]';
+const breakingFilterSelector = '[data-testid="breaking-filter"]';
describe('component: Deprecations Filter', () => {
- it('Filter is visible', () => {
+ it('Filters are visible', () => {
const wrapper = mount(DeprecationFilters, { propsData });
expect(wrapper.find(removalsFilterSelector).isVisible()).toBe(true);
- });
-
- it('Validates a URL parameter', () => {
- const location = {
- ...window.location,
- search: '?removal_milestone=16.0',
- toString: () => {
- return 'http://localhost/ee/update/deprecations.html';
- },
- };
- Object.defineProperty(window, 'location', {
- writable: true,
- value: location,
- });
-
- const searchParams = new URLSearchParams(window.location.search);
- const versionValue = searchParams.get('removal_milestone').replace(/\./g, '');
-
- const wrapper = mount(DeprecationFilters, { propsData });
- expect(wrapper.vm.isValidVersion(versionValue)).toBe(true);
+ expect(wrapper.find(breakingFilterSelector).isVisible()).toBe(true);
});
});