diff options
Diffstat (limited to 'app/assets/javascripts/pipelines/components')
15 files changed, 187 insertions, 103 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue b/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue index e995d400907..534ad25a35d 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component_wrapper.vue @@ -273,6 +273,7 @@ export default { <local-storage-sync :storage-key="$options.viewTypeKey" :value="currentViewType" + as-string @input="updateViewType" > <graph-view-selector diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue index 795b95421c7..f69b25dfa7c 100644 --- a/app/assets/javascripts/pipelines/components/graph/job_item.vue +++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue @@ -234,8 +234,9 @@ export default { :title="tooltipText" :class="jobClasses" :href="detailsPath" - class="js-pipeline-graph-job-link qa-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none gl-w-full" + class="js-pipeline-graph-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none gl-w-full" :data-testid="testId" + data-qa-selector="job_link" @click="jobItemClick" @mouseout="hideTooltips" > diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue index c59f56fc68f..d59802196af 100644 --- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue +++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue @@ -133,7 +133,7 @@ export default { class="gl-h-full gl-display-flex! gl-border-solid gl-border-gray-100 gl-border-1" :class="flexDirection" :title="tooltipText" - data-qa-selector="child_pipeline" + data-qa-selector="linked_pipeline_container" @mouseover="onDownstreamHovered" @mouseleave="onDownstreamHoverLeave" > @@ -171,7 +171,7 @@ export default { :icon="expandedIcon" :aria-label="__('Expand pipeline')" data-testid="expand-pipeline-button" - data-qa-selector="expand_pipeline_button" + data-qa-selector="expand_linked_pipeline_button" @click="onClickLinkedPipeline" /> </div> diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue index b0f375c9aeb..6ab4eb58977 100644 --- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue @@ -141,7 +141,9 @@ export default { class="gl-display-flex gl-justify-content-space-between gl-relative" :class="$options.titleClasses" > - <div>{{ formattedTitle }}</div> + <span :title="formattedTitle" class="gl-text-truncate gl-pr-3 gl-w-85p"> + {{ formattedTitle }} + </span> <action-component v-if="hasAction && canUpdatePipeline" :action-icon="action.icon" diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue index ac97c9d2743..04b78b8aa23 100644 --- a/app/assets/javascripts/pipelines/components/header_component.vue +++ b/app/assets/javascripts/pipelines/components/header_component.vue @@ -249,8 +249,7 @@ export default { :title="$options.BUTTON_TOOLTIP_RETRY" :loading="isRetrying" :disabled="isRetrying" - category="secondary" - variant="info" + variant="confirm" data-testid="retryPipeline" class="js-retry-button" @click="retryPipeline()" @@ -262,7 +261,6 @@ export default { v-if="canCancelPipeline" :loading="isCanceling" :disabled="isCanceling" - class="gl-ml-3" variant="danger" data-testid="cancelPipeline" @click="cancelPipeline()" diff --git a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue b/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue index fffd8e1818a..70d1a5c08cc 100644 --- a/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue +++ b/app/assets/javascripts/pipelines/components/jobs_shared/job_name_component.vue @@ -1,5 +1,5 @@ <script> -import ciIcon from '../../../vue_shared/components/ci_icon.vue'; +import ciIcon from '~/vue_shared/components/ci_icon.vue'; /** * Component that renders both the CI icon status and the job name. diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue new file mode 100644 index 00000000000..62c785d7ad2 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue @@ -0,0 +1,50 @@ +<script> +import { GlTabs, GlTab } from '@gitlab/ui'; +import { __ } from '~/locale'; +import PipelineGraphWrapper from './graph/graph_component_wrapper.vue'; +import Dag from './dag/dag.vue'; +import JobsApp from './jobs/jobs_app.vue'; +import TestReports from './test_reports/test_reports.vue'; + +export default { + i18n: { + tabs: { + failedJobsTitle: __('Failed Jobs'), + jobsTitle: __('Jobs'), + needsTitle: __('Needs'), + pipelineTitle: __('Pipeline'), + testsTitle: __('Tests'), + }, + }, + components: { + Dag, + GlTab, + GlTabs, + JobsApp, + FailedJobsApp: JobsApp, + PipelineGraphWrapper, + TestReports, + }, +}; +</script> + +<template> + <gl-tabs> + <gl-tab :title="$options.i18n.tabs.pipelineTitle" data-testid="pipeline-tab"> + <pipeline-graph-wrapper /> + </gl-tab> + <gl-tab :title="$options.i18n.tabs.needsTitle" data-testid="dag-tab"> + <dag /> + </gl-tab> + <gl-tab :title="$options.i18n.tabs.jobsTitle" data-testid="jobs-tab"> + <jobs-app /> + </gl-tab> + <gl-tab :title="$options.i18n.tabs.failedJobsTitle" data-testid="failed-jobs-tab"> + <failed-jobs-app /> + </gl-tab> + <gl-tab :title="$options.i18n.tabs.testsTitle" data-testid="tests-tab"> + <test-reports /> + </gl-tab> + <slot></slot> + </gl-tabs> +</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue index 0380ba646cc..5a9c85a0f10 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue @@ -1,7 +1,7 @@ <script> import { GlEmptyState } from '@gitlab/ui'; import { s__ } from '~/locale'; -import PipelinesCiTemplates from './pipelines_ci_templates.vue'; +import PipelinesCiTemplates from './empty_state/pipelines_ci_templates.vue'; export default { i18n: { diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue new file mode 100644 index 00000000000..3b312e78d11 --- /dev/null +++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/ci_templates.vue @@ -0,0 +1,81 @@ +<script> +import { GlAvatar, GlButton } from '@gitlab/ui'; +import { s__, sprintf } from '~/locale'; +import { mergeUrlParams } from '~/lib/utils/url_utility'; +import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants'; +import Tracking from '~/tracking'; + +export default { + components: { + GlAvatar, + GlButton, + }, + mixins: [Tracking.mixin()], + inject: ['pipelineEditorPath', 'suggestedCiTemplates'], + data() { + const templates = this.suggestedCiTemplates.map(({ name, logo }) => { + return { + name, + logo, + link: mergeUrlParams({ template: name }, this.pipelineEditorPath), + description: sprintf(this.$options.i18n.description, { name }), + }; + }); + + return { + templates, + }; + }, + methods: { + trackEvent(template) { + this.track('template_clicked', { + label: template, + }); + }, + }, + i18n: { + description: s__('Pipelines|CI/CD template to test and deploy your %{name} project.'), + cta: s__('Pipelines|Use template'), + }, + AVATAR_SHAPE_OPTION_RECT, +}; +</script> +<template> + <ul class="gl-list-style-none gl-pl-0"> + <li v-for="template in templates" :key="template.name"> + <div + class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-3 gl-pt-3" + > + <div class="gl-display-flex gl-flex-direction-row gl-align-items-center"> + <gl-avatar + :src="template.logo" + :size="48" + class="gl-mr-5 gl-bg-white dark-mode-override" + :shape="$options.AVATAR_SHAPE_OPTION_RECT" + :alt="template.name" + data-testid="template-logo" + /> + <div class="gl-flex-direction-row"> + <div class="gl-mb-3"> + <strong class="gl-text-gray-800" data-testid="template-name"> + {{ template.name }} + </strong> + </div> + <p class="gl-mb-0 gl-font-sm" data-testid="template-description"> + {{ template.description }} + </p> + </div> + </div> + <gl-button + category="primary" + variant="confirm" + :href="template.link" + data-testid="template-link" + @click="trackEvent(template.name)" + > + {{ $options.i18n.cta }} + </gl-button> + </div> + </li> + </ul> +</template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue index d50229e47c4..be46a7f5cec 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_ci_templates.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state/pipelines_ci_templates.vue @@ -1,7 +1,6 @@ <script> -import { GlAvatar, GlButton, GlCard, GlSprintf, GlIcon, GlLink } from '@gitlab/ui'; +import { GlButton, GlCard, GlSprintf, GlIcon, GlLink } from '@gitlab/ui'; import { mergeUrlParams } from '~/lib/utils/url_utility'; -import { sprintf } from '~/locale'; import { STARTER_TEMPLATE_NAME, RUNNERS_AVAILABILITY_SECTION_EXPERIMENT_NAME, @@ -10,21 +9,22 @@ import { RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, I18N, } from '~/pipeline_editor/constants'; +import Tracking from '~/tracking'; import { helpPagePath } from '~/helpers/help_page_helper'; +import { isExperimentVariant } from '~/experimentation/utils'; import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; import ExperimentTracking from '~/experimentation/experiment_tracking'; -import { isExperimentVariant } from '~/experimentation/utils'; -import Tracking from '~/tracking'; +import CiTemplates from './ci_templates.vue'; export default { components: { - GlAvatar, GlButton, GlCard, GlSprintf, GlIcon, GlLink, GitlabExperiment, + CiTemplates, }, mixins: [Tracking.mixin()], STARTER_TEMPLATE_NAME, @@ -33,7 +33,7 @@ export default { RUNNERS_DOCUMENTATION_LINK_CLICKED_EVENT, RUNNERS_SETTINGS_BUTTON_CLICKED_EVENT, I18N, - inject: ['pipelineEditorPath', 'suggestedCiTemplates'], + inject: ['pipelineEditorPath'], props: { ciRunnerSettingsPath: { type: String, @@ -47,17 +47,7 @@ export default { }, }, data() { - const templates = this.suggestedCiTemplates.map(({ name, logo }) => { - return { - name, - logo, - link: mergeUrlParams({ template: name }, this.pipelineEditorPath), - description: sprintf(this.$options.I18N.templates.description, { name }), - }; - }); - return { - templates, gettingStartedTemplateUrl: mergeUrlParams( { template: STARTER_TEMPLATE_NAME }, this.pipelineEditorPath, @@ -177,43 +167,7 @@ export default { <h2 class="gl-font-lg gl-text-gray-900">{{ $options.I18N.templates.title }}</h2> <p class="gl-text-gray-800 gl-mb-6">{{ $options.I18N.templates.subtitle }}</p> - <ul class="gl-list-style-none gl-pl-0"> - <li v-for="template in templates" :key="template.name"> - <div - class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-b-gray-100 gl-pb-3 gl-pt-3" - > - <div class="gl-display-flex gl-flex-direction-row gl-align-items-center"> - <gl-avatar - :src="template.logo" - :size="48" - class="gl-mr-5 gl-bg-white dark-mode-override" - shape="rect" - :alt="template.name" - data-testid="template-logo" - /> - <div class="gl-flex-direction-row"> - <div class="gl-mb-3"> - <strong class="gl-text-gray-800" data-testid="template-name"> - {{ template.name }} - </strong> - </div> - <p class="gl-mb-0 gl-font-sm" data-testid="template-description"> - {{ template.description }} - </p> - </div> - </div> - <gl-button - category="primary" - variant="confirm" - :href="template.link" - data-testid="template-link" - @click="trackEvent(template.name)" - > - {{ $options.I18N.templates.cta }} - </gl-button> - </div> - </li> - </ul> + <ci-templates /> </template> </div> </template> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue index b29c8426301..2a73795db0a 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue @@ -1,10 +1,14 @@ <script> -import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; +import { GlAvatarLink, GlAvatar, GlTooltipDirective } from '@gitlab/ui'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { components: { - UserAvatarLink, + GlAvatarLink, + GlAvatar, + }, + directives: { + GlTooltip: GlTooltipDirective, }, mixins: [glFeatureFlagMixin()], props: { @@ -22,15 +26,11 @@ export default { </script> <template> <div class="pipeline-triggerer" data-testid="pipeline-triggerer"> - <user-avatar-link - v-if="user" - :link-href="user.path" - :img-src="user.avatar_url" - :img-size="32" - :tooltip-text="user.name" - class="gl-ml-3 js-pipeline-url-user" - /> - <span v-else class="gl-ml-3 js-pipeline-url-api api"> + <gl-avatar-link v-if="user" v-gl-tooltip :href="user.path" :title="user.name" class="gl-ml-3"> + <gl-avatar :size="32" :src="user.avatar_url" /> + </gl-avatar-link> + + <span v-else class="gl-ml-3"> {{ s__('Pipelines|API') }} </span> </div> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue index 1dcbd77a92d..63c492c8bcd 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue @@ -2,6 +2,7 @@ import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui'; import { __ } from '~/locale'; 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 } from '../../constants'; import PipelineLabels from './pipeline_labels.vue'; @@ -11,6 +12,7 @@ export default { GlLink, PipelineLabels, TooltipOnTruncate, + UserAvatarLink, }, directives: { GlTooltip: GlTooltipDirective, @@ -169,6 +171,15 @@ export default { <gl-link :href="commitUrl" class="commit-sha mr-0" data-testid="commit-short-sha">{{ commitShortSha }}</gl-link> + <user-avatar-link + v-if="commitAuthor" + :link-href="commitAuthor.path" + :img-src="commitAuthor.avatar_url" + :img-size="16" + :img-alt="commitAuthor.name" + :tooltip-text="commitAuthor.name" + class="gl-ml-1" + /> <!--End of commit row--> </div> <pipeline-labels :pipeline-schedule-url="pipelineScheduleUrl" :pipeline="pipeline" /> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue index 6f0e67e1ae0..77b9c2b5203 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue @@ -127,6 +127,10 @@ export default { eventHub.$emit('refreshPipelinesTable'); }, }, + TBODY_TR_ATTR: { + 'data-testid': 'pipeline-table-row', + 'data-qa-selector': 'pipeline_row_container', + }, }; </script> <template> @@ -135,7 +139,7 @@ export default { :fields="$options.tableFields" :items="pipelines" tbody-tr-class="commit" - :tbody-tr-attr="{ 'data-testid': 'pipeline-table-row' }" + :tbody-tr-attr="$options.TBODY_TR_ATTR" stacked="lg" fixed > diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue index cde963e4051..387438fb726 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue @@ -1,13 +1,12 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import timeagoMixin from '~/vue_shared/mixins/timeago'; +import { formatDate, getTimeago, durationTimeFormatted } from '~/lib/utils/datetime_utility'; export default { directives: { GlTooltip: GlTooltipDirective, }, components: { GlIcon }, - mixins: [timeagoMixin], props: { pipeline: { type: Object, @@ -28,24 +27,7 @@ export default { return this.pipeline.flags.stuck; }, durationFormatted() { - const date = new Date(this.duration * 1000); - - let hh = date.getUTCHours(); - let mm = date.getUTCMinutes(); - let ss = date.getSeconds(); - - // left pad - if (hh < 10) { - hh = `0${hh}`; - } - if (mm < 10) { - mm = `0${mm}`; - } - if (ss < 10) { - ss = `0${ss}`; - } - - return `${hh}:${mm}:${ss}`; + return durationTimeFormatted(this.duration); }, showInProgress() { return !this.duration && !this.finishedTime && !this.skipped; @@ -53,6 +35,12 @@ export default { showSkipped() { return !this.duration && !this.finishedTime && this.skipped; }, + timeFormatted() { + return getTimeago().format(this.finishedTime); + }, + tooltipTitle() { + return formatDate(this.finishedTime); + }, }, }; </script> @@ -85,12 +73,12 @@ export default { <time v-gl-tooltip - :title="tooltipTitle(finishedTime)" + :title="tooltipTitle" :datetime="finishedTime" data-placement="top" data-container="body" > - {{ timeFormatted(finishedTime) }} + {{ timeFormatted }} </time> </p> </div> diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue index 33115d72b9c..746cf238646 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue @@ -83,13 +83,7 @@ export default { @input="searchAuthors" > <template #view="{ inputValue }"> - <gl-avatar - v-if="activeUser" - :size="16" - :src="activeUser.avatar_url" - shape="circle" - class="gl-mr-2" - /> + <gl-avatar v-if="activeUser" :size="16" :src="activeUser.avatar_url" class="gl-mr-2" /> <span>{{ activeUser ? activeUser.name : inputValue }}</span> </template> <template #suggestions> |