diff options
Diffstat (limited to 'app/assets/javascripts/ci/pipelines_page')
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue | 1 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue | 20 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue | 33 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue | 59 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipeline_status_badge.vue (renamed from app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue) | 16 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue | 31 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue | 19 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue | 3 | ||||
-rw-r--r-- | app/assets/javascripts/ci/pipelines_page/pipelines.vue | 81 |
9 files changed, 140 insertions, 123 deletions
diff --git a/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue b/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue index 6e7d6908cd9..728e8541ae3 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/empty_state/no_ci_empty_state.vue @@ -47,6 +47,7 @@ export default { v-else title="" :svg-path="emptyStateSvgPath" + :svg-height="null" :description="$options.i18n.noCiDescription" /> </div> diff --git a/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue index 235126fea0c..0165bbfe69d 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue @@ -7,28 +7,25 @@ export default { GlButton, }, props: { - newPipelinePath: { + ciLintPath: { type: String, required: false, default: null, }, - - resetCachePath: { - type: String, + isResetCacheButtonLoading: { + type: Boolean, required: false, - default: null, + default: false, }, - - ciLintPath: { + newPipelinePath: { type: String, required: false, default: null, }, - - isResetCacheButtonLoading: { - type: Boolean, + resetCachePath: { + type: String, required: false, - default: false, + default: null, }, }, methods: { @@ -61,7 +58,6 @@ export default { category="primary" class="js-run-pipeline" data-testid="run-pipeline-button" - data-qa-selector="run_pipeline_button" > {{ s__('Pipeline|Run pipeline') }} </gl-button> diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue index 082ede60244..8f45094eb74 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_labels.vue @@ -17,16 +17,15 @@ export default { targetProjectFullPath: { default: '', }, + pipelineSchedulesPath: { + default: '', + }, }, props: { pipeline: { type: Object, required: true, }, - pipelineScheduleUrl: { - type: String, - required: true, - }, }, computed: { isScheduled() { @@ -38,6 +37,13 @@ export default { this.pipeline?.project?.full_path !== `/${this.targetProjectFullPath}`, ); }, + showMergedResultsBadge() { + // A merge train pipeline is technically also a merged results pipeline, + // but we want the badges to be mutually exclusive. + return ( + this.pipeline.flags.merged_result_pipeline && !this.pipeline.flags.merge_train_pipeline + ); + }, autoDevopsTagId() { return `pipeline-url-autodevops-${this.pipeline.id}`; }, @@ -52,7 +58,7 @@ export default { <gl-badge v-if="isScheduled" v-gl-tooltip - :href="pipelineScheduleUrl" + :href="pipelineSchedulesPath" target="__blank" :title="__('This pipeline was created by a schedule.')" variant="info" @@ -74,7 +80,7 @@ export default { v-gl-tooltip :title=" s__( - 'Pipeline|This pipeline ran on the contents of this merge request combined with the contents of all other merge requests queued for merging into the target branch.', + 'Pipeline|This pipeline ran on the contents of the merge request combined with the contents of all other merge requests queued for merging into the target branch.', ) " variant="info" @@ -149,7 +155,7 @@ export default { v-gl-tooltip :title=" s__( - `Pipeline|This pipeline ran on the contents of this merge request's source branch, not the target branch.`, + `Pipeline|This pipeline ran on the contents of the merge request's source branch, not the target branch.`, ) " variant="info" @@ -158,6 +164,19 @@ export default { >{{ s__('Pipeline|merge request') }}</gl-badge > <gl-badge + v-if="showMergedResultsBadge" + v-gl-tooltip + :title=" + s__( + `Pipeline|This pipeline ran on the contents of the merge request combined with the contents of the target branch.`, + ) + " + variant="info" + size="sm" + data-testid="pipeline-url-merged-results" + >{{ s__('Pipeline|merged results') }}</gl-badge + > + <gl-badge v-if="isInFork" v-gl-tooltip :title="__('Pipeline ran in fork of project')" diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue index b05bdae65c4..8945bb06862 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue @@ -1,22 +1,22 @@ <script> -import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui'; +import { GlButton, GlTooltipDirective } from '@gitlab/ui'; import Tracking from '~/tracking'; import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, TRACKING_CATEGORIES } from '~/ci/constants'; -import eventHub from '../../event_hub'; import PipelineMultiActions from './pipeline_multi_actions.vue'; import PipelinesManualActions from './pipelines_manual_actions.vue'; +import PipelineStopModal from './pipeline_stop_modal.vue'; export default { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, directives: { GlTooltip: GlTooltipDirective, - GlModalDirective, }, components: { GlButton, PipelineMultiActions, PipelinesManualActions, + PipelineStopModal, }, mixins: [Tracking.mixin()], props: { @@ -24,15 +24,12 @@ export default { type: Object, required: true, }, - cancelingPipeline: { - type: Number, - required: false, - default: null, - }, }, data() { return { + isCanceling: false, isRetrying: false, + showConfirmationModal: false, }; }, computed: { @@ -41,27 +38,36 @@ export default { this.pipeline?.details?.has_manual_actions || this.pipeline?.details?.has_scheduled_actions ); }, - isCancelling() { - return this.cancelingPipeline === this.pipeline.id; - }, }, watch: { pipeline() { - this.isRetrying = false; + if (this.isCanceling || this.isRetrying) { + this.isCanceling = false; + this.isRetrying = false; + } }, }, methods: { + onCloseModal() { + this.showConfirmationModal = false; + }, + onConfirmCancelPipeline() { + this.isCanceling = true; + this.showConfirmationModal = false; + + this.$emit('cancel-pipeline', this.pipeline); + }, handleCancelClick() { + this.showConfirmationModal = true; + this.trackClick('click_cancel_button'); - eventHub.$emit('openConfirmationModal', { - pipeline: this.pipeline, - endpoint: this.pipeline.cancel_path, - }); }, handleRetryClick() { this.isRetrying = true; + this.trackClick('click_retry_button'); - eventHub.$emit('retryPipeline', this.pipeline.retry_path); + + this.$emit('retry-pipeline', this.pipeline); }, trackClick(action) { this.track(action, { label: TRACKING_CATEGORIES.table }); @@ -72,8 +78,19 @@ export default { <template> <div class="gl-text-right"> + <pipeline-stop-modal + :pipeline="pipeline" + :show-confirmation-modal="showConfirmationModal" + @submit="onConfirmCancelPipeline" + @close-modal="onCloseModal" + /> + <div class="btn-group"> - <pipelines-manual-actions v-if="hasActions" :iid="pipeline.iid" /> + <pipelines-manual-actions + v-if="hasActions" + :iid="pipeline.iid" + @refresh-pipeline-table="$emit('refresh-pipelines-table')" + /> <gl-button v-if="pipeline.flags.retryable" @@ -83,7 +100,6 @@ export default { :disabled="isRetrying" :loading="isRetrying" class="js-pipelines-retry-button" - data-qa-selector="pipeline_retry_button" data-testid="pipelines-retry-button" icon="retry" variant="default" @@ -94,11 +110,10 @@ export default { <gl-button v-if="pipeline.flags.cancelable" v-gl-tooltip.hover - v-gl-modal-directive="'confirmation-modal'" :aria-label="$options.BUTTON_TOOLTIP_CANCEL" :title="$options.BUTTON_TOOLTIP_CANCEL" - :loading="isCancelling" - :disabled="isCancelling" + :loading="isCanceling" + :disabled="isCanceling" icon="cancel" variant="danger" category="primary" diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_status_badge.vue index 2da9141df8e..20e2c7e9dce 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipelines_status_badge.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_status_badge.vue @@ -1,6 +1,5 @@ <script> import { TRACKING_CATEGORIES } from '~/ci/constants'; -import { CHILD_VIEW } from '~/ci/pipeline_details/constants'; import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue'; import Tracking from '~/tracking'; import PipelinesTimeago from './time_ago.vue'; @@ -16,18 +15,11 @@ export default { type: Object, required: true, }, - viewType: { - type: String, - required: true, - }, }, computed: { pipelineStatus() { return this.pipeline?.details?.status ?? {}; }, - isChildView() { - return this.viewType === CHILD_VIEW; - }, }, methods: { trackClick() { @@ -39,13 +31,7 @@ export default { <template> <div> - <ci-badge-link - class="gl-mb-3" - :status="pipelineStatus" - :show-text="!isChildView" - data-qa-selector="pipeline_commit_status" - @ciStatusBadgeClick="trackClick" - /> + <ci-badge-link class="gl-mb-3" :status="pipelineStatus" @ciStatusBadgeClick="trackClick" /> <pipelines-timeago :pipeline="pipeline" /> </div> </template> diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue index 9f38be668f2..d62a68f0dcc 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue @@ -7,7 +7,7 @@ import CiIcon from '~/vue_shared/components/ci_icon.vue'; /** * Pipeline Stop Modal. * - * Renders the modal used to confirm stopping a pipeline. + * Renders the modal used to confirm cancelling a pipeline. */ export default { components: { @@ -22,8 +22,15 @@ export default { required: true, deep: true, }, + showConfirmationModal: { + type: Boolean, + required: true, + }, }, computed: { + hasRef() { + return !isEmpty(this.pipeline.ref); + }, modalTitle() { return sprintf( s__('Pipeline|Stop pipeline #%{pipelineId}?'), @@ -34,10 +41,7 @@ export default { ); }, modalText() { - return s__(`Pipeline|You’re about to stop pipeline #%{pipelineId}.`); - }, - hasRef() { - return !isEmpty(this.pipeline.ref); + return s__(`Pipeline|You're about to stop pipeline #%{pipelineId}.`); }, primaryProps() { return { @@ -45,10 +49,13 @@ export default { attributes: { variant: 'danger' }, }; }, - cancelProps() { - return { - text: __('Cancel'), - }; + showModal: { + get() { + return this.showConfirmationModal; + }, + set() { + this.$emit('close-modal'); + }, }, }, methods: { @@ -56,14 +63,16 @@ export default { this.$emit('submit', event); }, }, + cancelProps: { text: __('Cancel') }, }; </script> <template> <gl-modal + v-model="showModal" modal-id="confirmation-modal" :title="modalTitle" :action-primary="primaryProps" - :action-cancel="cancelProps" + :action-cancel="$options.cancelProps" @primary="emitSubmit($event)" > <p> @@ -74,7 +83,7 @@ export default { </gl-sprintf> </p> - <p v-if="pipeline"> + <p> <ci-icon v-if="pipeline.details" :status="pipeline.details.status" diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue index edaeb481d7b..9a49eefbf98 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_url.vue @@ -4,7 +4,7 @@ import { __ } from '~/locale'; import Tracking from '~/tracking'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; -import { ICONS, TRACKING_CATEGORIES } from '~/ci/constants'; +import { ICONS, PIPELINE_ID_KEY, PIPELINE_IID_KEY, TRACKING_CATEGORIES } from '~/ci/constants'; import PipelineLabels from './pipeline_labels.vue'; export default { @@ -24,13 +24,13 @@ export default { type: Object, required: true, }, - pipelineScheduleUrl: { + pipelineIdType: { type: String, - required: true, - }, - pipelineKey: { - type: String, - required: true, + required: false, + default: PIPELINE_ID_KEY, + validator(value) { + return value === PIPELINE_IID_KEY || value === PIPELINE_ID_KEY; + }, }, refClass: { type: String, @@ -173,9 +173,8 @@ export default { :href="pipeline.path" class="gl-mr-1 gl-text-blue-500!" data-testid="pipeline-url-link" - data-qa-selector="pipeline_url_link" @click="trackClick('click_pipeline_id')" - >#{{ pipeline[pipelineKey] }}</gl-link + >#{{ pipeline[pipelineIdType] }}</gl-link > <!--Commit row--> <div class="gl-display-inline-flex gl-rounded-base gl-px-2 gl-bg-gray-50 gl-text-gray-700"> @@ -237,6 +236,6 @@ export default { /> <!--End of commit row--> </div> - <pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" /> + <pipeline-labels :pipeline="pipeline" /> </div> </template> diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue index 4dacd474bde..ebf1744aee2 100644 --- a/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue +++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue @@ -6,7 +6,6 @@ import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_m import { s__, __, sprintf } from '~/locale'; import Tracking from '~/tracking'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; -import eventHub from '../../event_hub'; import { TRACKING_CATEGORIES } from '../../constants'; import getPipelineActionsQuery from '../graphql/queries/get_pipeline_actions.query.graphql'; @@ -94,7 +93,7 @@ export default { .post(`${action.playPath}.json`) .then(() => { this.isLoading = false; - eventHub.$emit('updateTable'); + this.$emit('refresh-pipeline-table'); }) .catch(() => { this.isLoading = false; diff --git a/app/assets/javascripts/ci/pipelines_page/pipelines.vue b/app/assets/javascripts/ci/pipelines_page/pipelines.vue index 87ee5463bb0..faa013079be 100644 --- a/app/assets/javascripts/ci/pipelines_page/pipelines.vue +++ b/app/assets/javascripts/ci/pipelines_page/pipelines.vue @@ -1,5 +1,7 @@ <!-- eslint-disable vue/multi-word-component-names --> <script> +import NO_PIPELINES_SVG from '@gitlab/svgs/dist/illustrations/empty-state/empty-pipeline-md.svg?url'; +import ERROR_STATE_SVG from '@gitlab/svgs/dist/illustrations/pipelines_failed.svg?url'; import { GlEmptyState, GlIcon, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui'; import { isEqual } from 'lodash'; import * as Sentry from '@sentry/browser'; @@ -9,11 +11,12 @@ import { __, s__ } from '~/locale'; import Tracking from '~/tracking'; import { FILTER_TAG_IDENTIFIER, - PipelineKeyOptions, + PIPELINE_ID_KEY, + PIPELINE_IID_KEY, RAW_TEXT_WARNING, TRACKING_CATEGORIES, } from '~/ci/constants'; -import PipelinesTableComponent from '~/ci/common/pipelines_table.vue'; +import PipelinesTable from '~/ci/common/pipelines_table.vue'; import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin'; import { validateParams } from '~/ci/pipeline_details/utils'; import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue'; @@ -27,7 +30,6 @@ import NavigationControls from './components/nav_controls.vue'; import PipelinesFilteredSearch from './components/pipelines_filtered_search.vue'; export default { - PipelineKeyOptions, components: { NoCiEmptyState, GlCollapsibleListbox, @@ -37,7 +39,7 @@ export default { NavigationTabs, NavigationControls, PipelinesFilteredSearch, - PipelinesTableComponent, + PipelinesTable, TablePagination, }, mixins: [PipelinesMixin, Tracking.mixin()], @@ -46,36 +48,10 @@ export default { type: Object, required: true, }, - // Can be rendered in 3 different places, with some visual differences - // Accepts root | child - // `root` -> main view - // `child` -> rendered inside MR or Commit View - viewType: { - type: String, - required: false, - default: 'root', - }, endpoint: { type: String, required: true, }, - pipelineScheduleUrl: { - type: String, - required: false, - default: '', - }, - emptyStateSvgPath: { - type: String, - required: true, - }, - errorStateSvgPath: { - type: String, - required: true, - }, - noPipelinesSvgPath: { - type: String, - required: true, - }, hasGitlabCi: { type: Boolean, required: true, @@ -243,8 +219,9 @@ export default { }, selectedPipelineKeyOption() { return ( - this.$options.PipelineKeyOptions.find((e) => this.visibilityPipelineIdType === e.value) || - this.$options.PipelineKeyOptions[0] + this.$options.pipelineKeyOptions.find( + (option) => this.visibilityPipelineIdType === option.value, + ) || this.$options.pipelineKeyOptions[0] ); }, }, @@ -334,11 +311,12 @@ export default { }, changeVisibilityPipelineIDType(idType) { this.visibilityPipelineIdType = idType; - this.saveVisibilityPipelineIDType(idType); + + if (isLoggedIn()) { + this.saveVisibilityPipelineIDType(idType); + } }, saveVisibilityPipelineIDType(idType) { - if (!isLoggedIn()) return; - this.$apollo .mutate({ mutation: setSortPreferenceMutation, @@ -354,6 +332,20 @@ export default { }); }, }, + errorStateSvgPath: ERROR_STATE_SVG, + noPipelinesSvgPath: NO_PIPELINES_SVG, + pipelineKeyOptions: [ + { + text: __('Show Pipeline ID'), + label: __('Pipeline ID'), + value: PIPELINE_ID_KEY, + }, + { + text: __('Show Pipeline IID'), + label: __('Pipeline IID'), + value: PIPELINE_IID_KEY, + }, + ], }; </script> <template> @@ -393,9 +385,8 @@ export default { /> <gl-collapsible-listbox v-model="visibilityPipelineIdType" - data-testid="pipeline-key-collapsible-box" :toggle-text="selectedPipelineKeyOption.text" - :items="$options.PipelineKeyOptions" + :items="$options.pipelineKeyOptions" @select="changeVisibilityPipelineIDType" /> </div> @@ -411,32 +402,34 @@ export default { <no-ci-empty-state v-else-if="stateToRender === $options.stateMap.emptyState" - :empty-state-svg-path="emptyStateSvgPath" + :empty-state-svg-path="$options.noPipelinesSvgPath" :can-set-ci="canCreatePipeline" :registration-token="registrationToken" /> <gl-empty-state v-else-if="stateToRender === $options.stateMap.error" - :svg-path="errorStateSvgPath" + :svg-path="$options.errorStateSvgPath" + :svg-height="null" :title="s__('Pipelines|There was an error fetching the pipelines.')" :description="s__('Pipelines|Try again in a few moments or contact your support team.')" /> <gl-empty-state v-else-if="stateToRender === $options.stateMap.emptyTab" - :svg-path="noPipelinesSvgPath" + :svg-path="$options.noPipelinesSvgPath" :svg-height="150" :title="emptyTabMessage" /> <div v-else-if="stateToRender === $options.stateMap.tableList"> - <pipelines-table-component + <pipelines-table :pipelines="state.pipelines" - :pipeline-schedule-url="pipelineScheduleUrl" :update-graph-dropdown="updateGraphDropdown" - :view-type="viewType" - :pipeline-key-option="selectedPipelineKeyOption" + :pipeline-id-type="selectedPipelineKeyOption.value" + @cancel-pipeline="onCancelPipeline" + @refresh-pipelines-table="onRefreshPipelinesTable" + @retry-pipeline="onRetryPipeline" /> </div> |