diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-11 00:09:24 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-11 00:09:24 +0300 |
commit | 02c3b2af448be6a5004e8d833cbcbf8e5f185210 (patch) | |
tree | 27359dc5c21a8901c9eb95a0101cb97087b1f4ac /app | |
parent | 577bb49691b11bc8ebae3a4966153ed39af60d87 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
21 files changed, 166 insertions, 39 deletions
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue index fad98a66636..71560bd979f 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue +++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue @@ -6,7 +6,7 @@ import pipelinesMixin from '~/pipelines/mixins/pipelines'; import eventHub from '~/pipelines/event_hub'; import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; import { getParameterByName } from '~/lib/utils/common_utils'; -import CIPaginationMixin from '~/vue_shared/mixins/ci_pagination_api_mixin'; +import PipelinesPaginationApiMixin from '~/pipelines/mixins/pipelines_pagination_api_mixin'; export default { components: { @@ -16,7 +16,7 @@ export default { GlModal, GlLink, }, - mixins: [pipelinesMixin, CIPaginationMixin], + mixins: [pipelinesMixin, PipelinesPaginationApiMixin], props: { endpoint: { type: String, diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index 1a8a56e892a..09fe00a4042 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -2,9 +2,9 @@ import { GlBadge, GlButton, GlModalDirective, GlTab, GlTabs } from '@gitlab/ui'; import { deprecatedCreateFlash as Flash } from '~/flash'; import { s__ } from '~/locale'; -import CIPaginationMixin from '~/vue_shared/mixins/ci_pagination_api_mixin'; import eventHub from '../event_hub'; import environmentsMixin from '../mixins/environments_mixin'; +import EnvironmentsPaginationApiMixin from '../mixins/environments_pagination_api_mixin'; import emptyState from './empty_state.vue'; import EnableReviewAppModal from './enable_review_app_modal.vue'; import StopEnvironmentModal from './stop_environment_modal.vue'; @@ -33,7 +33,7 @@ export default { directives: { 'gl-modal': GlModalDirective, }, - mixins: [CIPaginationMixin, environmentsMixin], + mixins: [EnvironmentsPaginationApiMixin, environmentsMixin], props: { endpoint: { type: String, diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue index d6244cbe4d7..7dc6c1b36ec 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.vue +++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue @@ -1,7 +1,7 @@ <script> import { GlBadge, GlTab, GlTabs } from '@gitlab/ui'; import environmentsMixin from '../mixins/environments_mixin'; -import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; +import EnvironmentsPaginationApiMixin from '../mixins/environments_pagination_api_mixin'; import StopEnvironmentModal from '../components/stop_environment_modal.vue'; import DeleteEnvironmentModal from '../components/delete_environment_modal.vue'; @@ -14,7 +14,7 @@ export default { StopEnvironmentModal, }, - mixins: [environmentsMixin, CIPaginationMixin], + mixins: [environmentsMixin, EnvironmentsPaginationApiMixin], props: { endpoint: { diff --git a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js b/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js index 85a1ab6092b..b62fe196a6f 100644 --- a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_pagination_api_mixin.js @@ -1,6 +1,5 @@ /** * API callbacks for pagination and tabs - * shared between Pipelines and Environments table. * * Components need to have `scope`, `page` and `requestData` */ diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue index b4eb429748f..46c697f8066 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines.vue @@ -6,7 +6,7 @@ import { deprecatedCreateFlash as createFlash } from '~/flash'; import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue'; import { getParameterByName } from '~/lib/utils/common_utils'; -import CIPaginationMixin from '~/vue_shared/mixins/ci_pagination_api_mixin'; +import PipelinesPaginationApiMixin from '../../mixins/pipelines_pagination_api_mixin'; import pipelinesMixin from '../../mixins/pipelines'; import PipelinesService from '../../services/pipelines_service'; import { validateParams } from '../../utils'; @@ -22,7 +22,7 @@ export default { PipelinesFilteredSearch, GlIcon, }, - mixins: [pipelinesMixin, CIPaginationMixin], + mixins: [pipelinesMixin, PipelinesPaginationApiMixin], props: { store: { type: Object, diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue index 0fe03b3be6b..8f7a2a5025c 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue @@ -5,6 +5,7 @@ import { GlTooltipDirective, GlFriendlyWrap, GlIcon, + GlLink, GlButton, GlPagination, } from '@gitlab/ui'; @@ -16,6 +17,7 @@ export default { components: { GlIcon, GlFriendlyWrap, + GlLink, GlButton, GlPagination, TestCaseDetails, @@ -97,11 +99,9 @@ export default { <div class="table-section section-10 section-wrap"> <div role="rowheader" class="table-mobile-header">{{ __('Filename') }}</div> <div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break"> - <gl-friendly-wrap - v-if="testCase.file" - :symbols="$options.wrapSymbols" - :text="testCase.file" - /> + <gl-link v-if="testCase.file" :href="testCase.filePath" target="_blank"> + <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.file" /> + </gl-link> <gl-button v-if="testCase.file" v-gl-tooltip diff --git a/app/assets/javascripts/pipelines/mixins/pipelines_pagination_api_mixin.js b/app/assets/javascripts/pipelines/mixins/pipelines_pagination_api_mixin.js new file mode 100644 index 00000000000..b62fe196a6f --- /dev/null +++ b/app/assets/javascripts/pipelines/mixins/pipelines_pagination_api_mixin.js @@ -0,0 +1,66 @@ +/** + * API callbacks for pagination and tabs + * + * Components need to have `scope`, `page` and `requestData` + */ +import { validateParams } from '~/pipelines/utils'; +import { historyPushState, buildUrlWithCurrentLocation } from '../../lib/utils/common_utils'; + +export default { + methods: { + onChangeTab(scope) { + if (this.scope === scope) { + return; + } + + let params = { + scope, + page: '1', + }; + + params = this.onChangeWithFilter(params); + + this.updateContent(params); + }, + + onChangePage(page) { + /* URLS parameters are strings, we need to parse to match types */ + let params = { + page: Number(page).toString(), + }; + + if (this.scope) { + params.scope = this.scope; + } + + params = this.onChangeWithFilter(params); + + this.updateContent(params); + }, + + onChangeWithFilter(params) { + return { ...params, ...validateParams(this.requestData) }; + }, + + updateInternalState(parameters) { + // stop polling + this.poll.stop(); + + const queryString = Object.keys(parameters) + .map((parameter) => { + const value = parameters[parameter]; + // update internal state for UI + this[parameter] = value; + return `${parameter}=${encodeURIComponent(value)}`; + }) + .join('&'); + + // update polling parameters + this.requestData = parameters; + + historyPushState(buildUrlWithCurrentLocation(`?${queryString}`)); + + this.isLoading = true; + }, + }, +}; diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js index a61d9244099..69dbc2039e0 100644 --- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js +++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js @@ -58,8 +58,9 @@ const createLegacyPipelinesDetailApp = (mediator) => { const createTestDetails = () => { const el = document.querySelector(SELECTORS.PIPELINE_TESTS); - const { summaryEndpoint, suiteEndpoint } = el?.dataset || {}; + const { blobPath, summaryEndpoint, suiteEndpoint } = el?.dataset || {}; const testReportsStore = createTestReportsStore({ + blobPath, summaryEndpoint, suiteEndpoint, }); diff --git a/app/assets/javascripts/pipelines/stores/test_reports/getters.js b/app/assets/javascripts/pipelines/stores/test_reports/getters.js index c31e7dd114f..1685b4a846c 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/getters.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/getters.js @@ -1,4 +1,4 @@ -import { addIconStatus, formattedTime } from './utils'; +import { addIconStatus, formatFilePath, formattedTime } from './utils'; export const getTestSuites = (state) => { const { test_suites: testSuites = [] } = state.testReports; @@ -17,7 +17,13 @@ export const getSuiteTests = (state) => { const { page, perPage } = state.pageInfo; const start = (page - 1) * perPage; - return testCases.map(addIconStatus).slice(start, start + perPage); + return testCases + .map((testCase) => ({ + ...testCase, + filePath: testCase.file ? `${state.blobPath}/${formatFilePath(testCase.file)}` : null, + })) + .map(addIconStatus) + .slice(start, start + perPage); }; export const getSuiteTestCount = (state) => getSelectedSuite(state)?.test_cases?.length || 0; diff --git a/app/assets/javascripts/pipelines/stores/test_reports/state.js b/app/assets/javascripts/pipelines/stores/test_reports/state.js index 7f5da549a9d..0ee6f53fa58 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/state.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/state.js @@ -1,4 +1,5 @@ -export default ({ summaryEndpoint = '', suiteEndpoint = '' }) => ({ +export default ({ blobPath = '', summaryEndpoint = '', suiteEndpoint = '' }) => ({ + blobPath, summaryEndpoint, suiteEndpoint, testReports: {}, diff --git a/app/assets/javascripts/pipelines/stores/test_reports/utils.js b/app/assets/javascripts/pipelines/stores/test_reports/utils.js index 8d1a941058c..63a58798958 100644 --- a/app/assets/javascripts/pipelines/stores/test_reports/utils.js +++ b/app/assets/javascripts/pipelines/stores/test_reports/utils.js @@ -1,6 +1,15 @@ import { __, sprintf } from '../../../locale'; import { TestStatus } from '../../constants'; +/** + * Removes `./` from the beginning of a file path so it can be appended onto a blob path + * @param {String} file + * @returns {String} - formatted value + */ +export function formatFilePath(file) { + return file.replace(/^\.?\/*/, ''); +} + export function iconForTestStatus(status) { switch (status) { case TestStatus.SUCCESS: diff --git a/app/assets/javascripts/search_settings/components/search_settings.vue b/app/assets/javascripts/search_settings/components/search_settings.vue index de8ec57e255..116967a62c8 100644 --- a/app/assets/javascripts/search_settings/components/search_settings.vue +++ b/app/assets/javascripts/search_settings/components/search_settings.vue @@ -3,20 +3,37 @@ import { GlSearchBoxByType } from '@gitlab/ui'; import { uniq } from 'lodash'; import { EXCLUDED_NODES, HIDE_CLASS, HIGHLIGHT_CLASS, TYPING_DELAY } from '../constants'; +const origExpansions = new Map(); + const findSettingsSection = (sectionSelector, node) => { return node.parentElement.closest(sectionSelector); }; -const resetSections = ({ sectionSelector, expandSection, collapseSection }) => { - document.querySelectorAll(sectionSelector).forEach((section, index) => { - section.classList.remove(HIDE_CLASS); - - if (index === 0) { +const restoreExpansionState = ({ expandSection, collapseSection }) => { + origExpansions.forEach((isExpanded, section) => { + if (isExpanded) { expandSection(section); } else { collapseSection(section); } }); + + origExpansions.clear(); +}; + +const saveExpansionState = (sections, { isExpanded }) => { + // If we've saved expansions before, don't override it. + if (origExpansions.size > 0) { + return; + } + + sections.forEach((section) => origExpansions.set(section, isExpanded(section))); +}; + +const resetSections = ({ sectionSelector }) => { + document.querySelectorAll(sectionSelector).forEach((section) => { + section.classList.remove(HIDE_CLASS); + }); }; const clearHighlights = () => { @@ -85,6 +102,12 @@ export default { type: String, required: true, }, + isExpandedFn: { + type: Function, + required: false, + // default to a function that returns false + default: () => () => false, + }, }, data() { return { @@ -97,6 +120,7 @@ export default { sectionSelector: this.sectionSelector, expandSection: this.expandSection, collapseSection: this.collapseSection, + isExpanded: this.isExpandedFn, }; this.searchTerm = value; @@ -104,7 +128,11 @@ export default { clearResults(displayOptions); if (value.length) { + saveExpansionState(document.querySelectorAll(this.sectionSelector), displayOptions); + displayResults(displayOptions, search(this.searchRoot, value)); + } else { + restoreExpansionState(displayOptions); } }, expandSection(section) { diff --git a/app/assets/javascripts/search_settings/mount.js b/app/assets/javascripts/search_settings/mount.js index 9c0bc403fe9..260c793a769 100644 --- a/app/assets/javascripts/search_settings/mount.js +++ b/app/assets/javascripts/search_settings/mount.js @@ -1,6 +1,5 @@ import Vue from 'vue'; -import $ from 'jquery'; -import { expandSection, closeSection } from '~/settings_panels'; +import { expandSection, closeSection, isExpanded } from '~/settings_panels'; import SearchSettings from '~/search_settings/components/search_settings.vue'; const mountSearch = ({ el }) => @@ -12,10 +11,11 @@ const mountSearch = ({ el }) => props: { searchRoot: document.querySelector('#content-body'), sectionSelector: '.js-search-settings-section, section.settings', + isExpandedFn: isExpanded, }, on: { - collapse: (section) => closeSection($(section)), - expand: (section) => expandSection($(section)), + collapse: closeSection, + expand: expandSection, }, }), }); diff --git a/app/assets/javascripts/settings_panels.js b/app/assets/javascripts/settings_panels.js index 1f1f6e42576..2c6da5669ef 100644 --- a/app/assets/javascripts/settings_panels.js +++ b/app/assets/javascripts/settings_panels.js @@ -1,7 +1,22 @@ import $ from 'jquery'; import { __ } from './locale'; -export function expandSection($section) { +/** + * Returns true if the given section is expanded or not + * + * For legacy consistency, it supports both jQuery and DOM elements + * + * @param {jQuery | Element} section + */ +export function isExpanded(sectionArg) { + const section = sectionArg instanceof $ ? sectionArg[0] : sectionArg; + + return section.classList.contains('expanded'); +} + +export function expandSection(sectionArg) { + const $section = $(sectionArg); + $section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Collapse')); // eslint-disable-next-line @gitlab/no-global-event-off $section.find('.settings-content').off('scroll.expandSection').scrollTop(0); @@ -13,7 +28,9 @@ export function expandSection($section) { } } -export function closeSection($section) { +export function closeSection(sectionArg) { + const $section = $(sectionArg); + $section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Expand')); $section.find('.settings-content').on('scroll.expandSection', () => expandSection($section)); $section.removeClass('expanded'); @@ -26,7 +43,7 @@ export function closeSection($section) { export function toggleSection($section) { $section.removeClass('no-animate'); - if ($section.hasClass('expanded')) { + if (isExpanded($section)) { closeSection($section); } else { expandSection($section); @@ -38,7 +55,7 @@ export default function initSettingsPanels() { const $section = $(elm); $section.on('click.toggleSection', '.js-settings-toggle', () => toggleSection($section)); - if (!$section.hasClass('expanded')) { + if (!isExpanded($section)) { $section.find('.settings-content').on('scroll.expandSection', () => { $section.removeClass('no-animate'); expandSection($section); diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index f6162f65e21..1383f224979 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -326,7 +326,7 @@ color: $gl-text-color-secondary; } - .badge.badge-pill + span:not(.badge.badge-pill) { + .badge.badge-pill + span:not(.badge):not(.badge-pill) { // Expects up to 3 digits on the badge margin-right: 40px; } diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss index 31a501f3a36..849749ee7c7 100644 --- a/app/assets/stylesheets/startup/startup-dark.scss +++ b/app/assets/stylesheets/startup/startup-dark.scss @@ -903,7 +903,7 @@ table a code { padding: 0; background-color: #4f4f4f; } -.dropdown-menu .badge.badge-pill + span:not(.badge.badge-pill) { +.dropdown-menu .badge.badge-pill + span:not(.badge):not(.badge-pill) { margin-right: 40px; } .dropdown-select { diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss index 103a3999161..44da509481d 100644 --- a/app/assets/stylesheets/startup/startup-general.scss +++ b/app/assets/stylesheets/startup/startup-general.scss @@ -902,7 +902,7 @@ table a code { padding: 0; background-color: #dbdbdb; } -.dropdown-menu .badge.badge-pill + span:not(.badge.badge-pill) { +.dropdown-menu .badge.badge-pill + span:not(.badge):not(.badge-pill) { margin-right: 40px; } .dropdown-select { diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss index 608740078b6..4b88b94f3a6 100644 --- a/app/assets/stylesheets/startup/startup-signin.scss +++ b/app/assets/stylesheets/startup/startup-signin.scss @@ -1174,7 +1174,7 @@ table a code { padding: 0; background-color: #dbdbdb; } -.dropdown-menu .badge.badge-pill + span:not(.badge.badge-pill) { +.dropdown-menu .badge.badge-pill + span:not(.badge):not(.badge-pill) { margin-right: 40px; } .dropdown-select { diff --git a/app/views/layouts/_matomo.html.haml b/app/views/layouts/_matomo.html.haml index ef7c3a62902..81721baba64 100644 --- a/app/views/layouts/_matomo.html.haml +++ b/app/views/layouts/_matomo.html.haml @@ -1,11 +1,10 @@ <!-- Matomo --> -- matomo_disable_cookies = extra_config.has_key?('matomo_disable_cookies') && extra_config.matomo_disable_cookies = javascript_tag do :plain var _paq = window._paq = window._paq || []; _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); - #{matomo_disable_cookies ? '_paq.push(["disableCookies"])' : ""}; + #{extra_config.matomo_disable_cookies ? '_paq.push(["disableCookies"])' : ""}; (function() { var u="//#{extra_config.matomo_url}/"; _paq.push(['setTrackerUrl', u+'matomo.php']); diff --git a/app/views/projects/pipelines/_with_tabs.html.haml b/app/views/projects/pipelines/_with_tabs.html.haml index 0787cf5b735..904b3d6f483 100644 --- a/app/views/projects/pipelines/_with_tabs.html.haml +++ b/app/views/projects/pipelines/_with_tabs.html.haml @@ -82,5 +82,6 @@ #js-tab-tests.tab-pane #js-pipeline-tests-detail{ data: { summary_endpoint: summary_project_pipeline_tests_path(@project, @pipeline, format: :json), - suite_endpoint: project_pipeline_test_path(@project, @pipeline, suite_name: 'suite', format: :json) } } + suite_endpoint: project_pipeline_test_path(@project, @pipeline, suite_name: 'suite', format: :json), + blob_path: project_blob_path(@project, @pipeline.sha) } } = render_if_exists "projects/pipelines/tabs_content", pipeline: @pipeline, project: @project diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index c22025462ce..f26f4adc19a 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -59,7 +59,7 @@ = f.hidden_field 'milestone_id', value: milestone[:id], id: nil = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }}) - if @project.group.present? && issuable_sidebar[:supports_iterations] - = render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type + = render_if_exists 'shared/issuable/iteration_select', can_edit: can_edit_issuable.to_s, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type - if issuable_sidebar[:supports_time_tracking] #issuable-time-tracker.block |