diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-14 12:09:25 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-14 12:09:25 +0300 |
commit | 3438be0998953aa87854371f42df3c1f47bc2544 (patch) | |
tree | 0a7ff932c9b0ddd62da8f72fb24bd657f02777de /app | |
parent | ca1dcb848f19e854d2022587436fa5bc5f8ef933 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
6 files changed, 94 insertions, 14 deletions
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue index 76ee6ab613b..69509c9088b 100644 --- a/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue +++ b/app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue @@ -1,5 +1,6 @@ <script> -import { GlBadge, GlFriendlyWrap, GlLink, GlModal } from '@gitlab/ui'; +import { GlBadge, GlFriendlyWrap, GlLink, GlModal, GlTooltipDirective } from '@gitlab/ui'; +import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; import { __, n__, s__, sprintf } from '~/locale'; import CodeBlock from '~/vue_shared/components/code_block.vue'; @@ -11,6 +12,10 @@ export default { GlFriendlyWrap, GlLink, GlModal, + ModalCopyButton, + }, + directives: { + GlTooltip: GlTooltipDirective, }, props: { modalId: { @@ -57,6 +62,7 @@ export default { history: __('History'), trace: __('System output'), attachment: s__('TestReports|Attachment'), + copyTestName: s__('TestReports|Copy test name to rerun locally'), }, modalCloseButton: { text: __('Close'), @@ -85,6 +91,13 @@ export default { {{ testCase.file }} </gl-link> <span v-else>{{ testCase.file }}</span> + <modal-copy-button + :title="$options.text.copyTestName" + :text="testCase.file" + :modal-id="modalId" + category="tertiary" + class="gl-ml-1" + /> </div> </div> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue b/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue index 655ceb5f700..b76d5d90ead 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/actions.vue @@ -1,5 +1,5 @@ <script> -import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlButton, GlDropdown, GlDropdownItem, GlTooltipDirective } from '@gitlab/ui'; import { sprintf, __ } from '~/locale'; export default { @@ -8,6 +8,9 @@ export default { GlDropdown, GlDropdownItem, }, + directives: { + GlTooltip: GlTooltipDirective, + }, props: { widget: { type: String, @@ -19,6 +22,12 @@ export default { default: () => [], }, }, + data: () => { + return { + timeout: null, + updatingTooltip: false, + }; + }, computed: { dropdownLabel() { return sprintf(__('%{widget} options'), { widget: this.widget }); @@ -27,9 +36,29 @@ export default { methods: { onClickAction(action) { this.$emit('clickedAction', action); + if (action.onClick) { action.onClick(); } + + if (action.tooltipOnClick) { + this.updatingTooltip = true; + this.$root.$emit('bv::show::tooltip', action.id); + + clearTimeout(this.timeout); + + this.timeout = setTimeout(() => { + this.updatingTooltip = false; + this.$root.$emit('bv::hide::tooltip', action.id); + }, 1000); + } + }, + setTooltip(btn) { + if (this.updatingTooltip && btn.tooltipOnClick) { + return btn.tooltipOnClick; + } + + return btn.tooltipText; }, }, }; @@ -55,6 +84,7 @@ export default { :key="index" :href="btn.href" :target="btn.target" + :data-clipboard-text="btn.dataClipboardText" @click="onClickAction(btn)" > {{ btn.text }} @@ -63,15 +93,20 @@ export default { <template v-if="tertiaryButtons.length"> <gl-button v-for="(btn, index) in tertiaryButtons" + :id="btn.id" :key="index" + v-gl-tooltip.hover + :title="setTooltip(btn)" :href="btn.href" :target="btn.target" :class="{ 'gl-mr-3': index !== tertiaryButtons.length - 1 }" + :data-clipboard-text="btn.dataClipboardText" + :icon="btn.icon" + :data-testid="btn.testId || 'extension-actions-button'" + :variant="btn.variant || 'confirm'" category="tertiary" - variant="confirm" size="small" class="gl-display-none gl-md-display-block gl-float-left" - data-testid="extension-actions-button" @click="onClickAction(btn)" > {{ btn.text }} diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js index 23f14bea4e1..4994a0bcbeb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js +++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/constants.js @@ -7,6 +7,8 @@ export const TESTS_FAILED_STATUS = 'failed'; export const ERROR_STATUS = 'error'; export const i18n = { + copyFailedSpecs: s__('Reports|Copy failed tests'), + copyFailedSpecsTooltip: s__('Reports|Copy failed test names to run locally'), label: s__('Reports|Test summary'), loading: s__('Reports|Test summary results are loading'), error: s__('Reports|Test summary failed to load results'), diff --git a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js index 560ead9889b..c74445a5b80 100644 --- a/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js +++ b/app/assets/javascripts/vue_merge_request_widget/extensions/test_report/index.js @@ -1,4 +1,5 @@ import { uniqueId } from 'lodash'; +import { __ } from '~/locale'; import axios from '~/lib/utils/axios_utils'; import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue'; import { EXTENSION_ICONS } from '../../constants'; @@ -19,6 +20,20 @@ export default { props: ['testResultsPath', 'headBlobPath', 'pipeline'], modalComponent: TestCaseDetails, computed: { + failedTestNames() { + if (!this.collapsedData?.suites) { + return ''; + } + + const newFailures = this.collapsedData?.suites.flatMap((suite) => [suite.new_failures || []]); + const fileNames = newFailures.flatMap((newFailure) => { + return newFailure.map((failure) => { + return failure.file; + }); + }); + + return fileNames.join(' '); + }, summary(data) { if (data.parsingInProgress) { return this.$options.i18n.loading; @@ -41,14 +56,29 @@ export default { return EXTENSION_ICONS.success; }, tertiaryButtons() { - return [ - { - text: this.$options.i18n.fullReport, - href: `${this.pipeline.path}/test_report`, - target: '_blank', - fullReport: true, - }, - ]; + const actionButtons = []; + + if (this.failedTestNames().length > 0) { + actionButtons.push({ + dataClipboardText: this.failedTestNames(), + id: uniqueId('copy-to-clipboard'), + icon: 'copy-to-clipboard', + testId: 'copy-failed-specs-btn', + text: this.$options.i18n.copyFailedSpecs, + tooltipText: this.$options.i18n.copyFailedSpecsTooltip, + tooltipOnClick: __('Copied'), + }); + } + + actionButtons.push({ + text: this.$options.i18n.fullReport, + href: `${this.pipeline.path}/test_report`, + target: '_blank', + fullReport: true, + testId: 'full-report-link', + }); + + return actionButtons; }, }, methods: { diff --git a/app/graphql/mutations/user_callouts/create.rb b/app/graphql/mutations/user_callouts/create.rb index 1be99ea0ecd..7f372053e84 100644 --- a/app/graphql/mutations/user_callouts/create.rb +++ b/app/graphql/mutations/user_callouts/create.rb @@ -15,7 +15,7 @@ module Mutations description: 'User callout dismissed.' def resolve(feature_name:) - callout = Users::DismissCalloutService.new( + callout = ::Users::DismissCalloutService.new( container: nil, current_user: current_user, params: { feature_name: feature_name } ).execute errors = errors_on_object(callout) diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml index d6dd7fcc316..50bfd3c6976 100644 --- a/app/views/projects/settings/operations/show.html.haml +++ b/app/views/projects/settings/operations/show.html.haml @@ -16,7 +16,7 @@ .gl-alert-body %p = html_escape(s_('Deprecations|The metrics feature was deprecated in GitLab 14.7.')) - = html_escape(s_('Deprecations|The logs and tracing features were also deprecated in GitLab 14.7, and are %{removal_link_start} scheduled for removal %{link_end} in GitLab 15.0.')) % {removal_link_start: removal_epic_link_start, link_end: link_end } if Feature.enabled?(:monitor_tracing, @project) + = html_escape(s_('Deprecations|The logs and tracing features were also deprecated in GitLab 14.7, and are %{removal_link_start} scheduled for removal %{link_end} in GitLab 15.0.')) % {removal_link_start: removal_epic_link_start, link_end: link_end } = html_escape(s_('Deprecations|For information on a possible replacement, %{opstrace_link_start} learn more about Opstrace %{link_end}.')) % {opstrace_link_start: opstrace_link_start, link_end: link_end } = render 'projects/settings/operations/metrics_dashboard' |