diff options
-rw-r--r-- | .gitlab/ci/build-and-deploy.gitlab-ci.yml | 2 | ||||
-rw-r--r-- | content/_data/navigation.yaml | 9 | ||||
-rw-r--r-- | content/assets/stylesheets/_variables.scss | 3 | ||||
-rw-r--r-- | content/assets/stylesheets/stylesheet.scss | 5 | ||||
-rw-r--r-- | content/frontend/deprecations/components/deprecation_filters.vue | 164 | ||||
-rw-r--r-- | content/frontend/deprecations/filters.js | 17 | ||||
-rw-r--r-- | content/frontend/services/fetch_versions.js | 4 | ||||
-rw-r--r-- | package.json | 12 | ||||
-rw-r--r-- | spec/frontend/deprecations/deprecation_filters_spec.js | 26 | ||||
-rw-r--r-- | yarn.lock | 48 |
10 files changed, 166 insertions, 124 deletions
diff --git a/.gitlab/ci/build-and-deploy.gitlab-ci.yml b/.gitlab/ci/build-and-deploy.gitlab-ci.yml index ce41b369..8de5244c 100644 --- a/.gitlab/ci/build-and-deploy.gitlab-ci.yml +++ b/.gitlab/ci/build-and-deploy.gitlab-ci.yml @@ -105,6 +105,8 @@ review: extends: - .retry - .review-environment + needs: + - compile_dev before_script: [] cache: {} script: diff --git a/content/_data/navigation.yaml b/content/_data/navigation.yaml index 40a84959..ace04018 100644 --- a/content/_data/navigation.yaml +++ b/content/_data/navigation.yaml @@ -1931,14 +1931,17 @@ sections: docs: - doc_title: Vulnerability checks doc_url: 'ee/user/application_security/dast/checks/' + - doc_title: Troubleshooting + doc_url: 'ee/user/application_security/dast/browser_based_troubleshooting.html' - doc_title: DAST proxy-based analyzer doc_url: 'ee/user/application_security/dast/proxy-based.html' + docs: + - doc_title: Troubleshooting + doc_url: 'ee/user/application_security/dast/dast_troubleshooting.html' - doc_title: Authentication doc_url: 'ee/user/application_security/dast/authentication.html' - doc_title: DAST API doc_url: 'ee/user/application_security/dast_api/' - - doc_title: Troubleshooting - doc_url: 'ee/user/application_security/dast/dast_troubleshooting.html' - doc_title: Run DAST offline doc_url: 'ee/user/application_security/dast/run_dast_offline.html' - doc_title: API Fuzzing @@ -1985,6 +1988,8 @@ sections: docs: - doc_title: Environments Dashboard doc_url: 'ee/ci/environments/environments_dashboard.html' + - doc_title: Operations Dashboard + doc_url: 'ee/user/operations_dashboard/' - doc_title: Protected environments doc_url: 'ee/ci/environments/protected_environments.html' - doc_title: Deployment safety 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/content/frontend/services/fetch_versions.js b/content/frontend/services/fetch_versions.js index 16358c1d..4b73d879 100644 --- a/content/frontend/services/fetch_versions.js +++ b/content/frontend/services/fetch_versions.js @@ -51,6 +51,8 @@ export async function getArchivesVersions() { .map((object) => object.name) .filter( (v) => - compareVersions(v, oldestSupportedMinor) >= 0 && compareVersions(v, oldestCurrentMinor) < 0, + compareVersions(v, oldestSupportedMinor) >= 0 && + compareVersions(v, oldestCurrentMinor) < 0 && + !Object.values(onlineVersions).flat().includes(v), ); } diff --git a/package.json b/package.json index 6d3421ce..855427ad 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,11 @@ "@babel/core": "^7.20.5", "@babel/eslint-parser": "^7.19.1", "@babel/preset-env": "^7.20.2", - "@evilmartians/lefthook": "^1.2.3", + "@evilmartians/lefthook": "^1.2.4", "@gitlab/eslint-plugin": "^18.1.0", "@gitlab/stylelint-config": "^4.1.0", "@rollup/plugin-babel": "^6.0.3", - "@rollup/plugin-commonjs": "^23.0.3", + "@rollup/plugin-commonjs": "^23.0.4", "@rollup/plugin-inject": "^5.0.2", "@rollup/plugin-json": "^5.0.2", "@rollup/plugin-node-resolve": "^13.3.0", @@ -32,9 +32,9 @@ "jest-environment-jsdom": "^29.3.1", "jest-fail-on-console": "^3.0.2", "markdownlint-cli": "^0.32.2", - "postcss": "^8.4.19", - "prettier": "^2.8.0", - "rollup": "^3.5.1", + "postcss": "^8.4.20", + "prettier": "^2.8.1", + "rollup": "^3.7.3", "rollup-plugin-import-resolver": "^1.2.1", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-vue": "^5.1.9", @@ -45,7 +45,7 @@ "@docsearch/css": "^3.3.0", "@docsearch/js": "3", "@gitlab/svgs": "^3.13.0", - "@gitlab/ui": "^52.0.0", + "@gitlab/ui": "^52.3.1", "@popperjs/core": "^2.11.6", "algoliasearch": "^4.14.2", "bootstrap": "^4.6.1", 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); }); }); @@ -1143,10 +1143,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@evilmartians/lefthook@^1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@evilmartians/lefthook/-/lefthook-1.2.3.tgz#08ceb828daab5ae5e5d8bbc30455710cfbe51044" - integrity sha512-kmB0+Wgj5cgvUG5mMnuaBWo8KI+eWJsL8XN/aRwmuW0/IsHqhJUfzc+9X7fgyTTjNC/QhUeU0BOs+auYF0AnzA== +"@evilmartians/lefthook@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@evilmartians/lefthook/-/lefthook-1.2.4.tgz#e592d603db5fbf587fea8d560895d31c247818e7" + integrity sha512-dZb/eleGFas3vs2qXtpcs85LzVUHt9f43D9MY6/DB1IFNIkFDhnTYzrZ25jTabqH1laiJ5hVHtpeH/xXOhMcnA== "@gitlab/eslint-plugin@^18.1.0": version "18.1.0" @@ -1180,10 +1180,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.13.0.tgz#2d62286c956bd49ba7156b2aa4eed79507baca53" integrity sha512-Yv4dZ4pOyUVMCZXNxLuMinZ/x8E6+g8/yM1z/2ERT0t7hSAC3bCUHn2OEFpujtYzFtwMZXMFPQFEJJipQ1I/+w== -"@gitlab/ui@^52.0.0": - version "52.0.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-52.0.0.tgz#dfd1c0848a72fd872b1923567352c80b59afb0e2" - integrity sha512-vhjztkUc1Dol3sWVNNdpDWMuvj/TDCOnQZxSE2cXSYAeSdteUMrBLu9VdkIpIDoyPltDkGhtinzi5RaU1EVoqw== +"@gitlab/ui@^52.3.1": + version "52.3.1" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-52.3.1.tgz#87149dce78eca8e314036c61de4fcfa75eba2b9e" + integrity sha512-w53vBnEl9sUv6HqqrFbr9oSJhbIfwPGAIo1TVkyptOsc+RqlyN8D15WVHzId9CL+KSMNUxyKuNsUtchGGIUEGQ== dependencies: "@popperjs/core" "^2.11.2" bootstrap-vue "2.20.1" @@ -1519,10 +1519,10 @@ "@babel/helper-module-imports" "^7.18.6" "@rollup/pluginutils" "^5.0.1" -"@rollup/plugin-commonjs@^23.0.3": - version "23.0.3" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.3.tgz#442cd8ccca1b7563a503da86fc84a1a7112b54bb" - integrity sha512-31HxrT5emGfTyIfAs1lDQHj6EfYxTXcwtX5pIIhq+B/xZBNIqQ179d/CkYxlpYmFCxT78AeU4M8aL8Iv/IBxFA== +"@rollup/plugin-commonjs@^23.0.4": + version "23.0.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.4.tgz#854e9b1a83f0a715ded70a2ae411bebc11141de2" + integrity sha512-bOPJeTZg56D2MCm+TT4psP8e8Jmf1Jsi7pFUMl8BN5kOADNzofNHe47+84WVCt7D095xPghC235/YKuNDEhczg== dependencies: "@rollup/pluginutils" "^5.0.1" commondir "^1.0.1" @@ -6072,10 +6072,10 @@ postcss@^7.0.36: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.4.14, postcss@^8.4.19: - version "8.4.19" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" - integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== +postcss@^8.4.14, postcss@^8.4.19, postcss@^8.4.20: + version "8.4.20" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56" + integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g== dependencies: nanoid "^3.3.4" picocolors "^1.0.0" @@ -6096,10 +6096,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -"prettier@^1.18.2 || ^2.0.0", prettier@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.0.tgz#c7df58393c9ba77d6fba3921ae01faf994fb9dc9" - integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA== +"prettier@^1.18.2 || ^2.0.0", prettier@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.1.tgz#4e1fd11c34e2421bc1da9aea9bd8127cd0a35efc" + integrity sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg== pretty-format@^29.3.1: version "29.3.1" @@ -6502,10 +6502,10 @@ rollup-pluginutils@^2.8.2: dependencies: estree-walker "^0.6.1" -rollup@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.5.1.tgz#5aefd0d29288ce686239fa8c2e3de87c27708ae1" - integrity sha512-hdQWTvPeiAbM6SUkxV70HdGUVxsgsc+CLy5fuh4KdgUBJ0SowXiix8gANgXoG3wEuLwfoJhCT2V+WwxfWq9Ikw== +rollup@^3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.7.3.tgz#d440adff5f89099fd1f552e4e4333045e3bc71d4" + integrity sha512-7e68MQbAWCX6mI4/0lG1WHd+NdNAlVamg0Zkd+8LZ/oXojligdGnCNyHlzXqXCZObyjs5FRc3AH0b17iJESGIQ== optionalDependencies: fsevents "~2.3.2" |